/// <summary> /// Writes this enum to a file. /// </summary> /// <param name="enum">The enum to write.</param> /// <param name="file">The file to write to.</param> /// <param name="profile">The subsystem containing this enum.</param> /// <param name="project">The project containing this enum.</param> public static void WriteEnum(this Enum @enum, string file, Profile profile, Project project, BindTask task) { var sw = new StreamWriter(file); sw.WriteLine(task.LicenseText()); sw.WriteLine(); var ns = project.IsRoot ? task.Namespace : task.ExtensionsNamespace; sw.WriteLine("using System;"); sw.WriteLine("using Silk.NET.Core.Attributes;"); sw.WriteLine(); sw.WriteLine("#pragma warning disable 1591"); sw.WriteLine(); sw.WriteLine($"namespace {ns}{project.Namespace}"); sw.WriteLine("{"); foreach (var attr in @enum.Attributes) { sw.WriteLine($" {attr}"); } sw.WriteLine($" [NativeName(\"Name\", \"{@enum.NativeName}\")]"); sw.WriteLine($" public enum {@enum.Name}"); sw.WriteLine(" {"); for (var index = 0; index < @enum.Tokens.Count; index++) { var token = @enum.Tokens[index]; sw.WriteLine($" [NativeName(\"Name\", \"{token.NativeName}\")]"); sw.WriteLine ( $" {token.Name} = {token.Value}{(index != @enum.Tokens.Count ? "," : string.Empty)}" ); } sw.WriteLine(" }"); sw.WriteLine("}"); sw.Flush(); sw.Dispose(); }
/// <summary> /// Writes this struct to a file. /// </summary> /// <param name="struct">The enum to write.</param> /// <param name="file">The file to write to.</param> /// <param name="profile">The subsystem containing this enum.</param> /// <param name="project">The project containing this enum.</param> public static void WriteStruct(this Struct @struct, string file, Profile profile, Project project, BindTask task) { var sw = new StreamWriter(file); sw.WriteLine(task.LicenseText()); sw.WriteLine(); sw.WriteCoreUsings(); sw.WriteLine(); sw.WriteLine("#pragma warning disable 1591"); sw.WriteLine(); var ns = project.IsRoot ? task.Namespace : task.ExtensionsNamespace; sw.WriteLine($"namespace {ns}{project.Namespace}"); sw.WriteLine("{"); foreach (var attr in @struct.Attributes) { sw.WriteLine($" {attr}"); } sw.WriteLine($" [NativeName(\"Name\", \"{@struct.NativeName}\")]"); sw.WriteLine($" public unsafe partial struct {@struct.Name}"); sw.WriteLine(" {"); foreach (var comBase in @struct.ComBases) { var asSuffix = comBase.Split('.').Last(); asSuffix = (asSuffix.StartsWith('I') ? asSuffix.Substring(1) : comBase); asSuffix = asSuffix.StartsWith(task.FunctionPrefix) ? asSuffix.Substring(task.FunctionPrefix.Length) : asSuffix; var fromSuffix = @struct.Name.Split('.').Last(); fromSuffix = (fromSuffix.StartsWith('I') ? fromSuffix.Substring(1) : comBase); fromSuffix = fromSuffix.StartsWith(task.FunctionPrefix) ? fromSuffix.Substring(task.FunctionPrefix.Length) : fromSuffix; sw.WriteLine($" public static implicit operator {comBase}({@struct.Name} val)"); sw.WriteLine($" => Unsafe.As<{@struct.Name}, {comBase}>(ref val);"); sw.WriteLine(); if (@struct.Functions.Any(x => x.Signature.Name.Equals("QueryInterface"))) { sw.WriteLine($" public static explicit operator {@struct.Name}({comBase} val)"); sw.WriteLine($" => From{fromSuffix}(in val);"); sw.WriteLine(); sw.WriteLine($" public readonly ref {comBase} As{asSuffix}()"); sw.WriteLine(" {"); // yes i know this is unsafe and that there's a good reason why struct members can't return themselves // by reference, but this should work well enough. sw.WriteLine("#if NETSTANDARD2_1 || NET5_0 || NETCOREAPP3_1"); sw.WriteLine($" return ref Unsafe.As<{@struct.Name}, {comBase}>"); sw.WriteLine($" ("); sw.WriteLine($" ref MemoryMarshal.GetReference"); sw.WriteLine($" ("); sw.WriteLine($" MemoryMarshal.CreateSpan"); sw.WriteLine($" ("); sw.WriteLine($" ref Unsafe.AsRef(in this),"); sw.WriteLine($" 1"); sw.WriteLine($" )"); sw.WriteLine($" )"); sw.WriteLine($" );"); sw.WriteLine("#else"); sw.WriteLine($" fixed ({@struct.Name}* @this = &this)"); sw.WriteLine($" {{"); sw.WriteLine($" return ref *({comBase}*) @this;"); sw.WriteLine($" }}"); sw.WriteLine("#endif"); sw.WriteLine(" }"); sw.WriteLine(); sw.WriteLine($" public static ref {@struct.Name} From{fromSuffix}(in {comBase} @this)"); sw.WriteLine(" {"); sw.WriteLine($" {@struct.Name}* ret = default;"); sw.WriteLine($" SilkMarshal.ThrowHResult"); sw.WriteLine($" ("); sw.WriteLine($" @this.QueryInterface"); sw.WriteLine($" ("); sw.WriteLine($" ref SilkMarshal.GuidOf<{@struct.Name}>(),"); sw.WriteLine($" (void**) &ret"); sw.WriteLine($" )"); sw.WriteLine($" );"); sw.WriteLine(); sw.WriteLine($" return ref *ret;"); sw.WriteLine(" }"); sw.WriteLine(); } } if (@struct.Fields.Any(x => x.Count is null)) { sw.WriteLine($" public {@struct.Name}"); sw.WriteLine(" ("); var first = true; foreach (var field in @struct.Fields) { if (!(field.Count is null)) { continue; // I've chosen not to initialize multi-count fields from ctors. } var argName = field.Name[0].ToString().ToLower() + field.Name.Substring(1); argName = Utilities.CSharpKeywords.Contains(argName) ? $"@{argName}" : argName; if (!first) { sw.WriteLine(","); } else { first = false; } var nullable = field.Type.ToString().Contains('*') ? null : "?"; sw.Write($" {field.Type}{nullable} {argName} = {field.DefaultAssignment ?? "null"}"); } sw.WriteLine(); sw.WriteLine(" ) : this()"); sw.WriteLine(" {"); first = true; foreach (var field in @struct.Fields) { if (!(field.Count is null)) { continue; // I've chosen not to initialize multi-count fields from ctors. } var argName = field.Name[0].ToString().ToLower() + field.Name.Substring(1); argName = Utilities.CSharpKeywords.Contains(argName) ? $"@{argName}" : argName; if (!first) { sw.WriteLine(); } else { first = false; } sw.WriteLine($" if ({argName} is not null)"); sw.WriteLine(" {"); var value = field.Type.ToString().Contains('*') ? null : ".Value"; sw.WriteLine($" {field.Name} = {argName}{value};"); sw.WriteLine(" }"); } sw.WriteLine(" }"); sw.WriteLine(); } foreach (var structField in @struct.Fields) { if (!(structField.Count is null)) { if (!Field.FixedCapableTypes.Contains(structField.Type.Name)) { var count = structField.Count.IsConstant ? int.Parse ( profile.Projects.SelectMany(x => x.Value.Classes.SelectMany(y => y.Constants)) .FirstOrDefault(x => x.NativeName == structField.Count.ConstantName) ? .Value ?? throw new InvalidDataException("Couldn't find constant referenced") ) : structField.Count.IsStatic ? structField.Count.StaticCount : 1; var typeFixup09072020 = new TypeSignatureBuilder(structField.Type).WithIndirectionLevel (structField.Type.IndirectionLevels - 1).Build(); sw.WriteLine($" {structField.Doc}"); foreach (var attr in structField.Attributes) { sw.WriteLine($" {attr}"); } sw.WriteLine($" [NativeName(\"Type\", \"{structField.NativeType}\")]"); sw.WriteLine($" [NativeName(\"Type.Name\", \"{structField.Type.OriginalName}\")]"); sw.WriteLine($" [NativeName(\"Name\", \"{structField.NativeName}\")]"); sw.WriteLine($" public {structField.Name}Buffer {structField.Name};"); sw.WriteLine(); sw.WriteLine($" public struct {structField.Name}Buffer"); sw.WriteLine(" {"); for (var i = 0; i < count; i++) { sw.WriteLine($" public {typeFixup09072020} Element{i};"); } sw.WriteLine($" public ref {typeFixup09072020} this[int index]"); sw.WriteLine(" {"); sw.WriteLine(" get"); sw.WriteLine(" {"); sw.WriteLine($" if (index > {count - 1} || index < 0)"); sw.WriteLine(" {"); sw.WriteLine(" throw new ArgumentOutOfRangeException(nameof(index));"); sw.WriteLine(" }"); sw.WriteLine(); sw.WriteLine($" fixed ({typeFixup09072020}* ptr = &Element0)"); sw.WriteLine(" {"); sw.WriteLine(" return ref ptr[index];"); sw.WriteLine(" }"); sw.WriteLine(" }"); sw.WriteLine(" }"); if (!typeFixup09072020.IsPointer) { sw.WriteLine(); sw.WriteLine("#if NETSTANDARD2_1"); sw.WriteLine($" public Span<{typeFixup09072020}> AsSpan()"); sw.WriteLine($" => MemoryMarshal.CreateSpan(ref Element0, {count});"); sw.WriteLine("#endif"); } sw.WriteLine(" }"); sw.WriteLine(); } else { if (!string.IsNullOrEmpty(structField.Doc)) { sw.WriteLine($" {structField.Doc}"); } var count = structField.Count.IsConstant ? Utilities.ParseInt ( profile.Projects.SelectMany(x => x.Value.Classes.SelectMany(y => y.Constants)) .FirstOrDefault(x => x.NativeName == structField.Count.ConstantName)? .Value ?? profile.Projects.SelectMany(x => x.Value.Enums.SelectMany(y => y.Tokens)) .FirstOrDefault(x => x.NativeName == structField.Count.ConstantName)? .Value ?? throw new InvalidDataException("Couldn't find constant referenced") ) : structField.Count.IsStatic ? structField.Count.StaticCount : 1; var typeFixup09072020 = new TypeSignatureBuilder(structField.Type).WithIndirectionLevel //(structField.Type.IndirectionLevels - 1).Build(); (0).Build(); foreach (var attr in structField.Attributes) { sw.WriteLine($" {attr}"); } sw.WriteLine($" [NativeName(\"Type\", \"{structField.NativeType}\")]"); sw.WriteLine($" [NativeName(\"Type.Name\", \"{structField.Type.OriginalName}\")]"); sw.WriteLine($" [NativeName(\"Name\", \"{structField.NativeName}\")]"); sw.WriteLine ( $" public fixed {typeFixup09072020} {structField.Name}[{count}];" ); } }