-
Notifications
You must be signed in to change notification settings - Fork 75
Description
Would be beneficial if there were (ReadOnly)Span<byte> overloads to reduce allocations and make using existing buffers easier.
I'm happy to do a PR to implement if you are interested.
The native method declarations in C# would need to change since they use byte[] but won't be too much trouble since the native API uses a pointer anyway.
libplctag.NET/src/libplctag.NativeImport/NativeMethods.cs
Lines 247 to 251 in e28ec36
| [DllImport(DLL_NAME, EntryPoint = nameof(plc_tag_get_raw_bytes), CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | |
| public static extern int plc_tag_get_raw_bytes(Int32 tag_id, int start_offset, [Out] byte[] buffer, int buffer_length); | |
| [DllImport(DLL_NAME, EntryPoint = nameof(plc_tag_set_raw_bytes), CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | |
| public static extern int plc_tag_set_raw_bytes(Int32 tag_id, int start_offset, [In] byte[] buffer, int buffer_length); |
LIB_EXPORT int plc_tag_set_raw_bytes(int32_t id, int offset, uint8_t *buffer, int buffer_length);
LIB_EXPORT int plc_tag_get_raw_bytes(int32_t id, int offset, uint8_t *buffer, int buffer_length);
There are a few ways to do this, one approach can be found in Memory<T> and Span<T> usage guidelines under:
Rule #9: If you're wrapping a synchronous p/invoke method, your API should accept Span as a parameter.
Alternatively and ideally, would use P/Invoke source generation but this requires .NET 7+. Something like:
[LibraryImport(DLL_NAME, EntryPoint = nameof(plc_tag_get_raw_bytes))]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
public static partial int plc_tag_get_raw_bytes(Int32 tag_id, int start_offset, [MarshalUsing(CountElementName = nameof(buffer_length))] out Span<byte> buffer, int buffer_length);
[LibraryImport(DLL_NAME, EntryPoint = nameof(plc_tag_set_raw_bytes))]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
public static partial int plc_tag_set_raw_bytes(Int32 tag_id, int start_offset, ReadOnlySpan<byte> buffer, int buffer_length);This would also make it possible to create ReadAsync and WriteAsync with Memory<byte> overloads too. Similar to Stream.ReadAsync and Stream.WriteAsync
public ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default);
public ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default);Originally posted by @MitchRazga in #394 (comment)