public static TypeReferenceBuilder ToTypeReference( this ITypeDescriptor typeReferenceDescriptor, TypeReferenceBuilder?builder = null) { TypeReferenceBuilder actualBuilder = builder ?? TypeReferenceBuilder.New(); if (typeReferenceDescriptor is NonNullTypeDescriptor n) { typeReferenceDescriptor = n.InnerType; } else { actualBuilder.SetIsNullable(true); } return(typeReferenceDescriptor switch { ListTypeDescriptor list => ToTypeReference(list.InnerType, actualBuilder.SetListType()), EnumTypeDescriptor @enum => actualBuilder.SetName(@enum.RuntimeType.ToString()), ILeafTypeDescriptor leaf => actualBuilder.SetName(leaf.RuntimeType.ToString()), INamedTypeDescriptor named => actualBuilder.SetName(named.RuntimeType.ToString()), _ => throw new ArgumentOutOfRangeException(nameof(typeReferenceDescriptor)) });
private void AddArrayHandler( ClassBuilder classBuilder, ConstructorBuilder constructorBuilder, MethodBuilder methodBuilder, ListTypeDescriptor listTypeDescriptor, HashSet <string> processed, bool isNonNullable) { methodBuilder.AddParameter( ParameterBuilder.New() .SetType(listTypeDescriptor.ToEntityIdBuilder()) .SetName(ListParamName)); var listVarName = listTypeDescriptor.Name.WithLowerFirstChar() + "s"; if (!isNonNullable) { methodBuilder.AddCode(EnsureProperNullability(ListParamName, isNonNullable)); } methodBuilder.AddCode( AssignmentBuilder.New() .SetLefthandSide($"var {listVarName}") .SetRighthandSide( CodeBlockBuilder.New() .AddCode("new ") .AddCode(TypeNames.List) .AddCode("<") .AddCode( listTypeDescriptor.InnerType.ToBuilder() .SkipTrailingSpace()) .AddCode(">") .AddCode("()"))); methodBuilder.AddEmptyLine(); var loopbuilder = ForEachBuilder.New() .SetLoopHeader( CodeBlockBuilder.New() .AddCode(listTypeDescriptor.InnerType.ToEntityIdBuilder()) .AddCode($"child in {ListParamName}")) .AddCode( MethodCallBuilder.New() .SetPrefix($"{listVarName}.") .SetMethodName("Add") .AddArgument( BuildMapMethodCall( listTypeDescriptor.InnerType, "child"))); methodBuilder.AddCode(loopbuilder); methodBuilder.AddEmptyLine(); methodBuilder.AddCode($"return {listVarName};"); AddMapMethod( listVarName, listTypeDescriptor.InnerType, classBuilder, constructorBuilder, processed); }
public ITypeDescriptor Create(Type type) { SerializerTypeInfo result; if (_typeOrDescriptor2Info.TryGetValue(type, out result)) { return(result.Descriptor); } if (_typeOrDescriptor2InfoNew.TryGetValue(type, out result)) { return(result.Descriptor); } ITypeDescriptor desc = null; if (!type.IsSubclassOf(typeof(Delegate))) { if (type.IsGenericType) { if (type.GetGenericTypeDefinition().InheritsOrImplements(typeof(IList <>))) { desc = new ListTypeDescriptor(this, type); } else if (type.GetGenericTypeDefinition().InheritsOrImplements(typeof(IDictionary <,>))) { desc = new DictionaryTypeDescriptor(this, type); } } else if (type.IsArray) { desc = new ListTypeDescriptor(this, type); } else if (type.IsEnum) { desc = new EnumTypeDescriptor(this, type); } else { desc = new ObjectTypeDescriptor(this, type); } } if (desc == null) { throw new BTDBException("Don't know how to serialize type " + type.ToSimpleName()); } result = new SerializerTypeInfo { Id = 0, Descriptor = desc }; _typeOrDescriptor2InfoNew[desc] = result; _typeOrDescriptor2InfoNew[type] = result; desc.FinishBuildFromType(this); return(desc); }
private static string BuildDeserializeMethodName( ITypeDescriptor typeDescriptor, bool parentIsList = false) { return(typeDescriptor switch { ListTypeDescriptor listTypeDescriptor => BuildDeserializeMethodName(listTypeDescriptor.InnerType, true) + "Array", InterfaceTypeDescriptor { ImplementedBy : { Count : > 1 },
public static bool ContainsEntity(this ITypeDescriptor typeDescriptor) { return(typeDescriptor switch { ListTypeDescriptor listTypeDescriptor => listTypeDescriptor.InnerType.ContainsEntity(), ComplexTypeDescriptor namedTypeDescriptor => namedTypeDescriptor.Properties .Any(prop => prop.Type.IsEntityType() || prop.Type.ContainsEntity()), NonNullTypeDescriptor nonNullTypeDescriptor => nonNullTypeDescriptor.InnerType.ContainsEntity(), _ => false });
public static bool ContainsEntity(this ITypeDescriptor typeDescriptor) { return(typeDescriptor switch { ListTypeDescriptor listTypeDescriptor => listTypeDescriptor.InnerType.ContainsEntity(), NamedTypeDescriptor namedTypeDescriptor => namedTypeDescriptor.Properties.Any(prop => prop.Type.IsEntityType() || prop.Type.ContainsEntity()), NonNullTypeDescriptor nonNullTypeDescriptor => nonNullTypeDescriptor.InnerType.ContainsEntity(), _ => throw new ArgumentOutOfRangeException(nameof(typeDescriptor)) });
private static string BuildMapMethodName( ITypeDescriptor typeDescriptor, bool parentIsList = false) { return(typeDescriptor switch { ListTypeDescriptor listTypeDescriptor => BuildMapMethodName(listTypeDescriptor.InnerType, true) + "Array", ILeafTypeDescriptor leafTypeDescriptor => GetPropertyName(leafTypeDescriptor.Name), InterfaceTypeDescriptor { ImplementedBy : { Count : > 1 },
private void AddArrayHandler( ClassBuilder classBuilder, MethodBuilder methodBuilder, ListTypeDescriptor listTypeDescriptor, HashSet <string> processed) { var listVarName = GetParameterName(listTypeDescriptor.Name) + "s"; methodBuilder .AddCode( AssignmentBuilder .New() .SetLefthandSide($"var {listVarName}") .SetRighthandSide( CodeBlockBuilder .New() .AddCode("new ") .AddCode(TypeNames.List) .AddCode("<") .AddCode( listTypeDescriptor.InnerType .ToStateTypeReference() .SkipTrailingSpace()) .AddCode(">") .AddCode("()"))) .AddEmptyLine() .AddCode( ForEachBuilder .New() .SetLoopHeader( $"{TypeNames.JsonElement} {_child} in {_obj}.Value.EnumerateArray()") .AddCode( MethodCallBuilder .New() .SetMethodName(listVarName, nameof(List <object> .Add)) .AddArgument( BuildUpdateMethodCall( listTypeDescriptor.InnerType, CodeInlineBuilder.From(_child))))) .AddEmptyLine() .AddCode($"return {listVarName};"); AddDeserializeMethod(listTypeDescriptor.InnerType, classBuilder, processed); }
private static ICode BuildProperty( ITypeDescriptor type, string propertyName) { return(BuildPropertyInternal(type, propertyName, true)); ICode BuildPropertyInternal( ITypeDescriptor currentType, string variableName, bool isNullable) { ICode check = currentType switch { NonNullTypeDescriptor d => BuildPropertyInternal(d.InnerType, variableName, false), INamedTypeDescriptor => AssignmentBuilder .New() .SetLefthandSide(HashCodeBuilder.VariableName) .SetOperator("^=") .SetRighthandSide(MethodCallBuilder .Inline() .SetPrefix($"{HashCodeBuilder.Prime} * ") .SetMethodName(variableName, nameof(GetHashCode))), ListTypeDescriptor d => ForEachBuilder .New() .SetLoopHeader($"var {variableName}_elm in {variableName}") .AddCode(BuildPropertyInternal(d.InnerType, variableName + "_elm", true)), _ => throw new ArgumentOutOfRangeException() }; if (isNullable && currentType is not NonNullTypeDescriptor) { return(IfBuilder .New() .SetCondition($"!({variableName} is null)") .AddCode(check)); } return(check); } } }
private void AddArrayHandler( ClassBuilder classBuilder, MethodBuilder methodBuilder, ListTypeDescriptor listTypeDescriptor, HashSet <string> processed) { var listVarName = listTypeDescriptor.Name.WithLowerFirstChar() + "s"; methodBuilder.AddCode( AssignmentBuilder.New() .SetLefthandSide($"var {listVarName}") .SetRighthandSide( CodeBlockBuilder.New() .AddCode("new ") .AddCode(TypeNames.List) .AddCode("<") .AddCode(listTypeDescriptor.InnerType.ToEntityIdBuilder() .SkipTrailingSpace()) .AddCode(">") .AddCode("()") )); methodBuilder.AddEmptyLine(); methodBuilder.AddCode( ForEachBuilder.New() .SetLoopHeader( $"{TypeNames.JsonElement} child in {_objParamName}.Value.EnumerateArray()") .AddCode( MethodCallBuilder.New() .SetPrefix($"{listVarName}.") .SetMethodName("Add") .AddArgument( BuildUpdateMethodCall(listTypeDescriptor.InnerType, "child")))); methodBuilder.AddEmptyLine(); methodBuilder.AddCode($"return {listVarName};"); AddDeserializeMethod(listTypeDescriptor.InnerType, classBuilder, processed); }
/// <summary> /// Formats a list type /// </summary> /// <param name="listType"></param> /// <returns></returns> public override string FormatListType(ListTypeDescriptor listType) { return($"{listType.TypeArg.FormatType(this)}[]"); }
public void ProcessMetadataLog(ByteBuffer buffer) { var reader = new ByteBufferReader(buffer); var typeId = reader.ReadVInt32(); while (typeId != 0) { var typeCategory = (TypeCategory)reader.ReadUInt8(); ITypeDescriptor descriptor; switch (typeCategory) { case TypeCategory.BuildIn: throw new ArgumentOutOfRangeException(); case TypeCategory.Class: descriptor = new ObjectTypeDescriptor(this, reader, NestedDescriptorReader); break; case TypeCategory.List: descriptor = new ListTypeDescriptor(this, reader, NestedDescriptorReader); break; case TypeCategory.Dictionary: descriptor = new DictionaryTypeDescriptor(this, reader, NestedDescriptorReader); break; case TypeCategory.Enum: descriptor = new EnumTypeDescriptor(this, reader); break; case TypeCategory.Nullable: descriptor = new NullableTypeDescriptor(this, reader, NestedDescriptorReader); break; default: throw new ArgumentOutOfRangeException(); } while (-typeId - 1 >= _id2InfoNew.Count) { _id2InfoNew.Add(null); } if (_id2InfoNew[-typeId - 1] == null) { _id2InfoNew[-typeId - 1] = new DeserializerTypeInfo { Id = typeId, Descriptor = descriptor } } ; typeId = reader.ReadVInt32(); } for (var i = 0; i < _id2InfoNew.Count; i++) { _id2InfoNew[i].Descriptor.MapNestedTypes(d => { var placeHolderDescriptor = d as PlaceHolderDescriptor; return(placeHolderDescriptor != null ? _id2InfoNew[-placeHolderDescriptor.TypeId - 1].Descriptor : d); }); } // This additional cycle is needed to fill names of recursive structures for (var i = 0; i < _id2InfoNew.Count; i++) { _id2InfoNew[i].Descriptor.MapNestedTypes(d => d); } for (var i = 0; i < _id2InfoNew.Count; i++) { var infoForType = _id2InfoNew[i]; for (var j = ReservedBuildinTypes; j < _id2Info.Count; j++) { if (infoForType.Descriptor.Equals(_id2Info[j].Descriptor)) { _remapToOld[infoForType.Descriptor] = _id2Info[j].Descriptor; _id2InfoNew[i] = _id2Info[j]; infoForType = _id2InfoNew[i]; break; } } if (infoForType.Id < 0) { infoForType.Id = _id2Info.Count; _id2Info.Add(infoForType); _typeOrDescriptor2Info[infoForType.Descriptor] = infoForType; } } for (var i = 0; i < _id2InfoNew.Count; i++) { _id2InfoNew[i].Descriptor.MapNestedTypes(d => { ITypeDescriptor res; return(_remapToOld.TryGetValue(d, out res) ? res : d); }); } _id2InfoNew.Clear(); _remapToOld.Clear(); } Func <AbstractBufferedReader, ITypeBinaryDeserializerContext, ITypeDescriptor, object> LoaderFactory(ITypeDescriptor descriptor) { var loadAsType = LoadAsType(descriptor); var methodBuilder = ILBuilder.Instance.NewMethod <Func <AbstractBufferedReader, ITypeBinaryDeserializerContext, ITypeDescriptor, object> >("DeserializerFor" + descriptor.Name); var il = methodBuilder.Generator; descriptor.GenerateLoad(il, ilGen => ilGen.Ldarg(0), ilGen => ilGen.Ldarg(1), ilGen => ilGen.Ldarg(2), loadAsType); if (loadAsType.IsValueType) { il.Box(loadAsType); } else if (loadAsType != typeof(object)) { il.Castclass(typeof(object)); } il.Ret(); return(methodBuilder.Create()); }
public ITypeDescriptor Create(Type type) { if (_typeOrDescriptor2Info.TryGetValue(type, out var result)) { return(result.Descriptor); } if (_typeOrDescriptor2InfoNew.TryGetValue(type, out result)) { return(result.Descriptor); } ITypeDescriptor desc = null; Type typeAlternative = null; if (!type.IsSubclassOf(typeof(Delegate))) { if (type.IsGenericType) { typeAlternative = type.SpecializationOf(typeof(IList <>)); if (typeAlternative != null) { if (type != typeAlternative) { if (_typeOrDescriptor2Info.TryGetValue(typeAlternative, out result)) { _typeOrDescriptor2Info[type] = result; return(result.Descriptor); } if (_typeOrDescriptor2InfoNew.TryGetValue(typeAlternative, out result)) { _typeOrDescriptor2InfoNew[type] = result; return(result.Descriptor); } } desc = new ListTypeDescriptor(this, typeAlternative); } else { typeAlternative = type.SpecializationOf(typeof(IDictionary <,>)); if (typeAlternative != null) { if (type != typeAlternative) { if (_typeOrDescriptor2Info.TryGetValue(typeAlternative, out result)) { _typeOrDescriptor2Info[type] = result; return(result.Descriptor); } if (_typeOrDescriptor2InfoNew.TryGetValue(typeAlternative, out result)) { _typeOrDescriptor2InfoNew[type] = result; return(result.Descriptor); } } desc = new DictionaryTypeDescriptor(this, typeAlternative); } else if (type.GetGenericTypeDefinition().InheritsOrImplements(typeof(IIndirect <>))) { return(null); } else if (type.GetGenericTypeDefinition() == typeof(Nullable <>)) { typeAlternative = type.SpecializationOf(typeof(Nullable <>)); if (typeAlternative != null) { if (type != typeAlternative) { if (_typeOrDescriptor2Info.TryGetValue(typeAlternative, out result)) { _typeOrDescriptor2Info[type] = result; return(result.Descriptor); } if (_typeOrDescriptor2InfoNew.TryGetValue(typeAlternative, out result)) { _typeOrDescriptor2InfoNew[type] = result; return(result.Descriptor); } } desc = new NullableTypeDescriptor(this, typeAlternative); } } } } else if (type.IsArray) { typeAlternative = type.SpecializationOf(typeof(IList <>)); Debug.Assert(typeAlternative != null && type != typeAlternative); if (_typeOrDescriptor2Info.TryGetValue(typeAlternative, out result)) { _typeOrDescriptor2Info[type] = result; return(result.Descriptor); } if (_typeOrDescriptor2InfoNew.TryGetValue(typeAlternative, out result)) { _typeOrDescriptor2InfoNew[type] = result; return(result.Descriptor); } desc = new ListTypeDescriptor(this, typeAlternative); } else if (type.IsEnum) { desc = new EnumTypeDescriptor(this, type); } else if (type.IsValueType) { throw new BTDBException($"Unsupported value type {type.Name}."); } else { desc = new ObjectTypeDescriptor(this, type); } } if (desc == null) { throw new BTDBException("Don't know how to serialize type " + type.ToSimpleName()); } result = new SerializerTypeInfo { Id = 0, Descriptor = desc }; _typeOrDescriptor2InfoNew[desc] = result; _typeOrDescriptor2InfoNew[type] = result; if (typeAlternative != null) { _typeOrDescriptor2InfoNew[typeAlternative] = result; } if (!desc.FinishBuildFromType(this)) { _typeOrDescriptor2InfoNew.Remove(desc); _typeOrDescriptor2InfoNew.Remove(type); if (typeAlternative != null) { _typeOrDescriptor2InfoNew.Remove(typeAlternative); } return(null); } return(desc); }
public void ProcessMetadataLog(ByteBuffer buffer) { var reader = new ByteBufferReader(buffer); var typeId = reader.ReadVInt32(); while (typeId != 0) { var typeCategory = (TypeCategory)reader.ReadUInt8(); ITypeDescriptor descriptor; switch (typeCategory) { case TypeCategory.BuildIn: throw new ArgumentOutOfRangeException(); case TypeCategory.Class: descriptor = new ObjectTypeDescriptor(this, reader, NestedDescriptorReader); break; case TypeCategory.List: descriptor = new ListTypeDescriptor(this, reader, NestedDescriptorReader); break; case TypeCategory.Dictionary: descriptor = new DictionaryTypeDescriptor(this, reader, NestedDescriptorReader); break; case TypeCategory.Enum: descriptor = new EnumTypeDescriptor(this, reader); break; case TypeCategory.Nullable: descriptor = new NullableTypeDescriptor(this, reader, NestedDescriptorReader); break; default: throw new ArgumentOutOfRangeException(); } while (-typeId - 1 >= _id2InfoNew.Count) { _id2InfoNew.Add(null); } if (_id2InfoNew[-typeId - 1] == null) { _id2InfoNew[-typeId - 1] = new SerializerTypeInfo { Id = typeId, Descriptor = descriptor } } ; typeId = reader.ReadVInt32(); } for (var i = 0; i < _id2InfoNew.Count; i++) { _id2InfoNew[i] !.Descriptor.MapNestedTypes(d => { var placeHolderDescriptor = d as PlaceHolderDescriptor; return(placeHolderDescriptor != null ? _id2InfoNew[-placeHolderDescriptor.TypeId - 1] !.Descriptor : d); }); } // This additional cycle is needed to fill names of recursive structures for (var i = 0; i < _id2InfoNew.Count; i++) { _id2InfoNew[i] !.Descriptor.MapNestedTypes(d => d); } for (var i = 0; i < _id2InfoNew.Count; i++) { var infoForType = _id2InfoNew[i] !; for (var j = ReservedBuildinTypes; j < _id2Info.Count; j++) { if (infoForType.Descriptor.Equals(_id2Info[j].Descriptor)) { _remapToOld[infoForType.Descriptor] = _id2Info[j].Descriptor; _id2InfoNew[i] = _id2Info[j]; infoForType = _id2InfoNew[i]; break; } } if (infoForType.Id < 0) { infoForType.Id = _id2Info.Count; _id2Info.Add(infoForType); _typeOrDescriptor2Info[infoForType.Descriptor] = infoForType; } } for (var i = 0; i < _id2InfoNew.Count; i++) { _id2InfoNew[i] !.Descriptor.MapNestedTypes(d => { ITypeDescriptor res; return(_remapToOld.TryGetValue(d, out res) ? res : d); }); } _id2InfoNew.Clear(); _remapToOld.Clear(); }
private void AddArrayHandler( ClassBuilder classBuilder, ConstructorBuilder constructorBuilder, MethodBuilder methodBuilder, ListTypeDescriptor listTypeDescriptor, HashSet <string> processed, bool isNonNullable) { methodBuilder .AddParameter(_list) .SetType(listTypeDescriptor.ToEntityIdBuilder()); var listVarName = GetParameterName(listTypeDescriptor.Name) + "s"; if (!isNonNullable) { methodBuilder.AddCode(EnsureProperNullability(_list, isNonNullable)); } methodBuilder.AddCode( AssignmentBuilder .New() .SetLefthandSide($"var {listVarName}") .SetRighthandSide( CodeBlockBuilder .New() .AddCode("new ") .AddCode(TypeNames.List) .AddCode("<") .AddCode(listTypeDescriptor.InnerType.ToBuilder().SkipTrailingSpace()) .AddCode(">") .AddCode("()"))); methodBuilder.AddEmptyLine(); ForEachBuilder forEachBuilder = ForEachBuilder .New() .SetLoopHeader( CodeBlockBuilder .New() .AddCode(listTypeDescriptor.InnerType.ToEntityIdBuilder()) .AddCode($"{_child} in {_list}")) .AddCode( MethodCallBuilder .New() .SetMethodName(listVarName, nameof(List <object> .Add)) .AddArgument(MethodCallBuilder .Inline() .SetMethodName(MapMethodNameFromTypeName(listTypeDescriptor.InnerType)) .AddArgument(_child))); methodBuilder .AddCode(forEachBuilder) .AddEmptyLine() .AddCode($"return {listVarName};"); AddMapMethod( listVarName, listTypeDescriptor.InnerType, classBuilder, constructorBuilder, processed); }
/// <summary> /// Formats a list type /// </summary> /// <param name="listType"></param> /// <returns></returns> public abstract string FormatListType(ListTypeDescriptor listType);
private void AddArrayHandler( CSharpSyntaxGeneratorSettings settings, ClassBuilder classBuilder, ConstructorBuilder constructorBuilder, MethodBuilder methodBuilder, ListTypeDescriptor listTypeDescriptor, HashSet <string> processed, bool isNonNullable) { methodBuilder .AddParameter(_list) .SetType(listTypeDescriptor.ToStateTypeReference()); if (settings.IsStoreEnabled()) { methodBuilder .AddParameter(_snapshot) .SetType(TypeNames.IEntityStoreSnapshot); } var listVarName = GetParameterName(listTypeDescriptor.Name) + "s"; methodBuilder.AddCode(EnsureProperNullability(_list, isNonNullable)); methodBuilder.AddCode( AssignmentBuilder .New() .SetLefthandSide($"var {listVarName}") .SetRighthandSide( CodeBlockBuilder .New() .AddCode("new ") .AddCode(TypeNames.List) .AddCode("<") .AddCode( listTypeDescriptor.InnerType.ToTypeReference().SkipTrailingSpace()) .AddCode(">") .AddCode("()"))); methodBuilder.AddEmptyLine(); ForEachBuilder forEachBuilder = ForEachBuilder .New() .SetLoopHeader( CodeBlockBuilder .New() .AddCode(listTypeDescriptor.InnerType.ToStateTypeReference()) .AddCode($"{_child} in {_list}")) .AddCode( MethodCallBuilder .New() .SetMethodName(listVarName, nameof(List <object> .Add)) .AddArgument(MethodCallBuilder .Inline() .SetMethodName(MapMethodNameFromTypeName(listTypeDescriptor.InnerType)) .AddArgument(_child) .If(settings.IsStoreEnabled(), x => x.AddArgument(_snapshot)))); methodBuilder .AddCode(forEachBuilder) .AddEmptyLine() .AddCode($"return {listVarName};"); AddMapMethod( settings, listVarName, listTypeDescriptor.InnerType, classBuilder, constructorBuilder, processed); }