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