Last active
August 1, 2019 14:05
-
-
Save wi7a1ian/57465a0796e55a04f86307e670a34cac to your computer and use it in GitHub Desktop.
Example of fine interoop between .NET Core & C compatible ABI #csharp #cpp #rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
internal static class NativeMethods | |
{ | |
static class LastResult | |
{ | |
public static (CDllResult, string) GetLastResult() | |
{ | |
return FillLastResult(new Span<byte>(new byte[1024])); | |
} | |
private static unsafe (CDllResult, string) FillLastResult(Span<byte> buffer) | |
{ | |
fixed (byte* messageBufPtr = buffer) | |
{ | |
var result = c_last_result( | |
(IntPtr) messageBufPtr, | |
(UIntPtr) buffer.Length, | |
out var actualMessageLen, | |
out var lastResult); | |
if (result.IsBufferTooSmall()) return FillLastResult(new Span<byte>(new byte[(int) actualMessageLen])); | |
return (lastResult, Encoding.UTF8.GetString(messageBufPtr, (int) actualMessageLen)); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
internal static class NativeMethods | |
{ | |
[StructLayout(LayoutKind.Sequential)] | |
public struct CDllResult | |
{ | |
private enum Kind : uint | |
{ | |
Ok, | |
Done, | |
BufferTooSmall, | |
ArgumentNull, | |
InternalError | |
} | |
private readonly Kind _result; | |
private readonly uint _id; | |
public static (CDllResult, string) GetLastResult() | |
{ | |
return LastResult.GetLastResult(); | |
} | |
internal CDllResult Check() | |
{ | |
if (IsSuccess() || IsBufferTooSmall()) return this; | |
var (lastResult, msg) = GetLastResult(); | |
// Check whether the last result kind and id are the same | |
// We need to use both because successful results won't | |
// bother setting the id (it avoids some synchronization) | |
if (lastResult._result == _result && lastResult._id == _id) | |
throw new Exception($"Native call failed ({_result}), {msg?.TrimEnd()}"); | |
throw new Exception($"Native call failed with {_result}"); | |
} | |
public bool IsSuccess() | |
{ | |
return _result == Kind.Ok || _result == Kind.Done; | |
} | |
public bool IsDone() | |
{ | |
return _result == Kind.Done; | |
} | |
public bool IsBufferTooSmall() | |
{ | |
return _result == Kind.BufferTooSmall; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public sealed class Writer : IDisposable | |
{ | |
private readonly WriterHandle _handle; | |
internal Writer(WriterHandle handle) | |
{ | |
_handle = handle ?? throw new ArgumentNullException(nameof(handle)); | |
} | |
public void Dispose() | |
{ | |
_handle.Dispose(); | |
} | |
public void Set(Key key, ReadOnlySpan<byte> value) | |
{ | |
unsafe | |
{ | |
var rawKey = key.Value; | |
var keyPtr = Unsafe.AsPointer(ref rawKey); | |
fixed (byte* valuePtr = value) | |
{ | |
c_write_set(_handle, (IntPtr) keyPtr, (IntPtr) valuePtr, (UIntPtr) value.Length); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class WriterHandle : SafeHandle | |
{ | |
private WriterHandle() | |
: base(IntPtr.Zero, true) | |
{ | |
} | |
public override bool IsInvalid => handle == IntPtr.Zero; | |
protected override bool ReleaseHandle() | |
{ | |
if (handle == IntPtr.Zero) return true; | |
var h = handle; | |
handle = IntPtr.Zero; | |
c_write_end(h, false); | |
return true; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
internal static class NativeMethods | |
{ | |
[DllImport(NativeLibrary, EntryPoint = "c_write_begin", ExactSpelling = true, | |
CallingConvention = CallingConvention.Cdecl)] | |
private static extern CDllResult _c_write_begin(StoreHandle store, out WriterHandle writer); | |
public static CDllResult c_write_begin(StoreHandle store, out WriterHandle writer, bool check = true) | |
{ | |
return MaybeCheck(_c_write_begin(store, out writer), check); | |
} | |
private static CDllResult MaybeCheck(DbResult result, bool check) | |
{ | |
return check ? result.Check() : result; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public Writer BeginWrite() | |
{ | |
c_write_begin(out var writerHandle); | |
return new Writer(writerHandle); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Based on https://github.com/KodrAus/rust-csharp-ffi/tree/master/dotnet/Db.Storage/Native