• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "aidl_to_rust.h"
18 #include "aidl_language.h"
19 #include "aidl_typenames.h"
20 #include "logging.h"
21 
22 #include <android-base/stringprintf.h>
23 #include <android-base/strings.h>
24 
25 #include <functional>
26 #include <iostream>
27 #include <map>
28 #include <string>
29 #include <vector>
30 
31 using android::base::Join;
32 using android::base::Split;
33 using android::base::StringPrintf;
34 
35 namespace android {
36 namespace aidl {
37 namespace rust {
38 
39 namespace {
40 std::string GetRawRustName(const AidlTypeSpecifier& type);
41 
ConstantValueDecoratorInternal(const AidlTypeSpecifier & type,const std::variant<std::string,std::vector<std::string>> & raw_value,bool by_ref)42 std::string ConstantValueDecoratorInternal(
43     const AidlTypeSpecifier& type,
44     const std::variant<std::string, std::vector<std::string>>& raw_value, bool by_ref) {
45   if (type.IsArray()) {
46     const auto& values = std::get<std::vector<std::string>>(raw_value);
47     std::string value = "[" + Join(values, ", ") + "]";
48     if (type.IsDynamicArray()) {
49       value = "vec!" + value;
50     }
51     if (!type.IsMutated() && type.IsNullable()) {
52       value = "Some(" + value + ")";
53     }
54     return value;
55   }
56 
57   std::string value = std::get<std::string>(raw_value);
58 
59   const auto& aidl_name = type.GetName();
60   if (aidl_name == "char") {
61     return value + " as u16";
62   }
63 
64   if (aidl_name == "float") {
65     // value already ends in `f`, so just add `32`
66     return value + "32";
67   }
68 
69   if (aidl_name == "double") {
70     return value + "f64";
71   }
72 
73   if (auto defined_type = type.GetDefinedType(); defined_type) {
74     auto enum_type = defined_type->AsEnumDeclaration();
75     AIDL_FATAL_IF(!enum_type, type) << "Invalid type for \"" << value << "\"";
76     return GetRawRustName(type) + "::" + value.substr(value.find_last_of('.') + 1);
77   }
78 
79   if (aidl_name == "String" && !by_ref) {
80     // The actual type might be String or &str,
81     // and .into() transparently converts into either one
82     value = value + ".into()";
83   }
84 
85   if (type.IsNullable()) {
86     value = "Some(" + value + ")";
87   }
88 
89   return value;
90 }
91 
GetRawRustName(const AidlTypeSpecifier & type)92 std::string GetRawRustName(const AidlTypeSpecifier& type) {
93   const auto defined_type = type.GetDefinedType();
94   if (defined_type != nullptr) {
95     const auto unstructured = AidlCast<AidlParcelable>(*defined_type);
96     if (unstructured != nullptr) {
97       // Unstructured parcelable should set its rust_type. Use it.
98       const std::string rust_type = unstructured->GetRustType();
99       AIDL_FATAL_IF(rust_type.empty(), unstructured)
100           << "Parcelable " << unstructured->GetCanonicalName() << " has no rust_type defined.";
101       return rust_type;
102     }
103   }
104 
105   // Each Rust type is defined in a file with the same name,
106   // e.g., IFoo is in IFoo.rs
107   auto split_name = type.GetSplitName();
108   std::string rust_name{"crate::mangled::"};
109   for (const auto& component : split_name) {
110     rust_name += StringPrintf("_%zd_%s", component.size(), component.c_str());
111   }
112   return rust_name;
113 }
114 
115 // Usually, this means that the type implements `Default`, however `ParcelableHolder` is also
116 // included in this list because the code generator knows how to call `::new(stability)`.
AutoConstructor(const AidlTypeSpecifier & type,const AidlTypenames & typenames)117 bool AutoConstructor(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
118   return !(type.GetName() == "ParcelFileDescriptor" || type.GetName() == "IBinder" ||
119            TypeIsInterface(type, typenames));
120 }
121 
GetRustName(const AidlTypeSpecifier & type,const AidlTypenames & typenames,StorageMode mode)122 std::string GetRustName(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
123                         StorageMode mode) {
124   // map from AIDL built-in type name to the corresponding Rust type name
125   static map<string, string> m = {
126       {"void", "()"},
127       {"boolean", "bool"},
128       {"byte", "i8"},
129       {"char", "u16"},
130       {"int", "i32"},
131       {"long", "i64"},
132       {"float", "f32"},
133       {"double", "f64"},
134       {"String", "String"},
135       {"IBinder", "binder::SpIBinder"},
136       {"ParcelFileDescriptor", "binder::ParcelFileDescriptor"},
137       {"ParcelableHolder", "binder::ParcelableHolder"},
138   };
139   const string& type_name = type.GetName();
140   if (m.find(type_name) != m.end()) {
141     AIDL_FATAL_IF(!AidlTypenames::IsBuiltinTypename(type_name), type);
142     if (type_name == "String" && mode == StorageMode::UNSIZED_ARGUMENT) {
143       return "str";
144     } else {
145       return m[type_name];
146     }
147   }
148   auto name = GetRawRustName(type);
149   if (TypeIsInterface(type, typenames)) {
150     name = "binder::Strong<dyn " + name + ">";
151   }
152   if (type.IsGeneric()) {
153     name += "<";
154     for (const auto& param : type.GetTypeParameters()) {
155       name += GetRustName(*param, typenames, mode);
156       name += ",";
157     }
158     name += ">";
159   }
160   return name;
161 }
162 }  // namespace
163 
ConstantValueDecorator(const AidlTypeSpecifier & type,const std::variant<std::string,std::vector<std::string>> & raw_value)164 std::string ConstantValueDecorator(
165     const AidlTypeSpecifier& type,
166     const std::variant<std::string, std::vector<std::string>>& raw_value) {
167   return ConstantValueDecoratorInternal(type, raw_value, false);
168 }
169 
ConstantValueDecoratorRef(const AidlTypeSpecifier & type,const std::variant<std::string,std::vector<std::string>> & raw_value)170 std::string ConstantValueDecoratorRef(
171     const AidlTypeSpecifier& type,
172     const std::variant<std::string, std::vector<std::string>>& raw_value) {
173   return ConstantValueDecoratorInternal(type, raw_value, true);
174 }
175 
176 // Returns default value for array.
ArrayDefaultValue(const AidlTypeSpecifier & type)177 std::string ArrayDefaultValue(const AidlTypeSpecifier& type) {
178   AIDL_FATAL_IF(!type.IsFixedSizeArray(), type) << "not a fixed-size array";
179   auto dimensions = type.GetFixedSizeArrayDimensions();
180   std::string value = "Default::default()";
181   for (auto it = rbegin(dimensions), end = rend(dimensions); it != end; it++) {
182     value = "[" + Join(std::vector<std::string>(*it, value), ", ") + "]";
183   }
184   return value;
185 }
186 
187 // Returns true if @nullable T[] should be mapped Option<Vec<Option<T>>
UsesOptionInNullableVector(const AidlTypeSpecifier & type,const AidlTypenames & typenames)188 bool UsesOptionInNullableVector(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
189   AIDL_FATAL_IF(!type.IsArray() && !typenames.IsList(type), type) << "not a vector";
190   AIDL_FATAL_IF(typenames.IsList(type) && type.GetTypeParameters().size() != 1, type)
191       << "List should have a single type arg.";
192 
193   const auto& element_type = type.IsArray() ? type : *type.GetTypeParameters().at(0);
194   if (typenames.IsPrimitiveTypename(element_type.GetName())) {
195     return false;
196   }
197   if (typenames.GetEnumDeclaration(element_type)) {
198     return false;
199   }
200   return true;
201 }
202 
RustLifetimeName(Lifetime lifetime)203 std::string RustLifetimeName(Lifetime lifetime) {
204   switch (lifetime) {
205     case Lifetime::NONE:
206       return "";
207     case Lifetime::A:
208       return "'a ";
209   }
210 }
211 
RustLifetimeGeneric(Lifetime lifetime)212 std::string RustLifetimeGeneric(Lifetime lifetime) {
213   switch (lifetime) {
214     case Lifetime::NONE:
215       return "";
216     case Lifetime::A:
217       return "<'a>";
218   }
219 }
220 
RustNameOf(const AidlTypeSpecifier & type,const AidlTypenames & typenames,StorageMode mode,Lifetime lifetime)221 std::string RustNameOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
222                        StorageMode mode, Lifetime lifetime) {
223   std::string rust_name;
224   if (type.IsArray() || typenames.IsList(type)) {
225     const auto& element_type = type.IsGeneric() ? (*type.GetTypeParameters().at(0)) : type;
226     StorageMode element_mode;
227     if (type.IsFixedSizeArray() && mode == StorageMode::PARCELABLE_FIELD) {
228       // Elements of fixed-size array field need to have Default.
229       element_mode = StorageMode::DEFAULT_VALUE;
230     } else if (mode == StorageMode::OUT_ARGUMENT || mode == StorageMode::DEFAULT_VALUE) {
231       // Elements need to have Default for resize_out_vec()
232       element_mode = StorageMode::DEFAULT_VALUE;
233     } else {
234       element_mode = StorageMode::VALUE;
235     }
236     if (type.IsArray() && element_type.GetName() == "byte") {
237       rust_name = "u8";
238     } else {
239       rust_name = GetRustName(element_type, typenames, element_mode);
240     }
241 
242     // Needs `Option` wrapping because type is not default constructible
243     const bool default_option =
244         element_mode == StorageMode::DEFAULT_VALUE && !AutoConstructor(element_type, typenames);
245     // Needs `Option` wrapping due to being a nullable, non-primitive, non-enum type in a vector.
246     const bool nullable_option = type.IsNullable() && UsesOptionInNullableVector(type, typenames);
247     if (default_option || nullable_option) {
248       rust_name = "Option<" + rust_name + ">";
249     }
250 
251     if (mode == StorageMode::UNSIZED_ARGUMENT) {
252       rust_name = "[" + rust_name + "]";
253     } else if (type.IsFixedSizeArray()) {
254       auto dimensions = type.GetFixedSizeArrayDimensions();
255       // T[N][M] => [[T; M]; N]
256       for (auto it = rbegin(dimensions), end = rend(dimensions); it != end; it++) {
257         rust_name = "[" + rust_name + "; " + std::to_string(*it) + "]";
258       }
259     } else {
260       rust_name = "Vec<" + rust_name + ">";
261     }
262   } else {
263     rust_name = GetRustName(type, typenames, mode);
264   }
265 
266   if (mode == StorageMode::IN_ARGUMENT || mode == StorageMode::UNSIZED_ARGUMENT) {
267     // If this is a nullable input argument, put the reference inside the option,
268     // e.g., `Option<&str>` instead of `&Option<str>`
269     rust_name = "&" + RustLifetimeName(lifetime) + rust_name;
270   }
271 
272   if (type.IsNullable() ||
273       // Some types don't implement Default, so we wrap them
274       // in Option, which defaults to None
275       (TypeNeedsOption(type, typenames) &&
276        (mode == StorageMode::DEFAULT_VALUE || mode == StorageMode::OUT_ARGUMENT ||
277         mode == StorageMode::PARCELABLE_FIELD))) {
278     if (type.IsHeapNullable()) {
279       rust_name = "Option<Box<" + rust_name + ">>";
280     } else {
281       rust_name = "Option<" + rust_name + ">";
282     }
283   }
284 
285   if (mode == StorageMode::OUT_ARGUMENT || mode == StorageMode::INOUT_ARGUMENT) {
286     rust_name = "&" + RustLifetimeName(lifetime) + "mut " + rust_name;
287   }
288 
289   return rust_name;
290 }
291 
ArgumentStorageMode(const AidlArgument & arg,const AidlTypenames & typenames)292 StorageMode ArgumentStorageMode(const AidlArgument& arg, const AidlTypenames& typenames) {
293   if (arg.IsOut()) {
294     return arg.IsIn() ? StorageMode::INOUT_ARGUMENT : StorageMode::OUT_ARGUMENT;
295   }
296 
297   const auto typeName = arg.GetType().GetName();
298   const auto definedType = typenames.TryGetDefinedType(typeName);
299 
300   const bool isEnum = definedType && definedType->AsEnumDeclaration() != nullptr;
301   const bool isPrimitive = AidlTypenames::IsPrimitiveTypename(typeName);
302   if (typeName == "String" || arg.GetType().IsDynamicArray() || typenames.IsList(arg.GetType())) {
303     return StorageMode::UNSIZED_ARGUMENT;
304   } else if (!(isPrimitive || isEnum) || arg.GetType().IsFixedSizeArray()) {
305     return StorageMode::IN_ARGUMENT;
306   } else {
307     return StorageMode::VALUE;
308   }
309 }
310 
ArgumentReferenceMode(const AidlArgument & arg,const AidlTypenames & typenames)311 ReferenceMode ArgumentReferenceMode(const AidlArgument& arg, const AidlTypenames& typenames) {
312   auto arg_mode = ArgumentStorageMode(arg, typenames);
313   switch (arg_mode) {
314     case StorageMode::IN_ARGUMENT:
315       if (arg.GetType().IsNullable()) {
316         // &Option<T> => Option<&T>
317         return ReferenceMode::AS_REF;
318       } else {
319         return ReferenceMode::REF;
320       }
321 
322     case StorageMode::OUT_ARGUMENT:
323     case StorageMode::INOUT_ARGUMENT:
324       return ReferenceMode::MUT_REF;
325 
326     case StorageMode::UNSIZED_ARGUMENT:
327       if (arg.GetType().IsNullable()) {
328         // &Option<String> => Option<&str>
329         // &Option<Vec<T>> => Option<&[T]>
330         return ReferenceMode::AS_DEREF;
331       } else {
332         return ReferenceMode::REF;
333       }
334 
335     default:
336       return ReferenceMode::VALUE;
337   }
338 }
339 
TakeReference(ReferenceMode ref_mode,const std::string & name)340 std::string TakeReference(ReferenceMode ref_mode, const std::string& name) {
341   switch (ref_mode) {
342     case ReferenceMode::REF:
343       return "&" + name;
344 
345     case ReferenceMode::MUT_REF:
346       return "&mut " + name;
347 
348     case ReferenceMode::AS_REF:
349       return name + ".as_ref()";
350 
351     case ReferenceMode::AS_DEREF:
352       return name + ".as_deref()";
353 
354     default:
355       return name;
356   }
357 }
358 
TypeIsInterface(const AidlTypeSpecifier & type,const AidlTypenames & typenames)359 bool TypeIsInterface(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
360   const auto definedType = typenames.TryGetDefinedType(type.GetName());
361   return definedType != nullptr && definedType->AsInterface() != nullptr;
362 }
363 
TypeNeedsOption(const AidlTypeSpecifier & type,const AidlTypenames & typenames)364 bool TypeNeedsOption(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
365   if (type.IsArray() || typenames.IsList(type)) {
366     return false;
367   }
368 
369   // Already an Option<T>
370   if (type.IsNullable()) {
371     return false;
372   }
373 
374   const string& aidl_name = type.GetName();
375   if (aidl_name == "IBinder") {
376     return true;
377   }
378   if (aidl_name == "ParcelFileDescriptor") {
379     return true;
380   }
381   if (aidl_name == "ParcelableHolder") {
382     // ParcelableHolder never needs an Option because we always
383     // call its new() constructor directly instead of default()
384     return false;
385   }
386 
387   // Strong<dyn IFoo> values don't implement Default
388   if (TypeIsInterface(type, typenames)) {
389     return true;
390   }
391 
392   return false;
393 }
394 
395 }  // namespace rust
396 }  // namespace aidl
397 }  // namespace android
398