Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5000615e authored by Andrei Homescu's avatar Andrei Homescu
Browse files

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
parent 7e563f09
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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.
    ///
+85 −0
Original line number Diff line number Diff line
@@ -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]