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
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)