Add union support (Rust)
`union` in AIDL is represented as `enum` in Rust.
Bug: 170689477
Test: aidl_unittests / aidl_integration_test
Change-Id: I5fad878a32e24f84854f69d4da91737e84cadb63
diff --git a/Android.bp b/Android.bp
index 90fe3ff..4c3d839 100644
--- a/Android.bp
+++ b/Android.bp
@@ -257,6 +257,8 @@
"tests/android/aidl/tests/OtherParcelableForToString.aidl",
"tests/android/aidl/tests/ParcelableForToString.aidl",
"tests/android/aidl/tests/StructuredParcelable.aidl",
+ "tests/android/aidl/tests/Union.aidl",
+ "tests/android/aidl/tests/UnionWithFd.aidl",
],
path: "tests",
}
@@ -266,8 +268,6 @@
srcs: [
"tests/android/aidl/tests/ICppJavaTests.aidl",
"tests/android/aidl/tests/SimpleParcelable.aidl",
- "tests/android/aidl/tests/Union.aidl",
- "tests/android/aidl/tests/UnionWithFd.aidl",
"tests/android/aidl/tests/extension/*.aidl",
],
path: "tests",
diff --git a/aidl_language.cpp b/aidl_language.cpp
index bf6d2d9..728eb7f 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -1180,9 +1180,9 @@
AidlWithFields(variables) {}
std::set<AidlAnnotation::Type> AidlUnionDecl::GetSupportedAnnotations() const {
- return {AidlAnnotation::Type::VINTF_STABILITY, AidlAnnotation::Type::HIDE,
- AidlAnnotation::Type::JAVA_PASSTHROUGH, AidlAnnotation::Type::JAVA_DERIVE,
- AidlAnnotation::Type::JAVA_ONLY_IMMUTABLE};
+ return {AidlAnnotation::Type::VINTF_STABILITY, AidlAnnotation::Type::HIDE,
+ AidlAnnotation::Type::JAVA_PASSTHROUGH, AidlAnnotation::Type::JAVA_DERIVE,
+ AidlAnnotation::Type::JAVA_ONLY_IMMUTABLE, AidlAnnotation::Type::RUST_DERIVE};
}
void AidlUnionDecl::Dump(CodeWriter* writer) const {
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index a8136f4..1bcde1c 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -3424,6 +3424,83 @@
}
)";
+const char kUnionExampleExpectedOutputRust[] = R"(#[derive(Debug)]
+pub enum Foo {
+ Ns(Vec<i32>),
+ E(crate::mangled::_1_a_8_ByteEnum),
+ Pfd(Option<binder::parcel::ParcelFileDescriptor>),
+}
+pub(crate) mod mangled { pub use super::Foo as _1_a_3_Foo; }
+impl Default for Foo {
+ fn default() -> Self {
+ Self::Ns(vec!{42})
+ }
+}
+impl binder::parcel::Serialize for Foo {
+ fn serialize(&self, parcel: &mut binder::parcel::Parcel) -> binder::Result<()> {
+ <Self as binder::parcel::SerializeOption>::serialize_option(Some(self), parcel)
+ }
+}
+impl binder::parcel::SerializeArray for Foo {}
+impl binder::parcel::SerializeOption for Foo {
+ fn serialize_option(this: Option<&Self>, parcel: &mut binder::parcel::Parcel) -> binder::Result<()> {
+ let this = if let Some(this) = this {
+ parcel.write(&1i32)?;
+ this
+ } else {
+ return parcel.write(&0i32);
+ };
+ match this {
+ Self::Ns(v) => {
+ parcel.write(&0i32)?;
+ parcel.write(v)
+ }
+ Self::E(v) => {
+ parcel.write(&1i32)?;
+ parcel.write(v)
+ }
+ Self::Pfd(v) => {
+ parcel.write(&2i32)?;
+ let __field_ref = v.as_ref().ok_or(binder::StatusCode::UNEXPECTED_NULL)?;
+ parcel.write(__field_ref)
+ }
+ }
+ }
+}
+impl binder::parcel::Deserialize for Foo {
+ fn deserialize(parcel: &binder::parcel::Parcel) -> binder::Result<Self> {
+ <Self as binder::parcel::DeserializeOption>::deserialize_option(parcel)
+ .transpose()
+ .unwrap_or(Err(binder::StatusCode::UNEXPECTED_NULL))
+ }
+}
+impl binder::parcel::DeserializeArray for Foo {}
+impl binder::parcel::DeserializeOption for Foo {
+ fn deserialize_option(parcel: &binder::parcel::Parcel) -> binder::Result<Option<Self>> {
+ let status: i32 = parcel.read()?;
+ if status == 0 { return Ok(None); }
+ let tag: i32 = parcel.read()?;
+ match tag {
+ 0 => {
+ let value: Vec<i32> = parcel.read()?;
+ Ok(Some(Self::Ns(value)))
+ }
+ 1 => {
+ let value: crate::mangled::_1_a_8_ByteEnum = parcel.read()?;
+ Ok(Some(Self::E(value)))
+ }
+ 2 => {
+ let value: Option<binder::parcel::ParcelFileDescriptor> = Some(parcel.read()?);
+ Ok(Some(Self::Pfd(value)))
+ }
+ _ => {
+ Err(binder::StatusCode::BAD_VALUE)
+ }
+ }
+ }
+}
+)";
+
struct AidlUnionTest : ::testing::Test {
void SetUp() override {
io_delegate_.SetFileContents("a/Foo.aidl", R"(
@@ -3483,7 +3560,11 @@
Compile("java");
EXPECT_COMPILE_OUTPUTS(
map<string, string>({{"out/a/Foo.java", kUnionExampleExpectedOutputJava}}));
- // TODO(b/170689477) Rust
+}
+
+TEST_F(AidlUnionTest, Example_Rust) {
+ Compile("rust");
+ EXPECT_COMPILE_OUTPUTS(map<string, string>({{"out/a/Foo.rs", kUnionExampleExpectedOutputRust}}));
}
TEST_P(AidlTest, UnionRejectsEmptyDecl) {
diff --git a/generate_rust.cpp b/generate_rust.cpp
index d0800f5..e768820 100644
--- a/generate_rust.cpp
+++ b/generate_rust.cpp
@@ -459,6 +459,18 @@
return true;
}
+void GenerateParcelBody(CodeWriter& out, const AidlStructuredParcelable* parcel,
+ const AidlTypenames& typenames) {
+ out << "pub struct " << parcel->GetName() << " {\n";
+ out.Indent();
+ for (const auto& variable : parcel->GetFields()) {
+ auto field_type = RustNameOf(variable->GetType(), typenames, StorageMode::PARCELABLE_FIELD);
+ out << "pub " << variable->GetName() << ": " << field_type << ",\n";
+ }
+ out.Dedent();
+ out << "}\n";
+}
+
void GenerateParcelDefault(CodeWriter& out, const AidlStructuredParcelable* parcel) {
out << "impl Default for " << parcel->GetName() << " {\n";
out.Indent();
@@ -481,7 +493,140 @@
out << "}\n";
}
-void GenerateParcelSerialize(CodeWriter& out, const AidlStructuredParcelable* parcel,
+void GenerateParcelSerializeBody(CodeWriter& out, const AidlStructuredParcelable* parcel,
+ const AidlTypenames& typenames) {
+ out << "parcel.sized_write(|subparcel| {\n";
+ out.Indent();
+ for (const auto& variable : parcel->GetFields()) {
+ if (!TypeHasDefault(variable->GetType(), typenames)) {
+ out << "let __field_ref = this." << variable->GetName()
+ << ".as_ref().ok_or(binder::StatusCode::UNEXPECTED_NULL)?;\n";
+ out << "subparcel.write(__field_ref)?;\n";
+ } else {
+ out << "subparcel.write(&this." << variable->GetName() << ")?;\n";
+ }
+ }
+ out << "Ok(())\n";
+ out.Dedent();
+ out << "})\n";
+}
+
+void GenerateParcelDeserializeBody(CodeWriter& out, const AidlStructuredParcelable* parcel,
+ const AidlTypenames& typenames) {
+ out << "let start_pos = parcel.get_data_position();\n";
+ out << "let parcelable_size: i32 = parcel.read()?;\n";
+ out << "if parcelable_size < 0 { return Err(binder::StatusCode::BAD_VALUE); }\n";
+
+ // Pre-emit the common field epilogue code, shared between all fields:
+ ostringstream epilogue;
+ epilogue << "if (parcel.get_data_position() - start_pos) == parcelable_size {\n";
+ // We assume the lhs can never be > parcelable_size, because then the read
+ // immediately preceding this check would have returned NOT_ENOUGH_DATA
+ epilogue << " return Ok(Some(result));\n";
+ epilogue << "}\n";
+ string epilogue_str = epilogue.str();
+
+ out << "let mut result = Self::default();\n";
+ for (const auto& variable : parcel->GetFields()) {
+ if (!TypeHasDefault(variable->GetType(), typenames)) {
+ out << "result." << variable->GetName() << " = Some(parcel.read()?);\n";
+ } else {
+ out << "result." << variable->GetName() << " = parcel.read()?;\n";
+ }
+ out << epilogue_str;
+ }
+
+ out << "Ok(Some(result))\n";
+}
+
+void GenerateParcelBody(CodeWriter& out, const AidlUnionDecl* parcel,
+ const AidlTypenames& typenames) {
+ out << "pub enum " << parcel->GetName() << " {\n";
+ out.Indent();
+ for (const auto& variable : parcel->GetFields()) {
+ auto field_type = RustNameOf(variable->GetType(), typenames, StorageMode::PARCELABLE_FIELD);
+ out << variable->GetCapitalizedName() << "(" << field_type << "),\n";
+ }
+ out.Dedent();
+ out << "}\n";
+}
+
+void GenerateParcelDefault(CodeWriter& out, const AidlUnionDecl* parcel) {
+ out << "impl Default for " << parcel->GetName() << " {\n";
+ out.Indent();
+ out << "fn default() -> Self {\n";
+ out.Indent();
+
+ AIDL_FATAL_IF(parcel->GetFields().empty(), *parcel)
+ << "Union '" << parcel->GetName() << "' is empty.";
+ const auto& first_field = parcel->GetFields()[0];
+ const auto& first_value = first_field->ValueString(ConstantValueDecorator);
+
+ out << "Self::";
+ if (first_field->GetDefaultValue()) {
+ out << first_field->GetCapitalizedName() << "(" << first_value << ")\n";
+ } else {
+ out << first_field->GetCapitalizedName() << "(Default::default())\n";
+ }
+
+ out.Dedent();
+ out << "}\n";
+ out.Dedent();
+ out << "}\n";
+}
+
+void GenerateParcelSerializeBody(CodeWriter& out, const AidlUnionDecl* parcel,
+ const AidlTypenames& typenames) {
+ out << "match this {\n";
+ out.Indent();
+ int tag = 0;
+ for (const auto& variable : parcel->GetFields()) {
+ out << "Self::" << variable->GetCapitalizedName() << "(v) => {\n";
+ out.Indent();
+ out << "parcel.write(&" << std::to_string(tag++) << "i32)?;\n";
+ if (!TypeHasDefault(variable->GetType(), typenames)) {
+ out << "let __field_ref = v.as_ref().ok_or(binder::StatusCode::UNEXPECTED_NULL)?;\n";
+ out << "parcel.write(__field_ref)\n";
+ } else {
+ out << "parcel.write(v)\n";
+ }
+ out.Dedent();
+ out << "}\n";
+ }
+ out.Dedent();
+ out << "}\n";
+}
+
+void GenerateParcelDeserializeBody(CodeWriter& out, const AidlUnionDecl* parcel,
+ const AidlTypenames& typenames) {
+ out << "let tag: i32 = parcel.read()?;\n";
+ out << "match tag {\n";
+ out.Indent();
+ int tag = 0;
+ for (const auto& variable : parcel->GetFields()) {
+ auto field_type = RustNameOf(variable->GetType(), typenames, StorageMode::PARCELABLE_FIELD);
+
+ out << std::to_string(tag++) << " => {\n";
+ out.Indent();
+ out << "let value: " << field_type << " = ";
+ if (!TypeHasDefault(variable->GetType(), typenames)) {
+ out << "Some(parcel.read()?);\n";
+ } else {
+ out << "parcel.read()?;\n";
+ }
+ out << "Ok(Some(Self::" << variable->GetCapitalizedName() << "(value)))\n";
+ out.Dedent();
+ out << "}\n";
+ }
+ out << "_ => {\n";
+ out << " Err(binder::StatusCode::BAD_VALUE)\n";
+ out << "}\n";
+ out.Dedent();
+ out << "}\n";
+}
+
+template <typename ParcelableType>
+void GenerateParcelSerialize(CodeWriter& out, const ParcelableType* parcel,
const AidlTypenames& typenames) {
out << "impl binder::parcel::Serialize for " << parcel->GetName() << " {\n";
out << " fn serialize(&self, parcel: &mut binder::parcel::Parcel) -> binder::Result<()> {\n";
@@ -502,27 +647,17 @@
out << "} else {\n";
out << " return parcel.write(&0i32);\n";
out << "};\n";
- out << "parcel.sized_write(|subparcel| {\n";
- out.Indent();
- for (const auto& variable : parcel->GetFields()) {
- if (!TypeHasDefault(variable->GetType(), typenames)) {
- out << "let __field_ref = this." << variable->GetName()
- << ".as_ref().ok_or(binder::StatusCode::UNEXPECTED_NULL)?;\n";
- out << "subparcel.write(__field_ref)?;\n";
- } else {
- out << "subparcel.write(&this." << variable->GetName() << ")?;\n";
- }
- }
- out << "Ok(())\n";
- out.Dedent();
- out << "})\n";
+
+ GenerateParcelSerializeBody(out, parcel, typenames);
+
out.Dedent();
out << "}\n";
out.Dedent();
out << "}\n";
}
-void GenerateParcelDeserialize(CodeWriter& out, const AidlStructuredParcelable* parcel,
+template <typename ParcelableType>
+void GenerateParcelDeserialize(CodeWriter& out, const ParcelableType* parcel,
const AidlTypenames& typenames) {
out << "impl binder::parcel::Deserialize for " << parcel->GetName() << " {\n";
out << " fn deserialize(parcel: &binder::parcel::Parcel) -> binder::Result<Self> {\n";
@@ -535,39 +670,23 @@
out << "impl binder::parcel::DeserializeArray for " << parcel->GetName() << " {}\n";
out << "impl binder::parcel::DeserializeOption for " << parcel->GetName() << " {\n";
- out << " fn deserialize_option(parcel: &binder::parcel::Parcel) -> binder::Result<Option<Self>> "
+ out.Indent();
+ out << "fn deserialize_option(parcel: &binder::parcel::Parcel) -> binder::Result<Option<Self>> "
"{\n";
- out << " let status: i32 = parcel.read()?;\n";
- out << " if status == 0 { return Ok(None); }\n";
- out << " let start_pos = parcel.get_data_position();\n";
- out << " let parcelable_size: i32 = parcel.read()?;\n";
- out << " if parcelable_size < 0 { return Err(binder::StatusCode::BAD_VALUE); }\n";
+ out.Indent();
+ out << "let status: i32 = parcel.read()?;\n";
+ out << "if status == 0 { return Ok(None); }\n";
- // Pre-emit the common field epilogue code, shared between all fields:
- ostringstream epilogue;
- epilogue << " if (parcel.get_data_position() - start_pos) == parcelable_size {\n";
- // We assume the lhs can never be > parcelable_size, because then the read
- // immediately preceding this check would have returned NOT_ENOUGH_DATA
- epilogue << " return Ok(Some(result));\n";
- epilogue << " }\n";
- string epilogue_str = epilogue.str();
+ GenerateParcelDeserializeBody(out, parcel, typenames);
- out << " let mut result = Self::default();\n";
- for (const auto& variable : parcel->GetFields()) {
- if (!TypeHasDefault(variable->GetType(), typenames)) {
- out << " result." << variable->GetName() << " = Some(parcel.read()?);\n";
- } else {
- out << " result." << variable->GetName() << " = parcel.read()?;\n";
- }
- out << epilogue_str;
- }
-
- out << " Ok(Some(result))\n";
- out << " }\n";
+ out.Dedent();
+ out << "}\n";
+ out.Dedent();
out << "}\n";
}
-bool GenerateRustParcel(const string& filename, const AidlStructuredParcelable* parcel,
+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);
@@ -585,20 +704,11 @@
}
*code_writer << "#[derive(" << Join(derives, ", ") << ")]\n";
- *code_writer << "pub struct " << parcel->GetName() << " {\n";
- code_writer->Indent();
- for (const auto& variable : parcel->GetFields()) {
- auto field_type = RustNameOf(variable->GetType(), typenames, StorageMode::PARCELABLE_FIELD);
- *code_writer << "pub " << variable->GetName() << ": " << field_type << ",\n";
- }
- code_writer->Dedent();
- *code_writer << "}\n";
-
+ GenerateParcelBody(*code_writer, parcel, typenames);
GenerateMangledAlias(*code_writer, parcel);
GenerateParcelDefault(*code_writer, parcel);
GenerateParcelSerialize(*code_writer, parcel, typenames);
GenerateParcelDeserialize(*code_writer, parcel, typenames);
-
return true;
}
@@ -634,6 +744,10 @@
return GenerateRustParcel(filename, parcelable, typenames, io_delegate);
}
+ if (const AidlUnionDecl* parcelable = defined_type->AsUnionDeclaration(); parcelable != nullptr) {
+ return GenerateRustParcel(filename, parcelable, typenames, io_delegate);
+ }
+
if (const AidlEnumDeclaration* enum_decl = defined_type->AsEnumDeclaration();
enum_decl != nullptr) {
return GenerateRustEnumDeclaration(filename, enum_decl, typenames, io_delegate);
diff --git a/tests/aidl_test_client_parcelables.cpp b/tests/aidl_test_client_parcelables.cpp
index f4ab2f6..696261e 100644
--- a/tests/aidl_test_client_parcelables.cpp
+++ b/tests/aidl_test_client_parcelables.cpp
@@ -297,6 +297,8 @@
EXPECT_EQ(parcelable.addString1, "hello world!");
EXPECT_EQ(parcelable.addString2, "The quick brown fox jumps over the lazy dog.");
+
+ EXPECT_EQ(parcelable.u->get<Union::ns>(), vector<int32_t>({1, 2, 3}));
}
TEST_F(AidlTest, EmptyParcelableHolder) {
diff --git a/tests/aidl_test_service.cpp b/tests/aidl_test_service.cpp
index fc0eccd..cb2409f 100644
--- a/tests/aidl_test_service.cpp
+++ b/tests/aidl_test_service.cpp
@@ -574,6 +574,7 @@
parcelable->const_exprs_9 = ConstantExpressionEnum::hexInt32_3;
parcelable->const_exprs_10 = ConstantExpressionEnum::hexInt64_1;
+ parcelable->u = Union::make<Union::ns>({1, 2, 3});
return Status::ok();
}
diff --git a/tests/android/aidl/tests/StructuredParcelable.aidl b/tests/android/aidl/tests/StructuredParcelable.aidl
index a50bb15..9809de3 100644
--- a/tests/android/aidl/tests/StructuredParcelable.aidl
+++ b/tests/android/aidl/tests/StructuredParcelable.aidl
@@ -20,6 +20,7 @@
import android.aidl.tests.IntEnum;
import android.aidl.tests.LongEnum;
import android.aidl.tests.ConstantExpressionEnum;
+import android.aidl.tests.Union;
@JavaDerive(toString=true)
@RustDerive(Clone=true, PartialEq=true)
@@ -163,5 +164,7 @@
// String expressions
@utf8InCpp String addString1 = "hello" + " world!";
@utf8InCpp String addString2 = "The quick brown fox jumps " + "over the lazy dog.";
+
+ @nullable Union u;
}
diff --git a/tests/android/aidl/tests/Union.aidl b/tests/android/aidl/tests/Union.aidl
index f42ef16..a65d9c8 100644
--- a/tests/android/aidl/tests/Union.aidl
+++ b/tests/android/aidl/tests/Union.aidl
@@ -17,6 +17,8 @@
package android.aidl.tests;
import android.aidl.tests.ByteEnum;
+@JavaDerive(toString=true)
+@RustDerive(Clone=true, PartialEq=true)
union Union {
int[] ns;
int n;
diff --git a/tests/java/src/android/aidl/tests/TestServiceClient.java b/tests/java/src/android/aidl/tests/TestServiceClient.java
index fd0c0d6..de9f25e 100644
--- a/tests/java/src/android/aidl/tests/TestServiceClient.java
+++ b/tests/java/src/android/aidl/tests/TestServiceClient.java
@@ -609,59 +609,62 @@
assertThat(p.const_exprs_9, is(1));
assertThat(p.const_exprs_10, is(1));
- final String expected = "android.aidl.tests.StructuredParcelable{" +
- "shouldContainThreeFs: [17, 17, 17], " +
- "f: 17, " +
- "shouldBeJerry: Jerry, " +
- "shouldBeByteBar: 2, " +
- "shouldBeIntBar: 2000, " +
- "shouldBeLongBar: 200000000000, " +
- "shouldContainTwoByteFoos: [1, 1], " +
- "shouldContainTwoIntFoos: [1000, 1000], " +
- "shouldContainTwoLongFoos: [100000000000, 100000000000], " +
- "stringDefaultsToFoo: foo, " +
- "byteDefaultsToFour: 4, " +
- "intDefaultsToFive: 5, " +
- "longDefaultsToNegativeSeven: -7, " +
- "booleanDefaultsToTrue: true, " +
- "charDefaultsToC: C, " +
- "floatDefaultsToPi: 3.14, " +
- "doubleWithDefault: -3.14E17, " +
- "arrayDefaultsTo123: [1, 2, 3], " +
- "arrayDefaultsToEmpty: [], " +
- "boolDefault: false, " +
- "byteDefault: 0, " +
- "intDefault: 0, " +
- "longDefault: 0, " +
- "floatDefault: 0.0, " +
- "doubleDefault: 0.0, " +
- "checkDoubleFromFloat: 3.14, " +
- "checkStringArray1: [a, b], " +
- "checkStringArray2: [a, b], " +
- "int32_min: -2147483648, " +
- "int32_max: 2147483647, " +
- "int64_max: 9223372036854775807, " +
- "hexInt32_neg_1: -1, " +
- "ibinder: null, " +
- "int32_1: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, " +
- "1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, " +
- "1, 1, 1, 1], " +
- "int64_1: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], " +
- "hexInt32_pos_1: 1, " +
- "hexInt64_pos_1: 1, " +
- "const_exprs_1: 1, " +
- "const_exprs_2: 1, " +
- "const_exprs_3: 1, " +
- "const_exprs_4: 1, " +
- "const_exprs_5: 1, " +
- "const_exprs_6: 1, " +
- "const_exprs_7: 1, " +
- "const_exprs_8: 1, " +
- "const_exprs_9: 1, " +
- "const_exprs_10: 1, " +
- "addString1: hello world!, " +
- "addString2: The quick brown fox jumps over the lazy dog." +
- "}";
+ assertThat(p.u.getNs(), is(new int[] {1, 2, 3}));
+
+ final String expected = "android.aidl.tests.StructuredParcelable{"
+ + "shouldContainThreeFs: [17, 17, 17], "
+ + "f: 17, "
+ + "shouldBeJerry: Jerry, "
+ + "shouldBeByteBar: 2, "
+ + "shouldBeIntBar: 2000, "
+ + "shouldBeLongBar: 200000000000, "
+ + "shouldContainTwoByteFoos: [1, 1], "
+ + "shouldContainTwoIntFoos: [1000, 1000], "
+ + "shouldContainTwoLongFoos: [100000000000, 100000000000], "
+ + "stringDefaultsToFoo: foo, "
+ + "byteDefaultsToFour: 4, "
+ + "intDefaultsToFive: 5, "
+ + "longDefaultsToNegativeSeven: -7, "
+ + "booleanDefaultsToTrue: true, "
+ + "charDefaultsToC: C, "
+ + "floatDefaultsToPi: 3.14, "
+ + "doubleWithDefault: -3.14E17, "
+ + "arrayDefaultsTo123: [1, 2, 3], "
+ + "arrayDefaultsToEmpty: [], "
+ + "boolDefault: false, "
+ + "byteDefault: 0, "
+ + "intDefault: 0, "
+ + "longDefault: 0, "
+ + "floatDefault: 0.0, "
+ + "doubleDefault: 0.0, "
+ + "checkDoubleFromFloat: 3.14, "
+ + "checkStringArray1: [a, b], "
+ + "checkStringArray2: [a, b], "
+ + "int32_min: -2147483648, "
+ + "int32_max: 2147483647, "
+ + "int64_max: 9223372036854775807, "
+ + "hexInt32_neg_1: -1, "
+ + "ibinder: null, "
+ + "int32_1: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, "
+ + "1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, "
+ + "1, 1, 1, 1], "
+ + "int64_1: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "
+ + "hexInt32_pos_1: 1, "
+ + "hexInt64_pos_1: 1, "
+ + "const_exprs_1: 1, "
+ + "const_exprs_2: 1, "
+ + "const_exprs_3: 1, "
+ + "const_exprs_4: 1, "
+ + "const_exprs_5: 1, "
+ + "const_exprs_6: 1, "
+ + "const_exprs_7: 1, "
+ + "const_exprs_8: 1, "
+ + "const_exprs_9: 1, "
+ + "const_exprs_10: 1, "
+ + "addString1: hello world!, "
+ + "addString2: The quick brown fox jumps over the lazy dog., "
+ + "u: android.aidl.tests.Union.ns([1, 2, 3])"
+ + "}";
assertThat(p.toString(), is(expected));
}
diff --git a/tests/rust/test_client.rs b/tests/rust/test_client.rs
index b546528..6492782 100644
--- a/tests/rust/test_client.rs
+++ b/tests/rust/test_client.rs
@@ -22,7 +22,7 @@
self, BpTestService, ITestServiceDefault,
};
use aidl_test_interface::aidl::android::aidl::tests::{
- ByteEnum::ByteEnum, IntEnum::IntEnum, LongEnum::LongEnum, StructuredParcelable,
+ ByteEnum::ByteEnum, IntEnum::IntEnum, LongEnum::LongEnum, StructuredParcelable, Union,
};
use aidl_test_interface::binder;
use aidl_test_versioned_interface::aidl::android::aidl::versioned::tests::IFooInterface::{
@@ -526,6 +526,8 @@
parcelable.addString2,
"The quick brown fox jumps over the lazy dog."
);
+
+ assert_eq!(parcelable.u, Some(Union::Union::Ns(vec![1, 2, 3])))
}
const EXPECTED_ARG_VALUE: i32 = 100;
diff --git a/tests/rust/test_service.rs b/tests/rust/test_service.rs
index 5c32489..c6578b8 100644
--- a/tests/rust/test_service.rs
+++ b/tests/rust/test_service.rs
@@ -21,7 +21,7 @@
};
use aidl_test_interface::aidl::android::aidl::tests::{
ByteEnum::ByteEnum, ConstantExpressionEnum::ConstantExpressionEnum, INamedCallback, INewName,
- IOldName, IntEnum::IntEnum, LongEnum::LongEnum, StructuredParcelable,
+ IOldName, IntEnum::IntEnum, LongEnum::LongEnum, StructuredParcelable, Union,
};
use aidl_test_interface::binder::{self, Interface, ParcelFileDescriptor, SpIBinder};
use aidl_test_versioned_interface_V1::aidl::android::aidl::versioned::tests::IFooInterface::{
@@ -269,6 +269,8 @@
parcelable.const_exprs_9 = ConstantExpressionEnum::hexInt32_3;
parcelable.const_exprs_10 = ConstantExpressionEnum::hexInt64_1;
+ parcelable.u = Some(Union::Union::Ns(vec![1, 2, 3]));
+
Ok(())
}