/// <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); }
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); }
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); } }
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(); } }
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(); } }
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)); } }
/// <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)); }
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); }
/// <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)); }
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 )); }
/// <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()); }
private static async Task DisposeModuleOnActionQueueAsync(INativeModule module) { await module.ActionQueue.RunAsync(module.DisposeAsync).Unwrap(); module.ActionQueue.Dispose(); }
private static Task DisposeModuleAsync(INativeModule module) { return(module.ActionQueue != null ? DisposeModuleOnActionQueueAsync(module) : module.DisposeAsync()); }
/// <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)); }
/// <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()); }
/// <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);
/// <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()); }
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 )); }
/// <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);