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
23namespace OHOS {
24namespace Idl {
25namespace {
26const uint32_t WRAP_ANCHOR = 4;
27}
28
29void 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
41void RustCodeEmitter::EmitInterfaceProxy()
42{
43    return;
44}
45
46void RustCodeEmitter::EmitInterfaceStub()
47{
48    return;
49}
50
51void 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
73void RustCodeEmitter::EmitLicense(StringBuilder& sb)
74{
75    sb.Append(metaInterface_->license_).Append("\n");
76}
77
78void 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}
85void RustCodeEmitter::EmitHeaders(StringBuilder& sb)
86{
87    EmitCommonHeaders(sb);
88    EmitIPCHeaders(sb);
89    if (EmitCustomHeaders(sb)) {
90        sb.Append("\n");
91    }
92}
93
94void 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
106void 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
129String 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
152String 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
181bool 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
191bool 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
210void RustCodeEmitter::EmitCommands(StringBuilder& sb)
211{
212    EmitCommandEnums(sb);
213}
214
215void 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
228String 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
250String 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
274void RustCodeEmitter::EmitCommandEnums(StringBuilder& sb)
275{
276    sb.AppendFormat("pub enum %sCode {\n", interfaceName_.string());
277    AppendCommandEnums(sb);
278    sb.Append("}\n");
279}
280
281void 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
295void RustCodeEmitter::EmitBrokers(StringBuilder& sb)
296{
297    sb.AppendFormat("pub trait %s: IRemoteBroker {\n", interfaceName_.string());
298    AppendBrokerMethods(sb);
299    sb.Append("}\n");
300}
301
302void 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
311void 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
324void 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
330String 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
371void 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
383void 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
394void 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
401void 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
420void 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
433void 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
439void 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
449void 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
461void 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
486void 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
493void 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
503void 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
525void 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
532void 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