Browse Source

Support converting JsTypedArray instances under interop (#1646)

Also some utility extensions for float typed arrays.
Added tests for changes.
Diogo Gomes 1 năm trước cách đây
mục cha
commit
e5d60cb58f

+ 15 - 0
Jint.Tests/Runtime/EngineTests.cs

@@ -3037,6 +3037,21 @@ x.test = {
             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();

+ 28 - 0
Jint.Tests/Runtime/TypedArrayInteropTests.cs

@@ -120,6 +120,34 @@ namespace Jint.Tests.Runtime
             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());

+ 34 - 0
Jint/JsValueExtensions.cs

@@ -391,6 +391,40 @@ namespace Jint
 
             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)]

+ 22 - 0
Jint/Native/Object/ObjectInstance.cs

@@ -10,6 +10,7 @@ using Jint.Native.Number;
 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;
@@ -1054,6 +1055,27 @@ namespace Jint.Native.Object
                         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)
                     {