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" }
+}