• 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::string & raw_value,bool by_ref)42 std::string ConstantValueDecoratorInternal(const AidlTypeSpecifier& type,
43                                            const std::string& raw_value, bool by_ref) {
44   if (type.IsArray()) {
45     // Convert `{ ... }` to `vec!{ ... }`
46     return "vec!" + raw_value;
47   }
48 
49   const auto& aidl_name = type.GetName();
50   if (aidl_name == "char") {
51     return raw_value + " as u16";
52   }
53 
54   if (aidl_name == "float") {
55     // raw_value already ends in `f`, so just add `32`
56     return raw_value + "32";
57   }
58 
59   if (aidl_name == "double") {
60     return raw_value + "f64";
61   }
62 
63   if (aidl_name == "String" && !by_ref) {
64     // The actual type might be String or &str,
65     // and .into() transparently converts into either one
66     return raw_value + ".into()";
67   }
68 
69   if (auto defined_type = type.GetDefinedType(); defined_type) {
70     auto enum_type = defined_type->AsEnumDeclaration();
71     AIDL_FATAL_IF(!enum_type, type) << "Invalid type for \"" << raw_value << "\"";
72     return GetRawRustName(type) + "::" + raw_value.substr(raw_value.find_last_of('.') + 1);
73   }
74 
75   return raw_value;
76 }
77 
GetRawRustName(const AidlTypeSpecifier & type)78 std::string GetRawRustName(const AidlTypeSpecifier& type) {
79   // Each Rust type is defined in a file with the same name,
80   // e.g., IFoo is in IFoo.rs
81   auto split_name = type.GetSplitName();
82   std::string rust_name{"crate::mangled::"};
83   for (const auto& component : split_name) {
84     rust_name += StringPrintf("_%zd_%s", component.size(), component.c_str());
85   }
86   return rust_name;
87 }
88 
GetRustName(const AidlTypeSpecifier & type,const AidlTypenames & typenames,StorageMode mode)89 std::string GetRustName(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
90                         StorageMode mode) {
91   // map from AIDL built-in type name to the corresponding Rust type name
92   static map<string, string> m = {
93       {"void", "()"},
94       {"boolean", "bool"},
95       {"byte", "i8"},
96       {"char", "u16"},
97       {"int", "i32"},
98       {"long", "i64"},
99       {"float", "f32"},
100       {"double", "f64"},
101       {"String", "String"},
102       {"IBinder", "binder::SpIBinder"},
103       {"ParcelFileDescriptor", "binder::parcel::ParcelFileDescriptor"},
104   };
105 
106   // If the type is an array/List<T>, get the inner element type
107   AIDL_FATAL_IF(typenames.IsList(type) && type.GetTypeParameters().size() != 1, type);
108   const auto& element_type = type.IsGeneric() ? (*type.GetTypeParameters().at(0)) : type;
109   const string& element_type_name = element_type.GetName();
110   if (m.find(element_type_name) != m.end()) {
111     AIDL_FATAL_IF(!AidlTypenames::IsBuiltinTypename(element_type_name), type);
112     if (element_type_name == "byte" && type.IsArray()) {
113       return "u8";
114     } else if (element_type_name == "String" && mode == StorageMode::UNSIZED_ARGUMENT) {
115       return "str";
116     } else if (element_type_name == "ParcelFileDescriptor") {
117       if (type.IsArray() && mode == StorageMode::DEFAULT_VALUE) {
118         // Out-arguments of ParcelFileDescriptors arrays need to
119         // be Vec<Option<ParcelFileDescriptor>> so resize_out_vec
120         // can initialize all elements to None (it requires Default
121         // and ParcelFileDescriptor doesn't implement that)
122         return "Option<" + m[element_type_name] + ">";
123       } else {
124         return m[element_type_name];
125       }
126     }
127     return m[element_type_name];
128   }
129   if (TypeIsInterface(element_type, typenames)) {
130     return "binder::Strong<dyn " + GetRawRustName(element_type) + ">";
131   }
132 
133   return GetRawRustName(element_type);
134 }
135 }  // namespace
136 
ConstantValueDecorator(const AidlTypeSpecifier & type,const std::string & raw_value)137 std::string ConstantValueDecorator(const AidlTypeSpecifier& type, const std::string& raw_value) {
138   auto rust_value = ConstantValueDecoratorInternal(type, raw_value, false);
139   if (type.IsNullable()) {
140     return "Some(" + rust_value + ")";
141   }
142   return rust_value;
143 }
144 
ConstantValueDecoratorRef(const AidlTypeSpecifier & type,const std::string & raw_value)145 std::string ConstantValueDecoratorRef(const AidlTypeSpecifier& type, const std::string& raw_value) {
146   auto rust_value = ConstantValueDecoratorInternal(type, raw_value, true);
147   if (type.IsNullable()) {
148     return "Some(" + rust_value + ")";
149   }
150   return rust_value;
151 }
152 
RustNameOf(const AidlTypeSpecifier & type,const AidlTypenames & typenames,StorageMode mode)153 std::string RustNameOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
154                        StorageMode mode) {
155   std::string rust_name;
156   if (type.IsArray() || typenames.IsList(type)) {
157     StorageMode element_mode;
158     if (mode == StorageMode::OUT_ARGUMENT || mode == StorageMode::DEFAULT_VALUE) {
159       // Elements need to have Default for resize_out_vec()
160       element_mode = StorageMode::DEFAULT_VALUE;
161     } else {
162       element_mode = StorageMode::VALUE;
163     }
164     rust_name = GetRustName(type, typenames, element_mode);
165     if (type.IsNullable() && rust_name == "String") {
166       // The mapping for nullable string arrays is
167       // optional<vector<optional<string>>> in the NDK,
168       // so we do the same
169       rust_name = "Option<" + rust_name + ">";
170     }
171     if (mode == StorageMode::UNSIZED_ARGUMENT) {
172       rust_name = "[" + rust_name + "]";
173     } else {
174       rust_name = "Vec<" + rust_name + ">";
175     }
176   } else {
177     rust_name = GetRustName(type, typenames, mode);
178   }
179 
180   if (mode == StorageMode::IN_ARGUMENT || mode == StorageMode::UNSIZED_ARGUMENT) {
181     // If this is a nullable input argument, put the reference inside the option,
182     // e.g., `Option<&str>` instead of `&Option<str>`
183     rust_name = "&" + rust_name;
184   }
185 
186   if (type.IsNullable() ||
187       // Some types don't implement Default, so we wrap them
188       // in Option, which defaults to None
189       (!TypeHasDefault(type, typenames) &&
190        (mode == StorageMode::DEFAULT_VALUE || mode == StorageMode::OUT_ARGUMENT ||
191         mode == StorageMode::PARCELABLE_FIELD))) {
192     rust_name = "Option<" + rust_name + ">";
193   }
194 
195   if (mode == StorageMode::OUT_ARGUMENT || mode == StorageMode::INOUT_ARGUMENT) {
196     rust_name = "&mut " + rust_name;
197   }
198 
199   return rust_name;
200 }
201 
ArgumentStorageMode(const AidlArgument & arg,const AidlTypenames & typenames)202 StorageMode ArgumentStorageMode(const AidlArgument& arg, const AidlTypenames& typenames) {
203   if (arg.IsOut()) {
204     return arg.IsIn() ? StorageMode::INOUT_ARGUMENT : StorageMode::OUT_ARGUMENT;
205   }
206 
207   const auto typeName = arg.GetType().GetName();
208   const auto definedType = typenames.TryGetDefinedType(typeName);
209 
210   const bool isEnum = definedType && definedType->AsEnumDeclaration() != nullptr;
211   const bool isPrimitive = AidlTypenames::IsPrimitiveTypename(typeName);
212   if (typeName == "String" || arg.GetType().IsArray() || typenames.IsList(arg.GetType())) {
213     return StorageMode::UNSIZED_ARGUMENT;
214   } else if (!(isPrimitive || isEnum)) {
215     return StorageMode::IN_ARGUMENT;
216   } else {
217     return StorageMode::VALUE;
218   }
219 }
220 
ArgumentReferenceMode(const AidlArgument & arg,const AidlTypenames & typenames)221 ReferenceMode ArgumentReferenceMode(const AidlArgument& arg, const AidlTypenames& typenames) {
222   auto arg_mode = ArgumentStorageMode(arg, typenames);
223   switch (arg_mode) {
224     case StorageMode::IN_ARGUMENT:
225       if (arg.GetType().IsNullable()) {
226         // &Option<T> => Option<&T>
227         return ReferenceMode::AS_REF;
228       } else {
229         return ReferenceMode::REF;
230       }
231 
232     case StorageMode::OUT_ARGUMENT:
233     case StorageMode::INOUT_ARGUMENT:
234       return ReferenceMode::MUT_REF;
235 
236     case StorageMode::UNSIZED_ARGUMENT:
237       if (arg.GetType().IsNullable()) {
238         // &Option<String> => Option<&str>
239         // &Option<Vec<T>> => Option<&[T]>
240         return ReferenceMode::AS_DEREF;
241       } else {
242         return ReferenceMode::REF;
243       }
244 
245     default:
246       return ReferenceMode::VALUE;
247   }
248 }
249 
TakeReference(ReferenceMode ref_mode,const std::string & name)250 std::string TakeReference(ReferenceMode ref_mode, const std::string& name) {
251   switch (ref_mode) {
252     case ReferenceMode::REF:
253       return "&" + name;
254 
255     case ReferenceMode::MUT_REF:
256       return "&mut " + name;
257 
258     case ReferenceMode::AS_REF:
259       return name + ".as_ref()";
260 
261     case ReferenceMode::AS_DEREF:
262       return name + ".as_deref()";
263 
264     default:
265       return name;
266   }
267 }
268 
TypeIsInterface(const AidlTypeSpecifier & type,const AidlTypenames & typenames)269 bool TypeIsInterface(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
270   const auto definedType = typenames.TryGetDefinedType(type.GetName());
271   return definedType != nullptr && definedType->AsInterface() != nullptr;
272 }
273 
TypeHasDefault(const AidlTypeSpecifier & type,const AidlTypenames & typenames)274 bool TypeHasDefault(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
275   if (type.IsArray() || typenames.IsList(type)) {
276     return true;
277   }
278 
279   // Already an Option<T>
280   if (type.IsNullable()) {
281     return true;
282   }
283 
284   const string& aidl_name = type.GetName();
285   if (aidl_name == "IBinder") {
286     return false;
287   }
288   if (aidl_name == "ParcelFileDescriptor") {
289     return false;
290   }
291 
292   // Strong<dyn IFoo> values don't implement Default
293   if (TypeIsInterface(type, typenames)) {
294     return false;
295   }
296 
297   return true;
298 }
299 
300 }  // namespace rust
301 }  // namespace aidl
302 }  // namespace android
303