• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device 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  */
15 
16 #include "sa_rust_interface_code_emitter.h"
17 #include "util/file.h"
18 #include "util/logger.h"
19 
20 namespace OHOS {
21 namespace Idl {
22 namespace {
23 const uint32_t WRAP_ANCHOR = 4;
24 }
25 
ResolveDirectory(const std::string & targetDirectory)26 bool SaRustInterfaceCodeEmitter::ResolveDirectory(const std::string &targetDirectory)
27 {
28     directory_ = GetFileParentPath(targetDirectory);
29     if (!File::CreateParentDir(directory_)) {
30         Logger::E("SaRustInterfaceCodeEmitter", "Create '%s' failed!", directory_.c_str());
31         return false;
32     }
33 
34     return true;
35 }
36 
EmitCode()37 void SaRustInterfaceCodeEmitter::EmitCode()
38 {
39     EmitInterfaceHeaderFile();
40     return;
41 }
42 
EmitInterfaceHeaderFile()43 void SaRustInterfaceCodeEmitter::EmitInterfaceHeaderFile()
44 {
45     std::string filePath =
46         File::AdapterPath(StringHelper::Format("%s/%s.rs", directory_.c_str(), interfaceName_.c_str()));
47     File file(filePath, File::WRITE);
48     StringBuilder sb;
49 
50     EmitLicense(sb);
51     EmitHeadMacro(sb);
52     EmitHeaders(sb);
53     sb.Append("\n");
54     EmitCommands(sb);
55     sb.Append("\n");
56     EmitRemoteObject(sb);
57     sb.Append("\n");
58     EmitBrokers(sb);
59     sb.Append("\n");
60     EmitRemoteRequest(sb);
61     sb.Append("\n");
62     EmitStub(sb);
63     sb.Append("\n");
64     EmitProxy(sb);
65 
66     std::string data = sb.ToString();
67     file.WriteData(data.c_str(), data.size());
68     file.Flush();
69     file.Close();
70     return;
71 }
72 
EmitHeaders(StringBuilder & sb) const73 void SaRustInterfaceCodeEmitter::EmitHeaders(StringBuilder &sb) const
74 {
75     EmitCommonHeaders(sb);
76     EmitIPCHeaders(sb);
77     if (EmitCustomHeaders(sb)) {
78         sb.Append("\n");
79     }
80 }
81 
EmitIPCHeaders(StringBuilder & sb) const82 void SaRustInterfaceCodeEmitter::EmitIPCHeaders(StringBuilder &sb) const
83 {
84     sb.Append("extern crate ipc_rust;\n");
85     sb.Append("\n");
86     sb.Append("use ipc_rust::{\n");
87     sb.Append("    IRemoteBroker, IRemoteObj, RemoteStub, Result,\n");
88     sb.Append("    RemoteObj, define_remote_object, FIRST_CALL_TRANSACTION\n");
89     sb.Append("};\n");
90     sb.Append("use ipc_rust::{MsgParcel, BorrowedMsgParcel};\n");
91     sb.Append("\n");
92 }
93 
EmitCustomHeaders(StringBuilder & sb) const94 bool SaRustInterfaceCodeEmitter::EmitCustomHeaders(StringBuilder &sb) const
95 {
96     uint32_t custom = false;
97     int sequenceableNumber = static_cast<int>(ast_->GetSequenceableDefNumber());
98     for (int i = 0; i < sequenceableNumber; i++) {
99         AutoPtr<ASTSequenceableType> seqType = ast_->GetSequenceableDef(i);
100         bool addPathMsRes = AppendRealPath(sb, seqType->GetFullName());
101         custom |= static_cast<uint32_t>(addPathMsRes);
102     }
103 
104     for (auto interface : ast_->GetInterfaceDefs()) {
105         if (interface->IsExternal()) {
106             bool addPathMiRes = AppendRealPath(sb, interface->GetFullName());
107             custom |= static_cast<uint32_t>(addPathMiRes);
108         }
109     }
110     return static_cast<bool>(custom);
111 }
112 
AppendRealPath(StringBuilder & sb,const std::string & fpnpp) const113 bool SaRustInterfaceCodeEmitter::AppendRealPath(StringBuilder& sb, const std::string &fpnpp) const
114 {
115     std::string result = GeneratePath(fpnpp);
116     if (result.empty()) {
117         return false;
118     }
119     sb.Append("use ").Append(result).Append(";\n");
120     return true;
121 }
122 
GeneratePath(const std::string & fpnp) const123 std::string SaRustInterfaceCodeEmitter::GeneratePath(const std::string &fpnp) const
124 {
125     size_t pos = fpnp.rfind("..");
126     if (pos == std::string::npos) {
127         std::string path = TrimDot(fpnp);
128         if (path.empty()) {
129             return "";
130         }
131         return StringHelper::Replace(path, ".", "::");
132     }
133 
134     std::string path = TrimDot(fpnp.substr(0, pos + 1));
135     std::string file = TrimDot(fpnp.substr(pos));
136     if (path.empty()) {
137         return "";
138     }
139 
140     if ((path.find("..") != std::string::npos) || (file.find("..") != std::string::npos)) {
141         return "";
142     }
143 
144     StringBuilder realPath;
145     realPath.Append(StringHelper::Replace(path, ".", "::")).Append("::{");
146     realPath.Append(StringHelper::Replace(file, ".", ", "));
147     realPath.Append("}");
148 
149     return realPath.ToString();
150 }
151 
TrimDot(const std::string & fpnp) const152 std::string SaRustInterfaceCodeEmitter::TrimDot(const std::string &fpnp) const
153 {
154     if (fpnp.empty()) {
155         return "";
156     }
157 
158     int left = 0;
159     int right = static_cast<int>(fpnp.length()) - 1;
160     while ((fpnp[left] == ' ') || (fpnp[left] == '.')) {
161         left++;
162     }
163 
164     while ((fpnp[right] == ' ') || (fpnp[right] == '.')) {
165         right--;
166     }
167 
168     if (left >= right) {
169         return nullptr;
170     }
171 
172     return fpnp.substr(left, right + 1);
173 }
174 
EmitCommands(StringBuilder & sb) const175 void SaRustInterfaceCodeEmitter::EmitCommands(StringBuilder &sb) const
176 {
177     sb.AppendFormat("pub enum %sCode {\n", interfaceName_.c_str());
178     int methodNumber = static_cast<int>(interface_->GetMethodNumber());
179     for (int i = 0; i < methodNumber; i++) {
180         AutoPtr<ASTMethod> method = interface_->GetMethod(i);
181         if (i == 0) {
182             sb.AppendFormat("    %s  = FIRST_CALL_TRANSACTION,\n", GetCodeFromMethod(method->GetName()).c_str());
183         } else {
184             sb.AppendFormat("    %s,\n", GetCodeFromMethod(method->GetName()).c_str());
185         }
186     }
187     sb.Append("}\n");
188 }
189 
GetCodeFromMethod(const std::string & name) const190 std::string SaRustInterfaceCodeEmitter::GetCodeFromMethod(const std::string &name) const
191 {
192     StringBuilder sb;
193     std::string result = name;
194     bool hasUpper = false;
195 
196     sb.Append("Code");
197     for (size_t i = 0; i < result.size(); i++) {
198         if (result[i] != '_') {
199             if (!hasUpper) {
200                 sb.Append(toupper(result[i]));
201                 hasUpper = true;
202             } else {
203                 sb.Append(result[i]);
204             }
205         } else {
206             hasUpper = false;
207         }
208     }
209     return sb.ToString();
210 }
211 
EmitRemoteObject(StringBuilder & sb) const212 void SaRustInterfaceCodeEmitter::EmitRemoteObject(StringBuilder &sb) const
213 {
214     sb.Append("define_remote_object!(\n");
215     if (StringHelper::StartWith(interfaceFullName_, ".")) {
216         sb.AppendFormat("    %s[\"%s\"] {\n", interfaceName_.c_str(), interfaceName_.c_str());
217     } else {
218         sb.AppendFormat("    %s[\"%s\"] {\n", interfaceName_.c_str(), interfaceFullName_.c_str());
219     }
220     sb.AppendFormat("        stub: %s(on_remote_request),\n", stubName_.c_str());
221     sb.AppendFormat("        proxy: %s,\n", proxyName_.c_str());
222     sb.Append("    }\n");
223     sb.Append(");\n");
224 }
225 
EmitBrokers(StringBuilder & sb) const226 void SaRustInterfaceCodeEmitter::EmitBrokers(StringBuilder &sb) const
227 {
228     sb.AppendFormat("pub trait %s: IRemoteBroker {\n", interfaceName_.c_str());
229     int methodNumber = static_cast<int>(interface_->GetMethodNumber());
230     for (int i = 0; i < methodNumber; i++) {
231         AutoPtr<ASTMethod> method = interface_->GetMethod(i);
232         sb.AppendFormat("    fn %s(&self", method->GetName().c_str());
233         AppendBrokerParameters(sb, method);
234         AutoPtr<SaTypeEmitter> typeEmitter = GetTypeEmitter(method->GetReturnType());
235         if (typeEmitter != nullptr) {
236             sb.AppendFormat(") -> Result<%s>;\n", typeEmitter->EmitRustType().c_str());
237         }
238     }
239     sb.Append("}\n");
240 }
241 
AppendBrokerParameters(StringBuilder & sb,AutoPtr<ASTMethod> & method) const242 void SaRustInterfaceCodeEmitter::AppendBrokerParameters(StringBuilder &sb, AutoPtr<ASTMethod> &method) const
243 {
244     int paramNumber = static_cast<int>(method->GetParameterNumber());
245     for (int i = 0; i < paramNumber; i++) {
246         WrapLine(sb, i, "        ");
247         AutoPtr<ASTParameter> param = method->GetParameter(i);
248         AutoPtr<SaTypeEmitter> typeEmitter = GetTypeEmitter(param->GetType());
249         if (typeEmitter != nullptr) {
250             sb.AppendFormat("%s: &%s", GetNameFromParameter(param->GetName()).c_str(),
251                 typeEmitter->EmitRustType(true).c_str());
252         }
253     }
254 }
255 
WrapLine(StringBuilder & sb,int index,const std::string & prefix) const256 void SaRustInterfaceCodeEmitter::WrapLine(StringBuilder &sb, int index, const std::string &prefix) const
257 {
258     if ((index + 1) % WRAP_ANCHOR == 0) {
259         sb.AppendFormat(",\n%s", prefix.c_str());
260     } else {
261         sb.Append(", ");
262     }
263 }
264 
GetNameFromParameter(const std::string & name) const265 std::string SaRustInterfaceCodeEmitter::GetNameFromParameter(const std::string &name) const
266 {
267     StringBuilder sb;
268     std::string result = name;
269     bool start = true;
270     for (size_t i = 0; i < result.size(); i++) {
271         if (start) {
272             if (isupper(result[i])) {
273                 sb.Append('p');
274             }
275             start = false;
276         }
277 
278         if (isupper(result[i])) {
279             sb.Append('_');
280             sb.Append(tolower(result[i]));
281         } else {
282             sb.Append(result[i]);
283         }
284     }
285     return sb.ToString();
286 }
287 
EmitRemoteRequest(StringBuilder & sb) const288 void SaRustInterfaceCodeEmitter::EmitRemoteRequest(StringBuilder &sb) const
289 {
290     sb.AppendFormat("fn on_remote_request(stub: &dyn %s, code: u32, data: &BorrowedMsgParcel,\n",
291         interfaceName_.c_str());
292     sb.Append("    reply: &mut BorrowedMsgParcel) -> Result<()> {\n");
293     sb.Append("    match code {\n");
294     AddRemoteRequestMethods(sb);
295     sb.Append("        _ => Err(-1)\n");
296     sb.Append("    }\n");
297     sb.Append("}\n");
298 }
299 
AddRemoteRequestMethods(StringBuilder & sb) const300 void SaRustInterfaceCodeEmitter::AddRemoteRequestMethods(StringBuilder &sb) const
301 {
302     int methodNumber = static_cast<int>(interface_->GetMethodNumber());
303     for (int i = 0; i < methodNumber; i++) {
304         AutoPtr<ASTMethod> method = interface_->GetMethod(i);
305         sb.AppendFormat("        %d => {\n", i + 1);
306         int paramNumber = static_cast<int>(method->GetParameterNumber());
307         for (int j = 0; j < paramNumber; j++) {
308             AutoPtr<ASTParameter> param = method->GetParameter(j);
309             AutoPtr<SaTypeEmitter> typeEmitter = GetTypeEmitter(param->GetType());
310             if (typeEmitter != nullptr) {
311                 typeEmitter->EmitRustReadVar("data", GetNameFromParameter(param->GetName()), sb, "            ");
312             }
313         }
314         AutoPtr<ASTType> returnType = method->GetReturnType();
315         TypeKind retTypeKind = returnType->GetTypeKind();
316         if ((retTypeKind != TypeKind::TYPE_UNKNOWN) && (retTypeKind != TypeKind::TYPE_VOID)) {
317             sb.AppendFormat("            let result = stub.%s(", method->GetName().c_str());
318         } else {
319             sb.AppendFormat("            stub.%s(", method->GetName().c_str());
320         }
321         AddRemoteRequestParameters(sb, method);
322         sb.Append(")?;\n");
323         if ((retTypeKind != TypeKind::TYPE_UNKNOWN) && (retTypeKind != TypeKind::TYPE_VOID)) {
324             AutoPtr<SaTypeEmitter> typeEmitter = GetTypeEmitter(returnType);
325             typeEmitter->EmitRustWriteVar("reply", "result", sb, "            ");
326         }
327         sb.Append("            Ok(())\n");
328         sb.Append("        }\n");
329     }
330 }
331 
AddRemoteRequestParameters(StringBuilder & sb,AutoPtr<ASTMethod> & method) const332 void SaRustInterfaceCodeEmitter::AddRemoteRequestParameters(StringBuilder &sb, AutoPtr<ASTMethod> &method) const
333 {
334     int paramNumber = static_cast<int>(method->GetParameterNumber());
335     for (int i = 0; i < paramNumber; i++) {
336         AutoPtr<ASTParameter> param = method->GetParameter(i);
337         sb.AppendFormat("&%s", GetNameFromParameter(param->GetName()).c_str());
338         if (i + 1 != paramNumber) {
339             WrapLine(sb, i, "                ");
340         }
341     }
342 }
343 
EmitStub(StringBuilder & sb) const344 void SaRustInterfaceCodeEmitter::EmitStub(StringBuilder &sb) const
345 {
346     sb.AppendFormat("impl %s for RemoteStub<%s> {\n", interfaceName_.c_str(), stubName_.c_str());
347     int methodNumber = static_cast<int>(interface_->GetMethodNumber());
348     for (int i = 0; i < methodNumber; i++) {
349         AutoPtr<ASTMethod> method = interface_->GetMethod(i);
350         sb.AppendFormat("    fn %s(&self", method->GetName().c_str());
351         AppendBrokerParameters(sb, method);
352         AutoPtr<ASTType> returnType = method->GetReturnType();
353         AutoPtr<SaTypeEmitter> typeEmitter = GetTypeEmitter(returnType);
354         if (typeEmitter == nullptr) {
355             return;
356         }
357         sb.AppendFormat(") -> Result<%s> {\n", typeEmitter->EmitRustType().c_str());
358         sb.AppendFormat("        self.0.%s(", method->GetName().c_str());
359         AppendStubParameters(sb, method);
360         sb.Append(")\n");
361         sb.Append("    }\n");
362         if (i != methodNumber - 1) {
363             sb.Append("\n");
364         }
365     }
366     sb.Append("}\n");
367 }
368 
AppendStubParameters(StringBuilder & sb,AutoPtr<ASTMethod> & method) const369 void SaRustInterfaceCodeEmitter::AppendStubParameters(StringBuilder &sb, AutoPtr<ASTMethod> &method) const
370 {
371     int paramNumber = static_cast<int>(method->GetParameterNumber());
372     for (int i = 0; i < paramNumber; i++) {
373         AutoPtr<ASTParameter> param = method->GetParameter(i);
374         sb.Append(GetNameFromParameter(param->GetName()));
375         if (i + 1 != paramNumber) {
376             WrapLine(sb, i, "                ");
377         }
378     }
379 }
380 
EmitProxy(StringBuilder & sb) const381 void SaRustInterfaceCodeEmitter::EmitProxy(StringBuilder &sb) const
382 {
383     sb.AppendFormat("impl %s for %s {\n", interfaceName_.c_str(), proxyName_.c_str());
384     int methodNumber = static_cast<int>(interface_->GetMethodNumber());
385     for (int i = 0; i < methodNumber; i++) {
386         AutoPtr<ASTMethod> method = interface_->GetMethod(i);
387         EmitProxyMethodImpl(method, sb);
388         if (i != methodNumber - 1) {
389             sb.Append("\n");
390         }
391     }
392     sb.Append("}\n");
393 }
394 
EmitProxyMethodImpl(AutoPtr<ASTMethod> & method,StringBuilder & sb) const395 void SaRustInterfaceCodeEmitter::EmitProxyMethodImpl(AutoPtr<ASTMethod> &method, StringBuilder &sb) const
396 {
397     sb.AppendFormat("    fn %s(&self", method->GetName().c_str());
398     AppendBrokerParameters(sb, method);
399 
400     AutoPtr<ASTType> returnType = method->GetReturnType();
401     AutoPtr<SaTypeEmitter> typeEmitter = GetTypeEmitter(returnType);
402     if (typeEmitter == nullptr) {
403         return;
404     }
405     sb.AppendFormat(") -> Result<%s> {\n", typeEmitter->EmitRustType().c_str());
406     sb.Append("        let mut data = MsgParcel::new().expect(\"MsgParcel should success\");\n");
407     int paramNumber = static_cast<int>(method->GetParameterNumber());
408     for (int j = 0; j < paramNumber; j++) {
409         AutoPtr<ASTParameter> param = method->GetParameter(j);
410         typeEmitter = GetTypeEmitter(param->GetType());
411         if (typeEmitter == nullptr) {
412             return;
413         }
414         typeEmitter->EmitRustWriteVar("data", GetNameFromParameter(param->GetName()), sb, "        ");
415     }
416     TypeKind retTypeKind = returnType->GetTypeKind();
417     if ((retTypeKind == TypeKind::TYPE_UNKNOWN) || (retTypeKind == TypeKind::TYPE_VOID)) {
418         sb.AppendFormat("        let _reply = self.remote.send_request(%sCode", interfaceName_.c_str());
419     } else {
420         sb.AppendFormat("        let reply = self.remote.send_request(%sCode", interfaceName_.c_str());
421     }
422 
423     sb.AppendFormat("::%s as u32, &data, ", GetCodeFromMethod(method->GetName()).c_str());
424     if (method->IsOneWay()) {
425         sb.Append("true");
426     } else {
427         sb.Append("false");
428     }
429     sb.Append(")?;\n");
430     if ((retTypeKind == TypeKind::TYPE_UNKNOWN) || (retTypeKind == TypeKind::TYPE_VOID)) {
431         sb.Append("        ").Append("Ok(())\n");
432     } else {
433         typeEmitter = GetTypeEmitter(returnType);
434         if (typeEmitter == nullptr) {
435             return;
436         }
437         typeEmitter->EmitRustReadVar("reply", "result", sb, "        ");
438         sb.Append("        ").Append("Ok(result)\n");
439     }
440     sb.Append("    }\n");
441 }
442 } // namespace Idl
443 } // namespace OHOS