diff --git a/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs b/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs index 814983e9b..3e2ad1b31 100644 --- a/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs @@ -1,16 +1,17 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. using System.Collections.Generic; +using System.IO; namespace Flax.Build.Bindings { /// /// The native type information for bindings generator. /// - public class ApiTypeInfo + public class ApiTypeInfo : IBindingsCache { public ApiTypeInfo Parent; - public List Children; + public List Children = new List(); public string NativeName; public string Name; public string Namespace; @@ -91,6 +92,35 @@ namespace Flax.Build.Bindings Children.Add(apiTypeInfo); } + public virtual void Write(BinaryWriter writer) + { + BindingsGenerator.Write(writer, NativeName); + BindingsGenerator.Write(writer, Name); + BindingsGenerator.Write(writer, Namespace); + BindingsGenerator.Write(writer, Attributes); + BindingsGenerator.Write(writer, Comment); + writer.Write(IsInBuild); + BindingsGenerator.Write(writer, Children); + } + + public virtual void Read(BinaryReader reader) + { + NativeName = BindingsGenerator.Read(reader, NativeName); + Name = BindingsGenerator.Read(reader, Name); + Namespace = BindingsGenerator.Read(reader, Namespace); + Attributes = BindingsGenerator.Read(reader, Attributes); + Comment = BindingsGenerator.Read(reader, Comment); + IsInBuild = reader.ReadBoolean(); + Children = BindingsGenerator.Read(reader, Children); + + // Fix hierarchy + for (int i = 0; i < Children.Count; i++) + { + var child = Children[i]; + child.Parent = this; + } + } + public override string ToString() { return Name; diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index d9dc61521..2fd6a6edd 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -521,6 +521,7 @@ namespace Flax.Build.Bindings { if (!useUnmanaged) throw new NotImplementedException("TODO: support events inside non-static and non-scripting API class types."); + var paramsCount = eventInfo.Type.GenericArgs?.Count ?? 0; contents.AppendLine(); @@ -542,10 +543,10 @@ namespace Flax.Build.Bindings if (eventInfo.IsStatic) contents.Append("static "); string eventSignature = "event Action"; - if (eventInfo.Type.GenericArgs.Count != 0) + if (paramsCount != 0) { eventSignature += '<'; - for (var i = 0; i < eventInfo.Type.GenericArgs.Count; i++) + for (var i = 0; i < paramsCount; i++) { if (i != 0) eventSignature += ", "; @@ -583,7 +584,7 @@ namespace Flax.Build.Bindings if (eventInfo.IsStatic) contents.Append("static "); contents.Append($"void Internal_{eventInfo.Name}_Invoke("); - for (var i = 0; i < eventInfo.Type.GenericArgs.Count; i++) + for (var i = 0; i < paramsCount; i++) { if (i != 0) contents.Append(", "); @@ -594,7 +595,7 @@ namespace Flax.Build.Bindings contents.Append(indent).Append('{').AppendLine(); contents.Append(indent).Append(" Internal_").Append(eventInfo.Name); contents.Append('('); - for (var i = 0; i < eventInfo.Type.GenericArgs.Count; i++) + for (var i = 0; i < paramsCount; i++) { if (i != 0) contents.Append(", "); diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs new file mode 100644 index 000000000..bc141759c --- /dev/null +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs @@ -0,0 +1,266 @@ +// (c) 2012-2020 Wojciech Figat. All rights reserved. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using Flax.Build.NativeCpp; + +namespace Flax.Build.Bindings +{ + internal interface IBindingsCache + { + void Write(BinaryWriter writer); + void Read(BinaryReader reader); + } + + partial class BindingsGenerator + { + private static readonly Dictionary _typeCache = new Dictionary(); + + internal static void Write(BinaryWriter writer, string e) + { + var valid = e != null; + writer.Write(valid); + if (valid) + writer.Write(e); + } + + internal static void Write(BinaryWriter writer, string[] list) + { + if (list != null) + { + writer.Write(list.Length); + for (int i = 0; i < list.Length; i++) + writer.Write(list[i]); + } + else + { + writer.Write(0); + } + } + + internal static void Write(BinaryWriter writer, IEnumerable list) + { + if (list != null) + { + writer.Write(list.Count()); + foreach (var e in list) + writer.Write(e); + } + else + { + writer.Write(0); + } + } + + internal static void Write(BinaryWriter writer, T e) where T : IBindingsCache + { + if (e != null) + { + writer.Write(e.GetType().FullName); + e.Write(writer); + } + else + { + writer.Write(string.Empty); + } + } + + internal static void Write(BinaryWriter writer, IList list) where T : IBindingsCache + { + if (list != null) + { + var count = list.Count; + writer.Write(count); + for (int i = 0; i < count; i++) + { + var e = list[i]; + writer.Write(e.GetType().FullName); + e.Write(writer); + } + } + else + { + writer.Write(0); + } + } + + internal static string Read(BinaryReader reader, string e) + { + var valid = reader.ReadBoolean(); + if (valid) + e = reader.ReadString(); + return e; + } + + internal static string[] Read(BinaryReader reader, string[] list) + { + var count = reader.ReadInt32(); + if (count != 0) + { + list = new string[count]; + for (int i = 0; i < count; i++) + list[i] = reader.ReadString(); + } + return list; + } + + internal static T Read(BinaryReader reader, T e) where T : IBindingsCache + { + var typename = reader.ReadString(); + if (string.IsNullOrEmpty(typename)) + return e; + if (!_typeCache.TryGetValue(typename, out var type)) + { + type = Builder.BuildTypes.FirstOrDefault(x => x.FullName == typename); + if (type == null) + { + var msg = $"Missing type {typename}."; + Log.Error(msg); + throw new Exception(msg); + } + _typeCache.Add(typename, type); + } + e = (T)Activator.CreateInstance(type); + e.Read(reader); + return e; + } + + internal static List Read(BinaryReader reader, List list) where T : IBindingsCache + { + var count = reader.ReadInt32(); + if (count != 0) + { + list = new List(count); + for (int i = 0; i < count; i++) + { + var typename = reader.ReadString(); + if (!_typeCache.TryGetValue(typename, out var type)) + { + type = Builder.BuildTypes.FirstOrDefault(x => x.FullName == typename); + if (type == null) + { + var msg = $"Missing type {typename}."; + Log.Error(msg); + throw new Exception(msg); + } + _typeCache.Add(typename, type); + } + var e = (T)Activator.CreateInstance(type); + e.Read(reader); + list.Add(e); + } + } + return list; + } + + private static string GetCachePath(Module module, BuildOptions moduleOptions) + { + return Path.Combine(moduleOptions.IntermediateFolder, module.Name + ".Bindings.cache"); + } + + private static void SaveCache(ModuleInfo moduleInfo, BuildOptions moduleOptions, List headerFiles) + { + var path = GetCachePath(moduleInfo.Module, moduleOptions); + using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read)) + using (var writer = new BinaryWriter(stream, Encoding.UTF8)) + { + // Version + writer.Write(4); + writer.Write(File.GetLastWriteTime(Assembly.GetExecutingAssembly().Location).Ticks); + + // Build options + writer.Write(moduleOptions.IntermediateFolder); + writer.Write((int)moduleOptions.Platform.Target); + writer.Write((int)moduleOptions.Architecture); + writer.Write((int)moduleOptions.Configuration); + Write(writer, moduleOptions.PublicDefinitions); + Write(writer, moduleOptions.PrivateDefinitions); + Write(writer, moduleOptions.CompileEnv.PreprocessorDefinitions); + + // Header files + writer.Write(headerFiles.Count); + for (int i = 0; i < headerFiles.Count; i++) + { + var headerFile = headerFiles[i]; + writer.Write(headerFile); + writer.Write(File.GetLastWriteTime(headerFile).Ticks); + } + + // Info + moduleInfo.Write(writer); + } + } + + private static bool LoadCache(ref ModuleInfo moduleInfo, BuildOptions moduleOptions, List headerFiles) + { + var path = GetCachePath(moduleInfo.Module, moduleOptions); + if (!File.Exists(path)) + return false; + using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (var reader = new BinaryReader(stream, Encoding.UTF8)) + { + // Version + var version = reader.ReadInt32(); + if (version != 4) + return false; + if (File.GetLastWriteTime(Assembly.GetExecutingAssembly().Location).Ticks != reader.ReadInt64()) + return false; + + // Build options + if (reader.ReadString() != moduleOptions.IntermediateFolder || + reader.ReadInt32() != (int)moduleOptions.Platform.Target || + reader.ReadInt32() != (int)moduleOptions.Architecture || + reader.ReadInt32() != (int)moduleOptions.Configuration) + return false; + var publicDefinitions = Read(reader, Utilities.GetEmptyArray()); + if (publicDefinitions.Length != moduleOptions.PublicDefinitions.Count || publicDefinitions.Any(x => !moduleOptions.PublicDefinitions.Contains(x))) + return false; + var privateDefinitions = Read(reader, Utilities.GetEmptyArray()); + if (privateDefinitions.Length != moduleOptions.PrivateDefinitions.Count || privateDefinitions.Any(x => !moduleOptions.PrivateDefinitions.Contains(x))) + return false; + var preprocessorDefinitions = Read(reader, Utilities.GetEmptyArray()); + if (preprocessorDefinitions.Length != moduleOptions.CompileEnv.PreprocessorDefinitions.Count || preprocessorDefinitions.Any(x => !moduleOptions.CompileEnv.PreprocessorDefinitions.Contains(x))) + return false; + + // Header files + var headerFilesCount = reader.ReadInt32(); + if (headerFilesCount != headerFiles.Count) + return false; + for (int i = 0; i < headerFilesCount; i++) + { + var headerFile = headerFiles[i]; + if (headerFile != reader.ReadString()) + return false; + if (File.GetLastWriteTime(headerFile).Ticks > reader.ReadInt64()) + return false; + } + + // Info + var newModuleInfo = new ModuleInfo + { + Module = moduleInfo.Module, + Name = moduleInfo.Name, + Namespace = moduleInfo.Namespace, + Children = new List(), + }; + try + { + newModuleInfo.Read(reader); + + // Skip parsing and use data loaded from cache + moduleInfo = newModuleInfo; + return true; + } + catch + { + // Skip loading cache + return false; + } + } + } + } +} diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index ff2a2fadd..d62a53144 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -1091,7 +1091,7 @@ namespace Flax.Build.Bindings { if (!useScripting) continue; - var paramsCount = eventInfo.Type.GenericArgs.Count; + var paramsCount = eventInfo.Type.GenericArgs?.Count ?? 0; // C# event invoking wrapper (calls C# event from C++ delegate) CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MEvent.h"); @@ -1109,7 +1109,7 @@ namespace Flax.Build.Bindings contents.Append(" {").AppendLine(); contents.Append(" static MMethod* mmethod = nullptr;").AppendLine(); contents.Append(" if (!mmethod)").AppendLine(); - contents.AppendFormat(" mmethod = {1}::GetStaticClass()->GetMethod(\"Internal_{0}_Invoke\", {2});", eventInfo.Name, classTypeNameNative, eventInfo.Type.GenericArgs.Count).AppendLine(); + contents.AppendFormat(" mmethod = {1}::GetStaticClass()->GetMethod(\"Internal_{0}_Invoke\", {2});", eventInfo.Name, classTypeNameNative, paramsCount).AppendLine(); contents.Append(" CHECK(mmethod);").AppendLine(); contents.Append(" MonoObject* exception = nullptr;").AppendLine(); if (paramsCount == 0) @@ -1174,7 +1174,7 @@ namespace Flax.Build.Bindings if (paramsCount == 0) contents.AppendLine(" Variant* params = nullptr;"); else - contents.AppendLine($" Variant params[{eventInfo.Type.GenericArgs.Count}];"); + contents.AppendLine($" Variant params[{paramsCount}];"); for (var i = 0; i < paramsCount; i++) { var paramType = eventInfo.Type.GenericArgs[i]; diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs index 66f93fde3..7714e6abd 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs @@ -475,13 +475,8 @@ namespace Flax.Build.Bindings { var desc = new ClassInfo { - Children = new List(), Access = context.CurrentAccessLevel, BaseTypeInheritance = AccessLevel.Private, - Functions = new List(), - Properties = new List(), - Fields = new List(), - Events = new List(), }; // Read the documentation comment @@ -559,7 +554,6 @@ namespace Flax.Build.Bindings { var desc = new InterfaceInfo { - Children = new List(), Access = context.CurrentAccessLevel, }; @@ -622,7 +616,6 @@ namespace Flax.Build.Bindings var desc = new FunctionInfo { Access = context.CurrentAccessLevel, - Parameters = new List(), }; // Read the documentation comment @@ -821,9 +814,7 @@ namespace Flax.Build.Bindings { var desc = new EnumInfo { - Children = new List(), Access = context.CurrentAccessLevel, - Entries = new List(), }; // Read the documentation comment @@ -978,10 +969,7 @@ namespace Flax.Build.Bindings { var desc = new StructureInfo { - Children = new List(), Access = context.CurrentAccessLevel, - Fields = new List(), - Functions = new List(), }; // Read the documentation comment @@ -1200,7 +1188,6 @@ namespace Flax.Build.Bindings context.Tokenizer.ExpectToken(TokenType.LeftParent); var desc = new InjectCppCodeInfo { - Children = new List(), Code = context.Tokenizer.ExpectToken(TokenType.String).Value.Replace("\\\"", "\""), }; desc.Code = desc.Code.Substring(1, desc.Code.Length - 2); diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs index 1b12cb838..0135f1130 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs @@ -100,6 +100,26 @@ namespace Flax.Build.Bindings } } + // Sort file paths to have stable results + headerFiles.Sort(); + + // Load cache + using (new ProfileEventScope("LoadCache")) + { + if (LoadCache(ref moduleInfo, moduleOptions, headerFiles)) + { + buildData.ModulesInfo[module] = moduleInfo; + + // Initialize API + using (new ProfileEventScope("Init")) + { + moduleInfo.Init(buildData); + } + + return moduleInfo; + } + } + // Parse bindings Log.Verbose($"Parsing API bindings for {module.Name} ({moduleInfo.Name})"); int concurrency = Math.Min(Math.Max(1, (int)(Environment.ProcessorCount * Configuration.ConcurrencyProcessorScale)), Configuration.MaxConcurrency); @@ -117,9 +137,6 @@ namespace Flax.Build.Bindings } else { - // Sort by file size to improve performance (parse larger files first) - headerFiles.Sort((a, b) => new System.IO.FileInfo(b).Length.CompareTo(new System.IO.FileInfo(a).Length)); - // Multi-threaded ThreadPool.GetMinThreads(out var workerThreads, out var completionPortThreads); if (workerThreads != concurrency) @@ -133,6 +150,12 @@ namespace Flax.Build.Bindings }); } + // Save cache + using (new ProfileEventScope("SaveCache")) + { + SaveCache(moduleInfo, moduleOptions, headerFiles); + } + // Initialize API using (new ProfileEventScope("Init")) { @@ -162,7 +185,6 @@ namespace Flax.Build.Bindings var fileInfo = new FileInfo { Parent = null, - Children = new List(), Name = headerFiles[workIndex], Namespace = moduleInfo.Name, }; diff --git a/Source/Tools/Flax.Build/Bindings/ClassInfo.cs b/Source/Tools/Flax.Build/Bindings/ClassInfo.cs index a83ac2b55..c68ff1a59 100644 --- a/Source/Tools/Flax.Build/Bindings/ClassInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/ClassInfo.cs @@ -1,6 +1,7 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. using System.Collections.Generic; +using System.IO; using System.Linq; namespace Flax.Build.Bindings @@ -29,10 +30,10 @@ namespace Flax.Build.Bindings public bool IsAutoSerialization; public bool NoSpawn; public bool NoConstructor; - public List Functions; - public List Properties; - public List Fields; - public List Events; + public List Functions = new List(); + public List Properties = new List(); + public List Fields = new List(); + public List Events = new List(); internal HashSet UniqueFunctionNames; @@ -74,6 +75,40 @@ namespace Flax.Build.Bindings } } + public override void Write(BinaryWriter writer) + { + // TODO: convert into flags + writer.Write(IsStatic); + writer.Write(IsSealed); + writer.Write(IsAbstract); + writer.Write(IsAutoSerialization); + writer.Write(NoSpawn); + writer.Write(NoConstructor); + BindingsGenerator.Write(writer, Functions); + BindingsGenerator.Write(writer, Properties); + BindingsGenerator.Write(writer, Fields); + BindingsGenerator.Write(writer, Events); + + base.Write(writer); + } + + public override void Read(BinaryReader reader) + { + // TODO: convert into flags + IsStatic = reader.ReadBoolean(); + IsSealed = reader.ReadBoolean(); + IsAbstract = reader.ReadBoolean(); + IsAutoSerialization = reader.ReadBoolean(); + NoSpawn = reader.ReadBoolean(); + NoConstructor = reader.ReadBoolean(); + Functions = BindingsGenerator.Read(reader, Functions); + Properties = BindingsGenerator.Read(reader, Properties); + Fields = BindingsGenerator.Read(reader, Fields); + Events = BindingsGenerator.Read(reader, Events); + + base.Read(reader); + } + public int GetScriptVTableSize(Builder.BuildData buildData, out int offset) { if (_scriptVTableSize == -1) diff --git a/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs b/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs index dcb2d2e9e..2f0dad003 100644 --- a/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs @@ -1,7 +1,7 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. -using System; using System.Collections.Generic; +using System.IO; namespace Flax.Build.Bindings { @@ -36,5 +36,25 @@ namespace Flax.Build.Bindings Interfaces = null; } } + + public override void Write(BinaryWriter writer) + { + writer.Write((byte)Access); + writer.Write((byte)BaseTypeInheritance); + BindingsGenerator.Write(writer, BaseType); + BindingsGenerator.Write(writer, InterfaceNames); + + base.Write(writer); + } + + public override void Read(BinaryReader reader) + { + Access = (AccessLevel)reader.ReadByte(); + BaseTypeInheritance = (AccessLevel)reader.ReadByte(); + BaseType = BindingsGenerator.Read(reader, BaseType); + InterfaceNames = BindingsGenerator.Read(reader, InterfaceNames); + + base.Read(reader); + } } } diff --git a/Source/Tools/Flax.Build/Bindings/EnumInfo.cs b/Source/Tools/Flax.Build/Bindings/EnumInfo.cs index bf9fc8132..ddfcb3a38 100644 --- a/Source/Tools/Flax.Build/Bindings/EnumInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/EnumInfo.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.IO; namespace Flax.Build.Bindings { @@ -10,7 +11,7 @@ namespace Flax.Build.Bindings /// public class EnumInfo : ApiTypeInfo { - public struct EntryInfo + public struct EntryInfo : IBindingsCache { public string Name; public string[] Comment; @@ -21,11 +22,27 @@ namespace Flax.Build.Bindings { return Name + (string.IsNullOrEmpty(Value) ? string.Empty : " = " + Value); } + + public void Write(BinaryWriter writer) + { + writer.Write(Name); + BindingsGenerator.Write(writer, Comment); + BindingsGenerator.Write(writer, Value); + BindingsGenerator.Write(writer, Attributes); + } + + public void Read(BinaryReader reader) + { + Name = reader.ReadString(); + Comment = BindingsGenerator.Read(reader, Comment); + Value = BindingsGenerator.Read(reader, Value); + Attributes = BindingsGenerator.Read(reader, Attributes); + } } public AccessLevel Access; public TypeInfo UnderlyingType; - public List Entries; + public List Entries = new List(); public override bool IsValueType => true; public override bool IsEnum => true; @@ -36,6 +53,24 @@ namespace Flax.Build.Bindings throw new NotSupportedException("API enums cannot have sub-types."); } + public override void Write(BinaryWriter writer) + { + writer.Write((byte)Access); + BindingsGenerator.Write(writer, UnderlyingType); + BindingsGenerator.Write(writer, Entries); + + base.Write(writer); + } + + public override void Read(BinaryReader reader) + { + Access = (AccessLevel)reader.ReadByte(); + UnderlyingType = BindingsGenerator.Read(reader, UnderlyingType); + Entries = BindingsGenerator.Read(reader, Entries); + + base.Read(reader); + } + public override string ToString() { return "enum " + Name; diff --git a/Source/Tools/Flax.Build/Bindings/EventInfo.cs b/Source/Tools/Flax.Build/Bindings/EventInfo.cs index de93332ac..905bee803 100644 --- a/Source/Tools/Flax.Build/Bindings/EventInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/EventInfo.cs @@ -1,5 +1,7 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +using System.IO; + namespace Flax.Build.Bindings { /// @@ -9,6 +11,20 @@ namespace Flax.Build.Bindings { public TypeInfo Type; + public override void Write(BinaryWriter writer) + { + BindingsGenerator.Write(writer, Type); + + base.Write(writer); + } + + public override void Read(BinaryReader reader) + { + Type = BindingsGenerator.Read(reader, Type); + + base.Read(reader); + } + public override string ToString() { var result = string.Empty; diff --git a/Source/Tools/Flax.Build/Bindings/FieldInfo.cs b/Source/Tools/Flax.Build/Bindings/FieldInfo.cs index b1488ed09..d01cde5e7 100644 --- a/Source/Tools/Flax.Build/Bindings/FieldInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/FieldInfo.cs @@ -1,5 +1,7 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +using System.IO; + namespace Flax.Build.Bindings { /// @@ -16,6 +18,28 @@ namespace Flax.Build.Bindings public bool HasDefaultValue => !string.IsNullOrEmpty(DefaultValue); + public override void Write(BinaryWriter writer) + { + BindingsGenerator.Write(writer, Type); + // TODO: convert into flags + writer.Write(IsReadOnly); + writer.Write(NoArray); + BindingsGenerator.Write(writer, DefaultValue); + + base.Write(writer); + } + + public override void Read(BinaryReader reader) + { + Type = BindingsGenerator.Read(reader, Type); + // TODO: convert into flags + IsReadOnly = reader.ReadBoolean(); + NoArray = reader.ReadBoolean(); + DefaultValue = BindingsGenerator.Read(reader, DefaultValue); + + base.Read(reader); + } + public override string ToString() { var result = string.Empty; diff --git a/Source/Tools/Flax.Build/Bindings/FunctionInfo.cs b/Source/Tools/Flax.Build/Bindings/FunctionInfo.cs index 953fd7ed4..a78c9242a 100644 --- a/Source/Tools/Flax.Build/Bindings/FunctionInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/FunctionInfo.cs @@ -1,6 +1,7 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. using System.Collections.Generic; +using System.IO; namespace Flax.Build.Bindings { @@ -9,7 +10,7 @@ namespace Flax.Build.Bindings /// public class FunctionInfo : MemberInfo { - public struct ParameterInfo + public struct ParameterInfo : IBindingsCache { public string Name; public TypeInfo Type; @@ -25,6 +26,28 @@ namespace Flax.Build.Bindings return Attributes != null && Attributes.Contains(name); } + public void Write(BinaryWriter writer) + { + writer.Write(Name); + BindingsGenerator.Write(writer, Type); + BindingsGenerator.Write(writer, DefaultValue); + BindingsGenerator.Write(writer, Attributes); + // TODO: convert into flags + writer.Write(IsRef); + writer.Write(IsOut); + } + + public void Read(BinaryReader reader) + { + Name = reader.ReadString(); + Type = BindingsGenerator.Read(reader, Type); + DefaultValue = BindingsGenerator.Read(reader, DefaultValue); + Attributes = BindingsGenerator.Read(reader, Attributes); + // TODO: convert into flags + IsRef = reader.ReadBoolean(); + IsOut = reader.ReadBoolean(); + } + public override string ToString() { var result = Type + " " + Name; @@ -42,12 +65,36 @@ namespace Flax.Build.Bindings public string UniqueName; public TypeInfo ReturnType; - public List Parameters; + public List Parameters = new List(); public bool IsVirtual; public bool IsConst; public bool NoProxy; public GlueInfo Glue; + public override void Write(BinaryWriter writer) + { + BindingsGenerator.Write(writer, ReturnType); + BindingsGenerator.Write(writer, Parameters); + // TODO: convert into flags + writer.Write(IsVirtual); + writer.Write(IsConst); + writer.Write(NoProxy); + + base.Write(writer); + } + + public override void Read(BinaryReader reader) + { + ReturnType = BindingsGenerator.Read(reader, ReturnType); + Parameters = BindingsGenerator.Read(reader, Parameters); + // TODO: convert into flags + IsVirtual = reader.ReadBoolean(); + IsConst = reader.ReadBoolean(); + NoProxy = reader.ReadBoolean(); + + base.Read(reader); + } + public override string ToString() { var result = string.Empty; diff --git a/Source/Tools/Flax.Build/Bindings/InjectCppCodeInfo.cs b/Source/Tools/Flax.Build/Bindings/InjectCppCodeInfo.cs index dfdb551f6..0bb53fc99 100644 --- a/Source/Tools/Flax.Build/Bindings/InjectCppCodeInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/InjectCppCodeInfo.cs @@ -1,5 +1,7 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +using System.IO; + namespace Flax.Build.Bindings { /// @@ -9,6 +11,20 @@ namespace Flax.Build.Bindings { public string Code; + public override void Write(BinaryWriter writer) + { + writer.Write(Code); + + base.Write(writer); + } + + public override void Read(BinaryReader reader) + { + Code = reader.ReadString(); + + base.Read(reader); + } + /// public override string ToString() { diff --git a/Source/Tools/Flax.Build/Bindings/MemberInfo.cs b/Source/Tools/Flax.Build/Bindings/MemberInfo.cs index 3e09b9f0b..49187c101 100644 --- a/Source/Tools/Flax.Build/Bindings/MemberInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/MemberInfo.cs @@ -1,11 +1,13 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +using System.IO; + namespace Flax.Build.Bindings { /// /// The native member information for bindings generator. /// - public class MemberInfo + public class MemberInfo : IBindingsCache { public string Name; public string[] Comment; @@ -17,5 +19,23 @@ namespace Flax.Build.Bindings { return Attributes != null && Attributes.Contains(name); } + + public virtual void Write(BinaryWriter writer) + { + writer.Write(Name); + BindingsGenerator.Write(writer, Comment); + writer.Write(IsStatic); + writer.Write((byte)Access); + BindingsGenerator.Write(writer, Attributes); + } + + public virtual void Read(BinaryReader reader) + { + Name = reader.ReadString(); + Comment = BindingsGenerator.Read(reader, Comment); + IsStatic = reader.ReadBoolean(); + Access = (AccessLevel)reader.ReadByte(); + Attributes = BindingsGenerator.Read(reader, Attributes); + } } } diff --git a/Source/Tools/Flax.Build/Bindings/ModuleInfo.cs b/Source/Tools/Flax.Build/Bindings/ModuleInfo.cs index 7bb6d1608..dd83af9d9 100644 --- a/Source/Tools/Flax.Build/Bindings/ModuleInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/ModuleInfo.cs @@ -1,5 +1,8 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +using System; +using System.IO; + namespace Flax.Build.Bindings { /// @@ -22,5 +25,26 @@ namespace Flax.Build.Bindings // Sort module files to prevent bindings rebuild due to order changes (list might be created in async) Children.Sort(); } + + public override void Write(BinaryWriter writer) + { + writer.Write(Module.Name); + writer.Write(Module.FilePath); + BindingsGenerator.Write(writer, Module.BinaryModuleName); + writer.Write(Module.BuildNativeCode); + + base.Write(writer); + } + + public override void Read(BinaryReader reader) + { + if (reader.ReadString() != Module.Name || + reader.ReadString() != Module.FilePath || + BindingsGenerator.Read(reader, Module.BinaryModuleName) != Module.BinaryModuleName || + reader.ReadBoolean() != Module.BuildNativeCode) + throw new Exception(); + + base.Read(reader); + } } } diff --git a/Source/Tools/Flax.Build/Bindings/PropertyInfo.cs b/Source/Tools/Flax.Build/Bindings/PropertyInfo.cs index f53578b4e..96b0f8b93 100644 --- a/Source/Tools/Flax.Build/Bindings/PropertyInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/PropertyInfo.cs @@ -1,5 +1,7 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +using System.IO; + namespace Flax.Build.Bindings { /// @@ -11,6 +13,24 @@ namespace Flax.Build.Bindings public FunctionInfo Getter; public FunctionInfo Setter; + public override void Write(BinaryWriter writer) + { + BindingsGenerator.Write(writer, Type); + BindingsGenerator.Write(writer, Getter); + BindingsGenerator.Write(writer, Setter); + + base.Write(writer); + } + + public override void Read(BinaryReader reader) + { + Type = BindingsGenerator.Read(reader, Type); + Getter = BindingsGenerator.Read(reader, Getter); + Setter = BindingsGenerator.Read(reader, Setter); + + base.Read(reader); + } + public override string ToString() { return Type + " " + Name; diff --git a/Source/Tools/Flax.Build/Bindings/StructureInfo.cs b/Source/Tools/Flax.Build/Bindings/StructureInfo.cs index be24bb1f0..882ed6295 100644 --- a/Source/Tools/Flax.Build/Bindings/StructureInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/StructureInfo.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.IO; namespace Flax.Build.Bindings { @@ -10,8 +11,8 @@ namespace Flax.Build.Bindings /// public class StructureInfo : ClassStructInfo { - public List Fields; - public List Functions; + public List Fields = new List(); + public List Functions = new List(); public bool IsAutoSerialization; public bool ForceNoPod; @@ -43,6 +44,26 @@ namespace Flax.Build.Bindings } } + public override void Write(BinaryWriter writer) + { + BindingsGenerator.Write(writer, Fields); + BindingsGenerator.Write(writer, Functions); + writer.Write(IsAutoSerialization); + writer.Write(ForceNoPod); + + base.Write(writer); + } + + public override void Read(BinaryReader reader) + { + Fields = BindingsGenerator.Read(reader, Fields); + Functions = BindingsGenerator.Read(reader, Functions); + IsAutoSerialization = reader.ReadBoolean(); + ForceNoPod = reader.ReadBoolean(); + + base.Read(reader); + } + public override void AddChild(ApiTypeInfo apiTypeInfo) { if (apiTypeInfo is EnumInfo) diff --git a/Source/Tools/Flax.Build/Bindings/TypeInfo.cs b/Source/Tools/Flax.Build/Bindings/TypeInfo.cs index f2d7ff387..2d15f6651 100644 --- a/Source/Tools/Flax.Build/Bindings/TypeInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/TypeInfo.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; @@ -10,7 +11,7 @@ namespace Flax.Build.Bindings /// /// The native type information for bindings generator. /// - public class TypeInfo : IEquatable + public class TypeInfo : IEquatable, IBindingsCache { public string Type; public bool IsConst; @@ -51,6 +52,34 @@ namespace Flax.Build.Bindings return true; } + public void Write(BinaryWriter writer) + { + BindingsGenerator.Write(writer, Type); + // TODO: pack as flags + writer.Write(IsConst); + writer.Write(IsRef); + writer.Write(IsPtr); + writer.Write(IsArray); + writer.Write(IsBitField); + writer.Write(ArraySize); + writer.Write(BitSize); + BindingsGenerator.Write(writer, GenericArgs); + } + + public void Read(BinaryReader reader) + { + Type = BindingsGenerator.Read(reader, Type); + // TODO: convert into flags + IsConst = reader.ReadBoolean(); + IsRef = reader.ReadBoolean(); + IsPtr = reader.ReadBoolean(); + IsArray = reader.ReadBoolean(); + IsBitField = reader.ReadBoolean(); + ArraySize = reader.ReadInt32(); + BitSize = reader.ReadInt32(); + GenericArgs = BindingsGenerator.Read(reader, GenericArgs); + } + public override string ToString() { var sb = new StringBuilder(64); diff --git a/Source/Tools/Flax.Build/Flax.Build.csproj b/Source/Tools/Flax.Build/Flax.Build.csproj index 9d415beed..236348032 100644 --- a/Source/Tools/Flax.Build/Flax.Build.csproj +++ b/Source/Tools/Flax.Build/Flax.Build.csproj @@ -64,6 +64,7 @@ + diff --git a/Source/Tools/Flax.Build/Utilities/Utilities.cs b/Source/Tools/Flax.Build/Utilities/Utilities.cs index c37faa678..accf86209 100644 --- a/Source/Tools/Flax.Build/Utilities/Utilities.cs +++ b/Source/Tools/Flax.Build/Utilities/Utilities.cs @@ -14,6 +14,16 @@ namespace Flax.Build /// public static class Utilities { + /// + /// Gets the empty array of the given type (shared one). + /// + /// The type. + /// The empty array object. + public static T[] GetEmptyArray() + { + return Enumerable.Empty() as T[]; + } + /// /// Gets the size of the file as a readable string. ///