private static void GenerateWriteValue(WriterGenerationContext context, Variable valueLocal, Type formalType)
{
ObjectWriter.CheckLegality(formalType);
if (formalType.IsEnum)
{
formalType = Enum.GetUnderlyingType(formalType);
}
var writeMethod = typeof(PrimitiveWriter).GetMethod("Write", new[] { formalType });
// if this method is null, then it is a non-primitive (i.e. custom) struct
if (writeMethod != null)
{
context.PushPrimitiveWriterOntoStack();
context.Generator.PushVariableOntoStack(valueLocal);
context.Generator.Emit(OpCodes.Call, writeMethod);
return;
}
var nullableUnderlyingType = Nullable.GetUnderlyingType(formalType);
if (nullableUnderlyingType != null)
{
var hasValueLabel = context.Generator.DefineLabel();
var finishLabel = context.Generator.DefineLabel();
var underlyingValueLocal = context.Generator.DeclareLocal(nullableUnderlyingType);
var underlyingVariable = new Variable(underlyingValueLocal);
context.PushPrimitiveWriterOntoStack();
context.Generator.PushVariableAddressOntoStack(valueLocal);
context.Generator.Emit(OpCodes.Call, formalType.GetProperty("HasValue").GetGetMethod());
context.Generator.Emit(OpCodes.Brtrue_S, hasValueLabel);
context.Generator.PushIntegerOntoStack(0);
context.Generator.Call <PrimitiveWriter>(x => x.Write(false));
context.Generator.Emit(OpCodes.Br_S, finishLabel);
context.Generator.MarkLabel(hasValueLabel);
context.Generator.PushIntegerOntoStack(1);
context.Generator.Call <PrimitiveWriter>(x => x.Write(false));
context.Generator.PushVariableAddressOntoStack(valueLocal);
context.Generator.Emit(OpCodes.Call, formalType.GetProperty("Value").GetGetMethod());
context.Generator.StoreLocalValueFromStack(underlyingValueLocal);
GenerateWriteValue(context, underlyingVariable, nullableUnderlyingType);
context.Generator.MarkLabel(finishLabel);
return;
}
GenerateWriteFields(context, valueLocal, formalType);
}