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

Commit 430db867 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Add methods to get vectors." into main

parents 52b4e753 ba4ca763
Loading
Loading
Loading
Loading
+117 −9
Original line number Diff line number Diff line
@@ -22,17 +22,18 @@ use crate::{
};
use binder_ndk_sys::{
    APersistableBundle, APersistableBundle_delete, APersistableBundle_dup,
    APersistableBundle_erase, APersistableBundle_getBoolean, APersistableBundle_getDouble,
    APersistableBundle_getInt, APersistableBundle_getLong, APersistableBundle_getPersistableBundle,
    APersistableBundle_isEqual, APersistableBundle_new, APersistableBundle_putBoolean,
    APersistableBundle_putBooleanVector, APersistableBundle_putDouble,
    APersistableBundle_putDoubleVector, APersistableBundle_putInt, APersistableBundle_putIntVector,
    APersistableBundle_putLong, APersistableBundle_putLongVector,
    APersistableBundle_erase, APersistableBundle_getBoolean, APersistableBundle_getBooleanVector,
    APersistableBundle_getDouble, APersistableBundle_getDoubleVector, APersistableBundle_getInt,
    APersistableBundle_getIntVector, APersistableBundle_getLong, APersistableBundle_getLongVector,
    APersistableBundle_getPersistableBundle, APersistableBundle_isEqual, APersistableBundle_new,
    APersistableBundle_putBoolean, APersistableBundle_putBooleanVector,
    APersistableBundle_putDouble, APersistableBundle_putDoubleVector, APersistableBundle_putInt,
    APersistableBundle_putIntVector, APersistableBundle_putLong, APersistableBundle_putLongVector,
    APersistableBundle_putPersistableBundle, APersistableBundle_putString,
    APersistableBundle_putStringVector, APersistableBundle_readFromParcel, APersistableBundle_size,
    APersistableBundle_writeToParcel,
    APersistableBundle_writeToParcel, APERSISTABLEBUNDLE_KEY_NOT_FOUND,
};
use std::ffi::{CString, NulError};
use std::ffi::{c_char, CString, NulError};
use std::ptr::{null_mut, NonNull};

/// A mapping from string keys to values of various types.
@@ -373,6 +374,104 @@ impl PersistableBundle {
        }
    }

    /// Gets the vector of `T` associated with the given key.
    ///
    /// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
    /// in the bundle.
    ///
    /// `get_func` should be one of the `APersistableBundle_get*Vector` functions from
    /// `binder_ndk_sys`.
    ///
    /// # Safety
    ///
    /// `get_func` must only require that the pointers it takes are valid for the duration of the
    /// call. It must allow a null pointer for the buffer, and must return the size in bytes of
    /// buffer it requires. If it is given a non-null buffer pointer it must write that number of
    /// bytes to the buffer, which must be a whole number of valid `T` values.
    unsafe fn get_vec<T: Clone + Default>(
        &self,
        key: &str,
        get_func: unsafe extern "C" fn(
            *const APersistableBundle,
            *const c_char,
            *mut T,
            i32,
        ) -> i32,
    ) -> Result<Option<Vec<T>>, NulError> {
        let key = CString::new(key)?;
        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
        // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
        // to be valid for the lifetime of `key`. A null pointer is allowed for the buffer.
        match unsafe { get_func(self.0.as_ptr(), key.as_ptr(), null_mut(), 0) } {
            APERSISTABLEBUNDLE_KEY_NOT_FOUND => Ok(None),
            required_buffer_size => {
                let mut value = vec![
                    T::default();
                    usize::try_from(required_buffer_size).expect(
                        "APersistableBundle_get*Vector returned invalid size"
                    ) / size_of::<T>()
                ];
                // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for
                // the lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()`
                // is guaranteed to be valid for the lifetime of `key`. The value buffer pointer is
                // valid as it comes from the Vec we just allocated.
                match unsafe {
                    get_func(
                        self.0.as_ptr(),
                        key.as_ptr(),
                        value.as_mut_ptr(),
                        (value.len() * size_of::<T>()).try_into().unwrap(),
                    )
                } {
                    APERSISTABLEBUNDLE_KEY_NOT_FOUND => {
                        panic!("APersistableBundle_get*Vector failed to find key after first finding it");
                    }
                    _ => Ok(Some(value)),
                }
            }
        }
    }

    /// Gets the boolean vector value associated with the given key.
    ///
    /// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
    /// in the bundle.
    pub fn get_bool_vec(&self, key: &str) -> Result<Option<Vec<bool>>, NulError> {
        // SAFETY: APersistableBundle_getBooleanVector fulfils all the safety requirements of
        // `get_vec`.
        unsafe { self.get_vec(key, APersistableBundle_getBooleanVector) }
    }

    /// Gets the i32 vector value associated with the given key.
    ///
    /// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
    /// in the bundle.
    pub fn get_int_vec(&self, key: &str) -> Result<Option<Vec<i32>>, NulError> {
        // SAFETY: APersistableBundle_getIntVector fulfils all the safety requirements of
        // `get_vec`.
        unsafe { self.get_vec(key, APersistableBundle_getIntVector) }
    }

    /// Gets the i64 vector value associated with the given key.
    ///
    /// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
    /// in the bundle.
    pub fn get_long_vec(&self, key: &str) -> Result<Option<Vec<i64>>, NulError> {
        // SAFETY: APersistableBundle_getLongVector fulfils all the safety requirements of
        // `get_vec`.
        unsafe { self.get_vec(key, APersistableBundle_getLongVector) }
    }

    /// Gets the f64 vector value associated with the given key.
    ///
    /// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
    /// in the bundle.
    pub fn get_double_vec(&self, key: &str) -> Result<Option<Vec<f64>>, NulError> {
        // SAFETY: APersistableBundle_getDoubleVector fulfils all the safety requirements of
        // `get_vec`.
        unsafe { self.get_vec(key, APersistableBundle_getDoubleVector) }
    }

    /// Gets the `PersistableBundle` value associated with the given key.
    ///
    /// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
@@ -486,6 +585,10 @@ mod test {
        assert_eq!(bundle.get_int("foo"), Ok(None));
        assert_eq!(bundle.get_long("foo"), Ok(None));
        assert_eq!(bundle.get_double("foo"), Ok(None));
        assert_eq!(bundle.get_bool_vec("foo"), Ok(None));
        assert_eq!(bundle.get_int_vec("foo"), Ok(None));
        assert_eq!(bundle.get_long_vec("foo"), Ok(None));
        assert_eq!(bundle.get_double_vec("foo"), Ok(None));
    }

    #[test]
@@ -543,7 +646,7 @@ mod test {
    }

    #[test]
    fn insert_vec() {
    fn insert_get_vec() {
        let mut bundle = PersistableBundle::new();

        assert_eq!(bundle.insert_bool_vec("bool", &[]), Ok(()));
@@ -567,6 +670,11 @@ mod test {
        );

        assert_eq!(bundle.size(), 5);

        assert_eq!(bundle.get_bool_vec("bool"), Ok(Some(vec![])));
        assert_eq!(bundle.get_int_vec("int"), Ok(Some(vec![42])));
        assert_eq!(bundle.get_long_vec("long"), Ok(Some(vec![66, 67, 68])));
        assert_eq!(bundle.get_double_vec("double"), Ok(Some(vec![123.4])));
    }

    #[test]
+5 −0
Original line number Diff line number Diff line
@@ -92,6 +92,11 @@ enum {
#endif
};

enum {
    APERSISTABLEBUNDLE_KEY_NOT_FOUND = APERSISTABLEBUNDLE_KEY_NOT_FOUND,
    APERSISTABLEBUNDLE_ALLOCATOR_FAILED = APERSISTABLEBUNDLE_ALLOCATOR_FAILED,
};

} // namespace consts

} // namespace c_interface