diff --git a/CHANGELOG.md b/CHANGELOG.md
index 29813e9fcb..2fe161088d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,7 @@
### Internal
- Added C# bindings for C Event Tracing API. [#1440](https://github.com/spatialos/gdk-for-unity/pull/1440)
+- Added native classes for IO operations in Event Tracing API. [#1444](https://github.com/spatialos/gdk-for-unity/pull/1444)
## `0.3.9` - 2020-07-24
diff --git a/workers/unity/Packages/io.improbable.worker.sdk/CEventTrace.cs b/workers/unity/Packages/io.improbable.worker.sdk/CEventTrace.cs
index 337d7e32f3..b35e12f852 100644
--- a/workers/unity/Packages/io.improbable.worker.sdk/CEventTrace.cs
+++ b/workers/unity/Packages/io.improbable.worker.sdk/CEventTrace.cs
@@ -278,7 +278,7 @@ public struct EventTracerParameters
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Trace_Item_Create")]
- public static extern Item* ItemCreate(CIO.Storage storage, Item* item);
+ public static extern Item* ItemCreate(CIO.StorageHandle storage, Item* item);
/**
* Returns a pointer to a thread-local trace item.
@@ -320,7 +320,7 @@ public struct EventTracerParameters
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Trace_SerializeItemToStream")]
- public static extern Int8 SerializeItemToStream(CIO.Stream stream, Item* item, Uint32 size);
+ public static extern Int8 SerializeItemToStream(CIO.StreamHandle stream, Item* item, Uint32 size);
/**
* Get the serialized size, in bytes, of the next serialized trace item to be read from the stream.
@@ -332,7 +332,7 @@ public struct EventTracerParameters
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Trace_GetNextSerializedItemSize")]
- public static extern Uint32 GetNextSerializedItemSize(CIO.Stream stream);
+ public static extern Uint32 GetNextSerializedItemSize(CIO.StreamHandle stream);
/**
* Deserialize the next trace item from the stream.
@@ -356,7 +356,7 @@ public struct EventTracerParameters
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Trace_DeserializeItemFromStream")]
- public static extern Int8 DeserializeItemFromStream(CIO.Stream stream, Item* item, Uint32 size);
+ public static extern Int8 DeserializeItemFromStream(CIO.StreamHandle stream, Item* item, Uint32 size);
/**
* Returns the last error which occurred during a trace API method call. Returns nullptr if no
diff --git a/workers/unity/Packages/io.improbable.worker.sdk/CIO.cs b/workers/unity/Packages/io.improbable.worker.sdk/CIO.cs
index dfabb649d9..2bc19c2605 100644
--- a/workers/unity/Packages/io.improbable.worker.sdk/CIO.cs
+++ b/workers/unity/Packages/io.improbable.worker.sdk/CIO.cs
@@ -10,7 +10,7 @@ namespace Improbable.Worker.CInterop.Internal
{
internal unsafe class CIO
{
- public class Storage : CptrHandle
+ public class StorageHandle : CptrHandle
{
protected override bool ReleaseHandle()
{
@@ -19,7 +19,7 @@ protected override bool ReleaseHandle()
}
}
- public class Stream : CptrHandle
+ public class StreamHandle : CptrHandle
{
protected override bool ReleaseHandle()
{
@@ -45,7 +45,7 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Storage_Create")]
- public static extern Storage StorageCreate();
+ public static extern StorageHandle StorageCreate();
/* Destroys the trace storage. */
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
@@ -61,7 +61,7 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Storage_Clear")]
- public static extern void StorageClear(IntPtr storage);
+ public static extern void StorageClear(StorageHandle storage);
/**
* Creates an I/O stream implemented as a ring buffer.
@@ -77,7 +77,7 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_CreateRingBufferStream")]
- public static extern Stream CreateRingBufferStream(Uint32 capacityBytes);
+ public static extern StreamHandle CreateRingBufferStream(Uint32 capacityBytes);
/**
* Creates an I/O stream implemented as a read/write file.
@@ -94,7 +94,7 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_CreateFileStream")]
- public static extern Stream CreateFileStream(Char* filename, OpenMode openMode);
+ public static extern StreamHandle CreateFileStream(Char* filename, OpenMode openMode);
/* Destroys the I/O stream. */
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
@@ -111,7 +111,7 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Stream_Write")]
- public static extern Int64 StreamWrite(Stream stream, Uint8* bytes, Uint32 length);
+ public static extern Int64 StreamWrite(StreamHandle stream, Uint8* bytes, Uint32 length);
/**
* Gets the remaining write capacity in bytes.
@@ -121,7 +121,7 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Stream_GetRemainingWriteCapacityBytes")]
- public static extern Uint32 StreamGetRemainingWriteCapacityBytes(Stream stream);
+ public static extern Uint32 StreamGetRemainingWriteCapacityBytes(StreamHandle stream);
/**
* Reads as much of the stream's data as possible into the given buffer.
@@ -133,7 +133,7 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Stream_Read")]
- public static extern Uint64 StreamRead(Stream stream, Uint8* bytes, Uint32 length);
+ public static extern Int64 StreamRead(StreamHandle stream, Uint8* bytes, Uint32 length);
/**
* Reads as much of the stream's data as possible into the given buffer without advancing the read
@@ -142,11 +142,11 @@ public enum OpenMode
* Returns the actual number of bytes read. This may be less than the given length iff the stream
* has less data than the requested amount.
*
- * Returns -1 on error. Call StreamGetLastError() to get the associated error message.
+ * Returns -1 on error. Call StreamGetLastError to get the associated error message.
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Stream_Peek")]
- public static extern Int64 StreamPeek(Stream stream, Uint8* bytes, Uint32 length);
+ public static extern Int64 StreamPeek(StreamHandle stream, Uint8* bytes, Uint32 length);
/**
* Extracts the given number of bytes from the stream and discards them.
@@ -155,11 +155,11 @@ public enum OpenMode
* has advanced. This may be less than the given length iff the stream has less data than the
* requested amount.
*
- * Returns -1 on error. Call StreamGetLastError() to get the associated error message.
+ * Returns -1 on error. Call StreamGetLastError to get the associated error message.
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Stream_Ignore")]
- public static extern Int64 StreamIgnore(Stream stream, Uint32 length);
+ public static extern Int64 StreamIgnore(StreamHandle stream, Uint32 length);
/**
* Returns the last error which occurred during an API call on this stream. Returns nullptr if no
@@ -167,6 +167,6 @@ public enum OpenMode
*/
[DllImport(Constants.WorkerLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "Io_Stream_GetLastError")]
- public static extern Char* StreamGetLastError(Stream stream);
+ public static extern Char* StreamGetLastError(StreamHandle stream);
}
}
diff --git a/workers/unity/Packages/io.improbable.worker.sdk/IOStorage.cs b/workers/unity/Packages/io.improbable.worker.sdk/IOStorage.cs
new file mode 100644
index 0000000000..e2f58019f0
--- /dev/null
+++ b/workers/unity/Packages/io.improbable.worker.sdk/IOStorage.cs
@@ -0,0 +1,26 @@
+using System;
+using Improbable.Worker.CInterop.Internal;
+
+namespace Improbable.Worker.CInterop
+{
+ public sealed class IOStorage : IDisposable
+ {
+ private readonly CIO.StorageHandle storage;
+
+ public IOStorage()
+ {
+ storage = CIO.StorageCreate();
+ }
+
+ ///
+ public void Dispose()
+ {
+ storage.Dispose();
+ }
+
+ public void Clear()
+ {
+ CIO.StorageClear(storage);
+ }
+ }
+}
diff --git a/workers/unity/Packages/io.improbable.worker.sdk/IOStorage.cs.meta b/workers/unity/Packages/io.improbable.worker.sdk/IOStorage.cs.meta
new file mode 100644
index 0000000000..e9e14df0a1
--- /dev/null
+++ b/workers/unity/Packages/io.improbable.worker.sdk/IOStorage.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: e50ee44109544e7d8d9d06fe8c1243f2
+timeCreated: 1595864556
\ No newline at end of file
diff --git a/workers/unity/Packages/io.improbable.worker.sdk/IOStream.cs b/workers/unity/Packages/io.improbable.worker.sdk/IOStream.cs
new file mode 100644
index 0000000000..5a48eada96
--- /dev/null
+++ b/workers/unity/Packages/io.improbable.worker.sdk/IOStream.cs
@@ -0,0 +1,156 @@
+using System;
+using System.IO;
+using Improbable.Worker.CInterop.Internal;
+
+namespace Improbable.Worker.CInterop
+{
+ public enum OpenMode
+ {
+ /* Opens the stream in the default mode. */
+ OpenModeDefault = 0x00,
+ }
+
+ public sealed unsafe class IOStream : IDisposable
+ {
+ private readonly CIO.StreamHandle stream;
+
+ private IOStream(CIO.StreamHandle stream)
+ {
+ this.stream = stream;
+ }
+
+ ///
+ public void Dispose()
+ {
+ stream.Dispose();
+ }
+
+ public static IOStream CreateRingBufferStream(uint capacity)
+ {
+ return new IOStream(CIO.CreateRingBufferStream(capacity));
+ }
+
+ public static IOStream CreateFileStream(string fileName, OpenMode openMode)
+ {
+ fixed (byte* fileNameBytes = ApiInterop.ToUtf8Cstr(fileName))
+ {
+ return new IOStream(CIO.CreateFileStream(fileNameBytes, (CIO.OpenMode) openMode));
+ }
+ }
+
+ public long Write(byte[] data)
+ {
+ ThrowIfStreamClosed();
+
+ var remainingCapacity = CIO.StreamGetRemainingWriteCapacityBytes(stream);
+ if (remainingCapacity < data.Length)
+ {
+ throw new NotSupportedException("Not enough stream capacity to write data.");
+ }
+
+ var bytesWritten = 0L;
+ fixed (byte* dataToWrite = data)
+ {
+ bytesWritten = CIO.StreamWrite(stream, dataToWrite, 1);
+ }
+
+ if (bytesWritten != -1)
+ {
+ return bytesWritten;
+ }
+
+ var rawError = CIO.StreamGetLastError(stream);
+ throw new IOException(ApiInterop.FromUtf8Cstr(rawError));
+ }
+
+ public long Read(uint bytesToRead, out byte[] streamData)
+ {
+ ThrowIfStreamClosed();
+
+ streamData = new byte[bytesToRead];
+
+ var bytesRead = 0L;
+ fixed (byte* streamDataPointer = streamData)
+ {
+ bytesRead = CIO.StreamRead(stream, streamDataPointer, bytesToRead);
+ }
+
+ if (bytesRead != -1)
+ {
+ return bytesRead;
+ }
+
+ var rawError = CIO.StreamGetLastError(stream);
+ throw new IOException(ApiInterop.FromUtf8Cstr(rawError));
+ }
+
+ public long Read(byte[] streamData)
+ {
+ ThrowIfStreamClosed();
+
+ var bytesToRead = (uint) streamData.Length;
+ var bytesRead = 0L;
+ fixed (byte* streamDataPointer = streamData)
+ {
+ bytesRead = CIO.StreamRead(stream, streamDataPointer, bytesToRead);
+ }
+
+ if (bytesRead != -1)
+ {
+ return bytesRead;
+ }
+
+ var rawError = CIO.StreamGetLastError(stream);
+ throw new IOException(ApiInterop.FromUtf8Cstr(rawError));
+ }
+
+ public long Peek(uint bytesToPeek, out byte[] streamData)
+ {
+ ThrowIfStreamClosed();
+
+ streamData = new byte[bytesToPeek];
+
+ var bytesPeeked = 0L;
+ fixed (byte* streamDataPointer = streamData)
+ {
+ bytesPeeked = CIO.StreamPeek(stream, streamDataPointer, bytesToPeek);
+ }
+
+ if (bytesPeeked != -1)
+ {
+ return bytesPeeked;
+ }
+
+ var rawError = CIO.StreamGetLastError(stream);
+ throw new IOException(ApiInterop.FromUtf8Cstr(rawError));
+ }
+
+ public long Ignore(uint bytesToIgnore)
+ {
+ ThrowIfStreamClosed();
+
+ var bytesIgnored = CIO.StreamIgnore(stream, bytesToIgnore);
+
+ if (bytesIgnored != -1)
+ {
+ return bytesIgnored;
+ }
+
+ var rawError = CIO.StreamGetLastError(stream);
+ throw new IOException(ApiInterop.FromUtf8Cstr(rawError));
+ }
+
+ public uint GetRemainingCapacity()
+ {
+ return CIO.StreamGetRemainingWriteCapacityBytes(stream);
+ }
+
+ private void ThrowIfStreamClosed()
+ {
+ if (stream.IsClosed)
+ {
+ throw new ObjectDisposedException("Cannot access a disposed object.");
+ }
+ }
+ }
+}
diff --git a/workers/unity/Packages/io.improbable.worker.sdk/IOStream.cs.meta b/workers/unity/Packages/io.improbable.worker.sdk/IOStream.cs.meta
new file mode 100644
index 0000000000..61e529facb
--- /dev/null
+++ b/workers/unity/Packages/io.improbable.worker.sdk/IOStream.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: b0e0fbfec8ff4c5e99a8b505c9ccb705
+timeCreated: 1595944475
\ No newline at end of file