コード例 #1
0
            /// <summary>
            /// Add a native module to the builder.
            /// </summary>
            /// <param name="module">The native module.</param>
            /// <returns>The builder instance.</returns>
            public Builder Add(INativeModule module)
            {
                if (module == null)
                {
                    throw new ArgumentNullException(nameof(module));
                }
                if (module.Name == null)
                {
                    throw new ArgumentException(
                              Invariant($"Native module '{module.GetType()}' cannot have a null `Name`."),
                              nameof(module));
                }

                var existing = default(INativeModule);

                if (_modules.TryGetValue(module.Name, out existing) && !module.CanOverrideExistingModule)
                {
                    throw new InvalidOperationException(
                              string.Format(
                                  CultureInfo.InvariantCulture,
                                  "Native module '{0}' tried to override '{1}' for module name '{2}'. " +
                                  "If this was your intention, override `CanOverrideExistingModule`.",
                                  module.GetType().Name,
                                  existing.GetType().Name,
                                  module.Name));
                }

                _modules[module.Name] = module;

                return(this);
            }
コード例 #2
0
        private IList <Extractor> CreateExtractors(INativeModule module, MethodInfo method)
        {
            var parameters = method.GetParameters();
            var extractors = new List <Extractor>(parameters.Length);

            foreach (var parameter in parameters)
            {
                extractors.Add(CreateExtractor(parameter.ParameterType, module.Name, method.Name));
            }

            return(extractors);
        }
コード例 #3
0
        private static void Invoke(
            MethodInfo method,
            int expectedArguments,
            IList <Func <IReactInstance, JArray, int, Result> > extractors,
            IGenericDelegate genericDelegate,
            INativeModule moduleInstance,
            IReactInstance reactInstance,
            JArray jsArguments)
        {
            if (moduleInstance == null)
            {
                throw new ArgumentNullException(nameof(moduleInstance));
            }
            if (reactInstance == null)
            {
                throw new ArgumentNullException(nameof(reactInstance));
            }
            if (jsArguments == null)
            {
                throw new ArgumentNullException(nameof(jsArguments));
            }

            var n = expectedArguments;
            var c = extractors.Count;

            if (jsArguments.Count != n)
            {
                throw new NativeArgumentsParseException(
                          Invariant($"Module '{moduleInstance.Name}' method '{method.Name}' got '{jsArguments.Count}' arguments, expected '{n}'."),
                          nameof(jsArguments));
            }

            var idx  = 0;
            var args = new object[extractors.Count];

            for (var j = 0; j < c; ++j)
            {
                var result = extractors[j](reactInstance, jsArguments, idx);
                args[j] = result.Value;
                idx     = result.NextIndex;
            }

            if (genericDelegate != null)
            {
                genericDelegate.Invoke(args);
            }
            else
            {
                // This should only happen for React methods with greater than 16 arguments.
                method.Invoke(moduleInstance, args);
            }
        }
コード例 #4
0
 private static async Task RunAsync(INativeModule module, Action action)
 {
     // If the module has an action queue, call there;
     // otherwise execute inline.
     if (module.ActionQueue != null)
     {
         await module.ActionQueue.RunAsync(action);
     }
     else
     {
         action();
     }
 }
コード例 #5
0
 private static void Dispatch(INativeModule module, Action action)
 {
     // If the module has an action queue, dispatch there;
     // otherwise execute inline.
     if (module.ActionQueue != null)
     {
         module.ActionQueue.Dispatch(action);
     }
     else
     {
         action();
     }
 }
コード例 #6
0
            public ModuleDefinition(string name, INativeModule target)
            {
                Name     = name;
                Target   = target;
                _methods = new List <MethodRegistration>(target.Methods.Count);

                foreach (var entry in target.Methods)
                {
                    _methods.Add(
                        new MethodRegistration(
                            entry.Key,
                            "NativeCall__" + target.Name + "_" + entry.Key,
                            entry.Value));
                }
            }
コード例 #7
0
        /// <summary>
        /// Create an invocation delegate from the given method.
        /// </summary>
        /// <param name="module">The native module instance.</param>
        /// <param name="method">The method.</param>
        /// <returns>The invocation delegate.</returns>
        public override Action <INativeModule, IReactInstance, JArray> Create(INativeModule module, MethodInfo method)
        {
            var extractors        = CreateExtractors(module, method);
            var expectedArguments = extractors.Sum(e => e.ExpectedArguments);
            var extractFunctions  = extractors.Select(e => e.ExtractFunction).ToList();

            return((moduleInstance, reactInstance, arguments) =>
                   Invoke(
                       method,
                       expectedArguments,
                       extractFunctions,
                       moduleInstance,
                       reactInstance,
                       arguments));
        }
コード例 #8
0
        private static void Invoke(
            MethodInfo method,
            int expectedArguments,
            IList <Func <IReactInstance, JArray, int, Result> > extractors,
            INativeModule moduleInstance,
            IReactInstance reactInstance,
            JArray jsArguments)
        {
            if (moduleInstance == null)
            {
                throw new ArgumentNullException(nameof(moduleInstance));
            }
            if (reactInstance == null)
            {
                throw new ArgumentNullException(nameof(reactInstance));
            }
            if (jsArguments == null)
            {
                throw new ArgumentNullException(nameof(jsArguments));
            }

            var n = expectedArguments;
            var c = extractors.Count;

            if (jsArguments.Count != n)
            {
                throw new NativeArgumentsParseException(
                          $"Module '{moduleInstance.Name}' method '{method.Name}' got '{jsArguments.Count}' arguments, expected '{n}'.",
                          nameof(jsArguments));
            }

            var idx  = 0;
            var args = new object[extractors.Count];

            for (var j = 0; j < c; ++j)
            {
                var result = extractors[j](reactInstance, jsArguments, idx);
                args[j] = result.Value;
                idx     = result.NextIndex;
            }

            method.Invoke(moduleInstance, args);
        }
コード例 #9
0
        /// <summary>
        /// Create an invocation delegate from the given method.
        /// </summary>
        /// <param name="module">The native module instance.</param>
        /// <param name="method">The method.</param>
        /// <returns>The invocation delegate.</returns>
        public override Func <IReactInstance, JArray, JToken> Create(INativeModule module, MethodInfo method)
        {
            var extractors        = CreateExtractors(module, method);
            var expectedArguments = extractors.Sum(e => e.ExpectedArguments);
            var extractFunctions  = extractors.Select(e => e.ExtractFunction).ToList();
            var genericDelegate   = GenericDelegate.Create(module, method);
            var hasReturnType     = method.ReturnType != typeof(void);

            return((reactInstance, arguments) =>
                   Invoke(
                       method,
                       expectedArguments,
                       extractFunctions,
                       genericDelegate,
                       hasReturnType,
                       module,
                       reactInstance,
                       arguments));
        }
コード例 #10
0
        private static Expression <Func <InvokeCallback, JArray, JToken> > GenerateExpression(INativeModule module, MethodInfo method)
        {
            var parameterInfos = method.GetParameters();

            var n    = parameterInfos.Length;
            var argc = n > 0 && parameterInfos.Last().ParameterType == typeof(IPromise) ? n + 1 : n;

            var resultParameter           = Expression.Parameter(typeof(object), "result");
            var blockParameterExpressions = new ParameterExpression[n + 1];

            blockParameterExpressions[n] = resultParameter;
            var callParameterExpressions = new ParameterExpression[n];
            var extractExpressions       = new Expression[n];

            var moduleInstanceConstant  = Expression.Constant(module, typeof(INativeModule));
            var invokeCallbackParameter = Expression.Parameter(typeof(InvokeCallback), "invokeCallback");
            var jsArgumentsParameter    = Expression.Parameter(typeof(JArray), "jsArguments");

            for (var i = 0; i < n; ++i)
            {
                var parameterInfo       = parameterInfos[i];
                var parameterType       = parameterInfo.ParameterType;
                var parameterExpression = Expression.Parameter(parameterType, parameterInfo.Name);
                blockParameterExpressions[i] = callParameterExpressions[i] = parameterExpression;
                extractExpressions[i]        = GenerateExtractExpression(
                    parameterInfo.ParameterType,
                    parameterExpression,
                    jsArgumentsParameter,
                    invokeCallbackParameter,
                    jsArgumentsParameter.Name,
                    module.Name,
                    method.Name,
                    i);
            }

            var hasReturnType   = method.ReturnType != typeof(void);
            var blockStatements = new Expression[n + 5];

            //
            // if (invokeCallback == null)
            //     throw new ArgumentNullException(nameof(invokeCallback));
            //
            blockStatements[0] = CreateNullCheckExpression <IReactInstance>(invokeCallbackParameter);

            //
            // if (jsArguments == null)
            //     throw new ArgumentNullException(nameof(jsArguments));
            //
            blockStatements[1] = CreateNullCheckExpression <JArray>(jsArgumentsParameter);

            //
            // if (jsArguments.Count != argc)
            //     throw new NativeArgumentsParseException(
            //         string.Format(
            //             CultureInfo.InvariantCulture,
            //             "Module '{module.Name}' method '{method.Name}' got '{0}' arguments, expected '{parameterCount}'."
            //             jsArguments.Count));
            //
            blockStatements[2] = Expression.IfThen(
                Expression.NotEqual(
                    Expression.MakeMemberAccess(jsArgumentsParameter, s_countProperty),
                    Expression.Constant(argc)
                    ),
                Expression.Throw(
                    Expression.New(
                        s_newNativeArgumentParseException,
                        Expression.Call(
                            s_stringFormat,
                            Expression.Constant(CultureInfo.InvariantCulture),
                            Expression.Constant(
                                Invariant($"Module '{module.Name}' method '{method.Name}' got '{{0}}' arguments, expected '{argc}'.")
                                ),
                            Expression.Convert(
                                Expression.MakeMemberAccess(jsArgumentsParameter, s_countProperty),
                                typeof(object)
                                )
                            ),
                        Expression.Constant(jsArgumentsParameter.Name)
                        )
                    )
                );

            //
            // p0 = Extract<T>(jsArguments[0]);
            // p1 = Extract<T>(jsArguments[1]);
            // ...
            // pn = Extract<T>(jsArguments[n]);
            //
            Array.Copy(extractExpressions, 0, blockStatements, 3, n);

            //
            // module.NativeMethod(p0, p1, ..., pn);
            //
            var resultExpression = Expression.Call(
                Expression.Convert(moduleInstanceConstant, method.DeclaringType),
                method,
                callParameterExpressions
                );

            if (hasReturnType)
            {
                //
                // var result = ...;
                //
                blockStatements[blockStatements.Length - 2] =
                    Expression.Assign(resultParameter, resultExpression);

                //
                // return result == null ? JValue.CreateNull() : JObject.FromObject(result);
                //
                blockStatements[blockStatements.Length - 1] = Expression.Condition(
                    Expression.Equal(resultParameter, Expression.Constant(null, typeof(object))),
                    s_nullConstant,
                    Expression.Call(
                        s_fromObject,
                        resultParameter
                        )
                    );
            }
            else
            {
                //
                // ...
                //
                blockStatements[blockStatements.Length - 2] = resultExpression;

                //
                // return JValue.CreateNull();
                //
                blockStatements[blockStatements.Length - 1] = s_nullConstant;
            }

            return(Expression.Lambda <Func <InvokeCallback, JArray, JToken> >(
                       Expression.Block(blockParameterExpressions, blockStatements),
                       invokeCallbackParameter,
                       jsArgumentsParameter
                       ));
        }
コード例 #11
0
 /// <summary>
 /// Create an invocation delegate from the given method.
 /// </summary>
 /// <param name="module">The native module instance.</param>
 /// <param name="method">The method.</param>
 /// <returns>The invocation delegate.</returns>
 public override Action <INativeModule, IReactInstance, JArray> Create(INativeModule module, MethodInfo method)
 {
     return(GenerateExpression(module, method).Compile());
 }
コード例 #12
0
        private static async Task DisposeModuleOnActionQueueAsync(INativeModule module)
        {
            await module.ActionQueue.RunAsync(module.DisposeAsync).Unwrap();

            module.ActionQueue.Dispose();
        }
コード例 #13
0
 private static Task DisposeModuleAsync(INativeModule module)
 {
     return(module.ActionQueue != null
         ? DisposeModuleOnActionQueueAsync(module)
         : module.DisposeAsync());
 }
コード例 #14
0
 /// <summary>
 /// Create an invocation delegate from the given method.
 /// </summary>
 /// <param name="nativeModule">The native module instance.</param>
 /// <param name="method">The method.</param>
 /// <returns>The invocation delegate.</returns>
 public abstract Func <InvokeCallback, JArray, JToken> Create(INativeModule nativeModule, MethodInfo method);
        private static JToken Invoke(
            MethodInfo method,
            int expectedArguments,
            IList <ExtractArgument> extractors,
            IGenericDelegate genericDelegate,
            bool hasReturnType,
            INativeModule moduleInstance,
            InvokeCallback invokeCallback,
            JArray jsArguments)
        {
            if (moduleInstance == null)
            {
                throw new ArgumentNullException(nameof(moduleInstance));
            }
            if (invokeCallback == null)
            {
                throw new ArgumentNullException(nameof(invokeCallback));
            }
            if (jsArguments == null)
            {
                throw new ArgumentNullException(nameof(jsArguments));
            }

            var n = expectedArguments;
            var c = extractors.Count;

            if (jsArguments.Count != n)
            {
                throw new NativeArgumentsParseException(
                          Invariant($"Module '{moduleInstance.Name}' method '{method.Name}' got '{jsArguments.Count}' arguments, expected '{n}'."),
                          nameof(jsArguments));
            }

            var idx  = 0;
            var args = new object[extractors.Count];

            for (var j = 0; j < c; ++j)
            {
                var extractorResult = extractors[j](invokeCallback, jsArguments, idx);
                args[j] = extractorResult.Value;
                idx     = extractorResult.NextIndex;
            }

            object result;

            if (genericDelegate != null)
            {
                result = genericDelegate.Invoke(args);
            }
            else
            {
                // This should only happen for React methods with greater than 16 arguments.
                result = method.Invoke(moduleInstance, args);
            }

            if (!hasReturnType)
            {
                return(s_null);
            }
            else if (result == null)
            {
                return(s_null);
            }

            return(JToken.FromObject(result));
        }
コード例 #16
0
 /// <summary>
 /// Create an invocation delegate from the given method.
 /// </summary>
 /// <param name="module">The native module instance.</param>
 /// <param name="method">The method.</param>
 /// <returns>The invocation delegate.</returns>
 public override Func <IReactInstance, JArray, JToken> Create(INativeModule module, MethodInfo method)
 {
     return(GenerateExpression(module, method).Compile());
 }
コード例 #17
0
 /// <summary>
 /// Create an invocation delegate from the given method.
 /// </summary>
 /// <param name="nativeModule">The native module instance.</param>
 /// <param name="method">The method.</param>
 /// <returns>The invocation delegate.</returns>
 public abstract Action <IReactInstance, JArray> Create(INativeModule nativeModule, MethodInfo method);
コード例 #18
0
 /// <summary>
 /// Create an invocation delegate from the given method.
 /// </summary>
 /// <param name="module">The native module instance.</param>
 /// <param name="method">The method.</param>
 /// <returns>The invocation delegate.</returns>
 public override Func <InvokeCallback, JArray, JToken> Create(INativeModule module, MethodInfo method)
 {
     return(GenerateExpression(module, method).Compile());
 }
コード例 #19
0
        private static Expression <Action <INativeModule, IReactInstance, JArray> > GenerateExpression(INativeModule module, MethodInfo method)
        {
            var parameterInfos = method.GetParameters();

            var n    = parameterInfos.Length;
            var argc = n > 0 && parameterInfos.Last().ParameterType == typeof(IPromise) ? n + 1 : n;

            var parameterExpressions = new ParameterExpression[n];
            var extractExpressions   = new Expression[n];

            var moduleInstanceParameter = Expression.Parameter(typeof(INativeModule), "moduleInstance");
            var reactInstanceParameter  = Expression.Parameter(typeof(IReactInstance), "reactInstance");
            var jsArgumentsParameter    = Expression.Parameter(typeof(JArray), "jsArguments");

            for (var i = 0; i < n; ++i)
            {
                var parameterInfo       = parameterInfos[i];
                var parameterType       = parameterInfo.ParameterType;
                var parameterExpression = Expression.Parameter(parameterType, parameterInfo.Name);
                parameterExpressions[i] = parameterExpression;
                extractExpressions[i]   = GenerateExtractExpression(
                    parameterInfo.ParameterType,
                    parameterExpression,
                    jsArgumentsParameter,
                    reactInstanceParameter,
                    jsArgumentsParameter.Name,
                    module.Name,
                    method.Name,
                    i);
            }

            var blockStatements = new Expression[n + 5];

            //
            // if (moduleInstance == null)
            //     throw new ArgumentNullException(nameof(moduleInstance));
            //
            blockStatements[0] = CreateNullCheckExpression <IReactInstance>(moduleInstanceParameter);

            //
            // if (reactInstance == null)
            //     throw new ArgumentNullException(nameof(reactInstance));
            //
            blockStatements[1] = CreateNullCheckExpression <IReactInstance>(reactInstanceParameter);

            //
            // if (jsArguments == null)
            //     throw new ArgumentNullException(nameof(jsArguments));
            //
            blockStatements[2] = CreateNullCheckExpression <JArray>(jsArgumentsParameter);

            //
            // if (jsArguments.Count != argc)
            //     throw new NativeArgumentsParseException(
            //         string.Format(
            //             CultureInfo.InvariantCulture,
            //             "Module '{module.Name}' method '{method.Name}' got '{0}' arguments, expected '{parameterCount}'."
            //             jsArguments.Count));
            //
            blockStatements[3] = Expression.IfThen(
                Expression.NotEqual(
                    Expression.MakeMemberAccess(jsArgumentsParameter, s_countProperty),
                    Expression.Constant(argc)
                    ),
                Expression.Throw(
                    Expression.New(
                        s_newNativeArgumentParseException,
                        Expression.Call(
                            s_stringFormat,
                            Expression.Constant(CultureInfo.InvariantCulture),
                            Expression.Constant(
                                $"Module '{module.Name}' method '{method.Name}' got '{{0}}' arguments, expected '{argc}'."
                                ),
                            Expression.Convert(
                                Expression.MakeMemberAccess(jsArgumentsParameter, s_countProperty),
                                typeof(object)
                                )
                            ),
                        Expression.Constant(jsArgumentsParameter.Name)
                        )
                    )
                );

            //
            // p0 = Extract<T>(jsArguments[0]);
            // p1 = Extract<T>(jsArguments[1]);
            // ...
            // pn = Extract<T>(jsArguments[n]);
            //
            Array.Copy(extractExpressions, 0, blockStatements, 4, n);

            blockStatements[blockStatements.Length - 1] = Expression.Call(
                Expression.Convert(moduleInstanceParameter, method.DeclaringType),
                method,
                parameterExpressions);

            return(Expression.Lambda <Action <INativeModule, IReactInstance, JArray> >(
                       Expression.Block(parameterExpressions, blockStatements),
                       moduleInstanceParameter,
                       reactInstanceParameter,
                       jsArgumentsParameter
                       ));
        }
コード例 #20
0
 /// <summary>
 /// Create an invocation delegate from the given method.
 /// </summary>
 /// <param name="nativeModule">The native module instance.</param>
 /// <param name="method">The method.</param>
 /// <returns>The invocation delegate.</returns>
 public abstract Func <IReactInstance, JArray, JToken> Create(INativeModule nativeModule, MethodInfo method);