Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix byte-array JSValue conversions #220

Merged
merged 1 commit into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions src/NodeApi/JSValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1428,12 +1428,8 @@ public PinnedMemory(Memory<T> memory, object? owner) : base(memory.Pin(), owner)
public static implicit operator JSValue(float? value) => ValueOrDefault(value, value => CreateNumber(value));
public static implicit operator JSValue(double? value) => ValueOrDefault(value, value => CreateNumber(value));
public static implicit operator JSValue(string value) => value == null ? default : CreateStringUtf16(value);
public static implicit operator JSValue(char[] value) => value == null ? default : CreateStringUtf16(value);
public static implicit operator JSValue(Span<char> value) => CreateStringUtf16(value);
public static implicit operator JSValue(ReadOnlySpan<char> value) => CreateStringUtf16(value);
public static implicit operator JSValue(byte[] value) => value == null ? default : CreateStringUtf8(value);
public static implicit operator JSValue(Span<byte> value) => CreateStringUtf8(value);
public static implicit operator JSValue(ReadOnlySpan<byte> value) => CreateStringUtf8(value);

public static explicit operator bool(JSValue value) => value.GetValueBool();
public static explicit operator sbyte(JSValue value) => (sbyte)value.GetValueInt32();
Expand All @@ -1447,8 +1443,6 @@ public PinnedMemory(Memory<T> memory, object? owner) : base(memory.Pin(), owner)
public static explicit operator float(JSValue value) => (float)value.GetValueDouble();
public static explicit operator double(JSValue value) => value.GetValueDouble();
public static explicit operator string(JSValue value) => value.IsNullOrUndefined() ? null! : value.GetValueStringUtf16();
public static explicit operator char[](JSValue value) => value.IsNullOrUndefined() ? null! : value.GetValueStringUtf16AsCharArray();
public static explicit operator byte[](JSValue value) => value.IsNullOrUndefined() ? null! : value.GetValueStringUtf8();
public static explicit operator bool?(JSValue value) => ValueOrDefault(value, value => value.GetValueBool());
public static explicit operator sbyte?(JSValue value) => ValueOrDefault(value, value => (sbyte)value.GetValueInt32());
public static explicit operator byte?(JSValue value) => ValueOrDefault(value, value => (byte)value.GetValueUInt32());
Expand Down
16 changes: 11 additions & 5 deletions test/TestCases/napi-dotnet/ComplexTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,19 @@ public static class ComplexTypes

public static string[] StringArray { get; set; } = Array.Empty<string>();

public static Memory<uint> UIntArray { get; set; }
public static byte[] ByteArray { get; set; } = new[] { (byte)0, (byte)1, (byte)2 };

public static IEnumerable<int> Enumerable { get; set; } = new int[] { 0, 1, 2 };
public static int[] Int32Array { get; set; } = new int[] { 0, 1, 2 };

public static ICollection<int> Collection { get; set; } = new List<int>(new int[] { 0, 1, 2 });
public static Memory<byte> ByteMemory { get; set; } = new Memory<byte>(ByteArray);

public static IReadOnlyCollection<int> ReadOnlyCollection { get; set; } = new int[] { 0, 1, 2 };
public static Memory<int> Int32Memory { get; set; } = new Memory<int>(Int32Array);

public static IEnumerable<int> Enumerable { get; set; } = Int32Array;

public static ICollection<int> Collection { get; set; } = new List<int>(Int32Array);

public static IReadOnlyCollection<int> ReadOnlyCollection { get; set; } = Int32Array;

public static IList<int> List { get; set; } = new List<int>();

Expand All @@ -53,7 +59,7 @@ public static class ComplexTypes
public static IDictionary<string, IList<ClassObject>> ObjectListDictionary { get; set; }
= new Dictionary<string, IList<ClassObject>>();

public static Memory<uint> Slice(Memory<uint> array, int start, int length)
public static Memory<int> Slice(Memory<int> array, int start, int length)
=> array.Slice(start, length);

public static TestEnum TestEnum { get; set; }
Expand Down
55 changes: 43 additions & 12 deletions test/TestCases/napi-dotnet/complex_types.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,21 +71,52 @@ assert.notStrictEqual(ComplexTypes.stringArray, stringArrayValue);
assert.deepStrictEqual(ComplexTypes.stringArray, stringArrayValue);
ComplexTypes.stringArray = [ 'test' ];
assert.strictEqual(ComplexTypes.stringArray[0], 'test');
ComplexTypes.stringArray[0] = 'test2';
ComplexTypes.stringArray[0] = 'test2'; // Does not modify the original
assert.strictEqual(ComplexTypes.stringArray[0], 'test');

const byteArrayValue = ComplexTypes.byteArray;
assert(Array.isArray(byteArrayValue));
assert.strictEqual(byteArrayValue.length, 3);
assert.notStrictEqual(ComplexTypes.byteArray, byteArrayValue);
assert.deepStrictEqual(ComplexTypes.byteArray, byteArrayValue);
ComplexTypes.byteArray = [ 1 ];
assert.strictEqual(ComplexTypes.byteArray[0], 1);
ComplexTypes.byteArray[0] = 2; // Does not modify the original
assert.strictEqual(ComplexTypes.byteArray[0], 1);

const intArrayValue = ComplexTypes.int32Array;
assert(Array.isArray(intArrayValue));
assert.strictEqual(intArrayValue.length, 3);
assert.notStrictEqual(ComplexTypes.int32Array, intArrayValue);
assert.deepStrictEqual(ComplexTypes.int32Array, intArrayValue);
ComplexTypes.int32Array = [ 1 ];
assert.strictEqual(ComplexTypes.int32Array[0], 1);
ComplexTypes.int32Array[0] = 2; // Does not modify the original
assert.strictEqual(ComplexTypes.int32Array[0], 1);


// C# Memory<T> maps to/from JS TypedArray (without copying) for valid typed-array element types.
const uintArrayValue = ComplexTypes.uIntArray;
assert(uintArrayValue instanceof Uint32Array);
assert.strictEqual(uintArrayValue.length, 0);
assert.deepStrictEqual(ComplexTypes.uIntArray, uintArrayValue);
const uintArrayValue2 = new Uint32Array([0, 1, 2]);
ComplexTypes.uIntArray = uintArrayValue2;
assert.strictEqual(ComplexTypes.uIntArray.length, 3);
assert.strictEqual(ComplexTypes.uIntArray[1], 1);
assert.deepStrictEqual(ComplexTypes.uIntArray, uintArrayValue2);
const slicedArray = ComplexTypes.slice(new Uint32Array([0, 1, 2, 3]), 1, 2);
assert.deepStrictEqual(slicedArray, new Uint32Array([1, 2]))
const uint8ArrayValue = ComplexTypes.byteMemory;
assert(uint8ArrayValue instanceof Uint8Array);
assert.strictEqual(uint8ArrayValue.length, 3);
assert.deepStrictEqual(ComplexTypes.byteMemory, uint8ArrayValue);
const uint8ArrayValue2 = new Uint8Array([0, 1, 2, 3]);
ComplexTypes.byteMemory = uint8ArrayValue2;
assert.strictEqual(ComplexTypes.byteMemory.length, 4);
assert.strictEqual(ComplexTypes.byteMemory[3], 3);
assert.deepStrictEqual(ComplexTypes.byteMemory, uint8ArrayValue2);

const int32ArrayValue = ComplexTypes.int32Memory;
assert(int32ArrayValue instanceof Int32Array);
assert.strictEqual(int32ArrayValue.length, 3);
assert.deepStrictEqual(ComplexTypes.int32Memory, int32ArrayValue);
const int32ArrayValue2 = new Int32Array([0, 1, 2, 3]);
ComplexTypes.int32Memory = int32ArrayValue2;
assert.strictEqual(ComplexTypes.int32Memory.length, 4);
assert.strictEqual(ComplexTypes.int32Memory[3], 3);
assert.deepStrictEqual(ComplexTypes.int32Memory, int32ArrayValue2);
const slicedInt32Array = ComplexTypes.slice(new Int32Array([0, 1, 2, 3]), 1, 2);
assert.deepStrictEqual(slicedInt32Array, new Int32Array([1, 2]))

// C# IEnumerable<T> maps to/from JS Iterable<T> (without copying)
const enumerableValue = ComplexTypes.enumerable;
Expand Down
2 changes: 1 addition & 1 deletion test/TestCases/node-addon-api/object/delete_property.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ private static JSValue DeletePropertyWithUtf8StyleString(JSCallbackArgs args)
{
JSValue obj = args[0];
JSValue key = args[1];
return obj.DeleteProperty(key.GetValueStringUtf8());
return obj.DeleteProperty(JSValue.CreateStringUtf8(key.GetValueStringUtf8()));
}

private static JSValue DeletePropertyWithCSharpStyleString(JSCallbackArgs args)
Expand Down
2 changes: 1 addition & 1 deletion test/TestCases/node-addon-api/object/get_property.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ private static JSValue GetPropertyWithUtf8StyleString(JSCallbackArgs args)
{
JSValue obj = args[0];
JSValue key = args[1];
return obj.GetProperty(key.GetValueStringUtf8());
return obj.GetProperty(JSValue.CreateStringUtf8(key.GetValueStringUtf8()));
}

private static JSValue GetPropertyWithCSharpStyleString(JSCallbackArgs args)
Expand Down
2 changes: 1 addition & 1 deletion test/TestCases/node-addon-api/object/has_own_property.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ private static JSValue HasOwnPropertyWithUtf8StyleString(JSCallbackArgs args)
{
JSValue obj = args[0];
JSValue key = args[1];
return obj.HasOwnProperty(key.GetValueStringUtf8());
return obj.HasOwnProperty(JSValue.CreateStringUtf8(key.GetValueStringUtf8()));
}

private static JSValue HasOwnPropertyWithCSharpStyleString(JSCallbackArgs args)
Expand Down
2 changes: 1 addition & 1 deletion test/TestCases/node-addon-api/object/has_property.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ private static JSValue HasPropertyWithUtf8StyleString(JSCallbackArgs args)
{
JSValue obj = args[0];
JSValue key = args[1];
return obj.HasProperty(key.GetValueStringUtf8());
return obj.HasProperty(JSValue.CreateStringUtf8(key.GetValueStringUtf8()));
}

private static JSValue HasPropertyWithCSharpStyleString(JSCallbackArgs args)
Expand Down
2 changes: 1 addition & 1 deletion test/TestCases/node-addon-api/object/object.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ private static JSValue CreateObjectUsingMagic(JSCallbackArgs args)
obj["0.0f"] = 0.0f;
obj["0.0"] = 0.0;
obj["-1"] = -1;
obj["foo2"] = new ReadOnlySpan<byte>(new[] { (byte)'f', (byte)'o', (byte)'o' });
obj["foo2"] = JSValue.CreateStringUtf8(new[] { (byte)'f', (byte)'o', (byte)'o' });
obj["foo4"] = "foo";
obj["circular"] = obj;
obj["circular2"] = obj;
Expand Down
2 changes: 1 addition & 1 deletion test/TestCases/node-addon-api/object/set_property.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ private static JSValue SetPropertyWithUtf8StyleString(JSCallbackArgs args)
JSValue obj = args[0];
JSValue key = args[1];
JSValue value = args[2];
obj.SetProperty(key.GetValueStringUtf8(), value);
obj.SetProperty(JSValue.CreateStringUtf8(key.GetValueStringUtf8()), value);
return JSValue.Undefined;
}

Expand Down
4 changes: 2 additions & 2 deletions test/TestCases/node-addon-api/object/subscript_operator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ private static JSValue SubscriptGetWithUtf8StyleString(JSCallbackArgs args)
{
JSValue obj = args[0];
byte[] key = args[1].GetValueStringUtf8();
return obj[key];
return obj[JSValue.CreateStringUtf8(key)];
}

private static JSValue SubscriptGetWithCSharpStyleString(JSCallbackArgs args)
Expand All @@ -33,7 +33,7 @@ private static JSValue SubscriptSetWithUtf8StyleString(JSCallbackArgs args)
JSValue obj = args[0];
byte[] key = args[1].GetValueStringUtf8();
JSValue value = args[2];
obj[key] = value;
obj[JSValue.CreateStringUtf8(key)] = value;
return JSValue.Undefined;
}

Expand Down
Loading