From 117b0131b6162f1e596e0d50f6c93eb6b0f42743 Mon Sep 17 00:00:00 2001 From: Lucas Girouard-Stranks <519592+lithiumtoast@users.noreply.github.com> Date: Tue, 7 Jan 2025 13:38:02 -0500 Subject: [PATCH] Anonymous structs (#171) --- .../Generated/AssemblyAttributes.g.cs | 4 +- .../helloworld-app/Generated/Runtime.g.cs | 2 +- .../LibraryImports.g.cs | 32 +++- .../Generated/my_c_library.g.cs | 137 +++++++++++++++-- .../helloworld/helloworld-app/Program.cs | 42 +++++- .../my_c_library/include/my_c_library.h | 138 +++++++++++++++--- .../my_c_library/src/my_c_library.c | 85 +++++++++-- .../Generators/GeneratorEnum.cs | 2 +- .../Generators/GeneratorFunction.cs | 2 +- .../Generators/GeneratorFunctionPointer.cs | 2 +- .../Generators/GeneratorMacroObject.cs | 2 +- .../Generators/GeneratorOpaqueType.cs | 2 +- .../Generators/GeneratorStruct.cs | 95 +++++++----- src/cs/production/c2cs.Tool/c2cs.Tool.csproj | 2 +- 14 files changed, 451 insertions(+), 96 deletions(-) diff --git a/src/cs/examples/helloworld/helloworld-app/Generated/AssemblyAttributes.g.cs b/src/cs/examples/helloworld/helloworld-app/Generated/AssemblyAttributes.g.cs index e390c434..2fbb76d0 100644 --- a/src/cs/examples/helloworld/helloworld-app/Generated/AssemblyAttributes.g.cs +++ b/src/cs/examples/helloworld/helloworld-app/Generated/AssemblyAttributes.g.cs @@ -1,6 +1,6 @@ // -// This code was generated by the following tool on 2025-01-04 10:45:12 GMT-05:00: -// https://github.com/bottlenoselabs/c2cs (v2025-01-04 10:45:12 GMT-05:00) +// This code was generated by the following tool on 2025-01-07 13:23:17 GMT-05:00: +// https://github.com/bottlenoselabs/c2cs (v2025-01-07 13:23:17 GMT-05:00) // // Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. // diff --git a/src/cs/examples/helloworld/helloworld-app/Generated/Runtime.g.cs b/src/cs/examples/helloworld/helloworld-app/Generated/Runtime.g.cs index fb0dea8c..422701b1 100644 --- a/src/cs/examples/helloworld/helloworld-app/Generated/Runtime.g.cs +++ b/src/cs/examples/helloworld/helloworld-app/Generated/Runtime.g.cs @@ -1,5 +1,5 @@ // -// This code was generated by the following tool on 2025-01-04 10:45:12 GMT-05:00: +// This code was generated by the following tool on 2025-01-07 13:23:17 GMT-05:00: // https://github.com/bottlenoselabs/c2cs (v0.0.0.0) // // Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. diff --git a/src/cs/examples/helloworld/helloworld-app/Generated/SourceGenerators/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs b/src/cs/examples/helloworld/helloworld-app/Generated/SourceGenerators/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs index c05e4d89..941aff5c 100644 --- a/src/cs/examples/helloworld/helloworld-app/Generated/SourceGenerators/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs +++ b/src/cs/examples/helloworld/helloworld-app/Generated/SourceGenerators/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @@ -27,8 +27,16 @@ namespace helloworld { public static unsafe partial class my_c_library { - [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_enum", ExactSpelling = true)] - public static extern partial void hw_pass_enum(global::helloworld.my_c_library.hw_my_enum_week_day e); + [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_enum_by_reference", ExactSpelling = true)] + public static extern partial void hw_pass_enum_by_reference(global::helloworld.my_c_library.hw_week_day* e); + } +} +namespace helloworld +{ + public static unsafe partial class my_c_library + { + [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_enum_by_value", ExactSpelling = true)] + public static extern partial void hw_pass_enum_by_value(global::helloworld.my_c_library.hw_week_day e); } } namespace helloworld @@ -36,7 +44,7 @@ namespace helloworld public static unsafe partial class my_c_library { [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_integers_by_reference", ExactSpelling = true)] - public static extern partial void hw_pass_integers_by_reference(ushort* a, int* b, ulong* c); + public static extern partial void hw_pass_integers_by_reference(ushort* a, uint* b, ulong* c); } } namespace helloworld @@ -44,7 +52,7 @@ namespace helloworld public static unsafe partial class my_c_library { [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_integers_by_value", ExactSpelling = true)] - public static extern partial void hw_pass_integers_by_value(ushort a, int b, ulong c); + public static extern partial void hw_pass_integers_by_value(ushort a, uint b, ulong c); } } namespace helloworld @@ -55,3 +63,19 @@ public static unsafe partial class my_c_library public static extern partial void hw_pass_string(global::Interop.Runtime.CString s); } } +namespace helloworld +{ + public static unsafe partial class my_c_library + { + [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_struct_by_reference", ExactSpelling = true)] + public static extern partial void hw_pass_struct_by_reference(global::helloworld.my_c_library.hw_event* e); + } +} +namespace helloworld +{ + public static unsafe partial class my_c_library + { + [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_struct_by_value", ExactSpelling = true)] + public static extern partial void hw_pass_struct_by_value(global::helloworld.my_c_library.hw_event e); + } +} diff --git a/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.g.cs b/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.g.cs index 3c6d7637..4ed94004 100644 --- a/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.g.cs +++ b/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.g.cs @@ -1,5 +1,5 @@ // -// This code was generated by the following tool on 2025-01-04 10:45:12 GMT-05:00: +// This code was generated by the following tool on 2025-01-07 13:23:17 GMT-05:00: // https://github.com/bottlenoselabs/c2cs (v0.0.0.0) // // Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. @@ -37,33 +37,144 @@ public static unsafe partial class my_c_library [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] public static partial void hw_invoke_callback2(FnPtr_CString_Void f, CString s); - [LibraryImport(LibraryName, EntryPoint = "hw_pass_enum")] + [LibraryImport(LibraryName, EntryPoint = "hw_pass_enum_by_reference")] [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] - public static partial void hw_pass_enum(hw_my_enum_week_day e); + public static partial void hw_pass_enum_by_reference(hw_week_day* e); + + [LibraryImport(LibraryName, EntryPoint = "hw_pass_enum_by_value")] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial void hw_pass_enum_by_value(hw_week_day e); [LibraryImport(LibraryName, EntryPoint = "hw_pass_integers_by_reference")] [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] - public static partial void hw_pass_integers_by_reference(ushort* a, int* b, ulong* c); + public static partial void hw_pass_integers_by_reference(ushort* a, uint* b, ulong* c); [LibraryImport(LibraryName, EntryPoint = "hw_pass_integers_by_value")] [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] - public static partial void hw_pass_integers_by_value(ushort a, int b, ulong c); + public static partial void hw_pass_integers_by_value(ushort a, uint b, ulong c); [LibraryImport(LibraryName, EntryPoint = "hw_pass_string")] [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] public static partial void hw_pass_string(CString s); + [LibraryImport(LibraryName, EntryPoint = "hw_pass_struct_by_reference")] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial void hw_pass_struct_by_reference(hw_event* e); + + [LibraryImport(LibraryName, EntryPoint = "hw_pass_struct_by_value")] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial void hw_pass_struct_by_value(hw_event e); + public static readonly CString HW_STRING_POINTER = (CString)"Hello world using UTF-8 string literal from the C library's data segment!"u8; - public enum hw_my_enum_week_day : int + [StructLayout(LayoutKind.Explicit, Size = 40, Pack = 8)] + public partial struct hw_event + { + [FieldOffset(0)] + public hw_event_kind kind; // size = 4 + + [FieldOffset(8)] // size = 8 + public CString _string1; + + public string string1 + { + get + { + return CString.ToString(_string1); + } + set + { + _string1 = CString.FromString(value); + } + } + + [FieldOffset(16)] // size = 8 + public CString _string2; + + public string string2 + { + get + { + return CString.ToString(_string2); + } + set + { + _string2 = CString.FromString(value); + } + } + + [FieldOffset(8)] + public sbyte s8; // size = 1 + + [FieldOffset(8)] + public byte u8; // size = 1 + + [FieldOffset(8)] + public short s16; // size = 2 + + [FieldOffset(8)] + public ushort u16; // size = 2 + + [FieldOffset(8)] + public int s32; // size = 4 + + [FieldOffset(8)] + public uint u32; // size = 4 + + [FieldOffset(8)] + public long s64; // size = 8 + + [FieldOffset(8)] + public ulong u64; // size = 8 + + [FieldOffset(8)] // size = 16 + public fixed sbyte s128[16]; + + [FieldOffset(8)] // size = 16 + public fixed byte u128[16]; + + [FieldOffset(8)] // size = 32 + public fixed long s256[4]; + + [FieldOffset(8)] // size = 32 + public fixed ulong u256[4]; + + [FieldOffset(8)] + public ulong size; // size = 8 + + [FieldOffset(8)] + public CBool boolean; // size = 1 + } + + public enum hw_event_kind : int + { + HW_EVENT_KIND_UNKNOWN = 0, + HW_EVENT_KIND_STRING = 1, + HW_EVENT_KIND_S8 = 2, + HW_EVENT_KIND_U8 = 3, + HW_EVENT_KIND_S16 = 4, + HW_EVENT_KIND_U16 = 5, + HW_EVENT_KIND_S32 = 6, + HW_EVENT_KIND_U32 = 7, + HW_EVENT_KIND_S64 = 8, + HW_EVENT_KIND_U64 = 9, + HW_EVENT_KIND_S128 = 10, + HW_EVENT_KIND_U128 = 11, + HW_EVENT_KIND_S256 = 12, + HW_EVENT_KIND_U256 = 13, + HW_EVENT_KIND_BOOL = 14, + _HW_EVENT_KIND_FORCE_U32 = 2147483647 + } + + public enum hw_week_day : int { - HW_MY_ENUM_WEEK_DAY_UNKNOWN = 0, - HW_MY_ENUM_WEEK_DAY_MONDAY = 1, - HW_MY_ENUM_WEEK_DAY_TUESDAY = 2, - HW_MY_ENUM_WEEK_DAY_WEDNESDAY = 3, - HW_MY_ENUM_WEEK_DAY_THURSDAY = 4, - HW_MY_ENUM_WEEK_DAY_FRIDAY = 5, - _HW_MY_ENUM_WEEK_DAY_FORCE_U32 = 2147483647 + HW_WEEK_DAY_UNKNOWN = 0, + HW_WEEK_DAY_MONDAY = 1, + HW_WEEK_DAY_TUESDAY = 2, + HW_WEEK_DAY_WEDNESDAY = 3, + HW_WEEK_DAY_THURSDAY = 4, + HW_WEEK_DAY_FRIDAY = 5, + _HW_WEEK_DAY_FORCE_U32 = 2147483647 } [StructLayout(LayoutKind.Sequential)] diff --git a/src/cs/examples/helloworld/helloworld-app/Program.cs b/src/cs/examples/helloworld/helloworld-app/Program.cs index a713fa3b..44076b08 100644 --- a/src/cs/examples/helloworld/helloworld-app/Program.cs +++ b/src/cs/examples/helloworld/helloworld-app/Program.cs @@ -35,10 +35,10 @@ private static unsafe void Main() using var cString3 = (CString)"Hello world again from C# using UTF-16 converted UTF-8 and allocated! Don't forgot to free this string!"; hw_pass_string(cString3); - hw_pass_integers_by_value(65449, -255, 24242); + hw_pass_integers_by_value(65449, 255, 24242); ushort a = 65449; - var b = -255; + var b = 255U; ulong c = 24242; hw_pass_integers_by_reference(&a, &b, &c); @@ -48,16 +48,44 @@ private static unsafe void Main() // - It uses the same naming as `System.Func<>`. The last type on the name is always the return type. In this case 'void`. // Only available in C# 9 (.NET 5+). See https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/unsafe-code#function-pointers // Additionally function pointers need to use the `address-of` operator (&) to a C# static function marked with the UnmanagedCallersOnly attribute. See https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.unmanagedcallersonlyattribute?view=net-9.0 - var functionPointer = new hw_callback(&Callback); + var functionPointer1 = new hw_callback(&Callback); + var functionPointer2 = new FnPtr_CString_Void(&Callback); #else - var functionPointer = new FnPtr_CString_Void(Callback); + var functionPointer1 = new hw_callback(Callback); + var functionPointer2 = new FnPtr_CString_Void(Callback); #endif using var cStringCallback1 = (CString)"Hello from callback!"; - hw_invoke_callback1(functionPointer, cStringCallback1); + hw_invoke_callback1(functionPointer1, cStringCallback1); - // using var cStringCallback2 = (CString)"Hello again from callback!"; - // hw_invoke_callback2(functionPointer, cStringCallback2); + using var cStringCallback2 = (CString)"Hello again from callback!"; + hw_invoke_callback2(functionPointer2, cStringCallback2); + + var weekday = DateTime.UtcNow.DayOfWeek switch + { + DayOfWeek.Monday => hw_week_day.HW_WEEK_DAY_MONDAY, + DayOfWeek.Tuesday => hw_week_day.HW_WEEK_DAY_TUESDAY, + DayOfWeek.Wednesday => hw_week_day.HW_WEEK_DAY_WEDNESDAY, + DayOfWeek.Thursday => hw_week_day.HW_WEEK_DAY_THURSDAY, + DayOfWeek.Friday => hw_week_day.HW_WEEK_DAY_FRIDAY, + DayOfWeek.Sunday => hw_week_day.HW_WEEK_DAY_UNKNOWN, + DayOfWeek.Saturday => hw_week_day.HW_WEEK_DAY_UNKNOWN, + _ => hw_week_day.HW_WEEK_DAY_UNKNOWN + }; + + hw_pass_enum_by_value(weekday); + hw_pass_enum_by_reference(&weekday); + + var event1 = default(hw_event); + event1.kind = hw_event_kind.HW_EVENT_KIND_STRING; + event1.string1 = "Anonymous structs and unions have their fields inlined in C# with using the same value for the FieldOffset attribute."; + event1.string2 = "If the struct is larger than 16-24 bytes (as is the case here), consider passing it by reference rather than by value."; + hw_pass_struct_by_value(event1); + + var event2 = default(hw_event); + event2.kind = hw_event_kind.HW_EVENT_KIND_BOOL; + event2.boolean = true; + hw_pass_struct_by_reference(&event2); } #if NET5_0_OR_GREATER diff --git a/src/cs/examples/helloworld/helloworld-bindgen/my_c_library/include/my_c_library.h b/src/cs/examples/helloworld/helloworld-bindgen/my_c_library/include/my_c_library.h index d56d78ce..ab5dbda3 100644 --- a/src/cs/examples/helloworld/helloworld-bindgen/my_c_library/include/my_c_library.h +++ b/src/cs/examples/helloworld/helloworld-bindgen/my_c_library/include/my_c_library.h @@ -1,35 +1,137 @@ #pragma once #include +#include +#include #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) #if defined(__clang__) - #define MY_C_LIBRARY_API_DECL __declspec(dllexport) __attribute__ ((visibility("default"))) + #define MY_C_LIBRARY_API_DECL __declspec(dllexport) __attribute__((visibility("default"))) #else #define MY_C_LIBRARY_API_DECL __declspec(dllexport) #endif #else - #define MY_C_LIBRARY_API_DECL extern __attribute__ ((visibility("default"))) + #define MY_C_LIBRARY_API_DECL extern __attribute__((visibility("default"))) #endif #define HW_STRING_POINTER "Hello world using UTF-8 string literal from the C library's data segment!" -typedef enum hw_my_enum_week_day { - HW_MY_ENUM_WEEK_DAY_UNKNOWN, - HW_MY_ENUM_WEEK_DAY_MONDAY, - HW_MY_ENUM_WEEK_DAY_TUESDAY, - HW_MY_ENUM_WEEK_DAY_WEDNESDAY, - HW_MY_ENUM_WEEK_DAY_THURSDAY, - HW_MY_ENUM_WEEK_DAY_FRIDAY, - _HW_MY_ENUM_WEEK_DAY_FORCE_U32 = 0x7FFFFFFF -} hw_my_enum_week_day; +typedef void (*hw_callback)(const char *s); -typedef void (*hw_callback)(const char* s); +typedef enum hw_week_day +{ + HW_WEEK_DAY_UNKNOWN, + + HW_WEEK_DAY_MONDAY, + HW_WEEK_DAY_TUESDAY, + HW_WEEK_DAY_WEDNESDAY, + HW_WEEK_DAY_THURSDAY, + HW_WEEK_DAY_FRIDAY, + + _HW_WEEK_DAY_FORCE_U32 = 0x7FFFFFFF +} hw_week_day; + +typedef enum hw_event_kind +{ + HW_EVENT_KIND_UNKNOWN, + + HW_EVENT_KIND_STRING, + HW_EVENT_KIND_S8, + HW_EVENT_KIND_U8, + HW_EVENT_KIND_S16, + HW_EVENT_KIND_U16, + HW_EVENT_KIND_S32, + HW_EVENT_KIND_U32, + HW_EVENT_KIND_S64, + HW_EVENT_KIND_U64, + HW_EVENT_KIND_S128, + HW_EVENT_KIND_U128, + HW_EVENT_KIND_S256, + HW_EVENT_KIND_U256, + HW_EVENT_KIND_BOOL, + + _HW_EVENT_KIND_FORCE_U32 = 0x7FFFFFFF +} hw_event_kind; + +typedef struct hw_event +{ + hw_event_kind kind; + struct + { + union + { + struct + { + char* string1; + char* string2; + }; + struct + { + int8_t s8; + }; + struct + { + uint8_t u8; + }; + struct + { + int16_t s16; + }; + struct + { + uint16_t u16; + }; + struct + { + int32_t s32; + }; + struct + { + uint32_t u32; + }; + struct + { + int64_t s64; + }; + struct + { + uint64_t u64; + }; + struct + { + int8_t s128[16]; + }; + struct + { + uint8_t u128[16]; + }; + struct + { + int64_t s256[4]; + }; + struct + { + uint64_t u256[4]; + }; + struct + { + size_t size; + }; + struct + { + bool boolean; + }; + }; + }; +} hw_event; MY_C_LIBRARY_API_DECL void hw_hello_world(void); -MY_C_LIBRARY_API_DECL void hw_invoke_callback1(hw_callback f, const char* s); -MY_C_LIBRARY_API_DECL void hw_invoke_callback2(void f(const char*), const char* s); -MY_C_LIBRARY_API_DECL void hw_pass_string(const char* s); -MY_C_LIBRARY_API_DECL void hw_pass_integers_by_value(uint16_t a, int32_t b, uint64_t c); -MY_C_LIBRARY_API_DECL void hw_pass_integers_by_reference(const uint16_t* a, const int32_t* b, const uint64_t* c); -MY_C_LIBRARY_API_DECL void hw_pass_enum(const hw_my_enum_week_day e); +MY_C_LIBRARY_API_DECL void hw_invoke_callback1(hw_callback f, const char *s); +MY_C_LIBRARY_API_DECL void hw_invoke_callback2(void f(const char *), const char *s); +MY_C_LIBRARY_API_DECL void hw_pass_string(const char *s); +MY_C_LIBRARY_API_DECL void hw_pass_integers_by_value(uint16_t a, uint32_t b, uint64_t c); +MY_C_LIBRARY_API_DECL void hw_pass_integers_by_reference(const uint16_t *a, const uint32_t* b, const uint64_t* c); +MY_C_LIBRARY_API_DECL void hw_pass_enum_by_value(const hw_week_day e); +MY_C_LIBRARY_API_DECL void hw_pass_enum_by_reference(const hw_week_day* e); +MY_C_LIBRARY_API_DECL void hw_pass_struct_by_value(const hw_event e); +MY_C_LIBRARY_API_DECL void hw_pass_struct_by_reference(const hw_event* e); diff --git a/src/cs/examples/helloworld/helloworld-bindgen/my_c_library/src/my_c_library.c b/src/cs/examples/helloworld/helloworld-bindgen/my_c_library/src/my_c_library.c index ad4d4e2a..4abba1f8 100644 --- a/src/cs/examples/helloworld/helloworld-bindgen/my_c_library/src/my_c_library.c +++ b/src/cs/examples/helloworld/helloworld-bindgen/my_c_library/src/my_c_library.c @@ -1,6 +1,5 @@ #include "my_c_library.h" -#include #include void hw_hello_world(void) @@ -33,29 +32,93 @@ void hw_pass_string(const char* s) printf("%s\n", s); } -void hw_pass_integers_by_value(uint16_t a, int32_t b, uint64_t c) +void hw_pass_integers_by_value(uint16_t a, uint32_t b, uint64_t c) { uint64_t sum = a + b + c; - printf("%lu\n", sum); + printf("Sum: %llu\n", sum); } -void hw_pass_integers_by_reference(const uint16_t* a, const int32_t* b, const uint64_t* c) +void hw_pass_integers_by_reference(const uint16_t* a, const uint32_t* b, const uint64_t* c) { uint64_t sum = *a + *b + *c; - printf("%lu\n", sum); + printf("Sum: %llu\n", sum); } -void hw_pass_enum(const hw_my_enum_week_day e) +void _hw_print_weekday(const hw_week_day e) { switch (e) { - case HW_MY_ENUM_WEEK_DAY_UNKNOWN: - printf("UNKNOWN"); + case HW_WEEK_DAY_MONDAY: + printf("Monday :((\n"); break; - case HW_MY_ENUM_WEEK_DAY_MONDAY: - printf("MONDAY"); + case HW_WEEK_DAY_TUESDAY: + printf("Tuesday :(\n"); break; + case HW_WEEK_DAY_WEDNESDAY: + printf("Wednesday :|\n"); + break; + case HW_WEEK_DAY_THURSDAY: + printf("Thursday :)\n"); + break; + case HW_WEEK_DAY_FRIDAY: + printf("Friday :))\n"); + break; + case HW_WEEK_DAY_UNKNOWN: + default: + printf("Unknown week day!\n"); + break; + } +} + +void hw_pass_enum_by_value(const hw_week_day e) +{ + _hw_print_weekday(e); +} + +void hw_pass_enum_by_reference(const hw_week_day* e) +{ + _hw_print_weekday(*e); +} + +void _hw_print_event(const hw_event e) +{ + printf("Event kind: %d, event data:\n", e.kind); + switch (e.kind) + { + case HW_EVENT_KIND_STRING: + printf("\t%s\n", e.string1); + printf("\t%s\n", e.string2); + break; + case HW_EVENT_KIND_U8: + case HW_EVENT_KIND_S8: + case HW_EVENT_KIND_U16: + case HW_EVENT_KIND_S16: + case HW_EVENT_KIND_U32: + case HW_EVENT_KIND_S32: + case HW_EVENT_KIND_U64: + case HW_EVENT_KIND_S64: + case HW_EVENT_KIND_U128: + case HW_EVENT_KIND_S128: + case HW_EVENT_KIND_U256: + case HW_EVENT_KIND_S256: + printf("\tNot implemented.\n"); + break; + case HW_EVENT_KIND_BOOL: + printf("\t%s\n", e.boolean ? "true" : "false"); + break; + case HW_EVENT_KIND_UNKNOWN: default: - printf("???"); + printf("\tUnknown event!\n"); + break; } } + +void hw_pass_struct_by_value(const hw_event e) +{ + _hw_print_event(e); +} + +void hw_pass_struct_by_reference(const hw_event* e) +{ + _hw_print_event(*e); +} diff --git a/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorEnum.cs b/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorEnum.cs index 2fc547c5..539d0d80 100644 --- a/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorEnum.cs +++ b/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorEnum.cs @@ -13,7 +13,7 @@ namespace C2CS.GenerateCSharpCode.Generators; public class GeneratorEnum(ILogger logger) : BaseGenerator(logger) { - public override string? GenerateCode(CodeGeneratorContext context, string nameCSharp, CEnum node) + public override string GenerateCode(CodeGeneratorContext context, string nameCSharp, CEnum node) { var integerTypeNameCSharp = node.SizeOf switch { diff --git a/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorFunction.cs b/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorFunction.cs index 2f8368ff..dcf4d9e5 100644 --- a/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorFunction.cs +++ b/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorFunction.cs @@ -15,7 +15,7 @@ namespace C2CS.GenerateCSharpCode.Generators; public class GeneratorFunction(ILogger logger) : BaseGenerator(logger) { - public override string? GenerateCode(CodeGeneratorContext context, string nameCSharp, CFunction function) + public override string GenerateCode(CodeGeneratorContext context, string nameCSharp, CFunction function) { var returnTypeNameCSharp = context.NameMapper.GetTypeNameCSharp(function.ReturnType); var parametersStringCSharp = string.Join(',', function.Parameters.Select( diff --git a/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorFunctionPointer.cs b/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorFunctionPointer.cs index 6d234c96..d03e825d 100644 --- a/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorFunctionPointer.cs +++ b/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorFunctionPointer.cs @@ -13,7 +13,7 @@ namespace C2CS.GenerateCSharpCode.Generators; public sealed class GeneratorFunctionPointer(ILogger logger) : BaseGenerator(logger) { - public override string? GenerateCode(CodeGeneratorContext context, string nameCSharp, CFunctionPointer node) + public override string GenerateCode(CodeGeneratorContext context, string nameCSharp, CFunctionPointer node) { var nameMapper = context.NameMapper; var code = context.Input.IsEnabledFunctionPointers ? diff --git a/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorMacroObject.cs b/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorMacroObject.cs index 8da85261..20683a25 100644 --- a/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorMacroObject.cs +++ b/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorMacroObject.cs @@ -11,7 +11,7 @@ namespace C2CS.GenerateCSharpCode.Generators; public class GeneratorMacroObject(ILogger logger) : BaseGenerator(logger) { - public override string? GenerateCode(CodeGeneratorContext context, string nameCSharp, CMacroObject node) + public override string GenerateCode(CodeGeneratorContext context, string nameCSharp, CMacroObject node) { var cSharpTypeName = context.NameMapper.GetTypeNameCSharp(node.Type); diff --git a/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorOpaqueType.cs b/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorOpaqueType.cs index 77ac6c1b..26a0119d 100644 --- a/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorOpaqueType.cs +++ b/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorOpaqueType.cs @@ -11,7 +11,7 @@ namespace C2CS.GenerateCSharpCode.Generators; public class GeneratorOpaqueType(ILogger logger) : BaseGenerator(logger) { - public override string? GenerateCode(CodeGeneratorContext context, string nameCSharp, COpaqueType node) + public override string GenerateCode(CodeGeneratorContext context, string nameCSharp, COpaqueType node) { var code = $$""" [StructLayout(LayoutKind.Sequential)] diff --git a/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorStruct.cs b/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorStruct.cs index b3bbf573..eb30c49a 100644 --- a/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorStruct.cs +++ b/src/cs/production/c2cs.Tool/GenerateCSharpCode/Generators/GeneratorStruct.cs @@ -12,9 +12,10 @@ namespace C2CS.GenerateCSharpCode.Generators; public class GeneratorStruct(ILogger logger) : BaseGenerator(logger) { - public override string? GenerateCode(CodeGeneratorContext context, string nameCSharp, CRecord record) + public override string GenerateCode(CodeGeneratorContext context, string nameCSharp, CRecord record) { - var codeStructMembers = GenerateCodeStructMembers(context.NameMapper, record.Fields); + var codeStructMembers = GenerateCodeStructMembers( + context, record.Fields, record.NestedRecords, 0); var membersCode = string.Join("\n\n", codeStructMembers); var code = $$""" @@ -28,42 +29,67 @@ public partial struct {{nameCSharp}} return code; } - private string[] GenerateCodeStructMembers(NameMapper nameMapper, ImmutableArray fields) + private ImmutableArray GenerateCodeStructMembers( + CodeGeneratorContext context, + ImmutableArray fields, + ImmutableArray nestedStructs, + int parentFieldOffsetOf) { - var builder = ImmutableArray.CreateBuilder(); + var codeFields = ImmutableArray.CreateBuilder(); - foreach (var field in fields) + var nestedStructIndex = 0; + for (var i = 0; i < fields.Length; i++) { - var code = GenerateCodeStructField(nameMapper, field); - builder.Add(code); + var field = fields[i]; + var fieldOffsetOf = parentFieldOffsetOf + field.OffsetOf; + + if (field.Type.IsAnonymous ?? false) + { + var nestedStruct = nestedStructs[nestedStructIndex++]; + var codeNestedStructMembers = GenerateCodeStructMembers( + context, nestedStruct.Fields, nestedStruct.NestedRecords, fieldOffsetOf); + codeFields.AddRange(codeNestedStructMembers); + } + else + { + var fieldNameCSharp = context.NameMapper.GetIdentifierCSharp(field.Name); + var fieldTypeNameCSharp = context.NameMapper.GetTypeNameCSharp(field.Type); + var codeField = GenerateCodeStructField( + context.NameMapper, field, fieldNameCSharp, fieldTypeNameCSharp, fieldOffsetOf); + codeFields.Add(codeField); + } } - var structMembers = builder.ToArray(); - return structMembers; + return codeFields.ToImmutable(); } - private string GenerateCodeStructField(NameMapper nameMapper, CRecordField field) + private string GenerateCodeStructField( + NameMapper nameMapper, + CRecordField field, + string fieldNameCSharp, + string fieldTypeNameCSharp, + int fieldOffsetOf) { - var fieldNameCSharp = nameMapper.GetIdentifierCSharp(field.Name); var isArray = field.Type.ArraySizeOf != null; var code = isArray - ? GenerateCodeStructFieldFixedBuffer(fieldNameCSharp, nameMapper, field) - : GenerateCodeStructFieldNormal(fieldNameCSharp, nameMapper, field); + ? GenerateCodeStructFieldFixedBuffer(field, fieldNameCSharp, nameMapper, fieldOffsetOf) + : GenerateCodeStructFieldNormal(field, fieldNameCSharp, fieldTypeNameCSharp, fieldOffsetOf); return code; } private string GenerateCodeStructFieldFixedBuffer( + CRecordField field, string fieldNameCSharp, NameMapper nameMapper, - CRecordField field) + int fieldOffsetOf) { - var elementTypeName = nameMapper.GetTypeNameCSharp(field.Type.InnerType!); - if (elementTypeName.EndsWith('*')) + var elementTypeNameCSharp = nameMapper.GetTypeNameCSharp(field.Type.InnerType!); + if (elementTypeNameCSharp.EndsWith('*')) { - elementTypeName = "IntPtr"; + elementTypeNameCSharp = "IntPtr"; } - var typeNameIsFixedBufferCompatible = elementTypeName is "byte" + var typeNameIsFixedBufferCompatible = elementTypeNameCSharp is "byte" or "char" or "short" or "int" @@ -78,48 +104,49 @@ private string GenerateCodeStructFieldFixedBuffer( string code; if (typeNameIsFixedBufferCompatible) { - var fixedBufferTypeName = nameMapper.GetTypeNameCSharp(field.Type.InnerType!); code = $""" - [FieldOffset({field.OffsetOf})] // size = {field.Type.SizeOf} - public fixed {fixedBufferTypeName} {fieldNameCSharp}[{field.Type.ArraySizeOf}]; + [FieldOffset({fieldOffsetOf})] // size = {field.Type.SizeOf} + public fixed {elementTypeNameCSharp} {fieldNameCSharp}[{field.Type.ArraySizeOf}]; """; } else { - code = $$""" - [FieldOffset({{field.OffsetOf}})] // size = {{field.Type.SizeOf}} - public fixed byte _{{fieldNameCSharp}}[{{field.Type.SizeOf}}]; // {{field.Type.Name}} - """; + fieldNameCSharp = $"_{fieldNameCSharp.TrimStart('@')}"; + code = $""" + [FieldOffset({fieldOffsetOf})] // size = {field.Type.SizeOf} + public fixed byte {fieldNameCSharp}[{field.Type.SizeOf}]; // {field.Type.Name} + """; } return code; } private string GenerateCodeStructFieldNormal( + CRecordField field, string fieldNameCSharp, - NameMapper nameMapper, - CRecordField field) + string fieldTypeNameCSharp, + int fieldOffsetOf) { - var fieldTypeNameCSharp = nameMapper.GetTypeNameCSharp(field.Type); - string code; #pragma warning disable IDE0045 if (fieldTypeNameCSharp == "CString") #pragma warning restore IDE0045 { + var backingFieldNameCSharp = $"_{fieldNameCSharp.TrimStart('@')}"; + code = $$""" - [FieldOffset({{field.OffsetOf}})] // size = {{field.Type.SizeOf}} - public {{fieldTypeNameCSharp}} _{{fieldNameCSharp}}; + [FieldOffset({{fieldOffsetOf}})] // size = {{field.Type.SizeOf}} + public {{fieldTypeNameCSharp}} {{backingFieldNameCSharp}}; public string {{fieldNameCSharp}} { get { - return CString.ToString(_{{fieldNameCSharp}}); + return CString.ToString({{backingFieldNameCSharp}}); } set { - _{{fieldNameCSharp}} = CString.FromString(value); + {{backingFieldNameCSharp}} = CString.FromString(value); } } """; @@ -127,7 +154,7 @@ public string {{fieldNameCSharp}} else { code = $$""" - [FieldOffset({{field.OffsetOf}})] + [FieldOffset({{fieldOffsetOf}})] public {{fieldTypeNameCSharp}} {{fieldNameCSharp}}; // size = {{field.Type.SizeOf}} """; } diff --git a/src/cs/production/c2cs.Tool/c2cs.Tool.csproj b/src/cs/production/c2cs.Tool/c2cs.Tool.csproj index badab553..aaffc181 100644 --- a/src/cs/production/c2cs.Tool/c2cs.Tool.csproj +++ b/src/cs/production/c2cs.Tool/c2cs.Tool.csproj @@ -27,7 +27,7 @@ - +