a bunch of minor changes combined:

- From instead of Into
- unsafe_data_ref for other payloads
- CByteSlice for returning memory spans
- send Packet instead of Into<Packet>
- expose packet layer to C/C#
This commit is contained in:
Vinzenz Schroeter 2024-05-15 20:34:51 +02:00
parent 5803b71f3a
commit 1dad113ca1
33 changed files with 462 additions and 733 deletions

View file

@ -8,6 +8,8 @@ fn main() {
.input_extern_file("../servicepoint2/src/connection.rs")
.input_extern_file("../servicepoint2/src/pixel_grid.rs")
.input_extern_file("../servicepoint2/src/lib.rs")
.input_extern_file("../servicepoint2/src/c_slice.rs")
.input_extern_file("../servicepoint2/src/packet.rs")
.csharp_dll_name("servicepoint2")
.csharp_namespace("ServicePoint2.BindGen")
.csharp_use_nint_types(true)

View file

@ -50,6 +50,10 @@ namespace ServicePoint2.BindGen
[DllImport(__DllName, EntryPoint = "sp2_bit_vec_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern nuint sp2_bit_vec_len(BitVec* @this);
/// <summary>Gets an unsafe reference to the data of the `BitVec` instance. ## Safety The caller has to make sure to never access the returned memory after the `BitVec` instance has been consumed or manually deallocated. Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
[DllImport(__DllName, EntryPoint = "sp2_bit_vec_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern CByteSlice sp2_bit_vec_unsafe_data_ref(BitVec* @this);
/// <summary>Creates a new `ByteGrid` instance. The returned instance has to be freed with `byte_grid_dealloc`.</summary>
[DllImport(__DllName, EntryPoint = "sp2_byte_grid_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern ByteGrid* sp2_byte_grid_new(nuint width, nuint height);
@ -86,9 +90,13 @@ namespace ServicePoint2.BindGen
[DllImport(__DllName, EntryPoint = "sp2_byte_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern nuint sp2_byte_grid_height(ByteGrid* @this);
/// <summary>Tries to load a `Command` from the passed array with the specified length. returns: NULL in case of an error, pointer to the allocated command otherwise</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_try_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_try_load(byte* data, nuint length);
/// <summary>Gets an unsafe reference to the data of the `ByteGrid` instance. ## Safety The caller has to make sure to never access the returned memory after the `ByteGrid` instance has been consumed or manually deallocated. Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
[DllImport(__DllName, EntryPoint = "sp2_byte_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern CByteSlice sp2_byte_grid_unsafe_data_ref(ByteGrid* @this);
/// <summary>Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process. Returns: pointer to command or NULL</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_try_from_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp2_command_try_from_packet(Packet* packet);
/// <summary>Clones a `Command` instance</summary>
[DllImport(__DllName, EntryPoint = "sp2_command_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
@ -149,7 +157,7 @@ namespace ServicePoint2.BindGen
/// <summary>Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.</summary>
[DllImport(__DllName, EntryPoint = "sp2_connection_send", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool sp2_connection_send(Connection* connection, Command* command_ptr);
public static extern bool sp2_connection_send(Connection* connection, Packet* command_ptr);
/// <summary>Closes and deallocates a connection instance</summary>
[DllImport(__DllName, EntryPoint = "sp2_connection_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
@ -192,9 +200,21 @@ namespace ServicePoint2.BindGen
[DllImport(__DllName, EntryPoint = "sp2_pixel_grid_height", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern nuint sp2_pixel_grid_height(PixelGrid* @this);
/// <summary>Gets a reference to the data of the `PixelGrid` instance.</summary>
[DllImport(__DllName, EntryPoint = "sp2_pixel_grid_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern byte* sp2_pixel_grid_data_ref(PixelGrid* @this);
/// <summary>Gets an unsafe reference to the data of the `PixelGrid` instance. ## Safety The caller has to make sure to never access the returned memory after the `PixelGrid` instance has been consumed or manually deallocated. Reading and writing concurrently to either the original instance or the returned data will result in undefined behavior.</summary>
[DllImport(__DllName, EntryPoint = "sp2_pixel_grid_unsafe_data_ref", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern CByteSlice sp2_pixel_grid_unsafe_data_ref(PixelGrid* @this);
/// <summary>Turns a `Command` into a `Packet`. The command gets deallocated in the process.</summary>
[DllImport(__DllName, EntryPoint = "sp2_packet_from_command", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Packet* sp2_packet_from_command(Command* command);
/// <summary>Tries to load a `Packet` from the passed array with the specified length. returns: NULL in case of an error, pointer to the allocated packet otherwise</summary>
[DllImport(__DllName, EntryPoint = "sp2_packet_try_load", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Packet* sp2_packet_try_load(byte* data, nuint length);
/// <summary>Deallocates a `Packet`. Note: do not call this if the instance has been consumed in another way, e.g. by sending it.</summary>
[DllImport(__DllName, EntryPoint = "sp2_packet_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void sp2_packet_dealloc(Packet* @this);
}
@ -219,6 +239,18 @@ namespace ServicePoint2.BindGen
{
}
[StructLayout(LayoutKind.Sequential)]
public unsafe partial struct CByteSlice
{
public byte* start;
public nuint length;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe partial struct Packet
{
}
public enum Command
{

View file

@ -68,11 +68,23 @@ public sealed class BitVec : Sp2NativeInstance<BindGen.BitVec>
}
}
public Span<byte> Data
{
get
{
unsafe
{
var slice = NativeMethods.sp2_bit_vec_unsafe_data_ref(Instance);
return new Span<byte>(slice.start, (int)slice.length);
}
}
}
private unsafe BitVec(BindGen.BitVec* instance) : base(instance)
{
}
protected override unsafe void Dealloc()
private protected override unsafe void Dealloc()
{
NativeMethods.sp2_bit_vec_dealloc(Instance);
}

View file

@ -111,11 +111,23 @@ public sealed class ByteGrid : Sp2NativeInstance<BindGen.ByteGrid>
}
}
public Span<byte> Data
{
get
{
unsafe
{
var slice = NativeMethods.sp2_byte_grid_unsafe_data_ref(Instance);
return new Span<byte>(slice.start, (int)slice.length);
}
}
}
private unsafe ByteGrid(BindGen.ByteGrid* instance) : base(instance)
{
}
protected override unsafe void Dealloc()
private protected override unsafe void Dealloc()
{
NativeMethods.sp2_byte_grid_dealloc(Instance);
}

View file

@ -5,6 +5,22 @@ namespace ServicePoint2;
public sealed class Command : Sp2NativeInstance<BindGen.Command>
{
public static bool TryFromPacket(Packet packet, [MaybeNullWhen(false)] out Command command)
{
unsafe
{
var result = NativeMethods.sp2_command_try_from_packet(packet.Into());
if (result == null)
{
command = null;
return false;
}
command = new Command(result);
return true;
}
}
public Command Clone()
{
unsafe
@ -13,21 +29,6 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
}
}
public static bool TryLoad(Span<byte> bytes, [MaybeNullWhen(false)] out Command command)
{
unsafe
{
fixed (byte* bytesPtr = bytes)
{
var instance = NativeMethods.sp2_command_try_load(bytesPtr, (nuint)bytes.Length);
command = instance == null
? null
: new Command(instance);
return command != null;
}
}
}
public static Command Clear()
{
unsafe
@ -124,7 +125,7 @@ public sealed class Command : Sp2NativeInstance<BindGen.Command>
{
}
protected override unsafe void Dealloc()
private protected override unsafe void Dealloc()
{
NativeMethods.sp2_command_dealloc(Instance);
}

View file

@ -16,15 +16,15 @@ public sealed class Connection : Sp2NativeInstance<BindGen.Connection>
}
}
public bool Send(Command command)
public bool Send(Packet packet)
{
unsafe
{
return NativeMethods.sp2_connection_send(Instance, command.Into());
return NativeMethods.sp2_connection_send(Instance, packet.Into());
}
}
protected override unsafe void Dealloc()
private protected override unsafe void Dealloc()
{
NativeMethods.sp2_connection_dealloc(Instance);
}

View file

@ -0,0 +1,39 @@
using System.Diagnostics.CodeAnalysis;
using ServicePoint2.BindGen;
namespace ServicePoint2;
public sealed class Packet : Sp2NativeInstance<BindGen.Packet>
{
public static Packet FromCommand(Command command)
{
unsafe
{
return new Packet(NativeMethods.sp2_packet_from_command(command.Into()));
}
}
public static bool TryFromBytes(Span<byte> bytes, [MaybeNullWhen(false)] out Packet packet)
{
unsafe
{
fixed (byte* bytesPtr = bytes)
{
var instance = NativeMethods.sp2_packet_try_load(bytesPtr, (nuint)bytes.Length);
packet = instance == null
? null
: new Packet(instance);
return packet != null;
}
}
}
private unsafe Packet(BindGen.Packet* instance) : base(instance)
{
}
private protected override unsafe void Dealloc()
{
NativeMethods.sp2_packet_dealloc(Instance);
}
}

View file

@ -86,8 +86,8 @@ public sealed class PixelGrid : Sp2NativeInstance<BindGen.PixelGrid>
{
unsafe
{
var ptr = NativeMethods.sp2_pixel_grid_data_ref(Instance);
return new Span<byte>(ptr, Width * Height / 8);
var slice = NativeMethods.sp2_pixel_grid_unsafe_data_ref(Instance);
return new Span<byte>(slice.start, (int)slice.length);
}
}
}
@ -96,7 +96,7 @@ public sealed class PixelGrid : Sp2NativeInstance<BindGen.PixelGrid>
{
}
protected override unsafe void Dealloc()
private protected override unsafe void Dealloc()
{
NativeMethods.sp2_pixel_grid_dealloc(Instance);
}

View file

@ -0,0 +1,16 @@
using System.Diagnostics.CodeAnalysis;
namespace ServicePoint2;
public static class ServicePoint2Extensions
{
public static Packet IntoPacket(this Command command)
{
return Packet.FromCommand(command);
}
public static bool TryIntoCommand(this Packet packet, [MaybeNullWhen(false)] out Command command)
{
return Command.TryFromPacket(packet, out command);
}
}

View file

@ -22,7 +22,7 @@ public abstract class Sp2NativeInstance<T>
_instance = instance;
}
protected abstract void Dealloc();
private protected abstract void Dealloc();
internal unsafe T* Into()
{