diff --git a/.gitignore b/.gitignore
index dc1e685..8792323 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,6 @@
target
.idea
out
-bin
-obj
.direnv
.envrc
result
diff --git a/Cargo.toml b/Cargo.toml
index ddc5168..9eae2e7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,7 +3,8 @@ resolver = "2"
members = [
"crates/servicepoint",
"crates/servicepoint_binding_c",
- "crates/servicepoint_binding_c/examples/lang_c"
+ "crates/servicepoint_binding_c/examples/lang_c",
+ "crates/servicepoint_binding_uniffi"
]
[workspace.package]
diff --git a/crates/servicepoint_binding_uniffi/Cargo.toml b/crates/servicepoint_binding_uniffi/Cargo.toml
new file mode 100644
index 0000000..5ba77a5
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/Cargo.toml
@@ -0,0 +1,49 @@
+[package]
+name = "servicepoint_binding_uniffi"
+version.workspace = true
+publish = false
+edition = "2021"
+license = "GPL-3.0-or-later"
+description = "C bindings for the servicepoint crate."
+homepage = "https://docs.rs/crate/servicepoint_binding_c"
+repository = "https://github.com/cccb/servicepoint"
+#readme = "README.md"
+
+[lib]
+crate-type = ["cdylib"]
+
+[build-dependencies]
+uniffi = { version = "0.25.0" , features = [ "build" ] }
+
+[dependencies]
+uniffi = { version = "0.25.0" }
+thiserror = "1.0.66"
+
+[dependencies.servicepoint]
+version = "0.11.0"
+path = "../servicepoint"
+features = ["all_compressions"]
+
+[dependencies.uniffi-bindgen-cs]
+git="https://github.com/NordSecurity/uniffi-bindgen-cs"
+# tag="v0.8.3+v0.25.0"
+rev="f68639fbc720b50ebe561ba75c66c84dc456bdce"
+optional=true
+
+[lints]
+#workspace = true
+
+[package.metadata.docs.rs]
+all-features = true
+
+[[bin]]
+name = "uniffi-bindgen"
+required-features = ["uniffi/cli"]
+
+[[bin]]
+name = "uniffi-bindgen-cs"
+required-features= ["cs"]
+
+[features]
+default = []
+cs = ["dep:uniffi-bindgen-cs"]
diff --git a/crates/servicepoint_binding_uniffi/generate-bindings.sh b/crates/servicepoint_binding_uniffi/generate-bindings.sh
new file mode 100755
index 0000000..97ad72e
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/generate-bindings.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+set +x
+
+cargo build --release
+
+SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
+TARGETPATH="$(realpath $SCRIPTPATH/../../target/release/)"
+SERVICEPOINT_SO="$TARGETPATH/libservicepoint_binding_uniffi.so"
+CONFIG_TOML="$(realpath $SCRIPTPATH/../uniffi.toml)"
+
+BINDGEN="cargo run --features=uniffi/cli --bin uniffi-bindgen -- "
+BINDGEN_CS="cargo run --features=cs --bin uniffi-bindgen-cs -- "
+COMMON_ARGS="--library $SERVICEPOINT_SO"
+
+${BINDGEN} generate $COMMON_ARGS --language python --out-dir libraries/python
+${BINDGEN} generate $COMMON_ARGS --language kotlin --out-dir libraries/kotlin
+${BINDGEN} generate $COMMON_ARGS --language swift --out-dir libraries/swift
+${BINDGEN_CS} $COMMON_ARGS --out-dir libraries/csharp/ServicePoint
diff --git a/crates/servicepoint_binding_uniffi/libraries/csharp/.gitignore b/crates/servicepoint_binding_uniffi/libraries/csharp/.gitignore
new file mode 100644
index 0000000..1746e32
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/libraries/csharp/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Example/.gitignore b/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Example/.gitignore
new file mode 100644
index 0000000..1746e32
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Example/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Example/Program.cs b/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Example/Program.cs
new file mode 100644
index 0000000..edca01c
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Example/Program.cs
@@ -0,0 +1,5 @@
+using ServicePoint;
+
+var connection = new Connection("");
+
+var clear = new Clear();
diff --git a/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Example/ServicePoint.Example.csproj b/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Example/ServicePoint.Example.csproj
new file mode 100644
index 0000000..3e99664
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Example/ServicePoint.Example.csproj
@@ -0,0 +1,15 @@
+
+
+
+ Exe
+ net8.0
+ ServicePoint.Example
+ disable
+ enable
+
+
+
+
+
+
+
diff --git a/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Tests/ServicePoint.Tests.csproj b/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Tests/ServicePoint.Tests.csproj
new file mode 100644
index 0000000..50500b6
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Tests/ServicePoint.Tests.csproj
@@ -0,0 +1,27 @@
+
+
+
+ net8.0
+ disable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Tests/UnitTest1.cs b/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Tests/UnitTest1.cs
new file mode 100644
index 0000000..46991d7
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint.Tests/UnitTest1.cs
@@ -0,0 +1,12 @@
+using ServicePoint;
+
+namespace ServicePoint.Tests;
+
+public class UnitTest1
+{
+ [Fact]
+ public void Test1()
+ {
+ Assert.Throws(() => new Connection(""));
+ }
+}
diff --git a/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint/ServicePoint.csproj b/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint/ServicePoint.csproj
new file mode 100644
index 0000000..5b7dc28
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint/ServicePoint.csproj
@@ -0,0 +1,53 @@
+
+
+
+ net8.0
+ disable
+ enable
+ true
+
+
+
+ ServicePoint
+ 0.10.0
+ Repository Authors
+ None
+ ServicePoint
+ CCCB
+
+ C# bindings for the rust crate servicepoint. You will need a suitable native shared library to use this.
+ For documentation, see the rust documentation: https://docs.rs/servicepoint/latest/servicepoint/.
+ Note that this library is still in early development. Breaking changes are expected before 1.0 is released.
+
+ README.md
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+ libservicepoint_binding_uniffi.so
+
+
+
+
+ libservicepoint_binding_uniffi.so
+
+
+
+
+
+
+
+
+
+
+
diff --git a/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint/servicepoint_binding_uniffi.cs b/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint/servicepoint_binding_uniffi.cs
new file mode 100644
index 0000000..5e90f6c
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/libraries/csharp/ServicePoint/servicepoint_binding_uniffi.cs
@@ -0,0 +1,1077 @@
+//
+// This file was generated by uniffi-bindgen-cs v0.8.3+v0.25.0
+// See https://github.com/NordSecurity/uniffi-bindgen-cs for more information.
+//
+
+#nullable enable
+
+
+
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+namespace ServicePoint;
+
+
+
+// This is a helper for safely working with byte buffers returned from the Rust code.
+// A rust-owned buffer is represented by its capacity, its current length, and a
+// pointer to the underlying data.
+
+[StructLayout(LayoutKind.Sequential)]
+internal struct RustBuffer {
+ public int capacity;
+ public int len;
+ public IntPtr data;
+
+ public static RustBuffer Alloc(int size) {
+ return _UniffiHelpers.RustCall((ref RustCallStatus status) => {
+ var buffer = _UniFFILib.ffi_servicepoint_binding_uniffi_rustbuffer_alloc(size, ref status);
+ if (buffer.data == IntPtr.Zero) {
+ throw new AllocationException($"RustBuffer.Alloc() returned null data pointer (size={size})");
+ }
+ return buffer;
+ });
+ }
+
+ public static void Free(RustBuffer buffer) {
+ _UniffiHelpers.RustCall((ref RustCallStatus status) => {
+ _UniFFILib.ffi_servicepoint_binding_uniffi_rustbuffer_free(buffer, ref status);
+ });
+ }
+
+ public static BigEndianStream MemoryStream(IntPtr data, int length) {
+ unsafe {
+ return new BigEndianStream(new UnmanagedMemoryStream((byte*)data.ToPointer(), length));
+ }
+ }
+
+ public BigEndianStream AsStream() {
+ unsafe {
+ return new BigEndianStream(new UnmanagedMemoryStream((byte*)data.ToPointer(), len));
+ }
+ }
+
+ public BigEndianStream AsWriteableStream() {
+ unsafe {
+ return new BigEndianStream(new UnmanagedMemoryStream((byte*)data.ToPointer(), capacity, capacity, FileAccess.Write));
+ }
+ }
+}
+
+// This is a helper for safely passing byte references into the rust code.
+// It's not actually used at the moment, because there aren't many things that you
+// can take a direct pointer to managed memory, and if we're going to copy something
+// then we might as well copy it into a `RustBuffer`. But it's here for API
+// completeness.
+
+[StructLayout(LayoutKind.Sequential)]
+internal struct ForeignBytes {
+ public int length;
+ public IntPtr data;
+}
+
+
+// The FfiConverter interface handles converter types to and from the FFI
+//
+// All implementing objects should be public to support external types. When a
+// type is external we need to import it's FfiConverter.
+internal abstract class FfiConverter {
+ // Convert an FFI type to a C# type
+ public abstract CsType Lift(FfiType value);
+
+ // Convert C# type to an FFI type
+ public abstract FfiType Lower(CsType value);
+
+ // Read a C# type from a `ByteBuffer`
+ public abstract CsType Read(BigEndianStream stream);
+
+ // Calculate bytes to allocate when creating a `RustBuffer`
+ //
+ // This must return at least as many bytes as the write() function will
+ // write. It can return more bytes than needed, for example when writing
+ // Strings we can't know the exact bytes needed until we the UTF-8
+ // encoding, so we pessimistically allocate the largest size possible (3
+ // bytes per codepoint). Allocating extra bytes is not really a big deal
+ // because the `RustBuffer` is short-lived.
+ public abstract int AllocationSize(CsType value);
+
+ // Write a C# type to a `ByteBuffer`
+ public abstract void Write(CsType value, BigEndianStream stream);
+
+ // Lower a value into a `RustBuffer`
+ //
+ // This method lowers a value into a `RustBuffer` rather than the normal
+ // FfiType. It's used by the callback interface code. Callback interface
+ // returns are always serialized into a `RustBuffer` regardless of their
+ // normal FFI type.
+ public RustBuffer LowerIntoRustBuffer(CsType value) {
+ var rbuf = RustBuffer.Alloc(AllocationSize(value));
+ try {
+ var stream = rbuf.AsWriteableStream();
+ Write(value, stream);
+ rbuf.len = Convert.ToInt32(stream.Position);
+ return rbuf;
+ } catch {
+ RustBuffer.Free(rbuf);
+ throw;
+ }
+ }
+
+ // Lift a value from a `RustBuffer`.
+ //
+ // This here mostly because of the symmetry with `lowerIntoRustBuffer()`.
+ // It's currently only used by the `FfiConverterRustBuffer` class below.
+ protected CsType LiftFromRustBuffer(RustBuffer rbuf) {
+ var stream = rbuf.AsStream();
+ try {
+ var item = Read(stream);
+ if (stream.HasRemaining()) {
+ throw new InternalException("junk remaining in buffer after lifting, something is very wrong!!");
+ }
+ return item;
+ } finally {
+ RustBuffer.Free(rbuf);
+ }
+ }
+}
+
+// FfiConverter that uses `RustBuffer` as the FfiType
+internal abstract class FfiConverterRustBuffer: FfiConverter {
+ public override CsType Lift(RustBuffer value) {
+ return LiftFromRustBuffer(value);
+ }
+ public override RustBuffer Lower(CsType value) {
+ return LowerIntoRustBuffer(value);
+ }
+}
+
+
+// A handful of classes and functions to support the generated data structures.
+// This would be a good candidate for isolating in its own ffi-support lib.
+// Error runtime.
+[StructLayout(LayoutKind.Sequential)]
+struct RustCallStatus {
+ public sbyte code;
+ public RustBuffer error_buf;
+
+ public bool IsSuccess() {
+ return code == 0;
+ }
+
+ public bool IsError() {
+ return code == 1;
+ }
+
+ public bool IsPanic() {
+ return code == 2;
+ }
+}
+
+// Base class for all uniffi exceptions
+public class UniffiException: Exception {
+ public UniffiException(): base() {}
+ public UniffiException(string message): base(message) {}
+}
+
+public class UndeclaredErrorException: UniffiException {
+ public UndeclaredErrorException(string message): base(message) {}
+}
+
+public class PanicException: UniffiException {
+ public PanicException(string message): base(message) {}
+}
+
+public class AllocationException: UniffiException {
+ public AllocationException(string message): base(message) {}
+}
+
+public class InternalException: UniffiException {
+ public InternalException(string message): base(message) {}
+}
+
+public class InvalidEnumException: InternalException {
+ public InvalidEnumException(string message): base(message) {
+ }
+}
+
+public class UniffiContractVersionException: UniffiException {
+ public UniffiContractVersionException(string message): base(message) {
+ }
+}
+
+public class UniffiContractChecksumException: UniffiException {
+ public UniffiContractChecksumException(string message): base(message) {
+ }
+}
+
+// Each top-level error class has a companion object that can lift the error from the call status's rust buffer
+interface CallStatusErrorHandler where E: Exception {
+ E Lift(RustBuffer error_buf);
+}
+
+// CallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR
+class NullCallStatusErrorHandler: CallStatusErrorHandler {
+ public static NullCallStatusErrorHandler INSTANCE = new NullCallStatusErrorHandler();
+
+ public UniffiException Lift(RustBuffer error_buf) {
+ RustBuffer.Free(error_buf);
+ return new UndeclaredErrorException("library has returned an error not declared in UNIFFI interface file");
+ }
+}
+
+// Helpers for calling Rust
+// In practice we usually need to be synchronized to call this safely, so it doesn't
+// synchronize itself
+class _UniffiHelpers {
+ public delegate void RustCallAction(ref RustCallStatus status);
+ public delegate U RustCallFunc(ref RustCallStatus status);
+
+ // Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err
+ public static U RustCallWithError(CallStatusErrorHandler errorHandler, RustCallFunc callback)
+ where E: UniffiException
+ {
+ var status = new RustCallStatus();
+ var return_value = callback(ref status);
+ if (status.IsSuccess()) {
+ return return_value;
+ } else if (status.IsError()) {
+ throw errorHandler.Lift(status.error_buf);
+ } else if (status.IsPanic()) {
+ // when the rust code sees a panic, it tries to construct a rustbuffer
+ // with the message. but if that code panics, then it just sends back
+ // an empty buffer.
+ if (status.error_buf.len > 0) {
+ throw new PanicException(FfiConverterString.INSTANCE.Lift(status.error_buf));
+ } else {
+ throw new PanicException("Rust panic");
+ }
+ } else {
+ throw new InternalException($"Unknown rust call status: {status.code}");
+ }
+ }
+
+ // Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err
+ public static void RustCallWithError(CallStatusErrorHandler errorHandler, RustCallAction callback)
+ where E: UniffiException
+ {
+ _UniffiHelpers.RustCallWithError(errorHandler, (ref RustCallStatus status) => {
+ callback(ref status);
+ return 0;
+ });
+ }
+
+ // Call a rust function that returns a plain value
+ public static U RustCall(RustCallFunc callback) {
+ return _UniffiHelpers.RustCallWithError(NullCallStatusErrorHandler.INSTANCE, callback);
+ }
+
+ // Call a rust function that returns a plain value
+ public static void RustCall(RustCallAction callback) {
+ _UniffiHelpers.RustCall((ref RustCallStatus status) => {
+ callback(ref status);
+ return 0;
+ });
+ }
+}
+
+
+// Big endian streams are not yet available in dotnet :'(
+// https://github.com/dotnet/runtime/issues/26904
+
+class StreamUnderflowException: Exception {
+ public StreamUnderflowException() {
+ }
+}
+
+class BigEndianStream {
+ Stream stream;
+ public BigEndianStream(Stream stream) {
+ this.stream = stream;
+ }
+
+ public bool HasRemaining() {
+ return (stream.Length - stream.Position) > 0;
+ }
+
+ public long Position {
+ get => stream.Position;
+ set => stream.Position = value;
+ }
+
+ public void WriteBytes(byte[] value) {
+ stream.Write(value, 0, value.Length);
+ }
+
+ public void WriteByte(byte value) {
+ stream.WriteByte(value);
+ }
+
+ public void WriteUShort(ushort value) {
+ stream.WriteByte((byte)(value >> 8));
+ stream.WriteByte((byte)value);
+ }
+
+ public void WriteUInt(uint value) {
+ stream.WriteByte((byte)(value >> 24));
+ stream.WriteByte((byte)(value >> 16));
+ stream.WriteByte((byte)(value >> 8));
+ stream.WriteByte((byte)value);
+ }
+
+ public void WriteULong(ulong value) {
+ WriteUInt((uint)(value >> 32));
+ WriteUInt((uint)value);
+ }
+
+ public void WriteSByte(sbyte value) {
+ stream.WriteByte((byte)value);
+ }
+
+ public void WriteShort(short value) {
+ WriteUShort((ushort)value);
+ }
+
+ public void WriteInt(int value) {
+ WriteUInt((uint)value);
+ }
+
+ public void WriteFloat(float value) {
+ unsafe {
+ WriteInt(*((int*)&value));
+ }
+ }
+
+ public void WriteLong(long value) {
+ WriteULong((ulong)value);
+ }
+
+ public void WriteDouble(double value) {
+ WriteLong(BitConverter.DoubleToInt64Bits(value));
+ }
+
+ public byte[] ReadBytes(int length) {
+ CheckRemaining(length);
+ byte[] result = new byte[length];
+ stream.Read(result, 0, length);
+ return result;
+ }
+
+ public byte ReadByte() {
+ CheckRemaining(1);
+ return Convert.ToByte(stream.ReadByte());
+ }
+
+ public ushort ReadUShort() {
+ CheckRemaining(2);
+ return (ushort)(stream.ReadByte() << 8 | stream.ReadByte());
+ }
+
+ public uint ReadUInt() {
+ CheckRemaining(4);
+ return (uint)(stream.ReadByte() << 24
+ | stream.ReadByte() << 16
+ | stream.ReadByte() << 8
+ | stream.ReadByte());
+ }
+
+ public ulong ReadULong() {
+ return (ulong)ReadUInt() << 32 | (ulong)ReadUInt();
+ }
+
+ public sbyte ReadSByte() {
+ return (sbyte)ReadByte();
+ }
+
+ public short ReadShort() {
+ return (short)ReadUShort();
+ }
+
+ public int ReadInt() {
+ return (int)ReadUInt();
+ }
+
+ public float ReadFloat() {
+ unsafe {
+ int value = ReadInt();
+ return *((float*)&value);
+ }
+ }
+
+ public long ReadLong() {
+ return (long)ReadULong();
+ }
+
+ public double ReadDouble() {
+ return BitConverter.Int64BitsToDouble(ReadLong());
+ }
+
+ private void CheckRemaining(int length) {
+ if (stream.Length - stream.Position < length) {
+ throw new StreamUnderflowException();
+ }
+ }
+}
+
+// Contains loading, initialization code,
+// and the FFI Function declarations in a com.sun.jna.Library.
+
+
+// This is an implementation detail which will be called internally by the public API.
+static class _UniFFILib {
+ static _UniFFILib() {
+ _UniFFILib.uniffiCheckContractApiVersion();
+ _UniFFILib.uniffiCheckApiChecksums();
+
+ }
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void uniffi_servicepoint_binding_uniffi_fn_free_clear(
+ IntPtr ptr,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern ClearSafeHandle uniffi_servicepoint_binding_uniffi_fn_constructor_clear_new(ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void uniffi_servicepoint_binding_uniffi_fn_free_command(
+ IntPtr ptr,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void uniffi_servicepoint_binding_uniffi_fn_free_connection(
+ IntPtr ptr,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern ConnectionSafeHandle uniffi_servicepoint_binding_uniffi_fn_constructor_connection_new(RustBuffer @host,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern RustBuffer ffi_servicepoint_binding_uniffi_rustbuffer_alloc(int @size,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern RustBuffer ffi_servicepoint_binding_uniffi_rustbuffer_from_bytes(ForeignBytes @bytes,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rustbuffer_free(RustBuffer @buf,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern RustBuffer ffi_servicepoint_binding_uniffi_rustbuffer_reserve(RustBuffer @buf,int @additional,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_continuation_callback_set(IntPtr @callback
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_poll_u8(IntPtr @handle,IntPtr @uniffiCallback
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_cancel_u8(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_free_u8(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern byte ffi_servicepoint_binding_uniffi_rust_future_complete_u8(IntPtr @handle,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_poll_i8(IntPtr @handle,IntPtr @uniffiCallback
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_cancel_i8(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_free_i8(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern sbyte ffi_servicepoint_binding_uniffi_rust_future_complete_i8(IntPtr @handle,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_poll_u16(IntPtr @handle,IntPtr @uniffiCallback
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_cancel_u16(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_free_u16(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern ushort ffi_servicepoint_binding_uniffi_rust_future_complete_u16(IntPtr @handle,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_poll_i16(IntPtr @handle,IntPtr @uniffiCallback
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_cancel_i16(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_free_i16(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern short ffi_servicepoint_binding_uniffi_rust_future_complete_i16(IntPtr @handle,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_poll_u32(IntPtr @handle,IntPtr @uniffiCallback
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_cancel_u32(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_free_u32(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern uint ffi_servicepoint_binding_uniffi_rust_future_complete_u32(IntPtr @handle,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_poll_i32(IntPtr @handle,IntPtr @uniffiCallback
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_cancel_i32(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_free_i32(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern int ffi_servicepoint_binding_uniffi_rust_future_complete_i32(IntPtr @handle,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_poll_u64(IntPtr @handle,IntPtr @uniffiCallback
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_cancel_u64(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_free_u64(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern ulong ffi_servicepoint_binding_uniffi_rust_future_complete_u64(IntPtr @handle,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_poll_i64(IntPtr @handle,IntPtr @uniffiCallback
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_cancel_i64(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_free_i64(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern long ffi_servicepoint_binding_uniffi_rust_future_complete_i64(IntPtr @handle,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_poll_f32(IntPtr @handle,IntPtr @uniffiCallback
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_cancel_f32(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_free_f32(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern float ffi_servicepoint_binding_uniffi_rust_future_complete_f32(IntPtr @handle,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_poll_f64(IntPtr @handle,IntPtr @uniffiCallback
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_cancel_f64(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_free_f64(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern double ffi_servicepoint_binding_uniffi_rust_future_complete_f64(IntPtr @handle,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_poll_pointer(IntPtr @handle,IntPtr @uniffiCallback
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_cancel_pointer(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_free_pointer(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern SafeHandle ffi_servicepoint_binding_uniffi_rust_future_complete_pointer(IntPtr @handle,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_poll_rust_buffer(IntPtr @handle,IntPtr @uniffiCallback
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_cancel_rust_buffer(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_free_rust_buffer(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern RustBuffer ffi_servicepoint_binding_uniffi_rust_future_complete_rust_buffer(IntPtr @handle,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_poll_void(IntPtr @handle,IntPtr @uniffiCallback
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_cancel_void(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_free_void(IntPtr @handle
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern void ffi_servicepoint_binding_uniffi_rust_future_complete_void(IntPtr @handle,ref RustCallStatus _uniffi_out_err
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern ushort uniffi_servicepoint_binding_uniffi_checksum_constructor_clear_new(
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern ushort uniffi_servicepoint_binding_uniffi_checksum_constructor_connection_new(
+ );
+
+ [DllImport("servicepoint_binding_uniffi")]
+ public static extern uint ffi_servicepoint_binding_uniffi_uniffi_contract_version(
+ );
+
+
+
+ static void uniffiCheckContractApiVersion() {
+ var scaffolding_contract_version = _UniFFILib.ffi_servicepoint_binding_uniffi_uniffi_contract_version();
+ if (24 != scaffolding_contract_version) {
+ throw new UniffiContractVersionException($"ServicePoint: uniffi bindings expected version `24`, library returned `{scaffolding_contract_version}`");
+ }
+ }
+
+ static void uniffiCheckApiChecksums() {
+ {
+ var checksum = _UniFFILib.uniffi_servicepoint_binding_uniffi_checksum_constructor_clear_new();
+ if (checksum != 31583) {
+ throw new UniffiContractChecksumException($"ServicePoint: uniffi bindings expected function `uniffi_servicepoint_binding_uniffi_checksum_constructor_clear_new` checksum `31583`, library returned `{checksum}`");
+ }
+ }
+ {
+ var checksum = _UniFFILib.uniffi_servicepoint_binding_uniffi_checksum_constructor_connection_new();
+ if (checksum != 63821) {
+ throw new UniffiContractChecksumException($"ServicePoint: uniffi bindings expected function `uniffi_servicepoint_binding_uniffi_checksum_constructor_connection_new` checksum `63821`, library returned `{checksum}`");
+ }
+ }
+ }
+}
+
+// Public interface members begin here.
+
+#pragma warning disable 8625
+
+
+
+
+class FfiConverterString: FfiConverter {
+ public static FfiConverterString INSTANCE = new FfiConverterString();
+
+ // Note: we don't inherit from FfiConverterRustBuffer, because we use a
+ // special encoding when lowering/lifting. We can use `RustBuffer.len` to
+ // store our length and avoid writing it out to the buffer.
+ public override string Lift(RustBuffer value) {
+ try {
+ var bytes = value.AsStream().ReadBytes(value.len);
+ return System.Text.Encoding.UTF8.GetString(bytes);
+ } finally {
+ RustBuffer.Free(value);
+ }
+ }
+
+ public override string Read(BigEndianStream stream) {
+ var length = stream.ReadInt();
+ var bytes = stream.ReadBytes(length);
+ return System.Text.Encoding.UTF8.GetString(bytes);
+ }
+
+ public override RustBuffer Lower(string value) {
+ var bytes = System.Text.Encoding.UTF8.GetBytes(value);
+ var rbuf = RustBuffer.Alloc(bytes.Length);
+ rbuf.AsWriteableStream().WriteBytes(bytes);
+ return rbuf;
+ }
+
+ // TODO(CS)
+ // We aren't sure exactly how many bytes our string will be once it's UTF-8
+ // encoded. Allocate 3 bytes per unicode codepoint which will always be
+ // enough.
+ public override int AllocationSize(string value) {
+ const int sizeForLength = 4;
+ var sizeForString = value.Length * 3;
+ return sizeForLength + sizeForString;
+ }
+
+ public override void Write(string value, BigEndianStream stream) {
+ var bytes = System.Text.Encoding.UTF8.GetBytes(value);
+ stream.WriteInt(bytes.Length);
+ stream.WriteBytes(bytes);
+ }
+}
+
+
+
+
+// `SafeHandle` implements the semantics outlined below, i.e. its thread safe, and the dispose
+// method will only be called once, once all outstanding native calls have completed.
+// https://github.com/mozilla/uniffi-rs/blob/0dc031132d9493ca812c3af6e7dd60ad2ea95bf0/uniffi_bindgen/src/bindings/kotlin/templates/ObjectRuntime.kt#L31
+// https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.criticalhandle
+
+public abstract class FFIObject: IDisposable where THandle : FFISafeHandle {
+ private THandle handle;
+
+ public FFIObject(THandle handle) {
+ this.handle = handle;
+ }
+
+ public THandle GetHandle() {
+ return handle;
+ }
+
+ public void Dispose() {
+ handle.Dispose();
+ }
+}
+
+public abstract class FFISafeHandle: SafeHandle {
+ public FFISafeHandle(): base(new IntPtr(0), true) {
+ }
+
+ public FFISafeHandle(IntPtr pointer): this() {
+ this.SetHandle(pointer);
+ }
+
+ public override bool IsInvalid {
+ get {
+ return handle.ToInt64() == 0;
+ }
+ }
+
+ // TODO(CS) this completely breaks any guarantees offered by SafeHandle.. Extracting
+ // raw value from SafeHandle puts responsiblity on the consumer of this function to
+ // ensure that SafeHandle outlives the stream, and anyone who might have read the raw
+ // value from the stream and are holding onto it. Otherwise, the result might be a use
+ // after free, or free while method calls are still in flight.
+ //
+ // This is also relevant for Kotlin.
+ //
+ public IntPtr DangerousGetRawFfiValue() {
+ return handle;
+ }
+}
+
+static class FFIObjectUtil {
+ public static void DisposeAll(params Object?[] list) {
+ foreach (var obj in list) {
+ Dispose(obj);
+ }
+ }
+
+ // Dispose is implemented by recursive type inspection at runtime. This is because
+ // generating correct Dispose calls for recursive complex types, e.g. List>
+ // is quite cumbersome.
+ private static void Dispose(dynamic? obj) {
+ if (obj == null) {
+ return;
+ }
+
+ if (obj is IDisposable disposable) {
+ disposable.Dispose();
+ return;
+ }
+
+ var type = obj.GetType();
+ if (type != null) {
+ if (type.IsGenericType) {
+ if (type.GetGenericTypeDefinition().IsAssignableFrom(typeof(List<>))) {
+ foreach (var value in obj) {
+ Dispose(value);
+ }
+ } else if (type.GetGenericTypeDefinition().IsAssignableFrom(typeof(Dictionary<,>))) {
+ foreach (var value in obj.Values) {
+ Dispose(value);
+ }
+ }
+ }
+ }
+ }
+}
+public interface IClear {
+
+}
+
+public class ClearSafeHandle: FFISafeHandle {
+ public ClearSafeHandle(): base() {
+ }
+ public ClearSafeHandle(IntPtr pointer): base(pointer) {
+ }
+ override protected bool ReleaseHandle() {
+ _UniffiHelpers.RustCall((ref RustCallStatus status) => {
+ _UniFFILib.uniffi_servicepoint_binding_uniffi_fn_free_clear(this.handle, ref status);
+ });
+ return true;
+ }
+}
+public class Clear: FFIObject, IClear {
+ public Clear(ClearSafeHandle pointer): base(pointer) {}
+ public Clear() :
+ this(
+ _UniffiHelpers.RustCall( (ref RustCallStatus _status) =>
+ _UniFFILib.uniffi_servicepoint_binding_uniffi_fn_constructor_clear_new( ref _status)
+)) {}
+
+
+
+
+}
+
+class FfiConverterTypeClear: FfiConverter {
+ public static FfiConverterTypeClear INSTANCE = new FfiConverterTypeClear();
+
+ public override ClearSafeHandle Lower(Clear value) {
+ return value.GetHandle();
+ }
+
+ public override Clear Lift(ClearSafeHandle value) {
+ return new Clear(value);
+ }
+
+ public override Clear Read(BigEndianStream stream) {
+ return Lift(new ClearSafeHandle(new IntPtr(stream.ReadLong())));
+ }
+
+ public override int AllocationSize(Clear value) {
+ return 8;
+ }
+
+ public override void Write(Clear value, BigEndianStream stream) {
+ stream.WriteLong(Lower(value).DangerousGetRawFfiValue().ToInt64());
+ }
+}
+
+
+
+public interface ICommand {
+
+}
+
+public class CommandSafeHandle: FFISafeHandle {
+ public CommandSafeHandle(): base() {
+ }
+ public CommandSafeHandle(IntPtr pointer): base(pointer) {
+ }
+ override protected bool ReleaseHandle() {
+ _UniffiHelpers.RustCall((ref RustCallStatus status) => {
+ _UniFFILib.uniffi_servicepoint_binding_uniffi_fn_free_command(this.handle, ref status);
+ });
+ return true;
+ }
+}
+public class Command: FFIObject, ICommand {
+ public Command(CommandSafeHandle pointer): base(pointer) {}
+
+
+
+
+}
+
+class FfiConverterTypeCommand: FfiConverter {
+ public static FfiConverterTypeCommand INSTANCE = new FfiConverterTypeCommand();
+
+ public override CommandSafeHandle Lower(Command value) {
+ return value.GetHandle();
+ }
+
+ public override Command Lift(CommandSafeHandle value) {
+ return new Command(value);
+ }
+
+ public override Command Read(BigEndianStream stream) {
+ return Lift(new CommandSafeHandle(new IntPtr(stream.ReadLong())));
+ }
+
+ public override int AllocationSize(Command value) {
+ return 8;
+ }
+
+ public override void Write(Command value, BigEndianStream stream) {
+ stream.WriteLong(Lower(value).DangerousGetRawFfiValue().ToInt64());
+ }
+}
+
+
+
+public interface IConnection {
+
+}
+
+public class ConnectionSafeHandle: FFISafeHandle {
+ public ConnectionSafeHandle(): base() {
+ }
+ public ConnectionSafeHandle(IntPtr pointer): base(pointer) {
+ }
+ override protected bool ReleaseHandle() {
+ _UniffiHelpers.RustCall((ref RustCallStatus status) => {
+ _UniFFILib.uniffi_servicepoint_binding_uniffi_fn_free_connection(this.handle, ref status);
+ });
+ return true;
+ }
+}
+public class Connection: FFIObject, IConnection {
+ public Connection(ConnectionSafeHandle pointer): base(pointer) {}
+ public Connection(String @host) :
+ this(
+ _UniffiHelpers.RustCallWithError(FfiConverterTypeConnectionException.INSTANCE, (ref RustCallStatus _status) =>
+ _UniFFILib.uniffi_servicepoint_binding_uniffi_fn_constructor_connection_new(FfiConverterString.INSTANCE.Lower(@host), ref _status)
+)) {}
+
+
+
+
+}
+
+class FfiConverterTypeConnection: FfiConverter {
+ public static FfiConverterTypeConnection INSTANCE = new FfiConverterTypeConnection();
+
+ public override ConnectionSafeHandle Lower(Connection value) {
+ return value.GetHandle();
+ }
+
+ public override Connection Lift(ConnectionSafeHandle value) {
+ return new Connection(value);
+ }
+
+ public override Connection Read(BigEndianStream stream) {
+ return Lift(new ConnectionSafeHandle(new IntPtr(stream.ReadLong())));
+ }
+
+ public override int AllocationSize(Connection value) {
+ return 8;
+ }
+
+ public override void Write(Connection value, BigEndianStream stream) {
+ stream.WriteLong(Lower(value).DangerousGetRawFfiValue().ToInt64());
+ }
+}
+
+
+
+
+
+public class ConnectionException: UniffiException {
+ // Each variant is a nested class
+
+
+ public class IoException : ConnectionException {
+ // Members
+ public String @error;
+
+ // Constructor
+ public IoException(
+ String @error) {
+ this.@error = @error;
+ }
+ }
+
+
+
+}
+
+class FfiConverterTypeConnectionException : FfiConverterRustBuffer, CallStatusErrorHandler {
+ public static FfiConverterTypeConnectionException INSTANCE = new FfiConverterTypeConnectionException();
+
+ public override ConnectionException Read(BigEndianStream stream) {
+ var value = stream.ReadInt();
+ switch (value) {
+ case 1:
+ return new ConnectionException.IoException(
+ FfiConverterString.INSTANCE.Read(stream));
+ default:
+ throw new InternalException(String.Format("invalid error value '{0}' in FfiConverterTypeConnectionException.Read()", value));
+ }
+ }
+
+ public override int AllocationSize(ConnectionException value) {
+ switch (value) {
+ case ConnectionException.IoException variant_value:
+ return 4
+ + FfiConverterString.INSTANCE.AllocationSize(variant_value.@error);
+ default:
+ throw new InternalException(String.Format("invalid error value '{0}' in FfiConverterTypeConnectionException.AllocationSize()", value));
+ }
+ }
+
+ public override void Write(ConnectionException value, BigEndianStream stream) {
+ switch (value) {
+ case ConnectionException.IoException variant_value:
+ stream.WriteInt(1);
+ FfiConverterString.INSTANCE.Write(variant_value.@error, stream);
+ break;
+ default:
+ throw new InternalException(String.Format("invalid error value '{0}' in FfiConverterTypeConnectionException.Write()", value));
+ }
+ }
+}
+#pragma warning restore 8625
+public static class ServicepointBindingUniffiMethods {
+}
+
diff --git a/crates/servicepoint_binding_uniffi/libraries/csharp/csharp.sln b/crates/servicepoint_binding_uniffi/libraries/csharp/csharp.sln
new file mode 100644
index 0000000..2fbf818
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/libraries/csharp/csharp.sln
@@ -0,0 +1,34 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint", "ServicePoint\ServicePoint.csproj", "{53576D3C-E32E-49BF-BF10-2DB504E50CE1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint.Example", "ServicePoint.Example\ServicePoint.Example.csproj", "{FEF24227-090E-46C2-B8F6-ACB5AA1A4309}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint.Tests", "ServicePoint.Tests\ServicePoint.Tests.csproj", "{9DC15508-A980-4135-9FC6-659FF54B4E5C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {53576D3C-E32E-49BF-BF10-2DB504E50CE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {53576D3C-E32E-49BF-BF10-2DB504E50CE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {53576D3C-E32E-49BF-BF10-2DB504E50CE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {53576D3C-E32E-49BF-BF10-2DB504E50CE1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FEF24227-090E-46C2-B8F6-ACB5AA1A4309}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FEF24227-090E-46C2-B8F6-ACB5AA1A4309}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FEF24227-090E-46C2-B8F6-ACB5AA1A4309}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FEF24227-090E-46C2-B8F6-ACB5AA1A4309}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9DC15508-A980-4135-9FC6-659FF54B4E5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9DC15508-A980-4135-9FC6-659FF54B4E5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9DC15508-A980-4135-9FC6-659FF54B4E5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9DC15508-A980-4135-9FC6-659FF54B4E5C}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/crates/servicepoint_binding_uniffi/src/bin/uniffi-bindgen-cs.rs b/crates/servicepoint_binding_uniffi/src/bin/uniffi-bindgen-cs.rs
new file mode 100644
index 0000000..ef11e75
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/src/bin/uniffi-bindgen-cs.rs
@@ -0,0 +1,3 @@
+fn main() {
+ uniffi_bindgen_cs::main().unwrap();
+}
diff --git a/crates/servicepoint_binding_uniffi/src/bin/uniffi-bindgen.rs b/crates/servicepoint_binding_uniffi/src/bin/uniffi-bindgen.rs
new file mode 100644
index 0000000..f6cff6c
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/src/bin/uniffi-bindgen.rs
@@ -0,0 +1,3 @@
+fn main() {
+ uniffi::uniffi_bindgen_main()
+}
diff --git a/crates/servicepoint_binding_uniffi/src/command.rs b/crates/servicepoint_binding_uniffi/src/command.rs
new file mode 100644
index 0000000..7d7906c
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/src/command.rs
@@ -0,0 +1,20 @@
+use std::sync::Arc;
+
+#[uniffi::export]
+trait Command: Send + Sync {}
+
+#[derive(uniffi::Object)]
+pub struct Clear {
+ actual: servicepoint::Command,
+}
+#[uniffi::export]
+impl Command for Clear {}
+
+#[uniffi::export]
+impl Clear {
+ #[uniffi::constructor]
+ pub fn new() -> Arc {
+ let actual = servicepoint::Command::Clear;
+ Arc::new(Clear { actual })
+ }
+}
diff --git a/crates/servicepoint_binding_uniffi/src/connection.rs b/crates/servicepoint_binding_uniffi/src/connection.rs
new file mode 100644
index 0000000..340e2fe
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/src/connection.rs
@@ -0,0 +1,23 @@
+use std::{sync::Arc};
+
+#[derive(uniffi::Object)]
+pub struct Connection {
+ actual: servicepoint::Connection,
+}
+
+#[derive(uniffi::Error, thiserror::Error, Debug)]
+pub enum ConnectionError {
+ #[error("An IO error occured: {error}")]
+ IOError {
+ error: String}
+}
+
+#[uniffi::export]
+impl Connection {
+ #[uniffi::constructor]
+ pub fn new(host: String) -> Result, ConnectionError> {
+ servicepoint::Connection::open(host)
+ .map(|actual|Arc::new(Connection { actual}) )
+ .map_err(|err| ConnectionError::IOError { error: err.to_string()})
+ }
+}
diff --git a/crates/servicepoint_binding_uniffi/src/lib.rs b/crates/servicepoint_binding_uniffi/src/lib.rs
new file mode 100644
index 0000000..b87a67a
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/src/lib.rs
@@ -0,0 +1,4 @@
+uniffi::setup_scaffolding!();
+
+mod command;
+mod connection;
diff --git a/crates/servicepoint_binding_uniffi/uniffi.toml b/crates/servicepoint_binding_uniffi/uniffi.toml
new file mode 100644
index 0000000..249e237
--- /dev/null
+++ b/crates/servicepoint_binding_uniffi/uniffi.toml
@@ -0,0 +1,3 @@
+[bindings.csharp]
+namespace = "ServicePoint"
+access_modifier = "public"