binder_rs: Add in-place deserialization methods
This adds deserialize_from methods to the Deserialize
and DeserializeOption traits in libbinder_rs that perform
in-place deserialization of values on top of existing objects.
The new methods are used for partial deserialization of parcelables
in the AIDL compiler.
Also adds a helper impl_deserialize_for_parcelable! helper macro.
Bug: 186724059
Test: m
Change-Id: I9fcbd4c7fa4ab85d8ab84792c9c5595ee149879f
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index 6c34824..ef84ade 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -219,6 +219,13 @@
D::deserialize(self)
}
+ /// Attempt to read a type that implements [`Deserialize`] from this
+ /// `Parcel` onto an existing value. This operation will overwrite the old
+ /// value partially or completely, depending on how much data is available.
+ pub fn read_onto<D: Deserialize>(&self, x: &mut D) -> Result<()> {
+ x.deserialize_from(self)
+ }
+
/// Read a vector size from the `Parcel` and resize the given output vector
/// to be correctly sized for that amount of data.
///
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index f57788b..956ecfe 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -39,6 +39,14 @@
pub trait Deserialize: Sized {
/// Deserialize an instance from the given [`Parcel`].
fn deserialize(parcel: &Parcel) -> Result<Self>;
+
+ /// Deserialize an instance from the given [`Parcel`] onto the
+ /// current object. This operation will overwrite the old value
+ /// partially or completely, depending on how much data is available.
+ fn deserialize_from(&mut self, parcel: &Parcel) -> Result<()> {
+ *self = Self::deserialize(parcel)?;
+ Ok(())
+ }
}
/// Helper trait for types that can be serialized as arrays.
@@ -184,6 +192,14 @@
parcel.read().map(Some)
}
}
+
+ /// Deserialize an Option of this type from the given [`Parcel`] onto the
+ /// current object. This operation will overwrite the current value
+ /// partially or completely, depending on how much data is available.
+ fn deserialize_option_from(this: &mut Option<Self>, parcel: &Parcel) -> Result<()> {
+ *this = Self::deserialize_option(parcel)?;
+ Ok(())
+ }
}
/// Callback to allocate a vector for parcel array read functions.
@@ -677,6 +693,75 @@
fn deserialize(parcel: &Parcel) -> Result<Self> {
DeserializeOption::deserialize_option(parcel)
}
+
+ fn deserialize_from(&mut self, parcel: &Parcel) -> Result<()> {
+ DeserializeOption::deserialize_option_from(self, parcel)
+ }
+}
+
+/// Implement `Deserialize` trait and friends for a parcelable
+///
+/// This is an internal macro used by the AIDL compiler to implement
+/// `Deserialize`, `DeserializeArray` and `DeserializeOption` for
+/// structured parcelables. The target type must implement a
+/// `deserialize_parcelable` method with the following signature:
+/// ```no_run
+/// fn deserialize_parcelable(
+/// &mut self,
+/// parcel: &binder::parcel::Parcelable,
+/// ) -> binder::Result<()> {
+/// // ...
+/// }
+/// ```
+#[macro_export]
+macro_rules! impl_deserialize_for_parcelable {
+ ($parcelable:ident) => {
+ impl $crate::parcel::Deserialize for $parcelable {
+ fn deserialize(
+ parcel: &$crate::parcel::Parcel,
+ ) -> $crate::Result<Self> {
+ $crate::parcel::DeserializeOption::deserialize_option(parcel)
+ .transpose()
+ .unwrap_or(Err($crate::StatusCode::UNEXPECTED_NULL))
+ }
+ fn deserialize_from(
+ &mut self,
+ parcel: &$crate::parcel::Parcel,
+ ) -> $crate::Result<()> {
+ let status: i32 = parcel.read()?;
+ if status == 0 {
+ Err($crate::StatusCode::UNEXPECTED_NULL)
+ } else {
+ self.deserialize_parcelable(parcel)
+ }
+ }
+ }
+
+ impl $crate::parcel::DeserializeArray for $parcelable {}
+
+ impl $crate::parcel::DeserializeOption for $parcelable {
+ fn deserialize_option(
+ parcel: &$crate::parcel::Parcel,
+ ) -> $crate::Result<Option<Self>> {
+ let mut result = None;
+ Self::deserialize_option_from(&mut result, parcel)?;
+ Ok(result)
+ }
+ fn deserialize_option_from(
+ this: &mut Option<Self>,
+ parcel: &$crate::parcel::Parcel,
+ ) -> $crate::Result<()> {
+ let status: i32 = parcel.read()?;
+ if status == 0 {
+ *this = None;
+ Ok(())
+ } else {
+ this.get_or_insert_with(Self::default)
+ .deserialize_parcelable(parcel)
+ }
+ }
+ }
+ }
}
#[test]