Ejemplo n.º 1
0
        public bool Equals(JsDynamicObject other)
        {
            if (other is null)
            {
                return(false);
            }
            if (Handle.Type != other.Handle.Type)
            {
                return(false);
            }

            System.Diagnostics.Debug.Assert(Handle.Type == JsType.Object || Handle.Type == JsType.Function,
                                            "Only objects are supported by JsDynamicObject atm.");

            CheckDisposed();
            // TODO: Do this using a native method, which would be more efficient.
            var gObj = _host.GetMember(JsValue.Global, "Object");

            try
            {
                var result = _host.InvokeByName("is",
                                                gObj,
                                                2,
                                                new DotNetValue[] { DotNetValue.FromJsValue(Handle), DotNetValue.FromJsValue(other.Handle) });
                return(result.TryGetObject(_host, typeof(bool), out object resultObj) && (bool)resultObj);
            }
            finally
            {
                _host.Release(gObj);
            }
        }
Ejemplo n.º 2
0
        public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
        {
            if (indexes.Length != 1)
            {
                throw new InvalidOperationException("We only support single parameter indexer");
            }
            CheckDisposed();

            var index = indexes[0];

            if (index == null)
            {
                throw new ArgumentNullException(nameof(index));
            }
            if (index is string stringIndex)
            {
                _host.SetMember(Handle, stringIndex, DotNetValue.FromObject(value, _host));
                return(true);
            }

            /*if (index is int intIndex)
             * {
             *  var jsHandle = _host.SetMemberByIndex(Handle, intIndex);
             *  return true;
             * }*/

            return(base.TrySetIndex(binder, indexes, value));
        }
Ejemplo n.º 3
0
        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            CheckDisposed();

            _host.SetMember(Handle, binder.Name, DotNetValue.FromObject(value, _host));
            return(true);
        }
Ejemplo n.º 4
0
        public dynamic CreateNewInstance(params object[] arguments)
        {
            var result = _host.CreateObject(Handle, arguments.Select(a => DotNetValue.FromObject(a, _host)).ToArray());

            if (!result.TryGetObject(_host, typeof(object), out object newInstance))
            {
                throw new InvalidOperationException("Could not create new instance");
            }
            return(newInstance);
        }
Ejemplo n.º 5
0
        public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
        {
            CheckDisposed();

            var resultHandle = _host.Invoke(Handle,
                                            Handle,
                                            args.Length,
                                            args.Select(a => DotNetValue.FromObject(a, _host)).ToArray());

            resultHandle.TryGetObject(_host, binder.ReturnType, out result);
            return(true);
        }
Ejemplo n.º 6
0
        private static DotNetValue DynamicInvoke(Delegate @delegate, IHostInProcess host, JsValue[] argv)
        {
            var requiredParameters = @delegate.Method.GetParameters();

            if (requiredParameters.Length > argv.Length)
            {
                foreach (var toRelease in argv)
                {
                    host.Release(toRelease);
                }
                // This exception will be passed properly to JS
                throw new InvalidOperationException($"We need at least {requiredParameters.Length} arguments!");
            }

            var mappedArgs = new object[requiredParameters.Length];

            for (var c = 0; c < requiredParameters.Length; c++)
            {
                var paramType = requiredParameters[c].ParameterType;
                if (!argv[c].TryGetObject(host, paramType, out object parameter))
                {
                    // Release remaining arguments
                    foreach (var toRelease in argv.Skip(c + 1))
                    {
                        host.Release(toRelease);
                    }
                    throw new InvalidOperationException($"Cannot get {paramType.FullName} from JS handle of type {argv[c].Type}");
                }

                mappedArgs[c] = parameter;
            }

            // Release remaining arguments
            foreach (var toRelease in argv.Skip(mappedArgs.Length))
            {
                host.Release(toRelease);
            }

            var resultObj = @delegate.DynamicInvoke(mappedArgs);

            return(DotNetValue.FromObject(resultObj, host));
        }
Ejemplo n.º 7
0
        // TODO DM 24.11.2019: This would require another bunch of reflection code to get working...

        /*
         *      public TaskAwaiter GetAwaiter()
         *      {
         *          if (TryConvertIntern(typeof(Task), out object task))
         *          {
         *              return ((Task)task).GetAwaiter();
         *          }
         *          throw new InvalidOperationException("JS object is not awaitable");
         *      }*/

        internal bool TryConvertIntern(Type type, out object result)
        {
            // Converting to string.
            if (type == typeof(object) || type.IsAssignableFrom(GetType()))
            {
                result = this;
                return(true);
            }

            //Console.WriteLine($"Converting to {type.Name}");
            if (type == typeof(string))
            {
                var jsResult = _host.InvokeByName("String",
                                                  JsValue.Global,
                                                  1,
                                                  new DotNetValue[] { DotNetValue.FromJsValue(Handle) });
                var gotString = jsResult.TryGetObject(_host, typeof(string), out result);
                if (!gotString)
                {
                    return(false);
                }
                return(result is string);
            }

            if (typeof(Task).IsAssignableFrom(type))
            {
                var thenHandle = _host.GetMember(Handle, "then");
                try
                {
                    // Ensure that Handle is a thenable/promise like object
                    if (thenHandle.Type == JsType.Function)
                    {
                        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Task <>))
                        {
                            // TODO DM 24.11.2019: This is inefficient. We need to do this in the native code somehow...
                            //                     How about _host.AttachTaskToPromise(Action<JsValue>,Action<JsValue>)?
                            var resultType           = type.GetGenericArguments()[0];
                            var completionSourceType = typeof(TaskCompletionSource <>).MakeGenericType(resultType);
                            var tcs = Activator.CreateInstance(completionSourceType);

                            var resolve = Delegate.CreateDelegate(typeof(Action <>).MakeGenericType(resultType),
                                                                  tcs,
                                                                  completionSourceType.GetMethod(nameof(TaskCompletionSource <object> .SetResult)));
                            var reject = new Action <object>(error =>
                            {
                                completionSourceType.GetMethod(nameof(TaskCompletionSource <object> .SetException))
                                .Invoke(tcs, new object[] { GetExceptionFromPromiseRejection(error) });
                            });
                            var thenResult = _host.Invoke(thenHandle,
                                                          Handle,
                                                          2,
                                                          new[] { DotNetValue.FromDelegate(resolve, _host), DotNetValue.FromDelegate(reject, _host) });
                            // DM 29.11.2019: thenResult is always another promise
                            _host.Release(thenResult);
                            result = completionSourceType.GetProperty(nameof(TaskCompletionSource <object> .Task))
                                     .GetValue(tcs);
                            return(true);
                        }
                        else
                        {
                            var tcs        = new TaskCompletionSource <object>();
                            var thenResult = _host.Invoke(thenHandle,
                                                          Handle,
                                                          2,
                                                          new DotNetValue[]
                            {
                                DotNetValue.FromDelegate(new Action(() => tcs.SetResult(null)), _host),
                                DotNetValue.FromDelegate(new Action <object>((error) => { tcs.SetException(GetExceptionFromPromiseRejection(error)); }), _host)
                            });
                            // DM 29.11.2019: thenResult is always another promise
                            _host.Release(thenResult);
                            result = tcs.Task;
                            return(true);
                        }
                    }
                }
                finally
                {
                    _host.Release(thenHandle);
                }

                result = null;
                return(false);
            }

            if (typeof(Exception).IsAssignableFrom(type))
            {
                dynamic dynamic = this;
                string  stack   = dynamic.stack;
                if (stack != null)
                {
                    result = new InvalidOperationException($"JS Error:\n{stack}");
                    return(true);
                }

                result = null;
                return(false);
            }

            if (type.IsArray)
            {
                var innerType = type.GetElementType();
                if (TryConvertToArray(innerType, out result))
                {
                    return(true);
                }

                result = null;
                return(false);
            }

            if (type.IsGenericType && type.IsInterface)
            {
                var unclosed = type.GetGenericTypeDefinition();
                if (unclosed == typeof(IEnumerable <>) || unclosed == typeof(IReadOnlyCollection <>))
                {
                    var innerType = type.GetGenericArguments()[0];
                    if (TryConvertToArray(innerType, out result))
                    {
                        return(true);
                    }
                }

                result = null;
                return(false);
            }

            // TODO DM 17.05.2020: This dependency is unwanted (circular), we should use opend/closed for type conversion
            if (type == typeof(ArrayBuffer))
            {
                if (_host.TryAccessArrayBuffer(Handle, out var address, out var byteLength))
                {
                    result = new ArrayBuffer(address, byteLength, this);
                    return(true);
                }

                result = null;
                return(false);
            }

            result = null;
            return(false);
        }
Ejemplo n.º 8
0
 public void SetMember(JsDynamicObject ownerHandle, string name, DotNetValue value)
 {
     _host.SetMember(ownerHandle.Handle, name, value);
 }
Ejemplo n.º 9
0
            private DotNetValue InvokeDelegate(JsValue[] argv)
            {
                ReleaseRemainingArgs(argv, 0);

                return(DotNetValue.FromObject(_func(), Host));
            }