public static Envelope Get(TypeDescription desc, POCOBuilder mapper, object payload) { using(var mem = new MemoryStream()) { // null *can* be serialized, it just has no value if (payload != null) { // A lot of models can skip the whole "create shadow type" operation, so let's squeeze those savings out if (!desc.NeedsMapping) { var model = desc.TypeModel ?? RuntimeTypeModel.Default; model.Serialize(mem, payload); } else { payload = mapper.GetMapper()(payload); ProtoBuf.Serializer.NonGeneric.Serialize(mem, payload); } } return new Envelope(desc, mem.ToArray()); } }
internal override TypeDescription DePromise(out Action afterPromise) { Action act1, act2; KeyType = KeyType.DePromise(out act1); ValueType = ValueType.DePromise(out act2); afterPromise = () => { act1(); act2(); }; return this; }
static internal ListTypeDescription Create(TypeDescription contains, Type type) { return(new ListTypeDescription(contains, type)); }
internal override void Seal(TypeDescription existing = null) { Contains.Seal(existing); }
internal static ListTypeDescription Create(TypeDescription contains, Type type) { return new ListTypeDescription(contains, type); }
internal override Type GetPocoType(TypeDescription existing = null) { return PocoType ?? TypeBuilder; }
private static bool IsExactMatch(Type type, TypeDescription description, Dictionary <int, Type> backLookup) { var simple = description as SimpleTypeDescription; if (simple != null) { switch (simple.Tag) { case SimpleTypeDescription.BoolTag: return(type == typeof(bool)); case SimpleTypeDescription.ByteTag: return(type == typeof(byte)); case SimpleTypeDescription.CharTag: return(type == typeof(char)); case SimpleTypeDescription.DateTimeTag: return(type == typeof(DateTime)); case SimpleTypeDescription.DecimalTag: return(type == typeof(decimal)); case SimpleTypeDescription.DoubleTag: return(type == typeof(double)); case SimpleTypeDescription.FloatTag: return(type == typeof(float)); case SimpleTypeDescription.GuidTag: return(type == typeof(Guid)); case SimpleTypeDescription.IntTag: return(type == typeof(int)); case SimpleTypeDescription.LongTag: return(type == typeof(long)); case SimpleTypeDescription.SByteTag: return(type == typeof(sbyte)); case SimpleTypeDescription.ShortTag: return(type == typeof(short)); case SimpleTypeDescription.StringTag: return(type == typeof(string)); case SimpleTypeDescription.TimeSpanTag: return(type == typeof(TimeSpan)); case SimpleTypeDescription.UIntTag: return(type == typeof(uint)); case SimpleTypeDescription.ULongTag: return(type == typeof(ulong)); case SimpleTypeDescription.UriTag: return(type == typeof(Uri)); case SimpleTypeDescription.UShortTag: return(type == typeof(ushort)); default: throw new Exception("Unexpected tag: " + simple.Tag); } } var nullable = description as NullableTypeDescription; if (nullable != null) { var underlying = Nullable.GetUnderlyingType(type); if (underlying == null) { return(false); } return(IsExactMatch(underlying, nullable.InnerType, backLookup)); } var list = description as ListTypeDescription; if (list != null) { if (!type.IsList()) { return(false); } // protobuf-net treats byte[] differently from all other []'s, bail because we need to make it a list. if (type == typeof(byte[])) { return(false); } var listI = type.GetListInterface(); return(IsExactMatch(listI.GetGenericArguments()[0], list.Contains, backLookup)); } var dict = description as DictionaryTypeDescription; if (dict != null) { if (!type.IsDictionary()) { return(false); } var dictI = type.GetDictionaryInterface(); return (IsExactMatch(dictI.GetGenericArguments()[0], dict.KeyType, backLookup) && IsExactMatch(dictI.GetGenericArguments()[1], dict.ValueType, backLookup)); } var enumD = description as EnumTypeDescription; if (enumD != null) { if (!type.IsEnum) { return(false); } if (Enum.GetUnderlyingType(type) != typeof(int)) { return(false); } var names = Enum.GetNames(type); if (!enumD.Values.All(a => names.Contains(a))) { return(false); } if (enumD.Id != 0) { backLookup[enumD.Id] = type; } return(true); } var back = description as BackReferenceTypeDescription; if (back != null) { return(backLookup[back.Id] == type); } var classD = description as ClassTypeDescription; if (classD != null) { if (type.IsList() || type.IsDictionary()) { return(false); } // Assume they're equal for back ref purposes; a contradiction here is going to be blow up anyway if (classD.Id != 0) { backLookup[classD.Id] = type; } foreach (var mem in classD.Members) { var classMem = type.GetMember(mem.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SingleOrDefault(); if (classMem == null) { continue; } if (classMem is FieldInfo) { if (!IsExactMatch(((FieldInfo)classMem).FieldType, mem.Value, backLookup)) { return(false); } } if (classMem is PropertyInfo) { var asProp = (PropertyInfo)classMem; // protobuf-net wants uniform access; it would be nice if we could get away with just a setter though if (!asProp.CanWrite || !asProp.CanRead) { return(false); } if (!IsExactMatch(asProp.PropertyType, mem.Value, backLookup)) { return(false); } } } return(true); } throw new Exception("Unexpected description [" + description + "]"); }
internal override Type GetPocoType(TypeDescription existingDescription = null) { if (existingDescription == null) throw new ArgumentNullException("existingDescription"); var stack = new Stack<TypeDescription>(); stack.Push(existingDescription); while (stack.Count > 0) { var top = stack.Pop(); if (top is SimpleTypeDescription) continue; if (top is BackReferenceTypeDescription) continue; if (top is NullableTypeDescription) { stack.Push(((NullableTypeDescription)top).InnerType); continue; } if (top is ListTypeDescription) { stack.Push(((ListTypeDescription)top).Contains); continue; } if (top is DictionaryTypeDescription) { var asDict = (DictionaryTypeDescription)top; stack.Push(asDict.KeyType); stack.Push(asDict.ValueType); continue; } if (top is ClassTypeDescription) { var asClass = (ClassTypeDescription)top; if (asClass.Id == Id) { asClass.Seal(existingDescription); return asClass.GetPocoType(existingDescription); } foreach (var member in asClass.Members) { stack.Push(member.Value); } continue; } if (top is EnumTypeDescription) { var asEnum = (EnumTypeDescription)top; if (asEnum.Id == Id) { asEnum.Seal(existingDescription); return asEnum.GetPocoType(existingDescription); } continue; } throw new Exception("Shouldn't be possible"); } throw new Exception("Couldn't find reference to ClassId = " + Id); }
public static void Flatten(TypeDescription root, Func<int> nextId) { var seenClasses = new HashSet<ClassTypeDescription>(); var finishedClasses = new HashSet<ClassTypeDescription>(); var seenEnums = new HashSet<EnumTypeDescription>(); var toCheck = new Stack<TypeDescription>(); toCheck.Push(root); while (toCheck.Count > 0) { var top = toCheck.Pop(); if (top is SimpleTypeDescription) continue; if (top is BackReferenceTypeDescription) continue; var asNullable = top as NullableTypeDescription; if (asNullable != null) { if (seenClasses.Contains(asNullable.InnerType)) { var id = ((ClassTypeDescription)asNullable.InnerType).Id != 0 ? ((ClassTypeDescription)asNullable.InnerType).Id : nextId(); ((ClassTypeDescription)asNullable.InnerType).Id = id; asNullable.InnerType = new BackReferenceTypeDescription(id); continue; } if (seenEnums.Contains(asNullable.InnerType)) { var id = ((EnumTypeDescription)asNullable.InnerType).Id != 0 ? ((EnumTypeDescription)asNullable.InnerType).Id : nextId(); ((EnumTypeDescription)asNullable.InnerType).Id = id; asNullable.InnerType = new BackReferenceTypeDescription(id); continue; } toCheck.Push(asNullable.InnerType); continue; } var asDict = top as DictionaryTypeDescription; if (asDict != null) { if (seenClasses.Contains(asDict.KeyType)) { var id = ((ClassTypeDescription)asDict.KeyType).Id != 0 ? ((ClassTypeDescription)asDict.KeyType).Id : nextId(); ((ClassTypeDescription)asDict.KeyType).Id = id; asDict.KeyType = new BackReferenceTypeDescription(id); } else { toCheck.Push(asDict.KeyType); } if (seenClasses.Contains(asDict.ValueType)) { var id = ((ClassTypeDescription)asDict.ValueType).Id != 0 ? ((ClassTypeDescription)asDict.ValueType).Id : nextId(); ((ClassTypeDescription)asDict.ValueType).Id = id; asDict.ValueType = new BackReferenceTypeDescription(id); } else { toCheck.Push(asDict.ValueType); } continue; } var asList = top as ListTypeDescription; if (asList != null) { if (seenClasses.Contains(asList.Contains)) { var id = ((ClassTypeDescription)asList.Contains).Id != 0 ? ((ClassTypeDescription)asList.Contains).Id : nextId(); ((ClassTypeDescription)asList.Contains).Id = id; asList.Contains = new BackReferenceTypeDescription(id); } else { toCheck.Push(asList.Contains); } continue; } var asClass = top as ClassTypeDescription; if (asClass != null) { if (finishedClasses.Contains(asClass)) { continue; } seenClasses.Add(asClass); foreach (var key in asClass.Members.Keys.ToList()) { var val = asClass.Members[key]; if (seenClasses.Contains(val)) { var id = ((ClassTypeDescription)val).Id != 0 ? ((ClassTypeDescription)val).Id : nextId(); ((ClassTypeDescription)val).Id = id; asClass.Members[key] = new BackReferenceTypeDescription(id); continue; } if (seenEnums.Contains(val)) { var id = ((EnumTypeDescription)val).Id != 0 ? ((EnumTypeDescription)val).Id : nextId(); ((EnumTypeDescription)val).Id = id; asClass.Members[key] = new BackReferenceTypeDescription(id); continue; } if(val is ClassTypeDescription) { seenClasses.Add((ClassTypeDescription)val); } if (val is EnumTypeDescription) { seenEnums.Add((EnumTypeDescription)val); } toCheck.Push(val); finishedClasses.Add(asClass); } continue; } var asEnum = top as EnumTypeDescription; if (asEnum != null) { if (seenEnums.Contains(asEnum)) { continue; } seenEnums.Add(asEnum); continue; } throw new Exception("Should have been able to get here, found [" + top + "]"); } }
public static RuntimeTypeModel BuildTypeModel(TypeDescription desc, RuntimeTypeModel existing = null) { existing = existing ?? RuntimeTypeModel.Create(); if (desc is SimpleTypeDescription) { return(existing); } if (desc is NullableTypeDescription) { return(existing); } if (desc is BackReferenceTypeDescription) { return(existing); } if (desc is DictionaryTypeDescription) { var key = ((DictionaryTypeDescription)desc).KeyType; var val = ((DictionaryTypeDescription)desc).ValueType; BuildTypeModel(key, existing); BuildTypeModel(val, existing); return(existing); } if (desc is ListTypeDescription) { var contains = ((ListTypeDescription)desc).Contains; BuildTypeModel(contains, existing); return(existing); } if (desc is EnumTypeDescription) { var meta = existing.Add(((EnumTypeDescription)desc).ForType, applyDefaultBehaviour: false); var ordered = ((EnumTypeDescription)desc).Values.OrderBy(o => o, StringOrdinalComparer.Singleton); var equiv = 0; foreach (var val in ordered) { meta.AddField(equiv, val); equiv++; } return(existing); } if (!(desc is ClassTypeDescription)) { throw new Exception("Unexpected desc: " + desc); } var asClass = desc as ClassTypeDescription; var type = existing.Add(asClass.ForType, applyDefaultBehaviour: false); int ix = 1; foreach (var mem in asClass.Members.OrderBy(o => o.Key, StringComparer.Ordinal)) { type.AddField(ix, mem.Key); BuildTypeModel(mem.Value, existing); ix++; } return(existing); }
internal override Type GetPocoType(TypeDescription existing = null) { return(PocoType ?? TypeBuilder); }
internal override void Seal(TypeDescription existing = null) { if (PocoType != null || TypeBuilder != null) { return; } var name = "POCO" + Guid.NewGuid().ToString().Replace("-", ""); var protoMemberAttr = typeof(ProtoMemberAttribute).GetConstructor(new[] { typeof(int) }); var protoContractAttr = typeof(ProtoContractAttribute).GetConstructor(new Type[0]); var fields = new Dictionary <string, FieldInfo>(); TypeBuilder = ModuleBuilder.DefineType(name, TypeAttributes.Public, typeof(DynamicObject), new [] { typeof(IEnumerable) }); var ix = 1; foreach (var kv in Members.OrderBy(o => o.Key, StringComparer.Ordinal)) { var memberAttrBuilder = new CustomAttributeBuilder(protoMemberAttr, new object[] { ix }); kv.Value.Seal(existing); var propType = kv.Value.GetPocoType(existing); var field = TypeBuilder.DefineField(kv.Key, propType, FieldAttributes.Public); field.SetCustomAttribute(memberAttrBuilder); fields[kv.Key] = field; ix++; } var contractAttrBuilder = new CustomAttributeBuilder(protoContractAttr, new object[0]); TypeBuilder.SetCustomAttribute(contractAttrBuilder); // Define indexer var strEq = typeof(object).GetMethod("Equals", new[] { typeof(object) }); var tryGetIndexEmit = Sigil.Emit <TryGetIndexerDelegate> .BuildMethod(TypeBuilder, "TryGetIndex", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.Standard | CallingConventions.HasThis); tryGetIndexEmit.LoadArgument(2); // object[] var invalid = tryGetIndexEmit.DefineLabel("invalid"); tryGetIndexEmit .Duplicate() // object[] object[] .LoadLength <object>() // int object[] .LoadConstant(1); // int int object[] tryGetIndexEmit.UnsignedBranchIfNotEqual(invalid); // object[] tryGetIndexEmit .LoadConstant(0) // int object[] .LoadElement <object>() // object .IsInstance <string>(); // int var valid = tryGetIndexEmit.DefineLabel("valid"); tryGetIndexEmit .BranchIfTrue(valid) // --empty-- .LoadArgument(2); // object[] tryGetIndexEmit.MarkLabel(invalid); tryGetIndexEmit.Pop(); // --empty-- tryGetIndexEmit .LoadArgument(3) // object& .LoadNull() // null object& .StoreIndirect(typeof(object)); // --empty-- tryGetIndexEmit .LoadConstant(0) // int .Return(); // --empty-- tryGetIndexEmit.MarkLabel(valid); tryGetIndexEmit.LoadArgument(3); // object& tryGetIndexEmit .LoadArgument(2) // object[] object& .LoadConstant(0) // int object[] object& .LoadElement <object>(); // object object& Sigil.Label next; var done = tryGetIndexEmit.DefineLabel("done"); foreach (var mem in Members) { next = tryGetIndexEmit.DefineLabel("next_" + mem.Key); var memKey = mem.Key; var field = fields[memKey]; tryGetIndexEmit .Duplicate() // object object object& .LoadConstant(memKey); // string object object object& tryGetIndexEmit.CallVirtual(strEq); // int object object7& tryGetIndexEmit.BranchIfFalse(next); // object object& tryGetIndexEmit .Pop() // object& .LoadArgument(0) // this object& .LoadField(field); // fieldType object& if (field.FieldType.IsValueType) { tryGetIndexEmit.Box(field.FieldType); // fieldType object& } tryGetIndexEmit.Branch(done); // fieldType object& tryGetIndexEmit.MarkLabel(next); // object object& } tryGetIndexEmit .Pop() // object& .LoadNull(); // null object& tryGetIndexEmit.MarkLabel(done); // *something* object& tryGetIndexEmit .StoreIndirect(typeof(object)) // --empty-- .LoadConstant(1) // int .Return(); // --empty-- var tryGetIndex = tryGetIndexEmit.CreateMethod(); TypeBuilder.DefineMethodOverride(tryGetIndex, typeof(DynamicObject).GetMethod("TryGetIndex")); // Implement IEnumerable var getEnumeratorEmit = Sigil.Emit <Func <IEnumerator> > .BuildMethod(TypeBuilder, "GetEnumerator", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.Standard | CallingConventions.HasThis); var newStrList = typeof(List <string>).GetConstructor(new[] { typeof(int) }); var newEnumerator = Enumerator.GetConstructor(new[] { typeof(List <string>), typeof(object) }); var add = typeof(List <string>).GetMethod("Add"); getEnumeratorEmit.LoadConstant(Members.Count); getEnumeratorEmit.NewObject(newStrList); foreach (var mem in Members) { getEnumeratorEmit.Duplicate(); getEnumeratorEmit.LoadConstant(mem.Key); getEnumeratorEmit.Call(add); } getEnumeratorEmit.LoadArgument(0); getEnumeratorEmit.NewObject(newEnumerator); getEnumeratorEmit.Return(); var getEnumerator = getEnumeratorEmit.CreateMethod(); TypeBuilder.DefineMethodOverride(getEnumerator, typeof(IEnumerable).GetMethod("GetEnumerator")); // Define ToString() var toStringEmit = Sigil.Emit <Func <string> > .BuildMethod(TypeBuilder, "ToString", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.Standard | CallingConventions.HasThis); var objToString = typeof(object).GetMethod("ToString"); var thunkField = TypeBuilder.DefineField("__ToStringThunk", typeof(Func <object, string>), FieldAttributes.Static | FieldAttributes.Private); var invoke = typeof(Func <object, string>).GetMethod("Invoke"); toStringEmit .LoadField(thunkField) .LoadArgument(0) .CallVirtual(invoke) .Return(); var toString = toStringEmit.CreateMethod(); TypeBuilder.DefineMethodOverride(toString, objToString); PocoType = TypeBuilder.CreateType(); // Set the ToStringCallback var firstInst = PocoType.GetConstructor(Type.EmptyTypes).Invoke(new object[0]); var setThunk = firstInst.GetType().GetField("__ToStringThunk", BindingFlags.NonPublic | BindingFlags.Static); setThunk.SetValue(firstInst, ToStringFunc); }
internal override Type GetPocoType(TypeDescription existingDescription = null) { if (existingDescription == null) { throw new ArgumentNullException("existingDescription"); } var stack = new Stack <TypeDescription>(); stack.Push(existingDescription); while (stack.Count > 0) { var top = stack.Pop(); if (top is SimpleTypeDescription) { continue; } if (top is BackReferenceTypeDescription) { continue; } if (top is NullableTypeDescription) { stack.Push(((NullableTypeDescription)top).InnerType); continue; } if (top is ListTypeDescription) { stack.Push(((ListTypeDescription)top).Contains); continue; } if (top is DictionaryTypeDescription) { var asDict = (DictionaryTypeDescription)top; stack.Push(asDict.KeyType); stack.Push(asDict.ValueType); continue; } if (top is ClassTypeDescription) { var asClass = (ClassTypeDescription)top; if (asClass.Id == Id) { asClass.Seal(existingDescription); return(asClass.GetPocoType(existingDescription)); } foreach (var member in asClass.Members) { stack.Push(member.Value); } continue; } if (top is EnumTypeDescription) { var asEnum = (EnumTypeDescription)top; if (asEnum.Id == Id) { asEnum.Seal(existingDescription); return(asEnum.GetPocoType(existingDescription)); } continue; } throw new Exception("Shouldn't be possible"); } throw new Exception("Couldn't find reference to ClassId = " + Id); }
internal override Type GetPocoType(TypeDescription existing = null) { throw new NotImplementedException(); }
internal override void Seal(TypeDescription existing = null) { if (PocoType != null || TypeBuilder != null) return; var name = "POCO" + Guid.NewGuid().ToString().Replace("-", ""); var protoMemberAttr = typeof(ProtoMemberAttribute).GetConstructor(new[] { typeof(int) }); var protoContractAttr = typeof(ProtoContractAttribute).GetConstructor(new Type[0]); var fields = new Dictionary<string, FieldInfo>(); TypeBuilder = ModuleBuilder.DefineType(name, TypeAttributes.Public, typeof(DynamicObject), new [] { typeof(IEnumerable) }); var ix = 1; foreach (var kv in Members.OrderBy(o => o.Key, StringComparer.Ordinal)) { var memberAttrBuilder = new CustomAttributeBuilder(protoMemberAttr, new object[] { ix }); kv.Value.Seal(existing); var propType = kv.Value.GetPocoType(existing); var field = TypeBuilder.DefineField(kv.Key, propType, FieldAttributes.Public); field.SetCustomAttribute(memberAttrBuilder); fields[kv.Key] = field; ix++; } var contractAttrBuilder = new CustomAttributeBuilder(protoContractAttr, new object[0]); TypeBuilder.SetCustomAttribute(contractAttrBuilder); // Define indexer var strEq = typeof(string).GetMethod("Equals", new[] { typeof(string) }); var tryGetIndex = TypeBuilder.DefineMethod("TryGetIndex", MethodAttributes.Public | MethodAttributes.Virtual, typeof(bool), new[] { typeof(GetIndexBinder), typeof(object[]), Type.GetType("System.Object&") }); var il = tryGetIndex.GetILGenerator(); il.Emit(OpCodes.Ldarg_2); // object[] var invalid = il.DefineLabel(); il.Emit(OpCodes.Dup); // object[] object[] il.Emit(OpCodes.Ldlen); // length object[] il.Emit(OpCodes.Ldc_I4_1); // 1 length object[] il.Emit(OpCodes.Bne_Un_S, invalid); // object[] il.Emit(OpCodes.Ldc_I4_0); // 0 object[] il.Emit(OpCodes.Ldelem_Ref); // object il.Emit(OpCodes.Isinst, typeof(string));// bool var valid = il.DefineLabel(); il.Emit(OpCodes.Brtrue_S, valid); // ---- il.Emit(OpCodes.Ldc_I4_0); // 0 il.MarkLabel(invalid); // (object[] or 0) il.Emit(OpCodes.Pop); // ---- il.Emit(OpCodes.Ldarg_3); // (out object) il.Emit(OpCodes.Ldnull); // null (out object); il.Emit(OpCodes.Stind_Ref); // ---- il.Emit(OpCodes.Ldc_I4_0); // 0 il.Emit(OpCodes.Ret); il.MarkLabel(valid); il.Emit(OpCodes.Ldarg_3); // (out object) il.Emit(OpCodes.Ldarg_2); // object[] (out object) il.Emit(OpCodes.Ldc_I4_0); // 0 object[] (out object) il.Emit(OpCodes.Ldelem_Ref); // key (out object) Label next; var done = il.DefineLabel(); foreach (var mem in Members) { next = il.DefineLabel(); var memKey = mem.Key; var field = fields[memKey]; il.Emit(OpCodes.Dup); // key key (out object) il.Emit(OpCodes.Ldstr, memKey); // memKey key key (out object) il.Emit(OpCodes.Callvirt, strEq); // bool key (out object) il.Emit(OpCodes.Brfalse_S, next); // key (out object) il.Emit(OpCodes.Pop); // (out object) il.Emit(OpCodes.Ldarg_0); // this (out object) il.Emit(OpCodes.Ldfld, field); // ret (out object) if (field.FieldType.IsValueType) { il.Emit(OpCodes.Box, field.FieldType); // ret (out object); } il.Emit(OpCodes.Br, done); // ret (out object); il.MarkLabel(next); // key (out object); } il.Emit(OpCodes.Pop); // (out object) il.Emit(OpCodes.Ldnull); // null (out object) il.MarkLabel(done); // ret (out object); il.Emit(OpCodes.Stind_Ref); // ---- il.Emit(OpCodes.Ldc_I4_1); // 1 il.Emit(OpCodes.Ret); // ---- TypeBuilder.DefineMethodOverride(tryGetIndex, typeof(DynamicObject).GetMethod("TryGetIndex")); // Implement IEnumerable var getEnumerator = TypeBuilder.DefineMethod("GetEnumerator", MethodAttributes.Public | MethodAttributes.Virtual, typeof(IEnumerator), Type.EmptyTypes); il = getEnumerator.GetILGenerator(); var newStrList = typeof(List<string>).GetConstructor(new[] { typeof(int) }); var newEnumerator = Enumerator.GetConstructor(new[] { typeof(List<string>), typeof(object) }); var add = typeof(List<string>).GetMethod("Add"); il.Emit(OpCodes.Ldc_I4, Members.Count); // [count] il.Emit(OpCodes.Newobj, newStrList); // [mems] foreach (var mem in Members) { il.Emit(OpCodes.Dup); // [mems] [mems] il.Emit(OpCodes.Ldstr, mem.Key); // [key] [mems] [mems] il.Emit(OpCodes.Call, add); // [mems] } il.Emit(OpCodes.Ldarg_0); // [this] [mems] il.Emit(OpCodes.Newobj, newEnumerator); // [ret] il.Emit(OpCodes.Ret); // ----- TypeBuilder.DefineMethodOverride(getEnumerator, typeof(IEnumerable).GetMethod("GetEnumerator")); // Define ToString() var toString = TypeBuilder.DefineMethod("ToString", MethodAttributes.Public | MethodAttributes.Virtual, typeof(string), Type.EmptyTypes); var objToString = typeof(object).GetMethod("ToString"); var thunkField = TypeBuilder.DefineField("__ToStringThunk", typeof(Func<object, string>), FieldAttributes.Static | FieldAttributes.Private); var invoke = typeof(Func<object, string>).GetMethod("Invoke"); il = toString.GetILGenerator(); il.Emit(OpCodes.Ldsfld, thunkField); // [Func<object, string>] il.Emit(OpCodes.Ldarg_0); // [this] [Func<object, string>] il.Emit(OpCodes.Callvirt, invoke); // [string] il.Emit(OpCodes.Ret); // ----- TypeBuilder.DefineMethodOverride(toString, objToString); PocoType = TypeBuilder.CreateType(); // Set the ToStringCallback var firstInst = PocoType.GetConstructor(Type.EmptyTypes).Invoke(new object[0]); var setThunk = firstInst.GetType().GetField("__ToStringThunk", BindingFlags.NonPublic | BindingFlags.Static); setThunk.SetValue(firstInst, ToStringFunc); }
internal abstract Type GetPocoType(TypeDescription existingDescription = null);
internal override Type GetPocoType(TypeDescription existingDescription = null) { var inner = InnerType.GetPocoType(existingDescription); return(typeof(Nullable <>).MakeGenericType(inner)); }
internal virtual void Seal(TypeDescription existing = null) { }
public void Fulfil(TypeDescription desc) { Fulfilment = desc; }
public static void Flatten(TypeDescription root, Func <int> nextId) { var seenClasses = new HashSet <ClassTypeDescription>(); var finishedClasses = new HashSet <ClassTypeDescription>(); var seenEnums = new HashSet <EnumTypeDescription>(); var toCheck = new Stack <TypeDescription>(); toCheck.Push(root); while (toCheck.Count > 0) { var top = toCheck.Pop(); if (top is SimpleTypeDescription) { continue; } if (top is BackReferenceTypeDescription) { continue; } var asNullable = top as NullableTypeDescription; if (asNullable != null) { if (seenClasses.Contains(asNullable.InnerType)) { var id = ((ClassTypeDescription)asNullable.InnerType).Id != 0 ? ((ClassTypeDescription)asNullable.InnerType).Id : nextId(); ((ClassTypeDescription)asNullable.InnerType).Id = id; asNullable.InnerType = new BackReferenceTypeDescription(id); continue; } if (seenEnums.Contains(asNullable.InnerType)) { var id = ((EnumTypeDescription)asNullable.InnerType).Id != 0 ? ((EnumTypeDescription)asNullable.InnerType).Id : nextId(); ((EnumTypeDescription)asNullable.InnerType).Id = id; asNullable.InnerType = new BackReferenceTypeDescription(id); continue; } toCheck.Push(asNullable.InnerType); continue; } var asDict = top as DictionaryTypeDescription; if (asDict != null) { if (seenClasses.Contains(asDict.KeyType)) { var id = ((ClassTypeDescription)asDict.KeyType).Id != 0 ? ((ClassTypeDescription)asDict.KeyType).Id : nextId(); ((ClassTypeDescription)asDict.KeyType).Id = id; asDict.KeyType = new BackReferenceTypeDescription(id); } else { toCheck.Push(asDict.KeyType); } if (seenClasses.Contains(asDict.ValueType)) { var id = ((ClassTypeDescription)asDict.ValueType).Id != 0 ? ((ClassTypeDescription)asDict.ValueType).Id : nextId(); ((ClassTypeDescription)asDict.ValueType).Id = id; asDict.ValueType = new BackReferenceTypeDescription(id); } else { toCheck.Push(asDict.ValueType); } continue; } var asList = top as ListTypeDescription; if (asList != null) { if (seenClasses.Contains(asList.Contains)) { var id = ((ClassTypeDescription)asList.Contains).Id != 0 ? ((ClassTypeDescription)asList.Contains).Id : nextId(); ((ClassTypeDescription)asList.Contains).Id = id; asList.Contains = new BackReferenceTypeDescription(id); } else { toCheck.Push(asList.Contains); } continue; } var asClass = top as ClassTypeDescription; if (asClass != null) { if (finishedClasses.Contains(asClass)) { continue; } seenClasses.Add(asClass); foreach (var key in asClass.Members.Keys.ToList()) { var val = asClass.Members[key]; if (seenClasses.Contains(val)) { var id = ((ClassTypeDescription)val).Id != 0 ? ((ClassTypeDescription)val).Id : nextId(); ((ClassTypeDescription)val).Id = id; asClass.Members[key] = new BackReferenceTypeDescription(id); continue; } if (seenEnums.Contains(val)) { var id = ((EnumTypeDescription)val).Id != 0 ? ((EnumTypeDescription)val).Id : nextId(); ((EnumTypeDescription)val).Id = id; asClass.Members[key] = new BackReferenceTypeDescription(id); continue; } if (val is ClassTypeDescription) { seenClasses.Add((ClassTypeDescription)val); } if (val is EnumTypeDescription) { seenEnums.Add((EnumTypeDescription)val); } toCheck.Push(val); finishedClasses.Add(asClass); } continue; } var asEnum = top as EnumTypeDescription; if (asEnum != null) { if (seenEnums.Contains(asEnum)) { continue; } seenEnums.Add(asEnum); continue; } throw new Exception("Should have been able to get here, found [" + top + "]"); } }
private ListTypeDescription(TypeDescription contains, Type listType) { ForType = listType; Contains = contains; }
internal override Type GetPocoType(TypeDescription existing = null) { return typeof(IList<>).MakeGenericType(Contains.GetPocoType(existing)); }
private DictionaryTypeDescription(TypeDescription keyType, TypeDescription valueType) { KeyType = keyType; ValueType = valueType; }
static internal TypeDescription Create(TypeDescription keyType, TypeDescription valueType) { return(new DictionaryTypeDescription(keyType, valueType)); }
internal override Type GetPocoType(TypeDescription existing = null) { return(typeof(IList <>).MakeGenericType(Contains.GetPocoType(existing))); }
internal override Type GetPocoType(TypeDescription existing = null) { return(typeof(IDictionary <,>).MakeGenericType(KeyType.GetPocoType(existing), ValueType.GetPocoType(existing))); }
private Envelope(TypeDescription desc, byte[] payload) { Version = CurrentVersion; Description = desc; Payload = payload; }
internal override void Seal(TypeDescription existing = null) { KeyType.Seal(existing); ValueType.Seal(existing); }
public static RuntimeTypeModel BuildTypeModel(TypeDescription desc, RuntimeTypeModel existing = null) { existing = existing ?? RuntimeTypeModel.Create(); if (desc is SimpleTypeDescription) return existing; if (desc is NullableTypeDescription) return existing; if (desc is BackReferenceTypeDescription) return existing; if (desc is DictionaryTypeDescription) { var key = ((DictionaryTypeDescription)desc).KeyType; var val = ((DictionaryTypeDescription)desc).ValueType; BuildTypeModel(key, existing); BuildTypeModel(val, existing); return existing; } if (desc is ListTypeDescription) { var contains = ((ListTypeDescription)desc).Contains; BuildTypeModel(contains, existing); return existing; } if (desc is EnumTypeDescription) { var meta = existing.Add(((EnumTypeDescription)desc).ForType, applyDefaultBehaviour: false); var ordered = ((EnumTypeDescription)desc).Values.OrderBy(o => o, StringOrdinalComparer.Singleton); var equiv = 0; foreach (var val in ordered) { meta.AddField(equiv, val); equiv++; } return existing; } if (!(desc is ClassTypeDescription)) { throw new Exception("Unexpected desc: " + desc); } var asClass = desc as ClassTypeDescription; var type = existing.Add(asClass.ForType, applyDefaultBehaviour: false); int ix = 1; foreach (var mem in asClass.Members.OrderBy(o => o.Key, StringComparer.Ordinal)) { type.AddField(ix, mem.Key); BuildTypeModel(mem.Value, existing); ix++; } return existing; }
internal override Type GetPocoType(TypeDescription existing = null) { return typeof(IDictionary<,>).MakeGenericType(KeyType.GetPocoType(existing), ValueType.GetPocoType(existing)); }
internal NullableTypeDescription(TypeDescription inner) { InnerType = inner; }
internal override TypeDescription DePromise(out Action afterPromise) { InnerType = InnerType.DePromise(out afterPromise); return(this); }
private static void MakeModel(Type type, TypeDescription description, ProtoBuf.Meta.RuntimeTypeModel model) { if (description is SimpleTypeDescription) { return; } if (description is BackReferenceTypeDescription) { return; } var nullable = description as NullableTypeDescription; if (nullable != null) { var underlying = Nullable.GetUnderlyingType(type); MakeModel(underlying, nullable.InnerType, model); return; } var list = description as ListTypeDescription; if (list != null) { var listI = type.GetListInterface(); MakeModel(listI.GetGenericArguments()[0], list.Contains, model); return; } var dict = description as DictionaryTypeDescription; if (dict != null) { var dictI = type.GetDictionaryInterface(); MakeModel(dictI.GetGenericArguments()[0], dict.KeyType, model); MakeModel(dictI.GetGenericArguments()[1], dict.ValueType, model); return; } var enumD = description as EnumTypeDescription; if (enumD != null) { var eT = model.Add(type, applyDefaultBehaviour: false); for (var i = 0; i < enumD.Values.Count; i++) { eT.AddField(i, enumD.Values[i]); } return; } var classD = description as ClassTypeDescription; if (classD != null) { var cT = model.Add(type, applyDefaultBehaviour: false); var memNames = classD.Members.Keys.OrderBy(o => o, StringComparer.Ordinal).ToList(); for (var i = 0; i < memNames.Count; i++) { var mem = type.GetMember(memNames[i], BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SingleOrDefault(); if (mem == null) { continue; } var field = cT.AddField(i + 1, memNames[i]); var memType = mem is PropertyInfo ? ((PropertyInfo)mem).PropertyType : ((FieldInfo)mem).FieldType; MakeModel( memType, classD.Members[memNames[i]], model ); } return; } throw new Exception("Unexpected description [" + description + "]"); }
internal static TypeDescription Create(TypeDescription keyType, TypeDescription valueType) { return new DictionaryTypeDescription(keyType, valueType); }
internal override Type GetPocoType(TypeDescription existingDescription = null) { return(Fulfilment.GetPocoType(existingDescription)); }
internal override void Seal(TypeDescription existing = null) { if (PocoType != null || TypeBuilder != null) return; var name = "POCO" + Guid.NewGuid().ToString().Replace("-", ""); var protoMemberAttr = typeof(ProtoMemberAttribute).GetConstructor(new[] { typeof(int) }); var protoContractAttr = typeof(ProtoContractAttribute).GetConstructor(new Type[0]); var fields = new Dictionary<string, FieldInfo>(); TypeBuilder = ModuleBuilder.DefineType(name, TypeAttributes.Public, typeof(DynamicObject), new [] { typeof(IEnumerable) }); var ix = 1; foreach (var kv in Members.OrderBy(o => o.Key, StringComparer.Ordinal)) { var memberAttrBuilder = new CustomAttributeBuilder(protoMemberAttr, new object[] { ix }); kv.Value.Seal(existing); var propType = kv.Value.GetPocoType(existing); var field = TypeBuilder.DefineField(kv.Key, propType, FieldAttributes.Public); field.SetCustomAttribute(memberAttrBuilder); fields[kv.Key] = field; ix++; } var contractAttrBuilder = new CustomAttributeBuilder(protoContractAttr, new object[0]); TypeBuilder.SetCustomAttribute(contractAttrBuilder); // Define indexer var strEq = typeof(object).GetMethod("Equals", new[] { typeof(object) }); var tryGetIndexEmit = Sigil.Emit<TryGetIndexerDelegate>.BuildMethod(TypeBuilder, "TryGetIndex", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.Standard | CallingConventions.HasThis); tryGetIndexEmit.LoadArgument(2); // object[] var invalid = tryGetIndexEmit.DefineLabel("invalid"); tryGetIndexEmit .Duplicate() // object[] object[] .LoadLength<object>() // int object[] .LoadConstant(1); // int int object[] tryGetIndexEmit.UnsignedBranchIfNotEqual(invalid); // object[] tryGetIndexEmit .LoadConstant(0) // int object[] .LoadElement<object>() // object .IsInstance<string>(); // int var valid = tryGetIndexEmit.DefineLabel("valid"); tryGetIndexEmit .BranchIfTrue(valid) // --empty-- .LoadArgument(2); // object[] tryGetIndexEmit.MarkLabel(invalid); tryGetIndexEmit.Pop(); // --empty-- tryGetIndexEmit .LoadArgument(3) // object& .LoadNull() // null object& .StoreIndirect(typeof(object)); // --empty-- tryGetIndexEmit .LoadConstant(0) // int .Return(); // --empty-- tryGetIndexEmit.MarkLabel(valid); tryGetIndexEmit.LoadArgument(3); // object& tryGetIndexEmit .LoadArgument(2) // object[] object& .LoadConstant(0) // int object[] object& .LoadElement<object>(); // object object& Sigil.Label next; var done = tryGetIndexEmit.DefineLabel("done"); foreach (var mem in Members) { next = tryGetIndexEmit.DefineLabel("next_" + mem.Key); var memKey = mem.Key; var field = fields[memKey]; tryGetIndexEmit .Duplicate() // object object object& .LoadConstant(memKey); // string object object object& tryGetIndexEmit.CallVirtual(strEq); // int object object7& tryGetIndexEmit.BranchIfFalse(next); // object object& tryGetIndexEmit .Pop() // object& .LoadArgument(0) // this object& .LoadField(field); // fieldType object& if (field.FieldType.IsValueType) { tryGetIndexEmit.Box(field.FieldType); // fieldType object& } tryGetIndexEmit.Branch(done); // fieldType object& tryGetIndexEmit.MarkLabel(next); // object object& } tryGetIndexEmit .Pop() // object& .LoadNull(); // null object& tryGetIndexEmit.MarkLabel(done); // *something* object& tryGetIndexEmit .StoreIndirect(typeof(object)) // --empty-- .LoadConstant(1) // int .Return(); // --empty-- var tryGetIndex = tryGetIndexEmit.CreateMethod(); TypeBuilder.DefineMethodOverride(tryGetIndex, typeof(DynamicObject).GetMethod("TryGetIndex")); // Implement IEnumerable var getEnumeratorEmit = Sigil.Emit<Func<IEnumerator>>.BuildMethod(TypeBuilder, "GetEnumerator", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.Standard | CallingConventions.HasThis); var newStrList = typeof(List<string>).GetConstructor(new[] { typeof(int) }); var newEnumerator = Enumerator.GetConstructor(new[] { typeof(List<string>), typeof(object) }); var add = typeof(List<string>).GetMethod("Add"); getEnumeratorEmit.LoadConstant(Members.Count); getEnumeratorEmit.NewObject(newStrList); foreach (var mem in Members) { getEnumeratorEmit.Duplicate(); getEnumeratorEmit.LoadConstant(mem.Key); getEnumeratorEmit.Call(add); } getEnumeratorEmit.LoadArgument(0); getEnumeratorEmit.NewObject(newEnumerator); getEnumeratorEmit.Return(); var getEnumerator = getEnumeratorEmit.CreateMethod(); TypeBuilder.DefineMethodOverride(getEnumerator, typeof(IEnumerable).GetMethod("GetEnumerator")); // Define ToString() var toStringEmit = Sigil.Emit<Func<string>>.BuildMethod(TypeBuilder, "ToString", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.Standard | CallingConventions.HasThis); var objToString = typeof(object).GetMethod("ToString"); var thunkField = TypeBuilder.DefineField("__ToStringThunk", typeof(Func<object, string>), FieldAttributes.Static | FieldAttributes.Private); var invoke = typeof(Func<object, string>).GetMethod("Invoke"); toStringEmit .LoadField(thunkField) .LoadArgument(0) .CallVirtual(invoke) .Return(); var toString = toStringEmit.CreateMethod(); TypeBuilder.DefineMethodOverride(toString, objToString); PocoType = TypeBuilder.CreateType(); // Set the ToStringCallback var firstInst = PocoType.GetConstructor(Type.EmptyTypes).Invoke(new object[0]); var setThunk = firstInst.GetType().GetField("__ToStringThunk", BindingFlags.NonPublic | BindingFlags.Static); setThunk.SetValue(firstInst, ToStringFunc); }
internal override Type GetPocoType(TypeDescription existingDescription = null) { return Fulfilment.GetPocoType(existingDescription); }
internal override Type GetPocoType(TypeDescription existing = null) { switch (Tag) { case LongTag: return typeof(long); case ULongTag: return typeof(ulong); case IntTag: return typeof(int); case UIntTag: return typeof(uint); case ShortTag: return typeof(short); case UShortTag: return typeof(ushort); case ByteTag: return typeof(byte); case SByteTag: return typeof(sbyte); case BoolTag: return typeof(bool); case DoubleTag: return typeof(double); case FloatTag: return typeof(float); case DecimalTag: return typeof(decimal); case StringTag: return typeof(string); case CharTag: return typeof(char); case DateTimeTag: return typeof(DateTime); case TimeSpanTag: return typeof(TimeSpan); case GuidTag: return typeof(Guid); case UriTag: return typeof(Uri); default: throw new Exception("Unexpected Tag [" + Tag + "]"); } }