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 @@
-
+