1/* 2* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd. 3* Licensed under the Apache License, Version 2.0 (the "License"); 4* you may not use this file except in compliance with the License. 5* You may obtain a copy of the License at 6* 7* http://www.apache.org/licenses/LICENSE-2.0 8* 9* Unless required by applicable law or agreed to in writing, software 10* distributed under the License is distributed on an "AS IS" BASIS, 11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12* See the License for the specific language governing permissions and 13* limitations under the License. 14*/ 15const { replaceAll } = require("../tools/tool"); 16const { eventParamGenerate } = require("./param_generate"); 17const { returnGenerate } = require("./return_generate"); 18const { cToJs } = require("./return_generate"); 19 20/** 21 * on和off接口生成模板 22 */ 23let funcOnOffTemplete = ` 24struct [funcName]_value_struct { 25 std::string eventName; 26}; 27 28[static_define]napi_value [funcName]_middle(napi_env env, napi_callback_info info) 29{ 30 XNapiTool *pxt = std::make_unique<XNapiTool>(env, info).release(); 31 if (pxt->IsFailed()) { 32 napi_value err = pxt->GetError(); 33 delete pxt; 34 return err; 35 } 36 [unwarp_instance] 37 struct [funcName]_value_struct *vio = new [funcName]_value_struct(); 38 pxt->SwapJs2CUtf8(pxt->GetArgv(XNapiTool::ZERO), vio->eventName); 39 [handleRegist] 40 [instance][funcName](vio->eventName); 41 napi_value result = pxt->UndefinedValue(); 42 delete vio; 43 if (pxt->IsFailed()) { 44 result = pxt->GetError(); 45 } 46 delete pxt; // release 47 return result; 48} 49` 50 51let middleAsyncCallbackTemplate = ` 52void AsyncCallback(const std::string &eventName, [callback_param_type] &ret) 53{ 54 if(XNapiTool::asyncFuncs_.count(eventName) <= 0) { 55 return; 56 } 57 AsyncFunc *pAsyncFuncs = &XNapiTool::asyncFuncs_[eventName]; 58 napi_value exports = nullptr; 59 XNapiTool *pxt = std::make_unique<XNapiTool>(pAsyncFuncs->env_, exports).release(); 60 [native_return] 61 XNapiTool::CallAsyncFunc(pAsyncFuncs, napiRet); 62 delete pxt; 63} 64` 65 66let middleEventCallbakTemplate = ` 67void [eventName]Callback([callback_param_type] &ret) { 68 AsyncCallback("[eventName]", ret); 69} 70` 71let implHEventCallbakTemplate = ` 72void [eventName]Callback([callback_param_type] &ret); 73` 74 75function isOnTypeExist(onTypeList, newType) { 76 if (!onTypeList) { 77 return false 78 } 79 80 for (var i in onTypeList) { 81 if (onTypeList[i] == newType) { 82 return true 83 } 84 } 85 return false 86} 87 88function addOnTypeToList(data, newType) { 89 if (!data.onTypeList) { 90 data.onTypeList = [] 91 } 92 93 data.onTypeList.push(newType) 94} 95 96function isOnOffFuncExist(data, funcName) { 97 return data.onOffList && data.onOffList.indexOf(funcName) > -1 98} 99 100function addOnOffFunc(data, funcName) { 101 if (!data.onOffList) { 102 data.onOffList = [] 103 } 104 data.onOffList.push(funcName) 105} 106 107function gennerateOnOffContext(codeContext, func, data, className, param) { 108 codeContext.middleFunc = replaceAll(funcOnOffTemplete, "[funcName]", func.name) 109 if (className == null) { 110 codeContext.middleFunc = codeContext.middleFunc.replaceAll("[static_define]", "") 111 codeContext.middleFunc = codeContext.middleFunc.replaceAll("[unwarp_instance]", "") 112 } 113 else { 114 codeContext.middleFunc = codeContext.middleFunc.replaceAll("[static_define]", "static ") 115 codeContext.middleFunc = codeContext.middleFunc.replaceAll("[unwarp_instance]", 116 `void *instPtr = pxt->UnWarpInstance(); 117 %s *pInstance = static_cast<%s *>(instPtr);`.format(className, className)) 118 } 119 let instancePtr = "%s".format(className == null ? "" : "pInstance->") 120 codeContext.middleFunc = replaceAll(codeContext.middleFunc, "[instance]", instancePtr) //执行 121 122 let registLine = func.name == 'on' ? "pxt->RegistAsyncFunc(vio->eventName, pxt->GetArgv(XNapiTool::ONE));" 123 : "pxt->UnregistAsyncFunc(vio->eventName);" 124 codeContext.middleFunc = replaceAll(codeContext.middleFunc, "[handleRegist]", registLine) //注册/去注册event 125 126 codeContext.implH += "\nbool %s(%s);".format(func.name, param.valueDefine) 127 codeContext.implCpp += ` 128bool %s%s(%s) 129{ 130return true; 131} 132`.format(className == null ? "" : className + "::", func.name, param.valueDefine) 133 134 addOnOffFunc(data, func.name) 135} 136 137function gennerateEventCallback(codeContext, data, param) { 138 returnGenerate(param.callback, param) 139 let paramType = param.valueOut.substring(0, param.valueOut.length - "out;".length) 140 let realParamType = paramType.substring(0, 12) == "NUMBER_TYPE_" ? "uint32_t" : paramType 141 if (!isOnTypeExist(data.onTypeList, realParamType)) { 142 // 为每种callback参数类型的on方法生成一个统一回调方法 143 let nativeReturn = cToJs("ret", param.callback.type, "napi_value napiRet") 144 let callbackFunc = replaceAll(middleAsyncCallbackTemplate, "[callback_param_type]", realParamType) 145 callbackFunc = replaceAll(callbackFunc, "[native_return]", nativeReturn) 146 codeContext.middleFunc += callbackFunc 147 addOnTypeToList(data, realParamType) 148 } 149 150 // 为每个on的event事件生成回调方法 151 let middleEventCallBack = replaceAll(middleEventCallbakTemplate, "[eventName]", param.eventName) 152 middleEventCallBack = replaceAll(middleEventCallBack, "[callback_param_type]", realParamType) 153 codeContext.middleFunc += middleEventCallBack; 154 155 // 为每个on的event事件生成回调接口供用户侧使用 156 let implHCallBack = replaceAll(implHEventCallbakTemplate, "[eventName]", param.eventName) 157 implHCallBack = replaceAll(implHCallBack, "[callback_param_type]", paramType) 158 codeContext.implH += implHCallBack 159} 160 161function generateFunctionOnOff(func, data, className) { 162 let param = { 163 valueIn: "", // 定义输入 164 valueOut: "", // 定义输出 165 valueCheckout: "", // 解析 166 valueFill: "", // 填充到函数内 167 valuePackage: "", // 输出参数打包 168 valueDefine: "", // impl参数定义 169 eventName:"", // 注册/去注册事件名称 170 optionalParamDestory: "" // 可选参数内存释放 171 } 172 173 for (let i in func.value) { 174 eventParamGenerate(i, func.value[i], param, data) 175 } 176 177 let codeContext = { 178 middleFunc: "", 179 implH: "", 180 implCpp: "" 181 } 182 if (!isOnOffFuncExist(data, func.name)) { 183 // 同一个ts文件中所有的on和off 接口只需要生成一份公共的native方法 184 gennerateOnOffContext(codeContext, func, data, className, param) 185 } 186 187 if (func.name == 'on') { 188 // 为每个on接口同步生成eventCallback方法供用户回调使用 189 gennerateEventCallback(codeContext, data, param) 190 } 191 192 return [codeContext.middleFunc, codeContext.implH, codeContext.implCpp] 193} 194 195module.exports = { 196 generateFunctionOnOff 197}