Skip to content

Commit

Permalink
Support converting JsTypedArray instances under interop (#1646)
Browse files Browse the repository at this point in the history
Also some utility extensions for float typed arrays.
Added tests for changes.
  • Loading branch information
graphnode authored Oct 13, 2023
1 parent 48d512f commit e5d60cb
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 0 deletions.
15 changes: 15 additions & 0 deletions Jint.Tests/Runtime/EngineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3037,6 +3037,21 @@ public void ImportModuleShouldTriggerBeforeEvaluateEvents()
Assert.Equal(2, beforeEvaluateTriggeredCount);
}

[Fact]
public void ShouldConvertJsTypedArraysCorrectly()
{
var engine = new Engine();

var float32 = new float [] { 42f, 23 };

engine.SetValue("float32", float32);
engine.SetValue("testFloat32Array", new Action<float[]>(v => Assert.Equal(v, float32)));

engine.Evaluate(@"
testFloat32Array(new Float32Array(float32));
");
}

private static void TestBeforeEvaluateEvent(Action<Engine, string> call, string expectedSource)
{
var engine = new Engine();
Expand Down
28 changes: 28 additions & 0 deletions Jint.Tests/Runtime/TypedArrayInteropTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,34 @@ public void CanInteropWithBigUint64()
Assert.Equal(source, fromEngine.AsBigUint64Array());
}

[Fact]
public void CanInteropWithFloat32()
{
var engine = new Engine();
var source = new float[] { 42f, 12f };

engine.SetValue("testSubject", engine.Realm.Intrinsics.Float32Array.Construct(source));
ValidateCreatedTypeArray(engine, "Float32Array");

var fromEngine = engine.GetValue("testSubject");
Assert.True(fromEngine.IsFloat32Array());
Assert.Equal(source, fromEngine.AsFloat32Array());
}

[Fact]
public void CanInteropWithFloat64()
{
var engine = new Engine();
var source = new double[] { 42f, 12f };

engine.SetValue("testSubject", engine.Realm.Intrinsics.Float64Array.Construct(source));
ValidateCreatedTypeArray(engine, "Float64Array");

var fromEngine = engine.GetValue("testSubject");
Assert.True(fromEngine.IsFloat64Array());
Assert.Equal(source, fromEngine.AsFloat64Array());
}

private static void ValidateCreatedTypeArray(Engine engine, string arrayName)
{
Assert.Equal(arrayName, engine.Evaluate("testSubject.constructor.name").AsString());
Expand Down
34 changes: 34 additions & 0 deletions Jint/JsValueExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,40 @@ public static ulong[] AsBigUint64Array(this JsValue value)

return ((JsTypedArray) value).ToNativeArray<ulong>();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsFloat32Array(this JsValue value)
{
return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Float32 };
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float[] AsFloat32Array(this JsValue value)
{
if (!value.IsFloat32Array())
{
ThrowWrongTypeException(value, "Float32Array");
}

return ((JsTypedArray) value).ToNativeArray<float>();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsFloat64Array(this JsValue value)
{
return value is JsTypedArray { _arrayElementType: TypedArrayElementType.Float64 };
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double[] AsFloat64Array(this JsValue value)
{
if (!value.IsFloat64Array())
{
ThrowWrongTypeException(value, "Float64Array");
}

return ((JsTypedArray) value).ToNativeArray<double>();
}

[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
22 changes: 22 additions & 0 deletions Jint/Native/Object/ObjectInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Jint.Native.RegExp;
using Jint.Native.String;
using Jint.Native.Symbol;
using Jint.Native.TypedArray;
using Jint.Runtime;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Interop;
Expand Down Expand Up @@ -1054,6 +1055,27 @@ private object ToObject(ObjectTraverseStack stack)
converted = result;
break;
}

if (this is JsTypedArray typedArrayInstance)
{
converted = typedArrayInstance._arrayElementType switch
{
TypedArrayElementType.Int8 => typedArrayInstance.ToNativeArray<sbyte>(),
TypedArrayElementType.Int16 => typedArrayInstance.ToNativeArray<short>(),
TypedArrayElementType.Int32 => typedArrayInstance.ToNativeArray<int>(),
TypedArrayElementType.BigInt64 => typedArrayInstance.ToNativeArray<long>(),
TypedArrayElementType.Float32 => typedArrayInstance.ToNativeArray<float>(),
TypedArrayElementType.Float64 => typedArrayInstance.ToNativeArray<double>(),
TypedArrayElementType.Uint8 => typedArrayInstance.ToNativeArray<byte>(),
TypedArrayElementType.Uint8C => typedArrayInstance.ToNativeArray<byte>(),
TypedArrayElementType.Uint16 => typedArrayInstance.ToNativeArray<ushort>(),
TypedArrayElementType.Uint32 => typedArrayInstance.ToNativeArray<uint>(),
TypedArrayElementType.BigUint64 => typedArrayInstance.ToNativeArray<ulong>(),
_ => throw new ArgumentOutOfRangeException()
};

break;
}

if (this is BigIntInstance bigIntInstance)
{
Expand Down

0 comments on commit e5d60cb

Please sign in to comment.