Esempio n. 1
0
        private void WriteType(TypeDefinition type)
        {
            if (type.HasAttribute("PureJSService"))
            {
                return;
            }

            var interfaces = type.Interfaces.Select(x => x.InterfaceType.AsCsName()).ToList();

            var isComponentData = type.Interfaces.Count(x => x.InterfaceType.Name == "IComponentData") != 0 ||
                                  type.Interfaces.Count(x => x.InterfaceType.Name == "ISharedComponentData") != 0 ||
                                  type.Interfaces.Count(x => x.InterfaceType.Name == "ISystemStateComponentData") != 0;

            if (isComponentData && !BindGem.PureJS)
            {
                interfaces.Add("UTiny.IComponentDataInternal");
                if (type.IsPodType())
                {
                    interfaces.Add("UTiny.IComponentIsPodData");
                }
            }

            var interfacesLine = isComponentData ? ": " + String.Join(", ", interfaces) : "";

            string kind;

            if (type.IsInterface)
            {
                kind = type.HasAttribute("Service") ? "static class" : "partial struct";
            }
            else
            {
                kind = type.HasAttribute("CsPartial") ? "partial struct" : "struct";
            }

            bool isService         = type.HasAttribute("Service");
            bool isNativeClassType = type.IsInterface && !isService;
            bool isConstructable   = type.HasAttribute("Constructable") && !isService;

            line("namespace " + type.Namespace);
            line("{");

            if (type.IsComponentType() || type.IsStructValueType())
            {
                line(
                    "    [global::System.Runtime.InteropServices.StructLayout(global::System.Runtime.InteropServices.LayoutKind.Sequential)]");
            }

            line($"    public {kind} {type.CsName()} {interfacesLine}");
            line("    {");

            var constructorName = $"ut_{type.Name}_{type.Name}";

            var cppFnName = type.FullyQualifiedCppName("_");

            if (isNativeClassType)
            {
                line($"        public global::System.IntPtr mThis;");

                line($"        [global::System.Runtime.InteropServices.DllImport(UTiny.Interop.NativeLibraryName)]");
                line($"        private static extern global::System.IntPtr {constructorName}();");
                line($"        public {type.CsName()}(global::System.IntPtr t) {{ mThis = t; }}");
                line("");

                line($"        [global::System.Runtime.InteropServices.DllImport(UTiny.Interop.NativeLibraryName)]");
                line($"        private static extern void ut_{type.Name}_shRelease(global::System.IntPtr ptr);");
                line($"        public void _NativeRelease() {{ ut_{type.Name}_shRelease(mThis); mThis = global::System.IntPtr.Zero; }}");
            }

            if (isConstructable)
            {
                line($"        public static {type.CsName()} New{type.CsName()}() {{ return new {type.CsName()}({constructorName}()); }}");
            }

            line("");

            if (isComponentData && !BindGem.PureJS)
            {
                line($@"        [global::System.Runtime.InteropServices.DllImport(UTiny.Interop.NativeLibraryName)]");
                line($@"        internal static extern int {cppFnName}_cid();");
                line($@"        public int NativeComponentId() {{ return {cppFnName}_cid(); }}");

                GenerateComponentSerializeToNativeCppMethod(type);
                GenerateComponentDeserializeFromNativeCppMethod(type);
            }

            line("");

            foreach (var f in type.Fields)
            {
                if (f.FieldType.MetadataType == MetadataType.String)
                {
                    line($"        public string {f.Name};");
                }
                else if (f.FieldType.IsDynamicArray())
                {
                    line($"        public {f.FieldType.DynamicArrayElementType().AsCsName()}[] {f.Name};");
                }
                else
                {
                    line($"        public {f.FieldType.AsCsName()} {CSharpIdentifierFor(f.Name)};");
                }
            }

            line("");

            line("");

            foreach (var m in type.MemberFunctions())
            {
                if (m.HasAttribute("CsCustomImpl"))
                {
                    continue;
                }

                // Declare the DllImported C call
                line($"        [global::System.Runtime.InteropServices.DllImport(UTiny.Interop.NativeLibraryName)]");
                if (m.ReturnType.Resolve().MetadataType == MetadataType.Boolean && !m.ReturnType.IsPointer)
                {
                    line($"        [return:global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.I1)]");
                }
                line($"        private static unsafe extern {m.ReturnType.AsCsReturnName()} {cppFnName}_{m.Name}({ParameterListForCCall(m, isService, isService).JoinWithComma()});");

                // Then declare the public C# API
                line($"        public {(isService || m.IsStatic ? "static " : "")}unsafe {m.ReturnType.AsCsName()} {m.Name}({ParameterList(m, true, false).JoinWithComma()})");
                line($"        {{");

                var callStr =
                    $"{cppFnName}_{m.Name}({ParameterNamesForCCall(m, isNativeClassType || isService, isService).JoinWithComma()})";

                if ((type.IsStructValueType() || type.IsComponentType()) && !m.IsStatic)
                {
                    line($"            //fixed ({type.AsCsName()}* self = &this)");
                    line($"            void* self = UnsafeUtility.AddressOf(ref this);");
                }

                // Marshal type conversions for C# -> C++ call
                for (int i = 0; i < m.Parameters.Count; ++i)
                {
                    if (m.Parameters[i].ParameterType.MetadataType == MetadataType.String)
                    {
                        line($"            NativeString arg{i}str = new NativeString();");
                        line($"            StringInterop.ut_nativestring_placement_create(&arg{i}str, (uint)StringInterop.StringLengthUtf8(arg{i}));");
                        line($"            StringInterop.StringToUtf8(arg{i}, arg{i}str.mStr, arg{i}str.mSize+1);");
                    }
                    else if (m.Parameters[i].ParameterType.IsDynamicArray())
                    {
                        if (m.Parameters[i].ParameterType.DynamicArrayElementType().MetadataType == MetadataType.String)
                        {
                            line($"            NativeBuffer arg{i}arr = StringInterop.StringListToNewNativeBuffer(arg{i});");
                        }
                        else
                        {
                            var    sz32       = TypeUtils.AlignAndSizeOfType(m.Parameters[i].ParameterType.DynamicArrayElementType(), 32);
                            var    sz64       = TypeUtils.AlignAndSizeOfType(m.Parameters[i].ParameterType.DynamicArrayElementType(), 64);
                            string sizeString = (sz32.size == sz64.size) ? sz32.size.ToString() : $"global::System.IntPtr.Size == 8 ? {sz64.size} : {sz32.size}";
                            line($"            NativeBuffer arg{i}arr = StringInterop.PodDataListToNewNativeBuffer(arg{i}, {sizeString});");
                        }
                    }
                }

                string retval = null;
                if (m.ReturnType.MetadataType == MetadataType.Void)
                {
                    line($"            {callStr};");
                }
                else if (m.ReturnType.MetadataType == MetadataType.String)
                {
                    line($"            NativeString retval;");
                    line($"            {callStr};");
                    line($"            string str = StringInterop.Utf8ToString(retval.mStr, retval.mSize);");
                    line($"            StringInterop.ut_nativestring_free_data(&retval);");
                    retval = "str";
                }
                else if (m.ReturnType.IsSharedPtrType() || m.ReturnType.IsNonSharedPtrType())
                {
                    line($"            var ptr = {callStr};");
                    retval = $"new {m.ReturnType.Resolve().AsCsName()}(ptr)";
                }
                else if (m.ReturnType.EmCppReturnToFirstArgPtr())
                {
                    line($"            {m.ReturnType.AsCsName()} retval;");
                    line($"            {callStr};");
                    retval = "retval";
                }
                else
                {
                    line($"            {m.ReturnType.AsCsName()} retval = {callStr};");
                    retval = "retval";
                }

                // Cleanup for marshalled type conversions for C# -> C++ calls
                for (int i = 0; i < m.Parameters.Count; ++i)
                {
                    if (m.Parameters[i].ParameterType.MetadataType == MetadataType.String)
                    {
                        line($"            StringInterop.ut_nativestring_placement_delete(&arg{i}str);");
                    }
                    else if (m.Parameters[i].ParameterType.IsDynamicArray())
                    {
                        if (m.Parameters[i].ParameterType.DynamicArrayElementType().MetadataType == MetadataType.String)
                        {
                            line($"            StringInterop.ut_nativebuffer_nativestring_placement_delete(&arg{i}arr);");
                        }
                        else
                        {
                            line($"            StringInterop.ut_nativebuffer_pod_placement_delete(&arg{i}arr);");
                        }
                    }
                }

                if (retval != null)
                {
                    line($"            return {retval};");
                }

                line($"        }}");
                line("");
            }

            line("");

            foreach (var e in type.NestedTypes.Where(x => x.IsEnum))
            {
                line($"        public enum {e.Name}");
                line("        {");
                foreach (var field in e.Fields.Where(f => f.IsStatic))
                {
                    line($"            {field.Name} = {field.Constant},");
                }
                line("        }");
            }

            line("    }");
            line("}");
        }