private void HandleNilImplication(ref T instance, int index) { switch (this._nilImplications[index]) { case NilImplication.Null: { if (this._memberSetters[index] == null) { throw SerializationExceptions.NewReadOnlyMemberItemsMustNotBeNull(this._memberNames[index]); } this._memberSetters[index](ref instance, null); break; } case NilImplication.MemberDefault: { break; } case NilImplication.Prohibit: { throw SerializationExceptions.NewNullIsProhibited(this._memberNames[index]); } } }
private T UnpackMemberValue(T objectGraph, Unpacker unpacker, int itemsCount, ref int unpacked, int index, int unpackerOffset) { object nullable = null; var setter = this._setters[index]; if (unpacked < itemsCount) { if (!unpacker.Read()) { throw SerializationExceptions.NewMissingItem(unpackerOffset); } if (!unpacker.LastReadData.IsNil) { if (setter != null) { if (!unpacker.IsArrayHeader && !unpacker.IsMapHeader) { nullable = this._serializers[index].UnpackFrom(unpacker); } else { using (Unpacker subtreeUnpacker = unpacker.ReadSubtree()) { nullable = this._serializers[index].UnpackFrom(subtreeUnpacker); } } } else if (this._getters[index] != null) // null getter supposes undeclared member (should be treated as nil) { var collection = this._getters[index](objectGraph); if (collection == null) { throw SerializationExceptions.NewReadOnlyMemberItemsMustNotBeNull(this._contracts[index].Name); } using (Unpacker subtreeUnpacker = unpacker.ReadSubtree()) { this._serializers[index].UnpackTo(subtreeUnpacker, collection); } } } } if (setter != null) { if (nullable == null) { ReflectionNilImplicationHandler.Instance.OnUnpacked( new ReflectionSerializerNilImplicationHandlerOnUnpackedParameter( this._memberInfos[index].GetMemberValueType(), value => SetMemverValue(objectGraph, setter, value), this._contracts[index].Name, this._memberInfos[index].DeclaringType ), this._contracts[index].NilImplication )(null); } else { objectGraph = SetMemverValue(objectGraph, setter, nullable); } } unpacked++; return(objectGraph); }
private async Task UnpackAndAddCollectionItemAsync(object objectGraph, Unpacker unpacker, int index, CancellationToken cancellationToken) { var destination = this._getters[index](objectGraph); if (destination == null) { throw SerializationExceptions.NewReadOnlyMemberItemsMustNotBeNull(this._contracts[index].Name); } var traits = destination.GetType().GetCollectionTraits(CollectionTraitOptions.WithAddMethod, this.OwnerContext.CompatibilityOptions.AllowNonCollectionEnumerableTypes); if (traits.AddMethod == null) { throw SerializationExceptions.NewUnpackToIsNotSupported(destination.GetType(), null); } var source = await this._serializers[index].UnpackFromAsync(unpacker, cancellationToken).ConfigureAwait(false) as IEnumerable; if (source != null) { switch (traits.DetailedCollectionType) { case CollectionDetailedKind.GenericDictionary: { // item should be KeyValuePair<TKey, TValue> var arguments = new object[2]; var key = default(PropertyInfo); var value = default(PropertyInfo); foreach (var item in source) { if (key == null) { key = item.GetType().GetProperty("Key"); value = item.GetType().GetProperty("Value"); } arguments[0] = key.GetValue(item, null); arguments[1] = value.GetValue(item, null); traits.AddMethod.InvokePreservingExceptionType(destination, arguments); } break; } case CollectionDetailedKind.NonGenericDictionary: { // item should be DictionaryEntry var arguments = new object[2]; foreach (var item in source) { arguments[0] = ReflectionSerializerHelper.DictionaryEntryKeyProperty.GetValue(item, null); arguments[1] = ReflectionSerializerHelper.DictionaryEntryValueProperty.GetValue(item, null); traits.AddMethod.InvokePreservingExceptionType(destination, arguments); } break; } default: { var arguments = new object[1]; foreach (var item in source) { arguments[0] = item; traits.AddMethod.InvokePreservingExceptionType(destination, arguments); } break; } } } } // UnpackAndAddCollectionItemAsync
private void UnpackAndAddCollectionItem(object objectGraph, Unpacker unpacker, int index) { var destination = this._getters[index](objectGraph); if (destination == null) { throw SerializationExceptions.NewReadOnlyMemberItemsMustNotBeNull(this._contracts[index].Name); } var traits = destination.GetType().GetCollectionTraits(); if (traits.AddMethod == null) { throw SerializationExceptions.NewUnpackToIsNotSupported(destination.GetType(), null); } var source = this._serializers[index].UnpackFrom(unpacker) as IEnumerable; if (source != null) { switch (traits.DetailedCollectionType) { case CollectionDetailedKind.GenericDictionary: { // item should be KeyValuePair<TKey, TValue> var arguments = new object[2]; var key = default(PropertyInfo); var value = default(PropertyInfo); foreach (var item in source) { if (key == null) { key = item.GetType().GetProperty("Key"); value = item.GetType().GetProperty("Value"); } arguments[0] = key.GetValue(item, null); arguments[1] = value.GetValue(item, null); traits.AddMethod.InvokePreservingExceptionType(destination, arguments); } break; } case CollectionDetailedKind.NonGenericDictionary: { // item should be DictionaryEntry var arguments = new object[2]; foreach (var item in source) { arguments[0] = DictionaryEntryKeyProperty.GetValue(item, null); arguments[1] = DictionaryEntryValueProperty.GetValue(item, null); traits.AddMethod.InvokePreservingExceptionType(destination, arguments); } break; } default: { var arguments = new object[1]; foreach (var item in source) { arguments[0] = item; traits.AddMethod.InvokePreservingExceptionType(destination, arguments); } break; } } } }
protected ObjectReflectionMessagePackSerializer(Type type, SerializationContext context, SerializingMember[] members) : base(type, (context ?? SerializationContext.Default).CompatibilityOptions.PackerCompatibilityOptions) { if (type.GetIsAbstract() || type.GetIsInterface()) { throw SerializationExceptions.NewNotSupportedBecauseCannotInstanciateAbstractType(type); } this._createInstance = () => Activator.CreateInstance(type); //Expression.Lambda<Func<T>>( // typeof(T).GetIsValueType() // ? Expression.Default(typeof(T)) as Expression // : Expression.New(typeof(T).GetConstructor(ReflectionAbstractions.EmptyTypes)) // ).Compile(); var isPackable = typeof(IPackable).IsAssignableFrom(type); var isUnpackable = typeof(IUnpackable).IsAssignableFrom(type); if (isPackable && isUnpackable) { this._memberSerializers = null; this._indexMap = null; this._isCollection = null; this._nilImplications = null; this._memberNames = null; } else { this._memberSerializers = members.Select( m => m.Member == null ? NullSerializer.Instance : context.GetSerializer(m.Member.GetMemberValueType())).ToArray ( ); this._indexMap = members .Select((m, i) => new KeyValuePair <SerializingMember, int>(m, i)) .Where(kv => kv.Key.Member != null) .ToDictionary(kv => kv.Key.Contract.Name, kv => kv.Value); this._isCollection = members.Select( m => m.Member == null ? CollectionTraits.NotCollection : m.Member.GetMemberValueType().GetCollectionTraits()). Select(t => t.CollectionType != CollectionKind.NotCollection).ToArray(); // NilImplication validity check foreach (var member in members) { switch (member.Contract.NilImplication) { case NilImplication.Null: { if (member.Member.GetMemberValueType().GetIsValueType() && Nullable.GetUnderlyingType(member.Member.GetMemberValueType()) == null) { throw SerializationExceptions.NewValueTypeCannotBeNull( member.Contract.Name, member.Member.GetMemberValueType(), member.Member.DeclaringType ); } if (!member.Member.CanSetValue()) { throw SerializationExceptions.NewReadOnlyMemberItemsMustNotBeNull(member.Contract.Name); } break; } } } this._nilImplications = members.Select(m => m.Contract.NilImplication).ToArray(); this._memberNames = members.Select(m => m.Contract.Name).ToArray(); } if (isPackable) { this._packToMessage = (target, packer, packingOptions) => { ((IPackable)target).PackToMessage(packer, packingOptions); //typeof(T).GetInterfaceMap(typeof(IPackable)).TargetMethods.Single().Invoke(target, new object[] { packer, packingOptions }); }; this._memberGetters = null; } else { this._packToMessage = null; this._memberGetters = members.Select <SerializingMember, Func <object, object> >( m => m.Member == null ? (target => null) : CreateMemberGetter(m)).ToArray(); } if (isUnpackable) { this._unpackFromMessage = delegate(ref object target, Unpacker value) { ((IUnpackable)target).UnpackFromMessage(value); }; this._memberSetters = null; } else { this._unpackFromMessage = null; this._memberSetters = members.Select( m => m.Member == null ? delegate(ref object target, object memberValue) { } : m.Member.CanSetValue() ? CreateMemberSetter(m) : UnpackHelpers.IsReadOnlyAppendableCollectionMember(m.Member) ? default(MemberSetter) : ThrowGetOnlyMemberIsInvalid(m.Member) ).ToArray(); } }
/// <summary> /// Emits the nil implication. /// </summary> /// <param name="il">The il generator.</param> /// <param name="unpackerArgumentIndex">Index of the unpacker argument.</param> /// <param name="member">Metadata of the serializing member.</param> /// <param name="endOfDeserialization">The label to the end of deserialization.</param> /// <param name="localHolder">The <see cref="LocalVariableHolder"/> which holds shared local variable information.</param> public static void EmitNilImplication( TracingILGenerator il, int unpackerArgumentIndex, SerializingMember member, Label endOfDeserialization, LocalVariableHolder localHolder ) { switch (member.Contract.NilImplication) { case NilImplication.MemberDefault: { // TODO: This should be empty for extra items. /* * if( unpacker.Data.Value.IsNil ) * { * // Skip current. * goto END_OF_DESERIALIZATION; * } */ il.EmitAnyLdarg(unpackerArgumentIndex); il.EmitGetProperty(Metadata._Unpacker.LastReadData); var data = localHolder.UnpackedData; il.EmitAnyStloc(data); il.EmitAnyLdloca(data); il.EmitGetProperty(Metadata._MessagePackObject.IsNil); il.EmitBrtrue(endOfDeserialization); break; } case NilImplication.Null: { if (member.Member.GetMemberValueType().GetIsValueType() && Nullable.GetUnderlyingType(member.Member.GetMemberValueType()) == null) { throw SerializationExceptions.NewValueTypeCannotBeNull( member.Contract.Name, member.Member.GetMemberValueType(), member.Member.DeclaringType ); } if (!member.Member.CanSetValue()) { throw SerializationExceptions.NewReadOnlyMemberItemsMustNotBeNull( member.Contract.Name ); } break; } case NilImplication.Prohibit: { if (!member.Member.CanSetValue()) { throw SerializationExceptions.NewReadOnlyMemberItemsMustNotBeNull( member.Contract.Name ); } /* * if( unpacker.Data.Value.IsNil ) * { * throw SerializationEceptions.NewProhibitNullException( "..." ); * } */ il.EmitAnyLdarg(unpackerArgumentIndex); il.EmitGetProperty(Metadata._Unpacker.LastReadData); var data = localHolder.UnpackedData; il.EmitAnyStloc(data); il.EmitAnyLdloca(data); il.EmitGetProperty(Metadata._MessagePackObject.IsNil); var endIf0 = il.DefineLabel("END_IF0"); il.EmitBrfalse_S(endIf0); il.EmitLdstr(member.Contract.Name); il.EmitAnyCall(SerializationExceptions.NewNullIsProhibitedMethod); il.EmitThrow(); il.MarkLabel(endIf0); break; } } }
protected ObjectExpressionMessagePackSerializer(SerializationContext context, SerializingMember[] members) : base((context ?? SerializationContext.Default).CompatibilityOptions.PackerCompatibilityOptions) { if (typeof(T).GetIsAbstract() || typeof(T).GetIsInterface()) { throw SerializationExceptions.NewNotSupportedBecauseCannotInstanciateAbstractType(typeof(T)); } this._createInstance = Expression.Lambda <Func <T> >( typeof(T).GetIsValueType() ? Expression.Default(typeof(T)) as Expression : Expression.New(typeof(T).GetConstructor(ReflectionAbstractions.EmptyTypes)) ).Compile(); var isPackable = typeof(IPackable).IsAssignableFrom(typeof(T)); var isUnpackable = typeof(IUnpackable).IsAssignableFrom(typeof(T)); var targetParameter = Expression.Parameter(typeof(T), "target"); if (isPackable && isUnpackable) { this._memberSerializers = null; this._indexMap = null; this._isCollection = null; this._nilImplications = null; this._memberNames = null; } else { this._memberSerializers = members.Select( m => m.Member == null ? NullSerializer.Instance : context.GetSerializer(m.Member.GetMemberValueType())).ToArray ( ); this._indexMap = members .Zip(Enumerable.Range(0, members.Length), (m, i) => new KeyValuePair <SerializingMember, int>(m, i)) .Where(kv => kv.Key.Member != null) .ToDictionary(kv => kv.Key.Contract.Name, kv => kv.Value); this._isCollection = members.Select( m => m.Member == null ? CollectionTraits.NotCollection : m.Member.GetMemberValueType().GetCollectionTraits()). Select(t => t.CollectionType != CollectionKind.NotCollection).ToArray(); // NilImplication validity check foreach (var member in members) { switch (member.Contract.NilImplication) { case NilImplication.Null: { if (member.Member.GetMemberValueType().GetIsValueType() && Nullable.GetUnderlyingType(member.Member.GetMemberValueType()) == null) { throw SerializationExceptions.NewValueTypeCannotBeNull( member.Contract.Name, member.Member.GetMemberValueType(), member.Member.DeclaringType ); } if (!member.Member.CanSetValue()) { throw SerializationExceptions.NewReadOnlyMemberItemsMustNotBeNull(member.Contract.Name); } break; } } } this._nilImplications = members.Select(m => m.Contract.NilImplication).ToArray(); this._memberNames = members.Select(m => m.Contract.Name).ToArray(); } if (isPackable) { var packerParameter = Expression.Parameter(typeof(Packer), "packer"); var optionsParameter = Expression.Parameter(typeof(PackingOptions), "options"); this._packToMessage = Expression.Lambda <Action <T, Packer, PackingOptions> >( Expression.Call( targetParameter, typeof(T).GetInterfaceMap(typeof(IPackable)).TargetMethods.Single(), packerParameter, optionsParameter ), targetParameter, packerParameter, optionsParameter ).Compile(); this._memberGetters = null; } else { this._packToMessage = null; this._memberGetters = members.Select( m => m.Member == null ? Expression.Lambda <Func <T, object> >( Expression.Constant(null), targetParameter ).Compile() : CreateMemberGetter(targetParameter, m) ).ToArray(); } var refTargetParameter = Expression.Parameter(typeof(T).MakeByRefType(), "target"); if (isUnpackable) { var unpackerParameter = Expression.Parameter(typeof(Unpacker), "unpacker"); this._unpackFromMessage = Expression.Lambda <UnpackFromMessageInvocation>( Expression.Call( refTargetParameter, typeof(T).GetInterfaceMap(typeof(IUnpackable)).TargetMethods.Single(), unpackerParameter ), refTargetParameter, unpackerParameter ).Compile(); this._memberSetters = null; } else { this._unpackFromMessage = null; var valueParameter = Expression.Parameter(typeof(object), "value"); this._memberSetters = members.Select( m => m.Member == null ? Expression.Lambda <MemberSetter>( Expression.Empty(), refTargetParameter, valueParameter ).Compile() : m.Member.CanSetValue() ? Expression.Lambda <MemberSetter>( Expression.Assign( Expression.PropertyOrField( refTargetParameter, m.Member.Name ), Expression.Call( Metadata._UnpackHelpers.ConvertWithEnsuringNotNull_1Method.MakeGenericMethod(m.Member.GetMemberValueType()), valueParameter, Expression.Constant(m.Member.Name), Expression.Call( // Using RuntimeTypeHandle to avoid WinRT expression tree issue. null, Metadata._Type.GetTypeFromHandle, Expression.Constant(m.Member.DeclaringType.TypeHandle) ) ) ), refTargetParameter, valueParameter ).Compile() : UnpackHelpers.IsReadOnlyAppendableCollectionMember(m.Member) ? default(MemberSetter) : ThrowGetOnlyMemberIsInvalid(m.Member) ).ToArray(); } }
private void UnpackFromMap(Unpacker unpacker, ref T instance) { while (unpacker.Read()) { var memberName = GetMemberName(unpacker); int index; if (!this._indexMap.TryGetValue(memberName, out index)) { // Drains unused value. if (!unpacker.Read()) { throw SerializationExceptions.NewUnexpectedEndOfStream(); } // TODO: unknown member handling. continue; } // Fetches value if (!unpacker.Read()) { throw SerializationExceptions.NewUnexpectedEndOfStream(); } if (unpacker.Data.Value.IsNil) { switch (this._nilImplications[index]) { case NilImplication.Null: { if (this._memberSetters[index] == null) { throw SerializationExceptions.NewReadOnlyMemberItemsMustNotBeNull(this._memberNames[index]); } this._memberSetters[index](ref instance, null); continue; } case NilImplication.MemberDefault: { continue; } case NilImplication.Prohibit: { throw SerializationExceptions.NewNullIsProhibited(this._memberNames[index]); } } } if (unpacker.IsArrayHeader || unpacker.IsMapHeader) { using (var subtreeUnpacker = unpacker.ReadSubtree()) { this.UnpackMemberInMap(subtreeUnpacker, ref instance, index); } } else { this.UnpackMemberInMap(unpacker, ref instance, index); } } }