private static void GenerateCloneMethod( CodeWriter codeWriter, CompilerOptions options, ITypeModel typeModel, Dictionary <Type, string> methodNameMap) { string typeName = CSharpHelpers.GetCompilableTypeName(typeModel.ClrType); CodeGeneratedMethod method = typeModel.CreateCloneMethodBody(new CloneCodeGenContext("item", methodNameMap)); if (!typeModel.ClrType.IsValueType) { typeName += "?"; if (options.NullableWarnings == true) { codeWriter.AppendLine("[return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(\"item\")]"); } } codeWriter.AppendLine(method.GetMethodImplAttribute()); codeWriter.AppendLine($"public static {typeName} Clone({typeName} item)"); using (codeWriter.WithBlock()) { codeWriter.AppendLine(method.MethodBody); } }
/// <summary> /// Returns the fully qualified clone method name. /// </summary> public static string GenerateCloneMethodsForAssembly( CodeWriter writer, CompilerOptions options, Assembly assembly, TypeModelContainer container) { string @namespace = $"FlatSharp.Compiler.Generated"; string className = $"CloneHelpers_{Guid.NewGuid():n}"; string methodName = "Clone"; string fullyQualifiedMethodName = $"{@namespace}.{className}.{methodName}"; HashSet <Type> seenTypes = new HashSet <Type>(); foreach (var type in assembly.GetTypes()) { if (type.IsNested) { continue; } if (container.TryCreateTypeModel(type, out var typeModel)) { typeModel.TraverseObjectGraph(seenTypes); } } Dictionary <Type, string> methodNameMap = new Dictionary <Type, string>(); foreach (var seenType in seenTypes) { methodNameMap[seenType] = fullyQualifiedMethodName; } writer.AppendLine($"namespace {@namespace}"); using (writer.WithBlock()) { writer.AppendLine($"internal static class {className}"); using (writer.WithBlock()) { foreach (var seenType in seenTypes) { if (!container.TryCreateTypeModel(seenType, out ITypeModel? model)) { ErrorContext.Current.RegisterError($"Unable to create type model for Type '{seenType.FullName}.'"); continue; } GenerateCloneMethod(writer, options, model, methodNameMap); } } } return(fullyQualifiedMethodName); }
protected override void OnWriteCode(CodeWriter writer, CodeWritingPass pass, string forFile, IReadOnlyDictionary <string, string> precompiledSerailizers) { writer.AppendLine($"namespace {this.Name}"); writer.AppendLine($"{{"); using (writer.IncreaseIndent()) { foreach (var type in this.Children.Values) { type.WriteCode(writer, pass, forFile, precompiledSerailizers); } } writer.AppendLine($"}}"); }
protected override void OnWriteCode(CodeWriter writer, CompileContext context) { writer.AppendLine($"namespace {this.Name}"); writer.AppendLine($"{{"); using (writer.IncreaseIndent()) { foreach (var type in this.Children.Values) { type.WriteCode(writer, context); } } writer.AppendLine($"}}"); }
public void WriteCopyConstructorLine(CodeWriter writer, string sourceName, BaseSchemaMember parent) { bool isBuiltIn = SchemaDefinition.TryResolveBuiltInType(this.FbsFieldType, out _); bool foundNodeType = parent.TryResolveName(this.FbsFieldType, out var nodeType); if (!isBuiltIn && !foundNodeType) { ErrorContext.Current.RegisterError($"Unable to resolve type '{this.FbsFieldType}' as a built in or defined type"); return; } string selectStatement = this.GetLinqSelectStatement(isBuiltIn, nodeType); switch (this.VectorType) { case VectorType.IList: case VectorType.IReadOnlyList: writer.AppendLine($"this.{this.Name} = {sourceName}.{this.Name}?{selectStatement}.ToList();"); break; case VectorType.Array: writer.AppendLine($"this.{this.Name} = {sourceName}.{this.Name}?{selectStatement}.ToArray();"); break; case VectorType.Memory: case VectorType.ReadOnlyMemory: writer.AppendLine($"this.{this.Name} = {sourceName}.{this.Name}.ToArray();"); break; case VectorType.None: { if (isBuiltIn) { writer.AppendLine($"this.{this.Name} = {sourceName}.{this.Name};"); } else { string cloneStatement = nodeType.GetCopyExpression($"{sourceName}.{this.Name}"); writer.AppendLine($"this.{this.Name} = {cloneStatement};"); } } break; } }
protected override void OnWriteCode(CodeWriter writer, CodeWritingPass pass, IReadOnlyDictionary <string, string> precompiledSerailizers) { writer.AppendLine($@" //------------------------------------------------------------------------------ // <auto-generated> // This code was generated by the FlatSharp FBS to C# compiler (source hash: {this.inputHash}) // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // </auto-generated> //------------------------------------------------------------------------------ "); writer.AppendLine("using System;"); writer.AppendLine("using System.Collections.Generic;"); writer.AppendLine("using System.Linq;"); writer.AppendLine("using System.Runtime.CompilerServices;"); writer.AppendLine("using FlatSharp;"); writer.AppendLine("using FlatSharp.Attributes;"); foreach (var child in this.Children.Values) { child.WriteCode(writer, pass, precompiledSerailizers); } }
protected override void OnWriteCode(CodeWriter writer, CodeWritingPass pass, IReadOnlyDictionary <string, string> precompiledSerailizers) { this.AssignIndexes(); string attribute = this.IsTable ? "[FlatBufferTable]" : "[FlatBufferStruct]"; writer.AppendLine(attribute); writer.AppendLine("[System.Runtime.CompilerServices.CompilerGenerated]"); writer.AppendLine($"public partial class {this.Name} : object"); writer.AppendLine($"{{"); using (writer.IncreaseIndent()) { foreach (var field in this.Fields) { if (!this.IsTable && field.Deprecated) { ErrorContext.Current?.RegisterError($"FlatBuffer structs may not have deprecated fields."); } field.WriteField(writer, this); } if (pass == CodeWritingPass.SecondPass && precompiledSerailizers != null && this.RequestedSerializer != null) { if (precompiledSerailizers.TryGetValue(this.FullName, out string serializer)) { writer.AppendLine($"public static ISerializer<{this.FullName}> Serializer {{ get; }} = new {RoslynSerializerGenerator.GeneratedSerializerClassName}().AsISerializer();"); writer.AppendLine(string.Empty); writer.AppendLine($"#region Serializer for {this.FullName}"); writer.AppendLine(serializer); writer.AppendLine($"#endregion"); } else { ErrorContext.Current.RegisterError($"Table {this.FullName} requested serializer, but none was found."); } } } writer.AppendLine($"}}"); }
private void WriteField( CodeWriter writer, string clrTypeName, string defaultValue, string name, string accessModifier = "public") { string defaultValueAttribute = string.Empty; string defaultValueAssignment = string.Empty; string isKey = string.Empty; string sortedVector = string.Empty; string isDeprecated = string.Empty; if (!string.IsNullOrEmpty(defaultValue)) { defaultValueAttribute = $", DefaultValue = {defaultValue}"; defaultValueAssignment = $" = {defaultValue};"; } if (this.SortedVector) { sortedVector = ", SortedVector = true"; } if (this.IsKey) { isKey = ", Key = true"; } if (this.Deprecated) { isDeprecated = ", Deprecated = true"; } writer.AppendLine($"[FlatBufferItem({this.Index}{defaultValueAttribute}{isDeprecated}{sortedVector}{isKey})]"); writer.AppendLine($"{accessModifier} virtual {clrTypeName} {name} {{ get; set; }}{defaultValueAssignment}"); }
protected override void OnWriteCode(CodeWriter writer, CodeWritingPass pass, IReadOnlyDictionary <string, string> precompiledSerailizers) { writer.AppendLine($"[FlatBufferEnum(typeof({this.ClrUnderlyingType}))]"); writer.AppendLine("[System.Runtime.CompilerServices.CompilerGenerated]"); writer.AppendLine($"public enum {this.Name} : {this.ClrUnderlyingType}"); writer.AppendLine($"{{"); using (writer.IncreaseIndent()) { foreach (var item in this.nameValuePairs) { writer.AppendLine($"{item.Key} = {item.Value},"); } } writer.AppendLine($"}}"); writer.AppendLine(string.Empty); }
public void EmitStructVector(TableOrStructDefinition parent, CodeWriter writer, CompileContext context) { string typeName = parent.ResolveTypeName(this.FbsTypeName, context, out ITypeModel? typeModel); writer.AppendLine($"public {this.ClassName} {this.Name} {{ get; }}"); writer.AppendLine(); // class is next. writer.AppendLine($"public sealed partial class {this.ClassName} : System.Collections.Generic.IEnumerable<{typeName}>"); using (writer.WithBlock()) { writer.AppendLine($"private readonly {parent.Name} item;"); // ctor writer.AppendLine(); writer.AppendLine($"public {this.ClassName}({parent.Name} item)"); using (writer.WithBlock()) { writer.AppendLine($"this.item = item;"); } writer.AppendLine($"public int Count => {this.PropertyNames.Count};"); // indexer writer.AppendLine(); writer.AppendLine($"public {typeName} this[int index]"); using (writer.WithBlock()) { writer.AppendLine("get"); using (writer.WithBlock()) { writer.AppendLine("var thisItem = this.item;"); writer.AppendLine("switch (index)"); using (writer.WithBlock()) { for (int i = 0; i < this.PropertyNames.Count; ++i) { writer.AppendLine($"case {i}: return thisItem.{this.PropertyNames[i]};"); } writer.AppendLine($"default: throw new IndexOutOfRangeException();"); } } writer.AppendLine(); writer.AppendLine("set"); using (writer.WithBlock()) { writer.AppendLine("var thisItem = this.item;"); writer.AppendLine("switch (index)"); using (writer.WithBlock()) { for (int i = 0; i < this.PropertyNames.Count; ++i) { writer.AppendLine($"case {i}: thisItem.{this.PropertyNames[i]} = value; break;"); } writer.AppendLine($"default: throw new IndexOutOfRangeException();"); } } } writer.AppendLine("System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => this.GetEnumerator();"); writer.AppendLine(); writer.AppendLine($"public System.Collections.Generic.IEnumerator<{typeName}> GetEnumerator()"); using (writer.WithBlock()) { writer.AppendLine("var thisItem = this.item;"); for (int i = 0; i < this.PropertyNames.Count; ++i) { writer.AppendLine($"yield return thisItem.{this.PropertyNames[i]};"); } if (this.PropertyNames.Count == 0) { writer.AppendLine("yield break;"); } } string arrayOrSpanType = $"{typeName}[]"; if (typeModel is not null && typeModel.ClassifyContextually(FlatBufferSchemaType.Struct).IsRequiredValue()) { arrayOrSpanType = $"ReadOnlySpan<{typeName}>"; } foreach (var collectionType in new[] { arrayOrSpanType, $"IReadOnlyList<{typeName}>" }) { writer.AppendMethodSummaryComment($"Deep copies the first {this.PropertyNames.Count} items from the source into this struct vector."); writer.AppendLine($"public void CopyFrom({collectionType} source)"); using (writer.WithBlock()) { writer.AppendLine("var thisItem = this.item;"); // Load in reverse so that the JIT can just do a bounds check on the very first item. // This also requries the parameter being a local variable instead of a param. writer.AppendLine("var s = source;"); for (int i = this.PropertyNames.Count - 1; i >= 0; --i) { writer.AppendLine($"thisItem.{this.PropertyNames[i]} = {context.FullyQualifiedCloneMethodName}(s[{i}]);"); } } } } }
public void EmitStructVectorInitializer(CodeWriter writer) { writer.AppendLine($"this.{this.Name} = new {this.ClassName}(this);"); }
protected override void OnWriteCode(CodeWriter writer, CompileContext context) { this.AssignIndexes(); string attribute = "[FlatBufferStruct]"; if (this.IsTable) { if (string.IsNullOrEmpty(this.FileIdentifier)) { attribute = "[FlatBufferTable]"; } else { attribute = $"[FlatBufferTable({nameof(FlatBufferTableAttribute.FileIdentifier)} = \"{this.FileIdentifier}\")]"; } } writer.AppendLine(attribute); writer.AppendLine("[System.Runtime.CompilerServices.CompilerGenerated]"); writer.AppendLine($"public partial class {this.Name} : object"); writer.AppendLine($"{{"); using (writer.IncreaseIndent()) { // Default ctor. var defaultCtorKind = this.DefaultConstructorKind ?? Compiler.DefaultConstructorKind.Public; if (defaultCtorKind != Compiler.DefaultConstructorKind.None) { if (defaultCtorKind == Compiler.DefaultConstructorKind.PublicObsolete) { writer.AppendLine("[Obsolete]"); } writer.AppendLine($"public {this.Name}()"); using (writer.WithBlock()) { foreach (var field in this.Fields) { field.WriteDefaultConstructorLine(writer, context); } this.EmitStructVectorInitializations(writer); writer.AppendLine("this.OnInitialized(null);"); } } else if (!this.IsTable) { ErrorContext.Current.RegisterError("Structs must have default constructors."); } writer.AppendLine("#pragma warning disable CS8618"); // NULL FORGIVING writer.AppendLine($"protected {this.Name}({nameof(FlatBufferDeserializationContext)} context)"); using (writer.WithBlock()) { this.EmitStructVectorInitializations(writer); writer.AppendLine("this.OnInitialized(context);"); } writer.AppendLine("#pragma warning restore CS8618"); // NULL FORGIVING // Copy constructor. writer.AppendLine($"public {this.Name}({this.Name} source)"); using (writer.WithBlock()) { foreach (var field in this.Fields) { field.WriteCopyConstructorLine(writer, "source", context); } this.EmitStructVectorInitializations(writer); writer.AppendLine("this.OnInitialized(null);"); } writer.AppendLine($"partial void OnInitialized({nameof(FlatBufferDeserializationContext)}? context);"); foreach (var field in this.Fields) { field.WriteField(writer, this, context); } foreach (var structVector in this.StructVectors) { structVector.EmitStructVector(this, writer, context); } if (context.CompilePass >= CodeWritingPass.SerializerGeneration && this.RequestedSerializer is not null) { // generate the serializer. string serializer = this.GenerateSerializerForType( context, this.RequestedSerializer.Value); writer.AppendLine($"public static ISerializer<{this.FullName}> {SerializerPropertyName} {{ get; }} = new {RoslynSerializerGenerator.GeneratedSerializerClassName}().AsISerializer();"); writer.AppendLine(string.Empty); writer.AppendLine($"#region Serializer for {this.FullName}"); writer.AppendLine(serializer); writer.AppendLine($"#endregion"); } } writer.AppendLine($"}}"); }
private void WriteField( CodeWriter writer, string clrTypeName, string defaultValue, string name, TableOrStructDefinition parent) { string defaultValueAttribute = string.Empty; string defaultValueAssignment = string.Empty; string isKey = string.Empty; string sortedVector = string.Empty; string isDeprecated = string.Empty; if (!string.IsNullOrEmpty(defaultValue)) { defaultValueAttribute = $", DefaultValue = {defaultValue}"; defaultValueAssignment = $" = {defaultValue};"; } if (this.SortedVector) { sortedVector = ", SortedVector = true"; } if (this.IsKey) { isKey = ", Key = true"; } if (this.Deprecated) { isDeprecated = ", Deprecated = true"; } bool isNonVirtual = false; if (this.NonVirtual != null) { isNonVirtual = this.NonVirtual.Value; } else if (parent.NonVirtual != null) { isNonVirtual = parent.NonVirtual.Value; } string accessModifier = this.SetterKind switch { SetterKind.Public => string.Empty, // setter has same access as getter. SetterKind.Protected => "protected", SetterKind.ProtectedInternal => "protected internal", SetterKind.None => null, _ => string.Empty, }; string setter = $"{accessModifier} set;"; if (accessModifier == null) { setter = string.Empty; } writer.AppendLine($"[FlatBufferItem({this.Index}{defaultValueAttribute}{isDeprecated}{sortedVector}{isKey})]"); writer.AppendLine($"public {(isNonVirtual ? string.Empty : "virtual ")}{clrTypeName} {name} {{ get; {setter} }}{defaultValueAssignment}"); }
public void EmitStructVector(TableOrStructDefinition parent, CodeWriter writer, CompileContext context) { string typeName = parent.ResolveTypeName(this.FbsTypeName, context); string className = $"{this.Name}Vector"; // two parts: property definition and class definition. writer.AppendLine($"private {className}? _{this.Name};"); writer.AppendLine($"public {className} {this.Name} => (this._{this.Name} ??= new {className}(this));"); writer.AppendLine(); // class is next. writer.AppendLine($"public sealed partial class {className} : System.Collections.Generic.IEnumerable<{typeName}>"); using (writer.WithBlock()) { writer.AppendLine($"private readonly {parent.Name} item;"); // ctor writer.AppendLine(); writer.AppendLine($"public {className}({parent.Name} item)"); using (writer.WithBlock()) { writer.AppendLine($"this.item = item;"); } writer.AppendLine($"public int Count => {this.PropertyNames.Count};"); // indexer writer.AppendLine(); writer.AppendLine($"public {typeName} this[int index]"); using (writer.WithBlock()) { writer.AppendLine("get"); using (writer.WithBlock()) { writer.AppendLine("switch (index)"); using (writer.WithBlock()) { for (int i = 0; i < this.PropertyNames.Count; ++i) { writer.AppendLine($"case {i}: return this.item.{this.PropertyNames[i]};"); } writer.AppendLine($"default: throw new IndexOutOfRangeException();"); } } writer.AppendLine(); writer.AppendLine("set"); using (writer.WithBlock()) { writer.AppendLine("switch (index)"); using (writer.WithBlock()) { for (int i = 0; i < this.PropertyNames.Count; ++i) { writer.AppendLine($"case {i}: this.item.{this.PropertyNames[i]} = value; break;"); } writer.AppendLine($"default: throw new IndexOutOfRangeException();"); } } } writer.AppendLine("System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => this.GetEnumerator();"); writer.AppendLine(); writer.AppendLine($"public System.Collections.Generic.IEnumerator<{typeName}> GetEnumerator()"); using (writer.WithBlock()) { for (int i = 0; i < this.PropertyNames.Count; ++i) { writer.AppendLine($"yield return this.item.{this.PropertyNames[i]};"); } if (this.PropertyNames.Count == 0) { writer.AppendLine("yield break;"); } } } }