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/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) {