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 bool custom = false;
194 for (int i = 0; i < metaComponent_->sequenceableNumber_; i++) {
195 MetaSequenceable* ms = metaComponent_->sequenceables_[i];
196 custom |= AppendRealPath(sb, String(ms->namespace_) + String(ms->name_));
197 }
198
199 for (int i = 0; i < metaComponent_->interfaceNumber_; i++) {
200 MetaInterface* mi = metaComponent_->interfaces_[i];
201 if (mi->external_) {
202 custom |= AppendRealPath(sb, String(mi->namespace_) + String(mi->name_));
203 }
204 }
205 return custom;
206 }
207
EmitCommands(StringBuilder & sb)208 void RustCodeEmitter::EmitCommands(StringBuilder& sb)
209 {
210 EmitCommandEnums(sb);
211 }
212
AppendCommandEnums(StringBuilder & sb)213 void RustCodeEmitter::AppendCommandEnums(StringBuilder& sb)
214 {
215 if (metaInterface_->methodNumber_ > 0) {
216 sb.AppendFormat(" %s = FIRST_CALL_TRANSACTION,\n",
217 GetCodeFromMethod(metaInterface_->methods_[0]->name_).string());
218 }
219
220 for (int i = 1; i < metaInterface_->methodNumber_; i++) {
221 MetaMethod* mm = metaInterface_->methods_[i];
222 sb.AppendFormat(" %s,\n", GetCodeFromMethod(mm->name_).string(), i);
223 }
224 }
225
GetCodeFromMethod(const char * name)226 String RustCodeEmitter::GetCodeFromMethod(const char* name)
227 {
228 StringBuilder sb;
229 sb.Append("Code");
230 const char* p = name;
231 bool hasUpper = false;
232 while (p != nullptr && *p != '\0') {
233 if (*p != '_') {
234 if (!hasUpper) {
235 sb.Append(toupper(*p));
236 hasUpper = true;
237 } else {
238 sb.Append(*p);
239 }
240 } else {
241 hasUpper = false;
242 }
243 p++;
244 }
245 return sb.ToString();
246 }
247
GetNameFromParameter(const char * name)248 String RustCodeEmitter::GetNameFromParameter(const char* name)
249 {
250 StringBuilder sb;
251 const char* p = name;
252 bool start = true;
253 while (p != nullptr && *p != '\0') {
254 if (start) {
255 if (isupper(*p)) {
256 sb.Append('p');
257 }
258 start = false;
259 }
260
261 if (isupper(*p)) {
262 sb.Append('_');
263 sb.Append(tolower(*p));
264 } else {
265 sb.Append(*p);
266 }
267 p++;
268 }
269 return sb.ToString();
270 }
271
EmitCommandEnums(StringBuilder & sb)272 void RustCodeEmitter::EmitCommandEnums(StringBuilder& sb)
273 {
274 sb.AppendFormat("pub enum %sCode {\n", interfaceName_.string());
275 AppendCommandEnums(sb);
276 sb.Append("}\n");
277 }
278
EmitRemoteObject(StringBuilder & sb)279 void RustCodeEmitter::EmitRemoteObject(StringBuilder& sb)
280 {
281 sb.Append("define_remote_object!(\n");
282 if (interfaceFullName_.StartsWith(".")) {
283 sb.AppendFormat(" %s[\"%s\"] {\n", interfaceName_.string(), interfaceName_.string());
284 } else {
285 sb.AppendFormat(" %s[\"%s\"] {\n", interfaceName_.string(), interfaceFullName_.string());
286 }
287 sb.AppendFormat(" stub: %s(on_remote_request),\n", stubName_.string());
288 sb.AppendFormat(" proxy: %s,\n", proxyName_.string());
289 sb.Append(" }\n");
290 sb.Append(");\n");
291 }
292
EmitBrokers(StringBuilder & sb)293 void RustCodeEmitter::EmitBrokers(StringBuilder& sb)
294 {
295 sb.AppendFormat("pub trait %s: IRemoteBroker {\n", interfaceName_.string());
296 AppendBrokerMethods(sb);
297 sb.Append("}\n");
298 }
299
WrapLine(StringBuilder & sb,int index,const String & prefix)300 void RustCodeEmitter::WrapLine(StringBuilder& sb, int index, const String& prefix)
301 {
302 if ((index + 1) % WRAP_ANCHOR == 0) {
303 sb.AppendFormat(",\n%s", prefix.string());
304 } else {
305 sb.Append(", ");
306 }
307 }
308
AppendBrokerMethods(StringBuilder & sb)309 void RustCodeEmitter::AppendBrokerMethods(StringBuilder& sb)
310 {
311 for (int i = 0; i < metaInterface_->methodNumber_; i++) {
312 MetaMethod* mm = metaInterface_->methods_[i];
313 sb.AppendFormat(" fn %s(&self", mm->name_);
314 for (int i = 0; i < mm->parameterNumber_; i++) {
315 WrapLine(sb, i, " ");
316 AppendBrokerParameters(sb, mm->parameters_[i]);
317 }
318 sb.AppendFormat(") -> Result<%s>;\n", ConvertType(metaComponent_->types_[mm->returnTypeIndex_]).string());
319 }
320 }
321
AppendBrokerParameters(StringBuilder & sb,MetaParameter * mp)322 void RustCodeEmitter::AppendBrokerParameters(StringBuilder& sb, MetaParameter* mp)
323 {
324 sb.AppendFormat("%s: &%s",
325 GetNameFromParameter(mp->name_).string(), ConvertType(metaComponent_->types_[mp->typeIndex_], true).string());
326 }
327
ConvertType(MetaType * mt,bool pt)328 String RustCodeEmitter::ConvertType(MetaType* mt, bool pt)
329 {
330 switch (mt->kind_) {
331 case TypeKind::Unknown:
332 case TypeKind::Void:
333 return "()";
334 case TypeKind::Char:
335 return "char";
336 case TypeKind::Boolean:
337 return "bool";
338 case TypeKind::Byte:
339 return "i8";
340 case TypeKind::Short:
341 return "i16";
342 case TypeKind::Integer:
343 return "i32";
344 case TypeKind::Long:
345 return "i64";
346 case TypeKind::Float:
347 return "f32";
348 case TypeKind::Double:
349 return "f64";
350 case TypeKind::String:
351 return pt ? "str" : "String";
352 case TypeKind::Sequenceable:
353 return metaComponent_->sequenceables_[mt->index_]->name_;
354 case TypeKind::Interface:
355 return metaComponent_->interfaces_[mt->index_]->name_;
356 case TypeKind::Map:
357 return String::Format("HashMap<%s, %s>",
358 ConvertType(metaComponent_->types_[mt->nestedTypeIndexes_[0]]).string(),
359 ConvertType(metaComponent_->types_[mt->nestedTypeIndexes_[1]]).string());
360 case TypeKind::List:
361 case TypeKind::Array:
362 return String::Format((pt ? "[%s]" : "Vec<%s>"),
363 ConvertType(metaComponent_->types_[mt->nestedTypeIndexes_[0]]).string());
364 default:
365 return "()";
366 }
367 }
368
EmitRemoteRequest(StringBuilder & sb)369 void RustCodeEmitter::EmitRemoteRequest(StringBuilder& sb)
370 {
371 sb.AppendFormat("fn on_remote_request(stub: &dyn %s, code: u32, data: &BorrowedMsgParcel,\n",
372 interfaceName_.string());
373 sb.Append(" reply: &mut BorrowedMsgParcel) -> Result<()> {\n");
374 sb.Append(" match code {\n");
375 AddRemoteRequestMethods(sb);
376 sb.Append(" _ => Err(-1)\n");
377 sb.Append(" }\n");
378 sb.Append("}\n");
379 }
380
AddRemoteRequestParameters(StringBuilder & sb,MetaMethod * mm)381 void RustCodeEmitter::AddRemoteRequestParameters(StringBuilder& sb, MetaMethod* mm)
382 {
383 for (int i = 0; i < mm->parameterNumber_; i++) {
384 MetaParameter* mp = mm->parameters_[i];
385 sb.AppendFormat("&%s", GetNameFromParameter(mp->name_).string());
386 if (i + 1 != mm->parameterNumber_) {
387 WrapLine(sb, i, " ");
388 }
389 }
390 }
391
ReadListFromParcel(StringBuilder & sb,MetaType * mt,const String & result,const String & name,const String & prefix)392 void RustCodeEmitter::ReadListFromParcel(StringBuilder& sb, MetaType* mt, const String& result,
393 const String& name, const String& prefix)
394 {
395 sb.Append(prefix).AppendFormat("let %s : %s = %s.read()?;\n",
396 name.string(), ConvertType(mt).string(), result.string());
397 }
398
ReadMapFromParcel(StringBuilder & sb,MetaType * mt,const String & result,const String & name,const String & prefix)399 void RustCodeEmitter::ReadMapFromParcel(StringBuilder& sb, MetaType* mt, const String& result,
400 const String& name, const String& prefix)
401 {
402 sb.Append(prefix).AppendFormat("let mut %s = HashMap::new();\n", name.string());
403 sb.Append(prefix).AppendFormat("let len = %s.read()?;\n", result.string());
404 sb.Append(prefix).Append("for i in 0..len {\n");
405 StringBuilder k;
406 StringBuilder v;
407 k.Append(name).Append("k");
408 v.Append(name).Append("v");
409 ReadFromParcel(sb, metaComponent_->types_[mt->nestedTypeIndexes_[0]],
410 result, k.ToString().string(), prefix + " ");
411 ReadFromParcel(sb, metaComponent_->types_[mt->nestedTypeIndexes_[1]],
412 result, v.ToString().string(), prefix + " ");
413 sb.Append(prefix + " ").AppendFormat("%s.insert(%s, %s);\n",
414 name.string(), k.ToString().string(), v.ToString().string());
415 sb.Append(prefix).Append("}\n");
416 }
417
ReadFromParcel(StringBuilder & sb,MetaType * mt,const String & result,const String & name,const String & prefix)418 void RustCodeEmitter::ReadFromParcel(StringBuilder& sb, MetaType* mt, const String& result,
419 const String& name, const String& prefix)
420 {
421 if (mt->kind_ == TypeKind::Map) {
422 ReadMapFromParcel(sb, mt, result, name, prefix);
423 } else if (mt->kind_ == TypeKind::List || mt->kind_ == TypeKind::Array) {
424 ReadListFromParcel(sb, mt, result, name, prefix);
425 } else {
426 sb.Append(prefix).AppendFormat("let %s : %s = %s.read()?;\n",
427 name.string(), ConvertType(mt).string(), result.string());
428 }
429 }
430
WriteListToParcel(StringBuilder & sb,MetaType * mt,const String & result,const String & name,const String & prefix)431 void RustCodeEmitter::WriteListToParcel(StringBuilder& sb, MetaType* mt, const String& result,
432 const String& name, const String& prefix)
433 {
434 sb.Append(prefix).AppendFormat("%s.write(&%s)?;\n", result.string(), name.string());
435 }
436
WriteMapToParcel(StringBuilder & sb,MetaType * mt,const String & result,const String & name,const String & prefix)437 void RustCodeEmitter::WriteMapToParcel(StringBuilder& sb, MetaType* mt, const String& result,
438 const String& name, const String& prefix)
439 {
440 sb.Append(prefix).AppendFormat("%s.write(&(%s.len() as u32))?;\n", result.string(), name.string());
441 sb.Append(prefix).AppendFormat("for (key, value) in %s.iter() {\n", name.string());
442 WriteToParcel(sb, metaComponent_->types_[mt->nestedTypeIndexes_[0]], result, "key", prefix + " ");
443 WriteToParcel(sb, metaComponent_->types_[mt->nestedTypeIndexes_[1]], result, "value", prefix + " ");
444 sb.Append(prefix).Append("}\n");
445 }
446
WriteToParcel(StringBuilder & sb,MetaType * mt,const String & result,const String & name,const String & prefix)447 void RustCodeEmitter::WriteToParcel(StringBuilder& sb, MetaType* mt, const String& result,
448 const String& name, const String& prefix)
449 {
450 if (mt->kind_ == TypeKind::Map) {
451 WriteMapToParcel(sb, mt, result, name, prefix);
452 } else if (mt->kind_ == TypeKind::List || mt->kind_ == TypeKind::Array) {
453 WriteListToParcel(sb, mt, result, name, prefix);
454 } else {
455 sb.Append(prefix).AppendFormat("%s.write(&%s)?;\n", result.string(), name.string());
456 }
457 }
458
AddRemoteRequestMethods(StringBuilder & sb)459 void RustCodeEmitter::AddRemoteRequestMethods(StringBuilder& sb)
460 {
461 for (int i = 0; i < metaInterface_->methodNumber_; i++) {
462 MetaMethod* mm = metaInterface_->methods_[i];
463 sb.AppendFormat(" %d => {\n", i + 1);
464 for (int j = 0; j < mm->parameterNumber_; j++) {
465 ReadFromParcel(sb, metaComponent_->types_[mm->parameters_[j]->typeIndex_], "data",
466 GetNameFromParameter(mm->parameters_[j]->name_), " ");
467 }
468 MetaType* mt = metaComponent_->types_[mm->returnTypeIndex_];
469 if (mt->kind_ != TypeKind::Unknown && mt->kind_ != TypeKind::Void) {
470 sb.AppendFormat(" let result = stub.%s(", mm->name_);
471 } else {
472 sb.AppendFormat(" stub.%s(", mm->name_);
473 }
474 AddRemoteRequestParameters(sb, mm);
475 sb.Append(")?;\n");
476 if (mt->kind_ != TypeKind::Unknown && mt->kind_ != TypeKind::Void) {
477 WriteToParcel(sb, mt, "reply", "result", " ");
478 }
479 sb.Append(" Ok(())\n");
480 sb.Append(" }\n");
481 }
482 }
483
EmitStub(StringBuilder & sb)484 void RustCodeEmitter::EmitStub(StringBuilder& sb)
485 {
486 sb.AppendFormat("impl %s for RemoteStub<%s> {\n", interfaceName_.string(), stubName_.string());
487 AppendStubMethods(sb);
488 sb.Append("}\n");
489 }
490
AppendStubParameters(StringBuilder & sb,MetaMethod * mm)491 void RustCodeEmitter::AppendStubParameters(StringBuilder& sb, MetaMethod* mm)
492 {
493 for (int i = 0; i < mm->parameterNumber_; i++) {
494 sb.Append(GetNameFromParameter(mm->parameters_[i]->name_));
495 if (i + 1 != mm->parameterNumber_) {
496 WrapLine(sb, i, " ");
497 }
498 }
499 }
500
AppendStubMethods(StringBuilder & sb)501 void RustCodeEmitter::AppendStubMethods(StringBuilder& sb)
502 {
503 for (int i = 0; i < metaInterface_->methodNumber_; i++) {
504 MetaMethod* mm = metaInterface_->methods_[i];
505 sb.AppendFormat(" fn %s(&self", mm->name_);
506 for (int i = 0; i < mm->parameterNumber_; i++) {
507 WrapLine(sb, i, " ");
508 AppendBrokerParameters(sb, mm->parameters_[i]);
509 }
510
511 sb.AppendFormat(") -> Result<%s> {\n",
512 ConvertType(metaComponent_->types_[mm->returnTypeIndex_]).string());
513 sb.AppendFormat(" self.0.%s(", mm->name_);
514 AppendStubParameters(sb, mm);
515 sb.Append(")\n");
516 sb.Append(" }\n");
517 if (i != metaInterface_->methodNumber_ - 1) {
518 sb.Append("\n");
519 }
520 }
521 }
522
EmitProxy(StringBuilder & sb)523 void RustCodeEmitter::EmitProxy(StringBuilder& sb)
524 {
525 sb.AppendFormat("impl %s for %s {\n", interfaceName_.string(), proxyName_.string());
526 AppendProxyMethods(sb);
527 sb.Append("}\n");
528 }
529
AppendProxyMethods(StringBuilder & sb)530 void RustCodeEmitter::AppendProxyMethods(StringBuilder& sb)
531 {
532 for (int i = 0; i < metaInterface_->methodNumber_; i++) {
533 MetaMethod* mm = metaInterface_->methods_[i];
534 sb.AppendFormat(" fn %s(&self", mm->name_);
535 for (int i = 0; i < mm->parameterNumber_; i++) {
536 WrapLine(sb, i, " ");
537 AppendBrokerParameters(sb, mm->parameters_[i]);
538 }
539 sb.AppendFormat(") -> Result<%s> {\n",
540 ConvertType(metaComponent_->types_[mm->returnTypeIndex_]).string());
541 sb.Append(" let mut data = MsgParcel::new().expect(\"MsgParcel should success\");\n");
542 for (int j = 0; j < mm->parameterNumber_; j++) {
543 WriteToParcel(sb, metaComponent_->types_[mm->parameters_[j]->typeIndex_], "data",
544 GetNameFromParameter(mm->parameters_[j]->name_), " ");
545 }
546 MetaType* mt = metaComponent_->types_[mm->returnTypeIndex_];
547 if (mt->kind_ == TypeKind::Unknown || mt->kind_ == TypeKind::Void) {
548 sb.AppendFormat(" let _reply = self.remote.send_request(%sCode", interfaceName_.string());
549 } else {
550 sb.AppendFormat(" let reply = self.remote.send_request(%sCode", interfaceName_.string());
551 }
552 sb.AppendFormat("::%s as u32, &data, ", GetCodeFromMethod(mm->name_).string());
553 if ((mm->properties_ & METHOD_PROPERTY_ONEWAY) != 0) {
554 sb.Append("true");
555 } else {
556 sb.Append("false");
557 }
558 sb.Append(")?;\n");
559 if (mt->kind_ == TypeKind::Unknown || mt->kind_ == TypeKind::Void) {
560 sb.Append(" ").Append("Ok(())\n");
561 } else {
562 ReadFromParcel(sb, mt, "reply", "result", " ");
563 sb.Append(" ").Append("Ok(result)\n");
564 }
565 sb.Append(" }\n");
566
567 if (i != metaInterface_->methodNumber_ - 1) {
568 sb.Append("\n");
569 }
570 }
571 }
572 }
573 }
574