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