public object Read(ref ProtoReader.State state, object value) { object[] values = new object[members.Length]; bool invokeCtor = false; if (value == null) { invokeCtor = true; } for (int i = 0; i < values.Length; i++) { values[i] = GetValue(value, i); } int field; while ((field = state.ReadFieldHeader()) > 0) { invokeCtor = true; if (field <= tails.Length) { IRuntimeProtoSerializerNode tail = tails[field - 1]; values[field - 1] = tails[field - 1].Read(ref state, tail.RequiresOldValue ? values[field - 1] : null); } else { state.SkipField(); } } return(invokeCtor ? ctor.Invoke(values) : value); }
public SurrogateSerializer(Type declaredType, MethodInfo toTail, MethodInfo fromTail, IRuntimeProtoSerializerNode rootTail, SerializerFeatures features) { Debug.Assert(declaredType is object, "declaredType"); Debug.Assert(rootTail is object, "rootTail"); Debug.Assert(declaredType == rootTail.ExpectedType || Helpers.IsSubclassOf(declaredType, rootTail.ExpectedType), "surrogate type mismatch"); this.declaredType = declaredType; this.rootTail = rootTail; this.toTail = toTail ?? GetConversion(true); this.fromTail = fromTail ?? GetConversion(false); this.features = features; }
private IRuntimeProtoSerializerNode BuildSerializer(Type parentType) { // note the caller here is MetaType.BuildSerializer, which already has the sync-lock WireType wireType = WireType.String; if (dataFormat == DataFormat.Group) { wireType = WireType.StartGroup; // only one exception } IRuntimeProtoSerializerNode ser = SubItemSerializer.Create(derivedType.Type, derivedType, parentType); return(new TagDecorator(fieldNumber, wireType, false, ser)); }
public DefaultValueDecorator(object defaultValue, IRuntimeProtoSerializerNode tail) : base(tail) { if (defaultValue is null) { throw new ArgumentNullException(nameof(defaultValue)); } Type type = defaultValue.GetType(); if (type != tail.ExpectedType) { throw new ArgumentException("Default value is of incorrect type", nameof(defaultValue)); } this.defaultValue = defaultValue; }
public FieldDecorator(Type forType, FieldInfo field, IRuntimeProtoSerializerNode tail) : base(tail) { if (tail == null) { ThrowHelper.ThrowArgumentNullException(nameof(tail)); } if (field == null) { ThrowHelper.ThrowArgumentNullException(nameof(field)); } if (forType == null) { ThrowHelper.ThrowArgumentNullException(nameof(forType)); } ExpectedType = forType; this.field = field; }
private static void SanityCheck(PropertyInfo property, IRuntimeProtoSerializerNode tail, out bool writeValue, bool nonPublic, bool allowInternal) { if (property is null) { throw new ArgumentNullException(nameof(property)); } writeValue = tail.ReturnsValue && (GetShadowSetter(property) is object || (property.CanWrite && Helpers.GetSetMethod(property, nonPublic, allowInternal) is object)); if (!property.CanRead || Helpers.GetGetMethod(property, nonPublic, allowInternal) is null) { throw new InvalidOperationException($"Cannot serialize property without an accessible get accessor: {property.DeclaringType.FullName}.{property.Name}"); } if (!writeValue && (!tail.RequiresOldValue || tail.ExpectedType.IsValueType)) { // so we can't save the value, and the tail doesn't use it either... not helpful // or: can't write the value, so the struct value will be lost throw new InvalidOperationException($"Cannot apply changes to property {property.DeclaringType.FullName}.{property.Name}"); } }
public NullDecorator(IRuntimeProtoSerializerNode tail) : base(tail) { if (!tail.ReturnsValue) { throw new NotSupportedException("NullDecorator only supports implementations that return values"); } Type tailType = tail.ExpectedType; if (tailType.IsValueType) { ExpectedType = typeof(Nullable <>).MakeGenericType(tailType); } else { ExpectedType = tailType; } }
public EnumMemberSerializer(Type enumType) { if (!enumType.IsEnum) { ThrowHelper.ThrowInvalidOperationException("Expected an enum type; got " + enumType.NormalizeName()); } ExpectedType = enumType ?? throw new ArgumentNullException(nameof(enumType)); _tail = Type.GetTypeCode(enumType) switch { TypeCode.SByte => SByteSerializer.Instance, TypeCode.Int16 => Int16Serializer.Instance, TypeCode.Int32 => Int32Serializer.Instance, TypeCode.Int64 => Int64Serializer.Instance, TypeCode.Byte => ByteSerializer.Instance, TypeCode.UInt16 => UInt16Serializer.Instance, TypeCode.UInt32 => UInt32Serializer.Instance, TypeCode.UInt64 => UInt64Serializer.Instance, _ => default,
public PropertyDecorator(Type forType, PropertyInfo property, IRuntimeProtoSerializerNode tail) : base(tail) { if (tail is null) { ThrowHelper.ThrowArgumentNullException(nameof(tail)); } if (property is null) { ThrowHelper.ThrowArgumentNullException(nameof(property)); } if (forType is null) { ThrowHelper.ThrowArgumentNullException(nameof(forType)); } ExpectedType = forType; this.property = property; SanityCheck(property, tail, out readOptionsWriteValue, true, true); shadowSetter = GetShadowSetter(property); }
public TupleSerializer(RuntimeTypeModel model, ConstructorInfo ctor, MemberInfo[] members, SerializerFeatures features, CompatibilityLevel compatibilityLevel) { this.ctor = ctor ?? throw new ArgumentNullException(nameof(ctor)); this.members = members ?? throw new ArgumentNullException(nameof(members)); this.tails = new IRuntimeProtoSerializerNode[members.Length]; Features = features; ParameterInfo[] parameters = ctor.GetParameters(); for (int i = 0; i < members.Length; i++) { Type finalType = parameters[i].ParameterType; var repeated = model.TryGetRepeatedProvider(finalType); Type tmp = repeated?.ItemType ?? finalType; bool asReference = false; int typeIndex = model.FindOrAddAuto(tmp, false, true, false, compatibilityLevel); if (typeIndex >= 0) { asReference = model[tmp].AsReferenceDefault; } IRuntimeProtoSerializerNode tail = ValueMember.TryGetCoreSerializer(model, DataFormat.Default, compatibilityLevel, tmp, out WireType wireType, asReference, false, false, true), serializer; if (tail == null) { throw new InvalidOperationException("No serializer defined for type: " + tmp.FullName); } if (repeated == null) { serializer = new TagDecorator(i + 1, wireType, false, tail); } else if (repeated.IsMap) { serializer = ValueMember.CreateMap(repeated, model, DataFormat.Default, compatibilityLevel, DataFormat.Default, DataFormat.Default, asReference, false, true, false, i + 1); } else { SerializerFeatures listFeatures = wireType.AsFeatures() | SerializerFeatures.OptionPackedDisabled; serializer = RepeatedDecorator.Create(repeated, i + 1, listFeatures, compatibilityLevel, DataFormat.Default); } tails[i] = serializer; } }
public UriDecorator(IRuntimeProtoSerializerNode tail) : base(tail) { }
public MemberSpecifiedDecorator(MethodInfo getSpecified, MethodInfo setSpecified, IRuntimeProtoSerializerNode tail) : base(tail) { if (getSpecified is null && setSpecified is null) { throw new InvalidOperationException(); } this.getSpecified = getSpecified; this.setSpecified = setSpecified; }
public void EmitRead(Compiler.CompilerContext ctx, Compiler.Local incoming) { using Compiler.Local objValue = ctx.GetLocalWithValue(ExpectedType, incoming); Compiler.Local[] locals = new Compiler.Local[members.Length]; try { for (int i = 0; i < locals.Length; i++) { Type type = GetMemberType(i); bool store = true; locals[i] = new Compiler.Local(ctx, type); if (!ExpectedType.IsValueType) { // value-types always read the old value if (type.IsValueType) { switch (Helpers.GetTypeCode(type)) { case ProtoTypeCode.Boolean: case ProtoTypeCode.Byte: case ProtoTypeCode.Int16: case ProtoTypeCode.Int32: case ProtoTypeCode.SByte: case ProtoTypeCode.UInt16: case ProtoTypeCode.UInt32: ctx.LoadValue(0); break; case ProtoTypeCode.Int64: case ProtoTypeCode.UInt64: ctx.LoadValue(0L); break; case ProtoTypeCode.Single: ctx.LoadValue(0.0F); break; case ProtoTypeCode.Double: ctx.LoadValue(0.0D); break; case ProtoTypeCode.Decimal: ctx.LoadValue(0M); break; case ProtoTypeCode.Guid: ctx.LoadValue(Guid.Empty); break; default: ctx.LoadAddress(locals[i], type); ctx.EmitCtor(type); store = false; break; } } else { ctx.LoadNullRef(); } if (store) { ctx.StoreValue(locals[i]); } } } Compiler.CodeLabel skipOld = ExpectedType.IsValueType ? new Compiler.CodeLabel() : ctx.DefineLabel(); if (!ExpectedType.IsValueType) { ctx.LoadAddress(objValue, ExpectedType); ctx.BranchIfFalse(skipOld, false); } for (int i = 0; i < members.Length; i++) { ctx.LoadAddress(objValue, ExpectedType); if (members[i] is FieldInfo fieldInfo) { ctx.LoadValue(fieldInfo); } else if (members[i] is PropertyInfo propertyInfo) { ctx.LoadValue(propertyInfo); } ctx.StoreValue(locals[i]); } if (!ExpectedType.IsValueType) { ctx.MarkLabel(skipOld); } using (Compiler.Local fieldNumber = new Compiler.Local(ctx, typeof(int))) { Compiler.CodeLabel @continue = ctx.DefineLabel(), processField = ctx.DefineLabel(), notRecognised = ctx.DefineLabel(); ctx.Branch(@continue, false); Compiler.CodeLabel[] handlers = new Compiler.CodeLabel[members.Length]; for (int i = 0; i < members.Length; i++) { handlers[i] = ctx.DefineLabel(); } ctx.MarkLabel(processField); ctx.LoadValue(fieldNumber); ctx.LoadValue(1); ctx.Subtract(); // jump-table is zero-based ctx.Switch(handlers); // and the default: ctx.Branch(notRecognised, false); for (int i = 0; i < handlers.Length; i++) { ctx.MarkLabel(handlers[i]); IRuntimeProtoSerializerNode tail = tails[i]; Compiler.Local oldValIfNeeded = tail.RequiresOldValue ? locals[i] : null; ctx.ReadNullCheckedTail(locals[i].Type, tail, oldValIfNeeded); if (tail.ReturnsValue) { if (locals[i].Type.IsValueType) { ctx.StoreValue(locals[i]); } else { Compiler.CodeLabel hasValue = ctx.DefineLabel(), allDone = ctx.DefineLabel(); ctx.CopyValue(); ctx.BranchIfTrue(hasValue, true); // interpret null as "don't assign" ctx.DiscardValue(); ctx.Branch(allDone, true); ctx.MarkLabel(hasValue); ctx.StoreValue(locals[i]); ctx.MarkLabel(allDone); } } ctx.Branch(@continue, false); } ctx.MarkLabel(notRecognised); ctx.LoadState(); ctx.EmitCall(typeof(ProtoReader.State).GetMethod(nameof(ProtoReader.State.SkipField), Type.EmptyTypes)); ctx.MarkLabel(@continue); ctx.EmitStateBasedRead(nameof(ProtoReader.State.ReadFieldHeader), typeof(int)); ctx.CopyValue(); ctx.StoreValue(fieldNumber); ctx.LoadValue(0); ctx.BranchIfGreater(processField, false); } for (int i = 0; i < locals.Length; i++) { ctx.LoadValue(locals[i]); } ctx.EmitCtor(ctor); ctx.StoreValue(objValue); } finally { for (int i = 0; i < locals.Length; i++) { if (locals[i] != null) { locals[i].Dispose(); // release for re-use } } } }
protected ProtoDecoratorBase(IRuntimeProtoSerializerNode tail) { this.Tail = tail; }
internal IRuntimeProtoSerializerNode GetSerializer(Type parentType) => serializer ?? (serializer = BuildSerializer(parentType));