Expression FieldValue(IParser parser, Expression var, Expression valueType, Type schemaType, bool initialize) { Expression body; if (schemaType.IsBondStruct() && var.Type.IsValueType()) { // Special handling for properties of struct types: we deserialize into // a temp variable and then assign the value to the property. var temp = Expression.Variable(var.Type, $"{var.Type.Name}_temp"); body = Expression.Block( new[] { temp }, Value(parser, temp, valueType, schemaType, true), Expression.Assign(var, temp)); } else { body = Value(parser, var, valueType, schemaType, initialize); } if (schemaType.IsBondContainer() || schemaType.IsBondStruct() || schemaType.IsBondNullable()) { var expectedType = Expression.Constant(schemaType.GetBondDataType()); return(PrunedExpression.IfThenElse( Expression.Equal(valueType, expectedType), body, ThrowExpression.InvalidTypeException(expectedType, valueType))); } return(body); }
Expression Value(IParser parser, Expression valueType) { if (parser.IsBonded) { return(parser.Bonded(value => writer.WriteBonded(PrunedExpression.Convert(value, typeof(IBonded))))); } var switchCases = new List <DeferredSwitchCase> { PrunedExpression.SwitchCase( () => GenerateSerialize(Container, parser), BondDataType.BT_LIST, BondDataType.BT_SET), PrunedExpression.SwitchCase( () => GenerateSerialize(Map, parser), BondDataType.BT_MAP), PrunedExpression.SwitchCase( () => GenerateSerialize(Struct, parser), BondDataType.BT_STRUCT) }; switchCases.AddRange( from type in new[] { BondDataType.BT_BOOL, BondDataType.BT_UINT8, BondDataType.BT_UINT16, BondDataType.BT_UINT32, BondDataType.BT_UINT64, BondDataType.BT_FLOAT, BondDataType.BT_DOUBLE, BondDataType.BT_STRING, BondDataType.BT_INT8, BondDataType.BT_INT16, BondDataType.BT_INT32, BondDataType.BT_INT64, BondDataType.BT_WSTRING } select PrunedExpression.SwitchCase( () => parser.Scalar(Expression.Constant(type), type, value => writer.Write(value, type)), type)); return(PrunedExpression.Switch( valueType, ThrowExpression.InvalidTypeException(valueType), switchCases)); }
Expression Struct(IParser parser, Expression var, Type schemaType, bool initialize) { var body = new List <Expression>(); if (initialize) { body.Add(Expression.Assign(var, newObject(var.Type, schemaType))); } ITransform transform; if (parser.HierarchyDepth > schemaType.GetHierarchyDepth()) { // Parser inheritance hierarchy is deeper than the type we are deserializing. // Recurse until hierarchies align. transform = new Transform( Base: baseParser => Struct(baseParser, var, schemaType, initialize: false)); } else { var baseType = schemaType.GetBaseSchemaType(); transform = new Transform( Fields: from field in schemaType.GetSchemaFields() select new Field( Id: field.Id, Value: (fieldParser, fieldType) => FieldValue( fieldParser, DataExpression.PropertyOrField(var, field.Name), fieldType, field.GetSchemaType(), field.GetDefaultValue() == null), Omitted: () => field.GetModifier() == Modifier.Required ? ThrowExpression.RequiredFieldMissingException( field.DeclaringType.Name, Expression.Constant(field.Name)) : Expression.Empty()), Base: baseParser => baseType != null ? Struct(baseParser, Expression.Convert(var, baseType.GetObjectType()), baseType, initialize: false) : Expression.Empty()); } body.Add(parser.Apply(transform)); return(Expression.Block(body)); }