diff options
| author | 2021-05-01 07:34:51 +0000 | |
|---|---|---|
| committer | 2021-05-14 22:48:43 +0000 | |
| commit | 5000615e8959f3386cb44d4739de7e7396ad005e (patch) | |
| tree | 153bbb68074618ef4886af9ae47b9d17931979ff | |
| parent | 7e563f090ba19c36b9879e14388a0e377f1523b5 (diff) | |
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
| -rw-r--r-- | libs/binder/rust/src/parcel.rs | 7 | ||||
| -rw-r--r-- | libs/binder/rust/src/parcel/parcelable.rs | 85 |
2 files changed, 92 insertions, 0 deletions
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<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 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<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 @@ 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<Self>, parcel: &Parcel) -> Result<()> { + *this = Self::deserialize_option(parcel)?; + Ok(()) + } } /// Callback to allocate a vector for parcel array read functions. @@ -677,6 +693,75 @@ impl<T: DeserializeOption> Deserialize for Option<T> { 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] |