Merge "Add methods to get and insert primitives." into main
diff --git a/libs/binder/rust/src/persistable_bundle.rs b/libs/binder/rust/src/persistable_bundle.rs
index 1323d99..58ea138 100644
--- a/libs/binder/rust/src/persistable_bundle.rs
+++ b/libs/binder/rust/src/persistable_bundle.rs
@@ -22,9 +22,13 @@
 };
 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 @@
             .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 @@
         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);
+    }
 }