Rust: support ParcelableHolder
Bug: 169035750
Test: m
Change-Id: I2fbd4e5e11272a87fac948e68f8edc703f70f910
diff --git a/aidl_language.cpp b/aidl_language.cpp
index 1577e26..15bdfab 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -1281,11 +1281,6 @@
AIDL_ERROR(this) << "The " << to_string(lang) << " backend does not support array of IBinder";
return false;
}
- if (lang == Options::Language::RUST && GetName() == "ParcelableHolder") {
- // TODO(b/146611855): Remove it when Rust backend supports ParcelableHolder
- AIDL_ERROR(this) << "The Rust backend does not support ParcelableHolder yet.";
- return false;
- }
if ((lang == Options::Language::NDK || lang == Options::Language::RUST) && IsArray() &&
IsNullable()) {
if (GetName() == "ParcelFileDescriptor") {
diff --git a/aidl_to_rust.cpp b/aidl_to_rust.cpp
index f7e7166..78bc451 100644
--- a/aidl_to_rust.cpp
+++ b/aidl_to_rust.cpp
@@ -101,6 +101,7 @@
{"String", "String"},
{"IBinder", "binder::SpIBinder"},
{"ParcelFileDescriptor", "binder::parcel::ParcelFileDescriptor"},
+ {"ParcelableHolder", "binder::parcel::ParcelableHolder"},
};
// If the type is an array/List<T>, get the inner element type
@@ -186,7 +187,7 @@
if (type.IsNullable() ||
// Some types don't implement Default, so we wrap them
// in Option, which defaults to None
- (!TypeHasDefault(type, typenames) &&
+ (TypeNeedsOption(type, typenames) &&
(mode == StorageMode::DEFAULT_VALUE || mode == StorageMode::OUT_ARGUMENT ||
mode == StorageMode::PARCELABLE_FIELD))) {
if (type.IsHeapNullable()) {
@@ -275,30 +276,35 @@
return definedType != nullptr && definedType->AsInterface() != nullptr;
}
-bool TypeHasDefault(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
+bool TypeNeedsOption(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
if (type.IsArray() || typenames.IsList(type)) {
- return true;
+ return false;
}
// Already an Option<T>
if (type.IsNullable()) {
- return true;
+ return false;
}
const string& aidl_name = type.GetName();
if (aidl_name == "IBinder") {
- return false;
+ return true;
}
if (aidl_name == "ParcelFileDescriptor") {
+ return true;
+ }
+ if (aidl_name == "ParcelableHolder") {
+ // ParcelableHolder never needs an Option because we always
+ // call its new() constructor directly instead of default()
return false;
}
// Strong<dyn IFoo> values don't implement Default
if (TypeIsInterface(type, typenames)) {
- return false;
+ return true;
}
- return true;
+ return false;
}
} // namespace rust
diff --git a/aidl_to_rust.h b/aidl_to_rust.h
index 292e4df..7ba6d75 100644
--- a/aidl_to_rust.h
+++ b/aidl_to_rust.h
@@ -70,7 +70,7 @@
bool TypeIsInterface(const AidlTypeSpecifier& type, const AidlTypenames& typenames);
-bool TypeHasDefault(const AidlTypeSpecifier& type, const AidlTypenames& typenames);
+bool TypeNeedsOption(const AidlTypeSpecifier& type, const AidlTypenames& typenames);
} // namespace rust
} // namespace aidl
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index 4aaf7ae..a7f13f9 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -1955,16 +1955,8 @@
" ParcelableHolder extension;\n"
" ParcelableHolder extension2;\n"
"}";
- if (GetLanguage() == Options::Language::RUST) {
- EXPECT_EQ(nullptr, Parse("a/Data.aidl", extendable_parcelable, typenames_, GetLanguage()));
- EXPECT_EQ(
- "ERROR: a/Data.aidl:2.1-19: The Rust backend does not support ParcelableHolder "
- "yet.\n",
- GetCapturedStderr());
- } else {
- EXPECT_NE(nullptr, Parse("a/Data.aidl", extendable_parcelable, typenames_, GetLanguage()));
- EXPECT_EQ("", GetCapturedStderr());
- }
+ EXPECT_NE(nullptr, Parse("a/Data.aidl", extendable_parcelable, typenames_, GetLanguage()));
+ EXPECT_EQ("", GetCapturedStderr());
}
TEST_P(AidlTest, ParcelableHolderAsReturnType) {
CaptureStderr();
@@ -1975,14 +1967,6 @@
EXPECT_EQ(nullptr,
Parse("a/IFoo.aidl", parcelableholder_return_interface, typenames_, GetLanguage()));
- if (GetLanguage() == Options::Language::RUST) {
- EXPECT_EQ(
- "ERROR: a/IFoo.aidl:2.19-23: ParcelableHolder cannot be a return type\n"
- "ERROR: a/IFoo.aidl:2.1-19: The Rust backend does not support ParcelableHolder "
- "yet.\n",
- GetCapturedStderr());
- return;
- }
EXPECT_EQ("ERROR: a/IFoo.aidl:2.19-23: ParcelableHolder cannot be a return type\n",
GetCapturedStderr());
}
@@ -1996,14 +1980,6 @@
EXPECT_EQ(nullptr,
Parse("a/IFoo.aidl", extendable_parcelable_arg_interface, typenames_, GetLanguage()));
- if (GetLanguage() == Options::Language::RUST) {
- EXPECT_EQ(
- "ERROR: a/IFoo.aidl:2.31-34: ParcelableHolder cannot be an argument type\n"
- "ERROR: a/IFoo.aidl:2.14-31: The Rust backend does not support ParcelableHolder "
- "yet.\n",
- GetCapturedStderr());
- return;
- }
EXPECT_EQ("ERROR: a/IFoo.aidl:2.31-34: ParcelableHolder cannot be an argument type\n",
GetCapturedStderr());
}
@@ -2014,14 +1990,6 @@
const string expected_stderr = "ERROR: Foo.aidl:1.27-44: ParcelableHolder cannot be nullable.\n";
CaptureStderr();
EXPECT_FALSE(compile_aidl(options, io_delegate_));
- if (GetLanguage() == Options::Language::RUST) {
- EXPECT_EQ(
- "ERROR: Foo.aidl:1.27-44: ParcelableHolder cannot be nullable.\n"
- "ERROR: Foo.aidl:1.27-44: The Rust backend does not support ParcelableHolder "
- "yet.\n",
- GetCapturedStderr());
- return;
- }
EXPECT_EQ(expected_stderr, GetCapturedStderr());
}
diff --git a/generate_rust.cpp b/generate_rust.cpp
index 82d0564..a67bc62 100644
--- a/generate_rust.cpp
+++ b/generate_rust.cpp
@@ -253,7 +253,7 @@
// any None, return UNEXPECTED_NULL (this is what libbinder_ndk does)
out << "if " << arg_name << ".iter().any(Option::is_none) { "
<< "return Err(binder::StatusCode::UNEXPECTED_NULL); }\n";
- } else if (!arg->IsIn() && !TypeHasDefault(arg_type, typenames)) {
+ } else if (!arg->IsIn() && TypeNeedsOption(arg_type, typenames)) {
// Unwrap out-only arguments that we wrapped in Option<T>
out << "let " << arg_name << " = " << arg_name
<< ".ok_or(binder::StatusCode::UNEXPECTED_NULL)?;\n";
@@ -528,11 +528,21 @@
out << "Self {\n";
out.Indent();
for (const auto& variable : parcel->GetFields()) {
+ out << variable->GetName() << ": ";
if (variable->GetDefaultValue()) {
- out << variable->GetName() << ": " << variable->ValueString(ConstantValueDecorator) << ",\n";
+ out << variable->ValueString(ConstantValueDecorator);
+ } else if (variable->GetType().GetName() == "ParcelableHolder") {
+ out << "binder::parcel::ParcelableHolder::new(";
+ if (parcel->IsVintfStability()) {
+ out << "binder::Stability::Vintf";
+ } else {
+ out << "binder::Stability::Local";
+ }
+ out << ")";
} else {
- out << variable->GetName() << ": Default::default(),\n";
+ out << "Default::default()";
}
+ out << ",\n";
}
out.Dedent();
out << "}\n";
@@ -547,7 +557,7 @@
out << "parcel.sized_write(|subparcel| {\n";
out.Indent();
for (const auto& variable : parcel->GetFields()) {
- if (!TypeHasDefault(variable->GetType(), typenames)) {
+ if (TypeNeedsOption(variable->GetType(), typenames)) {
out << "let __field_ref = self." << variable->GetName()
<< ".as_ref().ok_or(binder::StatusCode::UNEXPECTED_NULL)?;\n";
out << "subparcel.write(__field_ref)?;\n";
@@ -568,7 +578,7 @@
for (const auto& variable : parcel->GetFields()) {
out << "if subparcel.has_more_data() {\n";
out.Indent();
- if (!TypeHasDefault(variable->GetType(), typenames)) {
+ if (TypeNeedsOption(variable->GetType(), typenames)) {
out << "self." << variable->GetName() << " = Some(subparcel.read()?);\n";
} else {
out << "self." << variable->GetName() << " = subparcel.read()?;\n";
@@ -628,7 +638,7 @@
out << "Self::" << variable->GetCapitalizedName() << "(v) => {\n";
out.Indent();
out << "parcel.write(&" << std::to_string(tag++) << "i32)?;\n";
- if (!TypeHasDefault(variable->GetType(), typenames)) {
+ if (TypeNeedsOption(variable->GetType(), typenames)) {
out << "let __field_ref = v.as_ref().ok_or(binder::StatusCode::UNEXPECTED_NULL)?;\n";
out << "parcel.write(__field_ref)\n";
} else {
@@ -653,7 +663,7 @@
out << std::to_string(tag++) << " => {\n";
out.Indent();
out << "let value: " << field_type << " = ";
- if (!TypeHasDefault(variable->GetType(), typenames)) {
+ if (TypeNeedsOption(variable->GetType(), typenames)) {
out << "Some(parcel.read()?);\n";
} else {
out << "parcel.read()?;\n";
@@ -699,6 +709,21 @@
}
template <typename ParcelableType>
+void GenerateMetadataTrait(CodeWriter& out, const ParcelableType* parcel) {
+ out << "impl binder::parcel::ParcelableMetadata for " << parcel->GetName() << " {\n";
+ out.Indent();
+
+ out << "fn get_descriptor() -> &'static str { \"" << parcel->GetCanonicalName() << "\" }\n";
+
+ if (parcel->IsVintfStability()) {
+ out << "fn get_stability(&self) -> binder::Stability { binder::Stability::Vintf }\n";
+ }
+
+ out.Dedent();
+ out << "}\n";
+}
+
+template <typename ParcelableType>
bool GenerateRustParcel(const string& filename, const ParcelableType* parcel,
const AidlTypenames& typenames, const IoDelegate& io_delegate) {
CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
@@ -726,6 +751,7 @@
GenerateMangledAlias(*code_writer, parcel);
GenerateParcelDefault(*code_writer, parcel);
GenerateParcelableTrait(*code_writer, parcel, typenames);
+ GenerateMetadataTrait(*code_writer, parcel);
return true;
}
diff --git a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/DeprecatedParcelable.rs b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/DeprecatedParcelable.rs
index 4eef5e8..40b0c9f 100644
--- a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/DeprecatedParcelable.rs
+++ b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/DeprecatedParcelable.rs
@@ -24,3 +24,6 @@
}
binder::impl_serialize_for_parcelable!(DeprecatedParcelable);
binder::impl_deserialize_for_parcelable!(DeprecatedParcelable);
+impl binder::parcel::ParcelableMetadata for DeprecatedParcelable {
+ fn get_descriptor() -> &'static str { "android.aidl.tests.DeprecatedParcelable" }
+}
diff --git a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/GenericStructuredParcelable.rs b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/GenericStructuredParcelable.rs
index 2d3bb0d..8417634 100644
--- a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/GenericStructuredParcelable.rs
+++ b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/GenericStructuredParcelable.rs
@@ -35,3 +35,6 @@
}
binder::impl_serialize_for_parcelable!(GenericStructuredParcelable);
binder::impl_deserialize_for_parcelable!(GenericStructuredParcelable);
+impl binder::parcel::ParcelableMetadata for GenericStructuredParcelable {
+ fn get_descriptor() -> &'static str { "android.aidl.tests.GenericStructuredParcelable" }
+}
diff --git a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/OtherParcelableForToString.rs b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/OtherParcelableForToString.rs
index d680ab1..10cce81 100644
--- a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/OtherParcelableForToString.rs
+++ b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/OtherParcelableForToString.rs
@@ -29,3 +29,6 @@
}
binder::impl_serialize_for_parcelable!(OtherParcelableForToString);
binder::impl_deserialize_for_parcelable!(OtherParcelableForToString);
+impl binder::parcel::ParcelableMetadata for OtherParcelableForToString {
+ fn get_descriptor() -> &'static str { "android.aidl.tests.OtherParcelableForToString" }
+}
diff --git a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/ParcelableForToString.rs b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/ParcelableForToString.rs
index ade629e..befd140 100644
--- a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/ParcelableForToString.rs
+++ b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/ParcelableForToString.rs
@@ -161,3 +161,6 @@
}
binder::impl_serialize_for_parcelable!(ParcelableForToString);
binder::impl_deserialize_for_parcelable!(ParcelableForToString);
+impl binder::parcel::ParcelableMetadata for ParcelableForToString {
+ fn get_descriptor() -> &'static str { "android.aidl.tests.ParcelableForToString" }
+}
diff --git a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/RecursiveList.rs b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/RecursiveList.rs
index 5b23a38..1a49392 100644
--- a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/RecursiveList.rs
+++ b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/RecursiveList.rs
@@ -35,3 +35,6 @@
}
binder::impl_serialize_for_parcelable!(RecursiveList);
binder::impl_deserialize_for_parcelable!(RecursiveList);
+impl binder::parcel::ParcelableMetadata for RecursiveList {
+ fn get_descriptor() -> &'static str { "android.aidl.tests.RecursiveList" }
+}
diff --git a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/StructuredParcelable.rs b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/StructuredParcelable.rs
index 1a0345c..780099f 100644
--- a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/StructuredParcelable.rs
+++ b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/StructuredParcelable.rs
@@ -344,3 +344,6 @@
}
binder::impl_serialize_for_parcelable!(StructuredParcelable);
binder::impl_deserialize_for_parcelable!(StructuredParcelable);
+impl binder::parcel::ParcelableMetadata for StructuredParcelable {
+ fn get_descriptor() -> &'static str { "android.aidl.tests.StructuredParcelable" }
+}
diff --git a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/Union.rs b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/Union.rs
index b24dccd..0e67ed1 100644
--- a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/Union.rs
+++ b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/Union.rs
@@ -95,3 +95,6 @@
}
binder::impl_serialize_for_parcelable!(Union);
binder::impl_deserialize_for_parcelable!(Union);
+impl binder::parcel::ParcelableMetadata for Union {
+ fn get_descriptor() -> &'static str { "android.aidl.tests.Union" }
+}
diff --git a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/UnionWithFd.rs b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/UnionWithFd.rs
index 7ce9185..12c2774 100644
--- a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/UnionWithFd.rs
+++ b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/UnionWithFd.rs
@@ -45,3 +45,6 @@
}
binder::impl_serialize_for_parcelable!(UnionWithFd);
binder::impl_deserialize_for_parcelable!(UnionWithFd);
+impl binder::parcel::ParcelableMetadata for UnionWithFd {
+ fn get_descriptor() -> &'static str { "android.aidl.tests.UnionWithFd" }
+}
diff --git a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/unions/EnumUnion.rs b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/unions/EnumUnion.rs
index 8937b3c..5d7320d 100644
--- a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/unions/EnumUnion.rs
+++ b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/unions/EnumUnion.rs
@@ -44,3 +44,6 @@
}
binder::impl_serialize_for_parcelable!(EnumUnion);
binder::impl_deserialize_for_parcelable!(EnumUnion);
+impl binder::parcel::ParcelableMetadata for EnumUnion {
+ fn get_descriptor() -> &'static str { "android.aidl.tests.unions.EnumUnion" }
+}
diff --git a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/unions/UnionInUnion.rs b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/unions/UnionInUnion.rs
index 0596c6c..88b9151 100644
--- a/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/unions/UnionInUnion.rs
+++ b/tests/golden_output/aidl-test-interface-rust-source/gen/android/aidl/tests/unions/UnionInUnion.rs
@@ -44,3 +44,6 @@
}
binder::impl_serialize_for_parcelable!(UnionInUnion);
binder::impl_deserialize_for_parcelable!(UnionInUnion);
+impl binder::parcel::ParcelableMetadata for UnionInUnion {
+ fn get_descriptor() -> &'static str { "android.aidl.tests.unions.UnionInUnion" }
+}