From 5000615e8959f3386cb44d4739de7e7396ad005e Mon Sep 17 00:00:00 2001 From: Andrei Homescu Date: Sat, 1 May 2021 07:34:51 +0000 Subject: 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 --- libs/binder/rust/src/parcel.rs | 7 +++ libs/binder/rust/src/parcel/parcelable.rs | 85 +++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs index 6c34824a5e..ef84ade585 100644 --- a/libs/binder/rust/src/parcel.rs +++ b/libs/binder/rust/src/parcel.rs @@ -219,6 +219,13 @@ impl Parcel { 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(&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 f57788b87e..956ecfe998 100644 --- a/libs/binder/rust/src/parcel/parcelable.rs +++ b/libs/binder/rust/src/parcel/parcelable.rs @@ -39,6 +39,14 @@ pub trait Serialize { pub trait Deserialize: Sized { /// Deserialize an instance from the given [`Parcel`]. fn deserialize(parcel: &Parcel) -> Result; + + /// 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 @@ pub trait DeserializeOption: Deserialize { 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, parcel: &Parcel) -> Result<()> { + *this = Self::deserialize_option(parcel)?; + Ok(()) + } } /// Callback to allocate a vector for parcel array read functions. @@ -677,6 +693,75 @@ impl Deserialize for Option { fn deserialize(parcel: &Parcel) -> Result { 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 { + $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> { + let mut result = None; + Self::deserialize_option_from(&mut result, parcel)?; + Ok(result) + } + fn deserialize_option_from( + this: &mut Option, + 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] -- cgit v1.2.3-59-g8ed1b