1 /*
2 * Copyright (c) 2023 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 "util/logger.h"
17
18 #include "codegen/rust_code_emitter.h"
19
20 #include "securec.h"
21 #include "util/file.h"
22
23 namespace OHOS {
24 namespace Idl {
25 namespace {
26 const uint32_t WRAP_ANCHOR = 4;
27 }
28
EmitInterface()29 void RustCodeEmitter::EmitInterface()
30 {
31 String filePath = String::Format("%s/%s.rs", directory_.string(), interfaceName_.string());
32 File file(filePath, File::WRITE);
33 StringBuilder sb;
34 EmitInterface(sb);
35 String data = sb.ToString();
36 file.WriteData(data.string(), data.GetLength());
37 file.Flush();
38 file.Close();
39 }
40
EmitInterfaceProxy()41 void RustCodeEmitter::EmitInterfaceProxy()
42 {
43 return;
44 }
45
EmitInterfaceStub()46 void RustCodeEmitter::EmitInterfaceStub()
47 {
48 return;
49 }
50
EmitInterface(StringBuilder & sb)51 void RustCodeEmitter::EmitInterface(StringBuilder& sb)
52 {
53 if (metaInterface_->license_) {
54 EmitLicense(sb);
55 sb.Append("\n");
56 }
57 EmitMacros(sb);
58 EmitHeaders(sb);
59 sb.Append("\n");
60 EmitCommands(sb);
61 sb.Append("\n");
62 EmitRemoteObject(sb);
63 sb.Append("\n");
64 EmitBrokers(sb);
65 sb.Append("\n");
66 EmitRemoteRequest(sb);
67 sb.Append("\n");
68 EmitStub(sb);
69 sb.Append("\n");
70 EmitProxy(sb);
71 }
72
EmitLicense(StringBuilder & sb)73 void RustCodeEmitter::EmitLicense(StringBuilder& sb)
74 {
75 sb.Append(metaInterface_->license_).Append("\n");
76 }
77
EmitMacros(StringBuilder & sb)78 void RustCodeEmitter::EmitMacros(StringBuilder& sb)
79 {
80 sb.Append("#![allow(missing_docs)]\n");
81 sb.Append("#![allow(unused_variables)]\n");
82 sb.Append("#![allow(unused_mut)]\n");
83 sb.Append("\n");
84 }
EmitHeaders(StringBuilder & sb)85 void RustCodeEmitter::EmitHeaders(StringBuilder& sb)
86 {
87 EmitCommonHeaders(sb);
88 EmitIPCHeaders(sb);
89 if (EmitCustomHeaders(sb)) {
90 sb.Append("\n");
91 }
92 }
93
EmitIPCHeaders(StringBuilder & sb)94 void RustCodeEmitter::EmitIPCHeaders(StringBuilder& sb)
95 {
96 sb.Append("extern crate ipc_rust;\n");
97 sb.Append("\n");
98 sb.Append("use ipc_rust::{\n");
99 sb.Append(" IRemoteBroker, IRemoteObj, RemoteStub, Result,\n");
100 sb.Append(" RemoteObj, define_remote_object, FIRST_CALL_TRANSACTION\n");
101 sb.Append("};\n");
102 sb.Append("use ipc_rust::{MsgParcel, BorrowedMsgParcel};\n");
103 sb.Append("\n");
104 }
105
EmitCommonHeaders(StringBuilder & sb)106 void RustCodeEmitter::EmitCommonHeaders(StringBuilder& sb)
107 {
108 bool useMap = false;
109 for (int i = 0; i < metaComponent_->typeNumber_; i++) {
110 MetaType* mt = metaComponent_->types_[i];
111 switch (mt->kind_) {
112 case TypeKind::Map: {
113 if (!useMap) {
114 sb.Append("use std::collections::HashMap;\n");
115 useMap = true;
116 }
117 break;
118 }
119
120 default:
121 break;
122 }
123 }
124 if (useMap) {
125 sb.Append("\n");
126 }
127 }
128
TrimDot(const String & fpnp)129 String RustCodeEmitter::TrimDot(const String& fpnp)
130 {
131 if (fpnp.IsEmpty()) {
132 return nullptr;
133 }
134
135 int left = 0;
136 int right = fpnp.GetLength() - 1;
137 while (fpnp[left] == ' ' || fpnp[left] == '.') {
138 left++;
139 }
140
141 while (fpnp[right] == ' ' || fpnp[right] == '.') {
142 right--;
143 }
144
145 if (left >= right) {
146 return nullptr;
147 }
148
149 return fpnp.Substring(left, right + 1);
150 }
151
GeneratePath(const String & fpnp)152 String RustCodeEmitter::GeneratePath(const String& fpnp)
153 {
154 int pos = fpnp.IndexOf("..");
155 if (pos == -1) {
156 String path = TrimDot(fpnp);
157 if (path.IsEmpty()) {
158 return nullptr;
159 }
160 return path.Replace(".", "::");
161 }
162
163 String path = TrimDot(fpnp.Substring(0, pos + 1));
164 String file = TrimDot(fpnp.Substring(pos));
165 if (path.IsEmpty()) {
166 return nullptr;
167 }
168
169 if (path.IndexOf("..") != -1 || file.IndexOf("..") != -1) {
170 return nullptr;
171 }
172
173 StringBuilder realPath;
174 realPath.Append(path.Replace(".", "::")).Append("::{");
175 realPath.Append(file.Replace(".", ", "));
176 realPath.Append("}");
177
178 return realPath.ToString();
179 }
180
AppendRealPath(StringBuilder & sb,const String & fpnpp)181 bool RustCodeEmitter::AppendRealPath(StringBuilder& sb, const String& fpnpp)
182 {
183 String result = GeneratePath(fpnpp);
184 if (result.IsEmpty()) {
185 return false;
186 }
187 sb.Append("use ").Append(result).Append(";\n");
188 return true;
189 }
190
EmitCustomHeaders(StringBuilder & sb)191 bool RustCodeEmitter::EmitCustomHeaders(StringBuilder& sb)
192 {
193 uint32_t custom = false;
194 for (int i = 0; i < metaComponent_->sequenceableNumber_; i++) {
195 MetaSequenceable* ms = metaComponent_->sequenceables_[i];
196 bool addPathMsRes = AppendRealPath(sb, String(ms->namespace_) + String(ms->name_));
197 custom |= static_cast<uint32_t>(addPathMsRes);
198 }
199
200 for (int i = 0; i < metaComponent_->interfaceNumber_; i++) {
201 MetaInterface* mi = metaComponent_->interfaces_[i];
202 if (mi->external_) {
203 bool addPathMiRes = AppendRealPath(sb, String(mi->namespace_) + String(mi->name_));
204 custom |= static_cast<uint32_t>(addPathMiRes);
205 }
206 }
207 return static_cast<bool>(custom);
208 }
209
EmitCommands(StringBuilder & sb)210 void RustCodeEmitter::EmitCommands(StringBuilder& sb)
211 {
212 EmitCommandEnums(sb);
213 }
214
AppendCommandEnums(StringBuilder & sb)215 void RustCodeEmitter::AppendCommandEnums(StringBuilder& sb)
216 {
217 if (metaInterface_->methodNumber_ > 0) {
218 sb.AppendFormat(" %s = FIRST_CALL_TRANSACTION,\n",
219 GetCodeFromMethod(metaInterface_->methods_[0]->name_).string());
220 }
221
222 for (int i = 1; i < metaInterface_->methodNumber_; i++) {
223 MetaMethod* mm = metaInterface_->methods_[i];
224 sb.AppendFormat(" %s,\n", GetCodeFromMethod(mm->name_).string(), i);
225 }
226 }
227
GetCodeFromMethod(const char * name)228 String RustCodeEmitter::GetCodeFromMethod(const char* name)
229 {
230 StringBuilder sb;
231 sb.Append("Code");
232 const char* p = name;
233 bool hasUpper = false;
234 while (p != nullptr && *p != '\0') {
235 if (*p != '_') {
236 if (!hasUpper) {
237 sb.Append(toupper(*p));
238 hasUpper = true;
239 } else {
240 sb.Append(*p);
241 }
242 } else {
243 hasUpper = false;
244 }
245 p++;
246 }
247 return sb.ToString();
248 }
249
GetNameFromParameter(const char * name)250 String RustCodeEmitter::GetNameFromParameter(const char* name)
251 {
252 StringBuilder sb;
253 const char* p = name;
254 bool start = true;
255 while (p != nullptr && *p != '\0') {
256 if (start) {
257 if (isupper(*p)) {
258 sb.Append('p');
259 }
260 start = false;
261 }
262
263 if (isupper(*p)) {
264 sb.Append('_');
265 sb.Append(tolower(*p));
266 } else {
267 sb.Append(*p);
268 }
269 p++;
270 }
271 return sb.ToString();
272 }
273
EmitCommandEnums(StringBuilder & sb)274 void RustCodeEmitter::EmitCommandEnums(StringBuilder& sb)
275 {
276 sb.AppendFormat("pub enum %sCode {\n", interfaceName_.string());
277 AppendCommandEnums(sb);
278 sb.Append("}\n");
279 }
280
EmitRemoteObject(StringBuilder & sb)281 void RustCodeEmitter::EmitRemoteObject(StringBuilder& sb)
282 {
283 sb.Append("define_remote_object!(\n");
284 if (interfaceFullName_.StartsWith(".")) {
285 sb.AppendFormat(" %s[\"%s\"] {\n", interfaceName_.string(), interfaceName_.string());
286 } else {
287 sb.AppendFormat(" %s[\"%s\"] {\n", interfaceName_.string(), interfaceFullName_.string());
288 }
289 sb.AppendFormat(" stub: %s(on_remote_request),\n", stubName_.string());
290 sb.AppendFormat(" proxy: %s,\n", proxyName_.string());
291 sb.Append(" }\n");
292 sb.Append(");\n");
293 }
294
EmitBrokers(StringBuilder & sb)295 void RustCodeEmitter::EmitBrokers(StringBuilder& sb)
296 {
297 sb.AppendFormat("pub trait %s: IRemoteBroker {\n", interfaceName_.string());
298 AppendBrokerMethods(sb);
299 sb.Append("}\n");
300 }
301
WrapLine(StringBuilder & sb,int index,const String & prefix)302 void RustCodeEmitter::WrapLine(StringBuilder& sb, int index, const String& prefix)
303 {
304 if ((index + 1) % WRAP_ANCHOR == 0) {
305 sb.AppendFormat(",\n%s", prefix.string());
306 } else {
307 sb.Append(", ");
308 }
309 }
310
AppendBrokerMethods(StringBuilder & sb)311 void RustCodeEmitter::AppendBrokerMethods(StringBuilder& sb)
312 {
313 for (int i = 0; i < metaInterface_->methodNumber_; i++) {
314 MetaMethod* mm = metaInterface_->methods_[i];
315 sb.AppendFormat(" fn %s(&self", mm->name_);
316 for (int i = 0; i < mm->parameterNumber_; i++) {
317 WrapLine(sb, i, " ");
318 AppendBrokerParameters(sb, mm->parameters_[i]);
319 }
320 sb.AppendFormat(") -> Result<%s>;\n", ConvertType(metaComponent_->types_[mm->returnTypeIndex_]).string());
321 }
322 }
323
AppendBrokerParameters(StringBuilder & sb,MetaParameter * mp)324 void RustCodeEmitter::AppendBrokerParameters(StringBuilder& sb, MetaParameter* mp)
325 {
326 sb.AppendFormat("%s: &%s",
327 GetNameFromParameter(mp->name_).string(), ConvertType(metaComponent_->types_[mp->typeIndex_], true).string());
328 }
329
ConvertType(MetaType * mt,bool pt)330 String RustCodeEmitter::ConvertType(MetaType* mt, bool pt)
331 {
332 switch (mt->kind_) {
333 case TypeKind::Unknown:
334 case TypeKind::Void:
335 return "()";
336 case TypeKind::Char:
337 return "char";
338 case TypeKind::Boolean:
339 return "bool";
340 case TypeKind::Byte:
341 return "i8";
342 case TypeKind::Short:
343 return "i16";
344 case TypeKind::Integer:
345 return "i32";
346 case TypeKind::Long:
347 return "i64";
348 case TypeKind::Float:
349 return "f32";
350 case TypeKind::Double:
351 return "f64";
352 case TypeKind::String:
353 return pt ? "str" : "String";
354 case TypeKind::Sequenceable:
355 return metaComponent_->sequenceables_[mt->index_]->name_;
356 case TypeKind::Interface:
357 return metaComponent_->interfaces_[mt->index_]->name_;
358 case TypeKind::Map:
359 return String::Format("HashMap<%s, %s>",
360 ConvertType(metaComponent_->types_[mt->nestedTypeIndexes_[0]]).string(),
361 ConvertType(metaComponent_->types_[mt->nestedTypeIndexes_[1]]).string());
362 case TypeKind::List:
363 case TypeKind::Array:
364 return String::Format((pt ? "[%s]" : "Vec<%s>"),
365 ConvertType(metaComponent_->types_[mt->nestedTypeIndexes_[0]]).string());
366 default:
367 return "()";
368 }
369 }
370
EmitRemoteRequest(StringBuilder & sb)371 void RustCodeEmitter::EmitRemoteRequest(StringBuilder& sb)
372 {
373 sb.AppendFormat("fn on_remote_request(stub: &dyn %s, code: u32, data: &BorrowedMsgParcel,\n",
374 interfaceName_.string());
375 sb.Append(" reply: &mut BorrowedMsgParcel) -> Result<()> {\n");
376 sb.Append(" match code {\n");
377 AddRemoteRequestMethods(sb);
378 sb.Append(" _ => Err(-1)\n");
379 sb.Append(" }\n");
380 sb.Append("}\n");
381 }
382
AddRemoteRequestParameters(StringBuilder & sb,MetaMethod * mm)383 void RustCodeEmitter::AddRemoteRequestParameters(StringBuilder& sb, MetaMethod* mm)
384 {
385 for (int i = 0; i < mm->parameterNumber_; i++) {
386 MetaParameter* mp = mm->parameters_[i];
387 sb.AppendFormat("&%s", GetNameFromParameter(mp->name_).string());
388 if (i + 1 != mm->parameterNumber_) {
389 WrapLine(sb, i, " ");
390 }
391 }
392 }
393
ReadListFromParcel(StringBuilder & sb,MetaType * mt,const String & result,const String & name,const String & prefix)394 void RustCodeEmitter::ReadListFromParcel(StringBuilder& sb, MetaType* mt, const String& result,
395 const String& name, const String& prefix)
396 {
397 sb.Append(prefix).AppendFormat("let %s : %s = %s.read()?;\n",
398 name.string(), ConvertType(mt).string(), result.string());
399 }
400
ReadMapFromParcel(StringBuilder & sb,MetaType * mt,const String & result,const String & name,const String & prefix)401 void RustCodeEmitter::ReadMapFromParcel(StringBuilder& sb, MetaType* mt, const String& result,
402 const String& name, const String& prefix)
403 {
404 sb.Append(prefix).AppendFormat("let mut %s = HashMap::new();\n", name.string());
405 sb.Append(prefix).AppendFormat("let len = %s.read()?;\n", result.string());
406 sb.Append(prefix).Append("for i in 0..len {\n");
407 StringBuilder k;
408 StringBuilder v;
409 k.Append(name).Append("k");
410 v.Append(name).Append("v");
411 ReadFromParcel(sb, metaComponent_->types_[mt->nestedTypeIndexes_[0]],
412 result, k.ToString().string(), prefix + " ");
413 ReadFromParcel(sb, metaComponent_->types_[mt->nestedTypeIndexes_[1]],
414 result, v.ToString().string(), prefix + " ");
415 sb.Append(prefix + " ").AppendFormat("%s.insert(%s, %s);\n",
416 name.string(), k.ToString().string(), v.ToString().string());
417 sb.Append(prefix).Append("}\n");
418 }
419
ReadFromParcel(StringBuilder & sb,MetaType * mt,const String & result,const String & name,const String & prefix)420 void RustCodeEmitter::ReadFromParcel(StringBuilder& sb, MetaType* mt, const String& result,
421 const String& name, const String& prefix)
422 {
423 if (mt->kind_ == TypeKind::Map) {
424 ReadMapFromParcel(sb, mt, result, name, prefix);
425 } else if (mt->kind_ == TypeKind::List || mt->kind_ == TypeKind::Array) {
426 ReadListFromParcel(sb, mt, result, name, prefix);
427 } else {
428 sb.Append(prefix).AppendFormat("let %s : %s = %s.read()?;\n",
429 name.string(), ConvertType(mt).string(), result.string());
430 }
431 }
432
WriteListToParcel(StringBuilder & sb,MetaType * mt,const String & result,const String & name,const String & prefix)433 void RustCodeEmitter::WriteListToParcel(StringBuilder& sb, MetaType* mt, const String& result,
434 const String& name, const String& prefix)
435 {
436 sb.Append(prefix).AppendFormat("%s.write(&%s)?;\n", result.string(), name.string());
437 }
438
WriteMapToParcel(StringBuilder & sb,MetaType * mt,const String & result,const String & name,const String & prefix)439 void RustCodeEmitter::WriteMapToParcel(StringBuilder& sb, MetaType* mt, const String& result,
440 const String& name, const String& prefix)
441 {
442 sb.Append(prefix).AppendFormat("%s.write(&(%s.len() as u32))?;\n", result.string(), name.string());
443 sb.Append(prefix).AppendFormat("for (key, value) in %s.iter() {\n", name.string());
444 WriteToParcel(sb, metaComponent_->types_[mt->nestedTypeIndexes_[0]], result, "key", prefix + " ");
445 WriteToParcel(sb, metaComponent_->types_[mt->nestedTypeIndexes_[1]], result, "value", prefix + " ");
446 sb.Append(prefix).Append("}\n");
447 }
448
WriteToParcel(StringBuilder & sb,MetaType * mt,const String & result,const String & name,const String & prefix)449 void RustCodeEmitter::WriteToParcel(StringBuilder& sb, MetaType* mt, const String& result,
450 const String& name, const String& prefix)
451 {
452 if (mt->kind_ == TypeKind::Map) {
453 WriteMapToParcel(sb, mt, result, name, prefix);
454 } else if (mt->kind_ == TypeKind::List || mt->kind_ == TypeKind::Array) {
455 WriteListToParcel(sb, mt, result, name, prefix);
456 } else {
457 sb.Append(prefix).AppendFormat("%s.write(&%s)?;\n", result.string(), name.string());
458 }
459 }
460
AddRemoteRequestMethods(StringBuilder & sb)461 void RustCodeEmitter::AddRemoteRequestMethods(StringBuilder& sb)
462 {
463 for (int i = 0; i < metaInterface_->methodNumber_; i++) {
464 MetaMethod* mm = metaInterface_->methods_[i];
465 sb.AppendFormat(" %d => {\n", i + 1);
466 for (int j = 0; j < mm->parameterNumber_; j++) {
467 ReadFromParcel(sb, metaComponent_->types_[mm->parameters_[j]->typeIndex_], "data",
468 GetNameFromParameter(mm->parameters_[j]->name_), " ");
469 }
470 MetaType* mt = metaComponent_->types_[mm->returnTypeIndex_];
471 if (mt->kind_ != TypeKind::Unknown && mt->kind_ != TypeKind::Void) {
472 sb.AppendFormat(" let result = stub.%s(", mm->name_);
473 } else {
474 sb.AppendFormat(" stub.%s(", mm->name_);
475 }
476 AddRemoteRequestParameters(sb, mm);
477 sb.Append(")?;\n");
478 if (mt->kind_ != TypeKind::Unknown && mt->kind_ != TypeKind::Void) {
479 WriteToParcel(sb, mt, "reply", "result", " ");
480 }
481 sb.Append(" Ok(())\n");
482 sb.Append(" }\n");
483 }
484 }
485
EmitStub(StringBuilder & sb)486 void RustCodeEmitter::EmitStub(StringBuilder& sb)
487 {
488 sb.AppendFormat("impl %s for RemoteStub<%s> {\n", interfaceName_.string(), stubName_.string());
489 AppendStubMethods(sb);
490 sb.Append("}\n");
491 }
492
AppendStubParameters(StringBuilder & sb,MetaMethod * mm)493 void RustCodeEmitter::AppendStubParameters(StringBuilder& sb, MetaMethod* mm)
494 {
495 for (int i = 0; i < mm->parameterNumber_; i++) {
496 sb.Append(GetNameFromParameter(mm->parameters_[i]->name_));
497 if (i + 1 != mm->parameterNumber_) {
498 WrapLine(sb, i, " ");
499 }
500 }
501 }
502
AppendStubMethods(StringBuilder & sb)503 void RustCodeEmitter::AppendStubMethods(StringBuilder& sb)
504 {
505 for (int i = 0; i < metaInterface_->methodNumber_; i++) {
506 MetaMethod* mm = metaInterface_->methods_[i];
507 sb.AppendFormat(" fn %s(&self", mm->name_);
508 for (int i = 0; i < mm->parameterNumber_; i++) {
509 WrapLine(sb, i, " ");
510 AppendBrokerParameters(sb, mm->parameters_[i]);
511 }
512
513 sb.AppendFormat(") -> Result<%s> {\n",
514 ConvertType(metaComponent_->types_[mm->returnTypeIndex_]).string());
515 sb.AppendFormat(" self.0.%s(", mm->name_);
516 AppendStubParameters(sb, mm);
517 sb.Append(")\n");
518 sb.Append(" }\n");
519 if (i != metaInterface_->methodNumber_ - 1) {
520 sb.Append("\n");
521 }
522 }
523 }
524
EmitProxy(StringBuilder & sb)525 void RustCodeEmitter::EmitProxy(StringBuilder& sb)
526 {
527 sb.AppendFormat("impl %s for %s {\n", interfaceName_.string(), proxyName_.string());
528 AppendProxyMethods(sb);
529 sb.Append("}\n");
530 }
531
AppendProxyMethods(StringBuilder & sb)532 void RustCodeEmitter::AppendProxyMethods(StringBuilder& sb)
533 {
534 for (int i = 0; i < metaInterface_->methodNumber_; i++) {
535 MetaMethod* mm = metaInterface_->methods_[i];
536 sb.AppendFormat(" fn %s(&self", mm->name_);
537 for (int i = 0; i < mm->parameterNumber_; i++) {
538 WrapLine(sb, i, " ");
539 AppendBrokerParameters(sb, mm->parameters_[i]);
540 }
541 sb.AppendFormat(") -> Result<%s> {\n",
542 ConvertType(metaComponent_->types_[mm->returnTypeIndex_]).string());
543 sb.Append(" let mut data = MsgParcel::new().expect(\"MsgParcel should success\");\n");
544 for (int j = 0; j < mm->parameterNumber_; j++) {
545 WriteToParcel(sb, metaComponent_->types_[mm->parameters_[j]->typeIndex_], "data",
546 GetNameFromParameter(mm->parameters_[j]->name_), " ");
547 }
548 MetaType* mt = metaComponent_->types_[mm->returnTypeIndex_];
549 if (mt->kind_ == TypeKind::Unknown || mt->kind_ == TypeKind::Void) {
550 sb.AppendFormat(" let _reply = self.remote.send_request(%sCode", interfaceName_.string());
551 } else {
552 sb.AppendFormat(" let reply = self.remote.send_request(%sCode", interfaceName_.string());
553 }
554 sb.AppendFormat("::%s as u32, &data, ", GetCodeFromMethod(mm->name_).string());
555 if ((mm->properties_ & METHOD_PROPERTY_ONEWAY) != 0) {
556 sb.Append("true");
557 } else {
558 sb.Append("false");
559 }
560 sb.Append(")?;\n");
561 if (mt->kind_ == TypeKind::Unknown || mt->kind_ == TypeKind::Void) {
562 sb.Append(" ").Append("Ok(())\n");
563 } else {
564 ReadFromParcel(sb, mt, "reply", "result", " ");
565 sb.Append(" ").Append("Ok(result)\n");
566 }
567 sb.Append(" }\n");
568
569 if (i != metaInterface_->methodNumber_ - 1) {
570 sb.Append("\n");
571 }
572 }
573 }
574 }
575 }
576