Skip to content

Commit

Permalink
Marshaller for output NetworkTableValue
Browse files Browse the repository at this point in the history
  • Loading branch information
ThadHouse committed Jan 28, 2024
1 parent b00d7ad commit 5d53917
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 51 deletions.
4 changes: 2 additions & 2 deletions src/ntcore/Natives/NetworkTableValueMarshaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ public static class ReturnFrom
{
public static NetworkTableValue ConvertToManaged(in NativeNetworkTableValue unmanaged)
{
throw new NotImplementedException();
return new(unmanaged);
}

public static void Free(NativeNetworkTableValue unmanaged)
{
NetworkTableValue.Free(&unmanaged);
NtCore.DisposeValue(&unmanaged);
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/ntcore/Natives/RefNetworkTableValueMarshaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ public void FromManaged(in RefNetworkTableValue managed, Span<byte> callerAlloca
if (byteCount > stringSpan.Length)
{
stringSpan = new byte[byteCount];
} else {
}
else
{
stringSpan = stringSpan[..byteCount];
}
int exactBytes = Encoding.UTF8.GetBytes(managed.m_stringValue!, stringSpan);
Expand Down
7 changes: 1 addition & 6 deletions src/ntcore/NetworkTableEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace NetworkTables;

[NativeMarshalling(typeof(NetworkTableEventMarshaller))]
public readonly struct NetworkTableEvent : INativeArrayFree<NetworkTableEventMarshaller.NativeNetworkTableEvent>, INativeFree<NetworkTableEventMarshaller.NativeNetworkTableEvent>
public readonly struct NetworkTableEvent : INativeArrayFree<NetworkTableEventMarshaller.NativeNetworkTableEvent>
{
public bool Is(EventFlags kind) => (Flags & kind) != 0;
public required NtListener ListenerHandle { get; init; }
Expand All @@ -19,11 +19,6 @@ namespace NetworkTables;
public LogMessage? LogMessage { get; init; }
public TimeSyncEventData? TimeSyncData { get; init; }

public static unsafe void Free(NetworkTableEventMarshaller.NativeNetworkTableEvent* ptr)
{
NtCore.DisposeEvent(ptr);
}

public static unsafe void FreeArray(NetworkTableEventMarshaller.NativeNetworkTableEvent* ptr, int len)
{
NtCore.DisposeEventArray(ptr, (nuint)len);
Expand Down
71 changes: 65 additions & 6 deletions src/ntcore/NetworkTableValue.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using System.Text;
using NetworkTables.Natives;
using WPIUtil.Marshal;

namespace NetworkTables;

[NativeMarshalling(typeof(NetworkTableValueMarshaller))]
[StructLayout(LayoutKind.Auto)]
public readonly partial struct NetworkTableValue : INativeArrayFree<NetworkTableValueMarshaller.NativeNetworkTableValue>, INativeFree<NetworkTableValueMarshaller.NativeNetworkTableValue>
public readonly partial struct NetworkTableValue : INativeArrayFree<NetworkTableValueMarshaller.NativeNetworkTableValue>
{
public static unsafe void Free(NetworkTableValueMarshaller.NativeNetworkTableValue* ptr)
{
NtCore.DisposeValue(ptr);
}

public static unsafe void FreeArray(NetworkTableValueMarshaller.NativeNetworkTableValue* ptr, int len)
{
NtCore.DisposeValueArray(ptr, (nuint)len);
Expand Down Expand Up @@ -205,4 +202,66 @@ public static implicit operator RefNetworkTableValue(in NetworkTableValue value)
_ => RefNetworkTableValue.MakeUnassigned(value.Time),
};
}

internal unsafe NetworkTableValue(in NetworkTableValueMarshaller.NativeNetworkTableValue value)
{
Time = value.lastChange;
ServerTime = value.serverTime;
Type = value.type;

switch (Type)
{
case NetworkTableType.Boolean:
m_structValue = new(value.data.valueBoolean != 0);
break;
case NetworkTableType.Integer:
m_structValue = new(value.data.valueInt);
break;
case NetworkTableType.Float:
m_structValue = new(value.data.valueFloat);
break;
case NetworkTableType.Double:
m_structValue = new(value.data.valueDouble);
break;
case NetworkTableType.String:
m_objectValue = value.data.valueString.ConvertToString();
break;
case NetworkTableType.Raw:
byte[] bytes = new byte[checked((int)value.data.valueRaw.size)];
new ReadOnlySpan<byte>(value.data.valueRaw.data, bytes.Length).CopyTo(bytes);
m_objectValue = bytes;
break;
case NetworkTableType.BooleanArray:
bool[] boolArr = new bool[checked((int)value.data.arrBoolean.size)];
for (int i = 0; i < boolArr.Length; i++)
{
boolArr[i] = value.data.valueRaw.data[i] != 0;
}
m_objectValue = boolArr;
break;
case NetworkTableType.IntegerArray:
long[] longArr = new long[checked((int)value.data.arrInt.size)];
new ReadOnlySpan<long>(value.data.arrInt.arr, longArr.Length).CopyTo(longArr);
m_objectValue = longArr;
break;
case NetworkTableType.FloatArray:
float[] floatArr = new float[checked((int)value.data.arrFloat.size)];
new ReadOnlySpan<float>(value.data.arrFloat.arr, floatArr.Length).CopyTo(floatArr);
m_objectValue = floatArr;
break;
case NetworkTableType.DoubleArray:
double[] doubleArr = new double[checked((int)value.data.arrDouble.size)];
new ReadOnlySpan<double>(value.data.arrDouble.arr, doubleArr.Length).CopyTo(doubleArr);
m_objectValue = doubleArr;
break;
case NetworkTableType.StringArray:
string[] stringArr = new string[checked((int)value.data.arrString.size)];
for (int i = 0; i < stringArr.Length; i++)
{
stringArr[i] = value.data.arrString.arr[i].ConvertToString();
}
m_objectValue = stringArr;
break;
}
}
}
24 changes: 12 additions & 12 deletions src/ntcore/TopicInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace NetworkTables.Natives;

[NativeMarshalling(typeof(TopicInfoMarshaller))]
[StructLayout(LayoutKind.Auto)]
public record struct TopicInfo(NtTopic TopicHandle, string Name, NetworkTableType Type, string TypeStr, string Properties) : INativeArrayFree<TopicInfoMarshaller.NativeTopicInfo>, INativeFree<TopicInfoMarshaller.NativeTopicInfo>
public record struct TopicInfo(NtTopic TopicHandle, string Name, NetworkTableType Type, string TypeStr, string Properties) : INativeArrayFree<TopicInfoMarshaller.NativeTopicInfo>
{
public readonly Topic GetTopic(NetworkTableInstance inst)
{
Expand All @@ -34,28 +34,28 @@ public static class ReturnFrom
{
public static TopicInfo ConvertToManaged(in NativeTopicInfo unmanaged)
{
return ReturnInArray.ConvertToManaged(unmanaged);
return new TopicInfo
{
TopicHandle = new NtTopic(unmanaged.topic),
Name = unmanaged.name.ConvertToString(),
Type = unmanaged.type,
TypeStr = unmanaged.typeStr.ConvertToString(),
Properties = unmanaged.properties.ConvertToString(),

};
}

public static void Free(NativeTopicInfo unmanaged)
{
TopicInfo.Free(&unmanaged);
NtCore.DisposeTopicInfo(&unmanaged);
}
}

public static class ReturnInArray
{
public static TopicInfo ConvertToManaged(in NativeTopicInfo unmanaged)
{
return new TopicInfo
{
TopicHandle = new NtTopic(unmanaged.topic),
Name = unmanaged.name.ConvertToString(),
Type = unmanaged.type,
TypeStr = unmanaged.typeStr.ConvertToString(),
Properties = unmanaged.properties.ConvertToString(),

};
return ReturnFrom.ConvertToManaged(unmanaged);
}

public static NativeTopicInfo ConvertToUnmanaged(in TopicInfo managed)
Expand Down
6 changes: 0 additions & 6 deletions src/wpiutil/Marshal/INativeFree.cs

This file was deleted.

50 changes: 32 additions & 18 deletions test/ntcore.test/RefNetworkTableValueMarshallerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ namespace NetworkTables.Test;

public class RefNetworkTableValueMarshallerTest
{

private unsafe delegate void DataInDelegate(NetworkTableValueMarshaller.NativeNetworkTableValue* value, void* pinned);

private static unsafe void HandleInMarshal(in RefNetworkTableValue value, DataInDelegate callback)
Expand Down Expand Up @@ -35,17 +34,18 @@ private static unsafe void HandleInMarshal(in RefNetworkTableValue value, DataIn

}


[Fact]
public unsafe void TestBool()
{
HandleInMarshal(RefNetworkTableValue.MakeBoolean(false), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeBoolean(false), (v, pinned) =>
{
Assert.Equal(NetworkTableType.Boolean, v->type);
Assert.Equal(0, v->data.valueBoolean);
Assert.True(pinned == null);
});

HandleInMarshal(RefNetworkTableValue.MakeBoolean(true), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeBoolean(true), (v, pinned) =>
{
Assert.Equal(NetworkTableType.Boolean, v->type);
Assert.Equal(1, v->data.valueBoolean);
Assert.True(pinned == null);
Expand All @@ -55,13 +55,15 @@ public unsafe void TestBool()
[Fact]
public unsafe void TestInt()
{
HandleInMarshal(RefNetworkTableValue.MakeInteger(42), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeInteger(42), (v, pinned) =>
{
Assert.Equal(NetworkTableType.Integer, v->type);
Assert.Equal(42, v->data.valueInt);
Assert.True(pinned == null);
});

HandleInMarshal(RefNetworkTableValue.MakeInteger(0), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeInteger(0), (v, pinned) =>
{
Assert.Equal(NetworkTableType.Integer, v->type);
Assert.Equal(0, v->data.valueInt);
Assert.True(pinned == null);
Expand All @@ -71,13 +73,15 @@ public unsafe void TestInt()
[Fact]
public unsafe void TestDouble()
{
HandleInMarshal(RefNetworkTableValue.MakeDouble(42.0), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeDouble(42.0), (v, pinned) =>
{
Assert.Equal(NetworkTableType.Double, v->type);
Assert.Equal(42.0, v->data.valueDouble);
Assert.True(pinned == null);
});

HandleInMarshal(RefNetworkTableValue.MakeDouble(56.5), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeDouble(56.5), (v, pinned) =>
{
Assert.Equal(NetworkTableType.Double, v->type);
Assert.Equal(56.5, v->data.valueDouble);
Assert.True(pinned == null);
Expand All @@ -87,13 +91,15 @@ public unsafe void TestDouble()
[Fact]
public unsafe void TestFloat()
{
HandleInMarshal(RefNetworkTableValue.MakeFloat(42.0f), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeFloat(42.0f), (v, pinned) =>
{
Assert.Equal(NetworkTableType.Float, v->type);
Assert.Equal(42.0f, v->data.valueFloat, 1e-9);
Assert.True(pinned == null);
});

HandleInMarshal(RefNetworkTableValue.MakeFloat(56.5f), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeFloat(56.5f), (v, pinned) =>
{
Assert.Equal(NetworkTableType.Float, v->type);
Assert.Equal(56.5f, v->data.valueFloat, 1e-9);
Assert.True(pinned == null);
Expand All @@ -103,12 +109,14 @@ public unsafe void TestFloat()
[Fact]
public unsafe void TestUnassigned()
{
HandleInMarshal(RefNetworkTableValue.MakeUnassigned(), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeUnassigned(), (v, pinned) =>
{
Assert.Equal(NetworkTableType.Unassigned, v->type);
Assert.True(pinned == null);
});

HandleInMarshal(RefNetworkTableValue.MakeUnassigned(), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeUnassigned(), (v, pinned) =>
{
Assert.Equal(NetworkTableType.Unassigned, v->type);
Assert.True(pinned == null);
});
Expand All @@ -120,7 +128,8 @@ public unsafe void TestRaw()
Span<byte> raw = stackalloc byte[3];
"abc"u8.CopyTo(raw);
void* ptr = Unsafe.AsPointer(ref raw.GetPinnableReference());
HandleInMarshal(RefNetworkTableValue.MakeRaw(raw), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeRaw(raw), (v, pinned) =>
{
Assert.Equal(NetworkTableType.Raw, v->type);
Assert.Equal((nuint)3, v->data.valueRaw.size);
ReadOnlySpan<byte> consumed = new ReadOnlySpan<byte>(v->data.valueRaw.data, (int)v->data.valueRaw.size);
Expand All @@ -129,7 +138,8 @@ public unsafe void TestRaw()
Assert.True(pinned == v->data.valueRaw.data);
});

HandleInMarshal(RefNetworkTableValue.MakeRaw(new()), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeRaw(new()), (v, pinned) =>
{
Assert.Equal(NetworkTableType.Raw, v->type);
Assert.Equal((nuint)0, v->data.valueRaw.size);
Assert.True(pinned == null);
Expand All @@ -143,7 +153,8 @@ public unsafe void TestString()
Span<byte> raw = stackalloc byte[3];
"abc"u8.CopyTo(raw);
void* ptr = Unsafe.AsPointer(ref raw.GetPinnableReference());
HandleInMarshal(RefNetworkTableValue.MakeString(raw), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeString(raw), (v, pinned) =>
{
Assert.Equal(NetworkTableType.String, v->type);
Assert.Equal((nuint)3, v->data.valueString.Len);
ReadOnlySpan<byte> consumed = new ReadOnlySpan<byte>(v->data.valueString.Str, (int)v->data.valueString.Len);
Expand All @@ -152,7 +163,8 @@ public unsafe void TestString()
Assert.True(pinned == v->data.valueString.Str);
});

HandleInMarshal(RefNetworkTableValue.MakeString("string"), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeString("string"), (v, pinned) =>
{
Assert.Equal(NetworkTableType.String, v->type);
Assert.Equal((nuint)6, v->data.valueString.Len);
ReadOnlySpan<byte> consumed = new ReadOnlySpan<byte>(v->data.valueString.Str, (int)v->data.valueString.Len);
Expand All @@ -161,7 +173,8 @@ public unsafe void TestString()
});

var longString = new string('a', 512);
HandleInMarshal(RefNetworkTableValue.MakeString(longString), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeString(longString), (v, pinned) =>
{
Assert.Equal(NetworkTableType.String, v->type);
Assert.Equal((nuint)512, v->data.valueString.Len);
ReadOnlySpan<byte> consumed = new ReadOnlySpan<byte>(v->data.valueString.Str, (int)v->data.valueString.Len);
Expand All @@ -170,7 +183,8 @@ public unsafe void TestString()
Assert.True(pinned == v->data.valueString.Str);
});

HandleInMarshal(RefNetworkTableValue.MakeString((string)null!), (v, pinned) => {
HandleInMarshal(RefNetworkTableValue.MakeString((string)null!), (v, pinned) =>
{
Assert.Equal(NetworkTableType.String, v->type);
Assert.Equal((nuint)0, v->data.valueString.Len);
Assert.True(pinned == null);
Expand Down

0 comments on commit 5d53917

Please sign in to comment.