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

Commit 4ebfd92b authored by Andrew Walbran's avatar Andrew Walbran
Browse files

Add methods to get and insert primitives.

Bug: 389074518
Test: atest libbinder_rs-internal_test
Change-Id: I12ecfe047c6800cd328be88f9c3862d4f64323cd
parent eea65996
Loading
Loading
Loading
Loading
+209 −1
Original line number Diff line number Diff line
@@ -22,9 +22,13 @@ use crate::{
};
use binder_ndk_sys::{
    APersistableBundle, APersistableBundle_delete, APersistableBundle_dup,
    APersistableBundle_isEqual, APersistableBundle_new, APersistableBundle_readFromParcel,
    APersistableBundle_erase, APersistableBundle_getBoolean, APersistableBundle_getDouble,
    APersistableBundle_getInt, APersistableBundle_getLong, APersistableBundle_isEqual,
    APersistableBundle_new, APersistableBundle_putBoolean, APersistableBundle_putDouble,
    APersistableBundle_putInt, APersistableBundle_putLong, APersistableBundle_readFromParcel,
    APersistableBundle_size, APersistableBundle_writeToParcel,
};
use std::ffi::{CString, NulError};
use std::ptr::{null_mut, NonNull};

/// A mapping from string keys to values of various types.
@@ -47,6 +51,154 @@ impl PersistableBundle {
            .try_into()
            .expect("APersistableBundle_size returned a negative size")
    }

    /// Removes any entry with the given key.
    ///
    /// Returns an error if the given key contains a NUL character, otherwise returns whether there
    /// was any entry to remove.
    pub fn remove(&mut self, key: &str) -> Result<bool, 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`.
        Ok(unsafe { APersistableBundle_erase(self.0.as_ptr(), key.as_ptr()) != 0 })
    }

    /// Inserts a key-value pair into the bundle.
    ///
    /// If the key is already present then its value will be overwritten by the given value.
    ///
    /// Returns an error if the key contains a NUL character.
    pub fn insert_bool(&mut self, key: &str, value: bool) -> Result<(), 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`.
        unsafe {
            APersistableBundle_putBoolean(self.0.as_ptr(), key.as_ptr(), value);
        }
        Ok(())
    }

    /// Inserts a key-value pair into the bundle.
    ///
    /// If the key is already present then its value will be overwritten by the given value.
    ///
    /// Returns an error if the key contains a NUL character.
    pub fn insert_int(&mut self, key: &str, value: i32) -> Result<(), 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`.
        unsafe {
            APersistableBundle_putInt(self.0.as_ptr(), key.as_ptr(), value);
        }
        Ok(())
    }

    /// Inserts a key-value pair into the bundle.
    ///
    /// If the key is already present then its value will be overwritten by the given value.
    ///
    /// Returns an error if the key contains a NUL character.
    pub fn insert_long(&mut self, key: &str, value: i64) -> Result<(), 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`.
        unsafe {
            APersistableBundle_putLong(self.0.as_ptr(), key.as_ptr(), value);
        }
        Ok(())
    }

    /// Inserts a key-value pair into the bundle.
    ///
    /// If the key is already present then its value will be overwritten by the given value.
    ///
    /// Returns an error if the key contains a NUL character.
    pub fn insert_double(&mut self, key: &str, value: f64) -> Result<(), 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`.
        unsafe {
            APersistableBundle_putDouble(self.0.as_ptr(), key.as_ptr(), value);
        }
        Ok(())
    }

    /// Gets the boolean 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(&self, key: &str) -> Result<Option<bool>, NulError> {
        let key = CString::new(key)?;
        let mut value = false;
        // 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 pointer must be valid because it comes
        // from a reference.
        if unsafe { APersistableBundle_getBoolean(self.0.as_ptr(), key.as_ptr(), &mut value) } {
            Ok(Some(value))
        } else {
            Ok(None)
        }
    }

    /// Gets the i32 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(&self, key: &str) -> Result<Option<i32>, NulError> {
        let key = CString::new(key)?;
        let mut value = 0;
        // 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 pointer must be valid because it comes
        // from a reference.
        if unsafe { APersistableBundle_getInt(self.0.as_ptr(), key.as_ptr(), &mut value) } {
            Ok(Some(value))
        } else {
            Ok(None)
        }
    }

    /// Gets the i64 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(&self, key: &str) -> Result<Option<i64>, NulError> {
        let key = CString::new(key)?;
        let mut value = 0;
        // 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 pointer must be valid because it comes
        // from a reference.
        if unsafe { APersistableBundle_getLong(self.0.as_ptr(), key.as_ptr(), &mut value) } {
            Ok(Some(value))
        } else {
            Ok(None)
        }
    }

    /// Gets the f64 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(&self, key: &str) -> Result<Option<f64>, NulError> {
        let key = CString::new(key)?;
        let mut value = 0.0;
        // 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 pointer must be valid because it comes
        // from a reference.
        if unsafe { APersistableBundle_getDouble(self.0.as_ptr(), key.as_ptr(), &mut value) } {
            Ok(Some(value))
        } else {
            Ok(None)
        }
    }
}

// SAFETY: The underlying *APersistableBundle can be moved between threads.
@@ -131,4 +283,60 @@ mod test {
        let duplicate = bundle.clone();
        assert_eq!(bundle, duplicate);
    }

    #[test]
    fn get_empty() {
        let bundle = PersistableBundle::new();
        assert_eq!(bundle.get_bool("foo"), Ok(None));
        assert_eq!(bundle.get_int("foo"), Ok(None));
        assert_eq!(bundle.get_long("foo"), Ok(None));
        assert_eq!(bundle.get_double("foo"), Ok(None));
    }

    #[test]
    fn remove_empty() {
        let mut bundle = PersistableBundle::new();
        assert_eq!(bundle.remove("foo"), Ok(false));
    }

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

        assert_eq!(bundle.insert_bool("bool", true), Ok(()));
        assert_eq!(bundle.insert_int("int", 42), Ok(()));
        assert_eq!(bundle.insert_long("long", 66), Ok(()));
        assert_eq!(bundle.insert_double("double", 123.4), Ok(()));

        assert_eq!(bundle.get_bool("bool"), Ok(Some(true)));
        assert_eq!(bundle.get_int("int"), Ok(Some(42)));
        assert_eq!(bundle.get_long("long"), Ok(Some(66)));
        assert_eq!(bundle.get_double("double"), Ok(Some(123.4)));
        assert_eq!(bundle.size(), 4);

        // Getting the wrong type should return nothing.
        assert_eq!(bundle.get_int("bool"), Ok(None));
        assert_eq!(bundle.get_long("bool"), Ok(None));
        assert_eq!(bundle.get_double("bool"), Ok(None));
        assert_eq!(bundle.get_bool("int"), Ok(None));
        assert_eq!(bundle.get_long("int"), Ok(None));
        assert_eq!(bundle.get_double("int"), Ok(None));
        assert_eq!(bundle.get_bool("long"), Ok(None));
        assert_eq!(bundle.get_int("long"), Ok(None));
        assert_eq!(bundle.get_double("long"), Ok(None));
        assert_eq!(bundle.get_bool("double"), Ok(None));
        assert_eq!(bundle.get_int("double"), Ok(None));
        assert_eq!(bundle.get_long("double"), Ok(None));

        // If they are removed they should no longer be present.
        assert_eq!(bundle.remove("bool"), Ok(true));
        assert_eq!(bundle.remove("int"), Ok(true));
        assert_eq!(bundle.remove("long"), Ok(true));
        assert_eq!(bundle.remove("double"), Ok(true));
        assert_eq!(bundle.get_bool("bool"), Ok(None));
        assert_eq!(bundle.get_int("int"), Ok(None));
        assert_eq!(bundle.get_long("long"), Ok(None));
        assert_eq!(bundle.get_double("double"), Ok(None));
        assert_eq!(bundle.size(), 0);
    }
}