Skip to content

Commit

Permalink
Anonymous structs (#171)
Browse files Browse the repository at this point in the history
  • Loading branch information
lithiumtoast authored Jan 7, 2025
1 parent 41eb0d2 commit 117b013
Show file tree
Hide file tree
Showing 14 changed files with 451 additions and 96 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// <auto-generated>
// 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.
// </auto-generated>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// <auto-generated>
// 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,32 @@ 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
{
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
{
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
Expand All @@ -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);
}
}
137 changes: 124 additions & 13 deletions src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.g.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// <auto-generated>
// 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.
Expand Down Expand Up @@ -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)]
Expand Down
42 changes: 35 additions & 7 deletions src/cs/examples/helloworld/helloworld-app/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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
Expand Down
Loading

0 comments on commit 117b013

Please sign in to comment.