Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Anonymous structs #171

Merged
merged 1 commit into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading