blob: 002abc41fe9d4cfdd703e84e3bb234a2a952352b [file] [log] [blame]
Andrei Homescub62afd92020-05-11 19:24:59 -07001/*
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 "generate_rust.h"
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <map>
23#include <memory>
24#include <sstream>
25
26#include <android-base/stringprintf.h>
Andrei Homescue61feb52020-08-18 15:44:24 -070027#include <android-base/strings.h>
Andrei Homescub62afd92020-05-11 19:24:59 -070028
29#include "aidl_to_cpp_common.h"
30#include "aidl_to_rust.h"
31#include "code_writer.h"
32#include "logging.h"
33
Andrei Homescue61feb52020-08-18 15:44:24 -070034using android::base::Join;
Andrei Homescub62afd92020-05-11 19:24:59 -070035using std::ostringstream;
36using std::shared_ptr;
37using std::string;
38using std::unique_ptr;
39using std::vector;
40
41namespace android {
42namespace aidl {
43namespace rust {
44
45static constexpr const char kArgumentPrefix[] = "_arg_";
46static constexpr const char kGetInterfaceVersion[] = "getInterfaceVersion";
47static constexpr const char kGetInterfaceHash[] = "getInterfaceHash";
48
49void GenerateMangledAlias(CodeWriter& out, const AidlDefinedType* type) {
50 ostringstream alias;
51 for (const auto& component : type->GetSplitPackage()) {
52 alias << "_" << component.size() << "_" << component;
53 }
54 alias << "_" << type->GetName().size() << "_" << type->GetName();
55 out << "pub(crate) mod mangled { pub use super::" << type->GetName() << " as " << alias.str()
56 << "; }\n";
57}
58
59string BuildArg(const AidlArgument& arg, const AidlTypenames& typenames) {
60 // We pass in parameters that are not primitives by const reference.
61 // Arrays get passed in as slices, which is handled in RustNameOf.
62 auto arg_mode = ArgumentStorageMode(arg, typenames);
63 auto arg_type = RustNameOf(arg.GetType(), typenames, arg_mode);
64 return kArgumentPrefix + arg.GetName() + ": " + arg_type;
65}
66
67string BuildMethod(const AidlMethod& method, const AidlTypenames& typenames) {
68 auto method_type = RustNameOf(method.GetType(), typenames, StorageMode::VALUE);
69 auto return_type = string{"binder::public_api::Result<"} + method_type + ">";
70 string parameters = "&self";
71 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
72 parameters += ", ";
73 parameters += BuildArg(*arg, typenames);
74 }
75 return "fn " + method.GetName() + "(" + parameters + ") -> " + return_type;
76}
77
78void GenerateClientMethod(CodeWriter& out, const AidlMethod& method, const AidlTypenames& typenames,
79 const Options& options, const std::string& trait_name) {
80 // Generate the method
81 out << BuildMethod(method, typenames) << " {\n";
82 out.Indent();
83
84 if (!method.IsUserDefined()) {
85 if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) {
86 // Check if the version is in the cache
87 out << "let _aidl_version = "
88 "self.cached_version.load(std::sync::atomic::Ordering::Relaxed);\n";
89 out << "if _aidl_version != -1 { return Ok(_aidl_version); }\n";
90 }
91
92 if (method.GetName() == kGetInterfaceHash && !options.Hash().empty()) {
93 out << "{\n";
94 out << " let _aidl_hash_lock = self.cached_hash.lock().unwrap();\n";
95 out << " if let Some(ref _aidl_hash) = *_aidl_hash_lock {\n";
96 out << " return Ok(_aidl_hash.clone());\n";
97 out << " }\n";
98 out << "}\n";
99 }
100 }
101
102 // Call transact()
103 auto transact_flags = method.IsOneway() ? "binder::SpIBinder::FLAG_ONEWAY" : "0";
104 out << "let _aidl_reply = self.binder.transact("
105 << "transactions::" << method.GetName() << ", " << transact_flags << ", |_aidl_data| {\n";
106 out.Indent();
107
108 // Arguments
109 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
110 auto arg_name = kArgumentPrefix + arg->GetName();
111 if (arg->IsIn()) {
112 // If the argument is already a reference, don't reference it again
113 // (unless we turned it into an Option<&T>)
114 auto ref_mode = ArgumentReferenceMode(*arg, typenames);
115 if (IsReference(ref_mode)) {
116 out << "_aidl_data.write(" << arg_name << ")?;\n";
117 } else {
118 out << "_aidl_data.write(&" << arg_name << ")?;\n";
119 }
120 } else if (arg->GetType().IsArray()) {
121 // For out-only arrays, send the array size
122 if (arg->GetType().IsNullable()) {
123 out << "_aidl_data.write_slice_size(" << arg_name << ".as_deref())?;\n";
124 } else {
125 out << "_aidl_data.write_slice_size(Some(" << arg_name << "))?;\n";
126 }
127 }
128 }
129
130 // Return Ok(()) if all the `_aidl_data.write(...)?;` calls pass
131 out << "Ok(())\n";
132 out.Dedent();
133 out << "});\n";
134
135 // Check for UNKNOWN_TRANSACTION and call the default impl
136 string default_args;
137 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
138 if (!default_args.empty()) {
139 default_args += ", ";
140 }
141 default_args += kArgumentPrefix;
142 default_args += arg->GetName();
143 }
144 out << "if let Err(binder::StatusCode::UNKNOWN_TRANSACTION) = _aidl_reply {\n";
145 out << " if let Some(_aidl_default_impl) = <Self as " << trait_name << ">::getDefaultImpl() {\n";
146 out << " return _aidl_default_impl." << method.GetName() << "(" << default_args << ");\n";
147 out << " }\n";
148 out << "}\n";
149
150 // Return all other errors
151 out << "let _aidl_reply = _aidl_reply?;\n";
152
153 string return_val = "()";
154 if (!method.IsOneway()) {
155 // Check for errors
156 out << "let _aidl_status: binder::Status = _aidl_reply.read()?;\n";
157 out << "if !_aidl_status.is_ok() { return Err(_aidl_status); }\n";
158
159 // Return reply value
160 if (method.GetType().GetName() != "void") {
161 auto return_type = RustNameOf(method.GetType(), typenames, StorageMode::VALUE);
162 out << "let _aidl_return: " << return_type << " = _aidl_reply.read()?;\n";
163 return_val = "_aidl_return";
164
165 if (!method.IsUserDefined()) {
166 if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) {
167 out << "self.cached_version.store(_aidl_return, std::sync::atomic::Ordering::Relaxed);\n";
168 }
169 if (method.GetName() == kGetInterfaceHash && !options.Hash().empty()) {
170 out << "*self.cached_hash.lock().unwrap() = Some(_aidl_return.clone());\n";
171 }
172 }
173 }
174
175 for (const AidlArgument* arg : method.GetOutArguments()) {
176 out << "*" << kArgumentPrefix << arg->GetName() << " = _aidl_reply.read()?;\n";
177 }
178 }
179
180 // Return the result
181 out << "Ok(" << return_val << ")\n";
182 out.Dedent();
183 out << "}\n";
184}
185
186void GenerateServerTransaction(CodeWriter& out, const AidlMethod& method,
187 const AidlTypenames& typenames) {
188 out << "transactions::" << method.GetName() << " => {\n";
189 out.Indent();
190
191 string args;
192 for (const auto& arg : method.GetArguments()) {
193 string arg_name = kArgumentPrefix + arg->GetName();
194 StorageMode arg_mode;
195 if (arg->IsIn()) {
196 arg_mode = StorageMode::VALUE;
197 } else {
198 // We need a value we can call Default::default() on
199 arg_mode = StorageMode::DEFAULT_VALUE;
200 }
201 auto arg_type = RustNameOf(arg->GetType(), typenames, arg_mode);
202
203 string arg_mut = arg->IsOut() ? "mut " : "";
204 string arg_init = arg->IsIn() ? "_aidl_data.read()?" : "Default::default()";
205 out << "let " << arg_mut << arg_name << ": " << arg_type << " = " << arg_init << ";\n";
206 if (!arg->IsIn() && arg->GetType().IsArray()) {
207 // _aidl_data.resize_[nullable_]out_vec(&mut _arg_foo)?;
208 auto resize_name = arg->GetType().IsNullable() ? "resize_nullable_out_vec" : "resize_out_vec";
209 out << "_aidl_data." << resize_name << "(&mut " << arg_name << ")?;\n";
210 }
211
212 auto ref_mode = ArgumentReferenceMode(*arg, typenames);
213 if (!args.empty()) {
214 args += ", ";
215 }
216 args += TakeReference(ref_mode, arg_name);
217 }
218 out << "let _aidl_return = _aidl_service." << method.GetName() << "(" << args << ");\n";
219
220 if (!method.IsOneway()) {
221 out << "match &_aidl_return {\n";
222 out.Indent();
223 out << "Ok(_aidl_return) => {\n";
224 out.Indent();
225 out << "_aidl_reply.write(&binder::Status::from(binder::StatusCode::OK))?;\n";
226 if (method.GetType().GetName() != "void") {
227 out << "_aidl_reply.write(_aidl_return)?;\n";
228 }
229
230 // Serialize out arguments
231 for (const AidlArgument* arg : method.GetOutArguments()) {
232 string arg_name = kArgumentPrefix + arg->GetName();
233
234 auto& arg_type = arg->GetType();
235 if (!arg->IsIn() && arg_type.IsArray() && arg_type.GetName() == "ParcelFileDescriptor") {
236 // We represent arrays of ParcelFileDescriptor as
237 // Vec<Option<ParcelFileDescriptor>> when they're out-arguments,
238 // but we need all of them to be initialized to Some; if there's
239 // any None, return UNEXPECTED_NULL (this is what libbinder_ndk does)
240 out << "if " << arg_name << ".iter().any(Option::is_none) { "
241 << "return Err(binder::StatusCode::UNEXPECTED_NULL); }\n";
242 } else if (!arg->IsIn() && !TypeHasDefault(arg_type, typenames)) {
243 // Unwrap out-only arguments that we wrapped in Option<T>
244 out << "let " << arg_name << " = " << arg_name
245 << ".ok_or(binder::StatusCode::UNEXPECTED_NULL)?;\n";
246 }
247
248 out << "_aidl_reply.write(&" << arg_name << ")?;\n";
249 }
250 out.Dedent();
251 out << "}\n";
252 out << "Err(_aidl_status) => _aidl_reply.write(_aidl_status)?\n";
253 out.Dedent();
254 out << "}\n";
255 }
256 out << "Ok(())\n";
257 out.Dedent();
258 out << "}\n";
259}
260
261void GenerateServerItems(CodeWriter& out, const AidlInterface* iface,
262 const AidlTypenames& typenames) {
263 auto trait_name = ClassName(*iface, cpp::ClassNames::INTERFACE);
264 auto server_name = ClassName(*iface, cpp::ClassNames::SERVER);
265
266 // Forward all IFoo functions from Binder to the inner object
267 out << "impl " << trait_name << " for binder::Binder<" << server_name << "> {\n";
268 out.Indent();
269 for (const auto& method : iface->GetMethods()) {
270 string args;
271 for (const std::unique_ptr<AidlArgument>& arg : method->GetArguments()) {
272 if (!args.empty()) {
273 args += ", ";
274 }
275 args += kArgumentPrefix;
276 args += arg->GetName();
277 }
278 out << BuildMethod(*method, typenames) << " { "
279 << "self.0." << method->GetName() << "(" << args << ") }\n";
280 }
281 out.Dedent();
282 out << "}\n";
283
284 out << "fn on_transact("
285 "_aidl_service: &dyn "
286 << trait_name
287 << ", "
288 "_aidl_code: binder::TransactionCode, "
289 "_aidl_data: &binder::parcel::Parcel, "
290 "_aidl_reply: &mut binder::parcel::Parcel) -> binder::Result<()> {\n";
291 out.Indent();
292 out << "match _aidl_code {\n";
293 out.Indent();
294 for (const auto& method : iface->GetMethods()) {
295 GenerateServerTransaction(out, *method, typenames);
296 }
297 out << "_ => Err(binder::StatusCode::UNKNOWN_TRANSACTION)\n";
298 out.Dedent();
299 out << "}\n";
300 out.Dedent();
301 out << "}\n";
302}
303
304bool GenerateRustInterface(const string& filename, const AidlInterface* iface,
305 const AidlTypenames& typenames, const IoDelegate& io_delegate,
306 const Options& options) {
307 CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
308
309 *code_writer << "#![allow(non_upper_case_globals)]\n";
310 *code_writer << "#![allow(non_snake_case)]\n";
311 // Import IBinder for transact()
312 *code_writer << "#[allow(unused_imports)] use binder::IBinder;\n";
313
314 auto trait_name = ClassName(*iface, cpp::ClassNames::INTERFACE);
315 auto client_name = ClassName(*iface, cpp::ClassNames::CLIENT);
316 auto server_name = ClassName(*iface, cpp::ClassNames::SERVER);
317 *code_writer << "use binder::declare_binder_interface;\n";
318 *code_writer << "declare_binder_interface! {\n";
319 code_writer->Indent();
320 *code_writer << trait_name << "[\"" << iface->GetDescriptor() << "\"] {\n";
321 code_writer->Indent();
322 *code_writer << "native: " << server_name << "(on_transact),\n";
323 *code_writer << "proxy: " << client_name << " {\n";
324 code_writer->Indent();
325 if (options.Version() > 0) {
326 string comma = options.Hash().empty() ? "" : ",";
327 *code_writer << "cached_version: "
328 "std::sync::atomic::AtomicI32 = "
329 "std::sync::atomic::AtomicI32::new(-1)"
330 << comma << "\n";
331 }
332 if (!options.Hash().empty()) {
333 *code_writer << "cached_hash: "
334 "std::sync::Mutex<Option<String>> = "
335 "std::sync::Mutex::new(None)\n";
336 }
337 code_writer->Dedent();
338 *code_writer << "},\n";
339 code_writer->Dedent();
340 *code_writer << "}\n";
341 code_writer->Dedent();
342 *code_writer << "}\n";
343
344 *code_writer << "pub trait " << trait_name << ": binder::Interface + Send {\n";
345 code_writer->Indent();
346 *code_writer << "fn get_descriptor() -> &'static str where Self: Sized { \""
347 << iface->GetDescriptor() << "\" }\n";
348
349 for (const auto& method : iface->GetMethods()) {
350 // Generate the method
351 *code_writer << BuildMethod(*method, typenames) << " {\n";
352 code_writer->Indent();
353 if (method->IsUserDefined()) {
354 // Return Err(UNKNOWN_TRANSACTION) by default
355 *code_writer << "Err(binder::StatusCode::UNKNOWN_TRANSACTION.into())\n";
356 } else {
357 // Generate default implementations for meta methods
358 // FIXME: is this fine, or do we want to leave the defaults out
359 // and force users to implement them manually (or with a helper macro we
360 // provide) on the server side?
361 if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) {
362 *code_writer << "Ok(VERSION)\n";
363 } else if (method->GetName() == kGetInterfaceHash && !options.Hash().empty()) {
364 *code_writer << "Ok(HASH.into())\n";
365 }
366 }
367 code_writer->Dedent();
368 *code_writer << "}\n";
369 }
370
371 // Emit the default implementation code inside the trait
372 auto default_name = ClassName(*iface, cpp::ClassNames::DEFAULT_IMPL);
373 *code_writer << "fn getDefaultImpl()"
374 << " -> " << default_name << " where Self: Sized {\n";
375 *code_writer << " DEFAULT_IMPL.lock().unwrap().clone()\n";
376 *code_writer << "}\n";
377 *code_writer << "fn setDefaultImpl(d: " << default_name << ")"
378 << " -> " << default_name << " where Self: Sized {\n";
379 *code_writer << " std::mem::replace(&mut *DEFAULT_IMPL.lock().unwrap(), d)\n";
380 *code_writer << "}\n";
381 code_writer->Dedent();
382 *code_writer << "}\n";
383
384 // Generate the transaction code constants
385 // The constants get their own sub-module to avoid conflicts
386 *code_writer << "pub mod transactions {\n";
387 code_writer->Indent();
388 // Import IBinder so we can access FIRST_CALL_TRANSACTION
389 *code_writer << "#[allow(unused_imports)] use binder::IBinder;\n";
390 for (const auto& method : iface->GetMethods()) {
391 // Generate the transaction code constant
392 *code_writer << "pub const " << method->GetName()
393 << ": binder::TransactionCode = "
394 "binder::SpIBinder::FIRST_CALL_TRANSACTION + " +
395 std::to_string(method->GetId()) + ";\n";
396 }
397 code_writer->Dedent();
398 *code_writer << "}\n";
399
400 // Emit the default implementation code outside the trait
401 *code_writer << "pub type " << default_name << " = Option<std::sync::Arc<dyn " << trait_name
402 << " + Sync>>;\n";
403 *code_writer << "use lazy_static::lazy_static;\n";
404 *code_writer << "lazy_static! {\n";
405 *code_writer << " static ref DEFAULT_IMPL: std::sync::Mutex<" << default_name
406 << "> = std::sync::Mutex::new(None);\n";
407 *code_writer << "}\n";
408
409 // Emit the interface constants
410 for (const auto& constant : iface->GetConstantDeclarations()) {
411 const AidlConstantValue& value = constant->GetValue();
412 string const_type;
413 switch (value.GetType()) {
414 case AidlConstantValue::Type::STRING: {
415 const_type = "&str";
416 break;
417 }
418 case AidlConstantValue::Type::BOOLEAN: // fall-through
419 case AidlConstantValue::Type::INT8: // fall-through
420 case AidlConstantValue::Type::INT32: {
421 const_type = "i32";
422 break;
423 }
424 default: {
425 LOG(FATAL) << "Unrecognized constant type: " << static_cast<int>(value.GetType());
426 }
427 }
428 *code_writer << "pub const " << constant->GetName() << ": " << const_type << " = "
429 << constant->ValueString(ConstantValueDecoratorRef) << ";\n";
430 }
431
432 GenerateMangledAlias(*code_writer, iface);
433
434 // Emit VERSION and HASH
435 // These need to be top-level item constants instead of associated consts
436 // because the latter are incompatible with trait objects, see
437 // https://doc.rust-lang.org/reference/items/traits.html#object-safety
438 if (options.Version() > 0) {
439 *code_writer << "pub const VERSION: i32 = " << std::to_string(options.Version()) << ";\n";
440 }
441 if (!options.Hash().empty()) {
442 *code_writer << "pub const HASH: &str = \"" << options.Hash() << "\";\n";
443 }
444
445 // Generate the client-side methods
446 *code_writer << "impl " << trait_name << " for " << client_name << " {\n";
447 code_writer->Indent();
448 for (const auto& method : iface->GetMethods()) {
449 GenerateClientMethod(*code_writer, *method, typenames, options, trait_name);
450 }
451 code_writer->Dedent();
452 *code_writer << "}\n";
453
454 // Generate the server-side methods
455 GenerateServerItems(*code_writer, iface, typenames);
456
457 return true;
458}
459
460void GenerateParcelDefault(CodeWriter& out, const AidlStructuredParcelable* parcel) {
461 out << "impl Default for " << parcel->GetName() << " {\n";
462 out.Indent();
463 out << "fn default() -> Self {\n";
464 out.Indent();
465 out << "Self {\n";
466 out.Indent();
467 for (const auto& variable : parcel->GetFields()) {
468 if (variable->GetDefaultValue()) {
469 out << variable->GetName() << ": " << variable->ValueString(ConstantValueDecorator) << ",\n";
470 } else {
471 out << variable->GetName() << ": Default::default(),\n";
472 }
473 }
474 out.Dedent();
475 out << "}\n";
476 out.Dedent();
477 out << "}\n";
478 out.Dedent();
479 out << "}\n";
480}
481
482void GenerateParcelSerialize(CodeWriter& out, const AidlStructuredParcelable* parcel,
483 const AidlTypenames& typenames) {
484 out << "impl binder::parcel::Serialize for " << parcel->GetName() << " {\n";
485 out << " fn serialize(&self, parcel: &mut binder::parcel::Parcel) -> binder::Result<()> {\n";
486 out << " <Self as binder::parcel::SerializeOption>::serialize_option(Some(self), parcel)\n";
487 out << " }\n";
488 out << "}\n";
489
490 out << "impl binder::parcel::SerializeArray for " << parcel->GetName() << " {}\n";
491
492 out << "impl binder::parcel::SerializeOption for " << parcel->GetName() << " {\n";
493 out.Indent();
494 out << "fn serialize_option(this: Option<&Self>, parcel: &mut binder::parcel::Parcel) -> "
495 "binder::Result<()> {\n";
496 out.Indent();
497 out << "let this = if let Some(this) = this {\n";
498 out << " parcel.write(&1i32)?;\n";
499 out << " this\n";
500 out << "} else {\n";
501 out << " return parcel.write(&0i32);\n";
502 out << "};\n";
503 out << "let start_pos = parcel.get_data_position();\n";
504 out << "parcel.write(&0i32)?;\n";
505 for (const auto& variable : parcel->GetFields()) {
506 if (!TypeHasDefault(variable->GetType(), typenames)) {
507 out << "let __field_ref = this." << variable->GetName()
508 << ".as_ref().ok_or(binder::StatusCode::UNEXPECTED_NULL)?;\n";
509 out << "parcel.write(__field_ref)?;\n";
510 } else {
511 out << "parcel.write(&this." << variable->GetName() << ")?;\n";
512 }
513 }
514 out << "let end_pos = parcel.get_data_position();\n";
515 out << "let parcelable_size = (end_pos - start_pos) as i32;\n";
516 out << "unsafe { parcel.set_data_position(start_pos)?; }\n";
517 out << "parcel.write(&parcelable_size)?;\n";
518 out << "unsafe { parcel.set_data_position(end_pos)?; }\n";
519 out << "Ok(())\n";
520 out.Dedent();
521 out << "}\n";
522 out.Dedent();
523 out << "}\n";
524}
525
526void GenerateParcelDeserialize(CodeWriter& out, const AidlStructuredParcelable* parcel,
527 const AidlTypenames& typenames) {
528 out << "impl binder::parcel::Deserialize for " << parcel->GetName() << " {\n";
529 out << " fn deserialize(parcel: &binder::parcel::Parcel) -> binder::Result<Self> {\n";
530 out << " <Self as binder::parcel::DeserializeOption>::deserialize_option(parcel)\n";
531 out << " .transpose()\n";
532 out << " .unwrap_or(Err(binder::StatusCode::UNEXPECTED_NULL))\n";
533 out << " }\n";
534 out << "}\n";
535
536 out << "impl binder::parcel::DeserializeArray for " << parcel->GetName() << " {}\n";
537
538 out << "impl binder::parcel::DeserializeOption for " << parcel->GetName() << " {\n";
539 out << " fn deserialize_option(parcel: &binder::parcel::Parcel) -> binder::Result<Option<Self>> "
540 "{\n";
541 out << " let status: i32 = parcel.read()?;\n";
542 out << " if status == 0 { return Ok(None); }\n";
543 out << " let start_pos = parcel.get_data_position();\n";
544 out << " let parcelable_size: i32 = parcel.read()?;\n";
545 out << " if parcelable_size < 0 { return Err(binder::StatusCode::BAD_VALUE); }\n";
546
547 // Pre-emit the common field epilogue code, shared between all fields:
548 ostringstream epilogue;
549 epilogue << " if (parcel.get_data_position() - start_pos) == parcelable_size {\n";
550 // We assume the lhs can never be > parcelable_size, because then the read
551 // immediately preceding this check would have returned NOT_ENOUGH_DATA
552 epilogue << " return Ok(Some(result));\n";
553 epilogue << " }\n";
554 string epilogue_str = epilogue.str();
555
556 out << " let mut result = Self::default();\n";
557 for (const auto& variable : parcel->GetFields()) {
558 if (!TypeHasDefault(variable->GetType(), typenames)) {
559 out << " result." << variable->GetName() << " = Some(parcel.read()?);\n";
560 } else {
561 out << " result." << variable->GetName() << " = parcel.read()?;\n";
562 }
563 out << epilogue_str;
564 }
565
566 out << " Ok(Some(result))\n";
567 out << " }\n";
568 out << "}\n";
569}
570
571bool GenerateRustParcel(const string& filename, const AidlStructuredParcelable* parcel,
572 const AidlTypenames& typenames, const IoDelegate& io_delegate) {
573 CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
574
Andrei Homescue61feb52020-08-18 15:44:24 -0700575 // Debug is always derived because all Rust AIDL types implement it
576 // ParcelFileDescriptor doesn't support any of the others because
577 // it's a newtype over std::fs::File which only implements Debug
578 vector<string> derives{"Debug"};
579 const AidlAnnotation* derive_annotation = parcel->RustDerive();
580 if (derive_annotation != nullptr) {
581 for (const auto& name_and_param : derive_annotation->AnnotationParams(ConstantValueDecorator)) {
582 if (name_and_param.second == "true") {
583 derives.push_back(name_and_param.first);
584 }
585 }
586 }
587
588 *code_writer << "#[derive(" << Join(derives, ", ") << ")]\n";
Andrei Homescub62afd92020-05-11 19:24:59 -0700589 *code_writer << "pub struct " << parcel->GetName() << " {\n";
590 code_writer->Indent();
591 for (const auto& variable : parcel->GetFields()) {
592 auto field_type = RustNameOf(variable->GetType(), typenames, StorageMode::PARCELABLE_FIELD);
593 *code_writer << "pub " << variable->GetName() << ": " << field_type << ", \n";
594 }
595 code_writer->Dedent();
596 *code_writer << "}\n";
597
598 GenerateMangledAlias(*code_writer, parcel);
599 GenerateParcelDefault(*code_writer, parcel);
600 GenerateParcelSerialize(*code_writer, parcel, typenames);
601 GenerateParcelDeserialize(*code_writer, parcel, typenames);
602
603 return true;
604}
605
606bool GenerateRustEnumDeclaration(const string& filename, const AidlEnumDeclaration* enum_decl,
607 const AidlTypenames& typenames, const IoDelegate& io_delegate) {
608 CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
609
610 const auto& aidl_backing_type = enum_decl->GetBackingType();
611 auto backing_type = RustNameOf(aidl_backing_type, typenames, StorageMode::VALUE);
612
613 *code_writer << "#![allow(non_upper_case_globals)]\n";
Andrei Homescu0717c432020-09-04 17:41:00 -0700614 *code_writer << "use binder::declare_binder_enum;\n";
615 *code_writer << "declare_binder_enum! { " << enum_decl->GetName() << " : " << backing_type
616 << " {\n";
617 code_writer->Indent();
Andrei Homescub62afd92020-05-11 19:24:59 -0700618 for (const auto& enumerator : enum_decl->GetEnumerators()) {
619 auto value = enumerator->GetValue()->ValueString(aidl_backing_type, ConstantValueDecorator);
Andrei Homescu0717c432020-09-04 17:41:00 -0700620 *code_writer << enumerator->GetName() << " = " << value << ",\n";
Andrei Homescub62afd92020-05-11 19:24:59 -0700621 }
Andrei Homescu0717c432020-09-04 17:41:00 -0700622 code_writer->Dedent();
623 *code_writer << "} }\n";
Andrei Homescub62afd92020-05-11 19:24:59 -0700624
625 GenerateMangledAlias(*code_writer, enum_decl);
626
627 return true;
628}
629
630bool GenerateRust(const string& filename, const AidlDefinedType* defined_type,
631 const AidlTypenames& typenames, const IoDelegate& io_delegate,
632 const Options& options) {
633 if (const AidlStructuredParcelable* parcelable = defined_type->AsStructuredParcelable();
634 parcelable != nullptr) {
635 return GenerateRustParcel(filename, parcelable, typenames, io_delegate);
636 }
637
638 if (const AidlEnumDeclaration* enum_decl = defined_type->AsEnumDeclaration();
639 enum_decl != nullptr) {
640 return GenerateRustEnumDeclaration(filename, enum_decl, typenames, io_delegate);
641 }
642
643 if (const AidlInterface* interface = defined_type->AsInterface(); interface != nullptr) {
644 return GenerateRustInterface(filename, interface, typenames, io_delegate, options);
645 }
646
647 CHECK(false) << "Unrecognized type sent for Rust generation.";
648 return false;
649}
650
651} // namespace rust
652} // namespace aidl
653} // namespace android