From 5709589a70a00ef70f43d417199f0986fd099c44 Mon Sep 17 00:00:00 2001 From: Brad Campbell Date: Tue, 1 Aug 2023 14:43:36 -0400 Subject: [PATCH 1/8] api: add key-value driver --- Cargo.toml | 4 +- apis/key_value/Cargo.toml | 16 ++++ apis/key_value/src/lib.rs | 149 ++++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 + 4 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 apis/key_value/Cargo.toml create mode 100644 apis/key_value/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 1d1267d1..ef430280 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ version = "0.1.0" rust-version = "1.70" [dependencies] -libtock_adc = { path = "apis/adc" } +libtock_adc = { path = "apis/adc"} libtock_air_quality = { path = "apis/air_quality" } libtock_alarm = { path = "apis/alarm" } libtock_ambient_light = { path = "apis/ambient_light" } @@ -26,6 +26,7 @@ libtock_console = { path = "apis/console" } libtock_debug_panic = { path = "panic_handlers/debug_panic" } libtock_gpio = { path = "apis/gpio" } libtock_i2c_master_slave = { path = "apis/i2c_master_slave" } +libtock_key_value = { path = "apis/key_value"} libtock_leds = { path = "apis/leds" } libtock_low_level_debug = { path = "apis/low_level_debug" } libtock_ninedof = { path = "apis/ninedof" } @@ -61,6 +62,7 @@ members = [ "apis/console", "apis/gpio", "apis/i2c_master_slave", + "apis/key_value", "apis/leds", "apis/low_level_debug", "apis/ninedof", diff --git a/apis/key_value/Cargo.toml b/apis/key_value/Cargo.toml new file mode 100644 index 00000000..b2b4b729 --- /dev/null +++ b/apis/key_value/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "libtock_key_value" +version = "0.1.0" +authors = [ + "Tock Project Developers ", +] +license = "MIT/Apache-2.0" +edition = "2021" +repository = "https://www.github.com/tock/libtock-rs" +description = "libtock key-value driver" + +[dependencies] +libtock_platform = { path = "../../platform" } + +[dev-dependencies] +libtock_unittest = { path = "../../unittest" } diff --git a/apis/key_value/src/lib.rs b/apis/key_value/src/lib.rs new file mode 100644 index 00000000..0bc810a3 --- /dev/null +++ b/apis/key_value/src/lib.rs @@ -0,0 +1,149 @@ +#![no_std] + +use core::cell::Cell; +use libtock_platform as platform; +use libtock_platform::allow_ro::AllowRo; +use libtock_platform::allow_rw::AllowRw; +use libtock_platform::share; +use libtock_platform::subscribe::Subscribe; +use libtock_platform::{DefaultConfig, ErrorCode, Syscalls}; + +/// The key-value driver. +/// +/// It provides access to a key-value store. +pub struct KeyValue(S, C); + +impl KeyValue { + /// Run a check against the key-value capsule to ensure it is present. + #[inline(always)] + pub fn exists() -> bool { + S::command(DRIVER_NUM, command::DRIVER_CHECK, 0, 0).is_success() + } + + /// Get a key-value object from the `key`. + pub fn get(key: &[u8], value: &mut [u8]) -> Result { + let called: Cell>> = Cell::new(None); + share::scope::< + ( + AllowRo<_, DRIVER_NUM, { allow_ro::KEY }>, + AllowRw<_, DRIVER_NUM, { allow_rw::VALUE_READ }>, + Subscribe<_, DRIVER_NUM, { subscribe::CALLBACK }>, + ), + _, + _, + >(|handle| { + let (allow_key, allow_value, subscribe) = handle.split(); + + S::allow_ro::(allow_key, key)?; + S::allow_rw::(allow_value, value)?; + + S::subscribe::<_, _, C, DRIVER_NUM, { subscribe::CALLBACK }>(subscribe, &called)?; + + S::command(DRIVER_NUM, command::GET, 0, 0).to_result()?; + + loop { + S::yield_wait(); + if let Some(ret) = called.get() { + return ret.map(|(arg0,)| arg0); + } + } + }) + } + + /// Set a key-value object for the `key`. + pub fn set(key: &[u8], value: &[u8]) -> Result<(), ErrorCode> { + let called: Cell>> = Cell::new(None); + share::scope::< + ( + AllowRo<_, DRIVER_NUM, { allow_ro::KEY }>, + AllowRo<_, DRIVER_NUM, { allow_ro::VALUE_WRITE }>, + Subscribe<_, DRIVER_NUM, { subscribe::CALLBACK }>, + ), + _, + _, + >(|handle| { + let (allow_key, allow_value, subscribe) = handle.split(); + + S::allow_ro::(allow_key, key)?; + S::allow_ro::(allow_value, value)?; + + S::subscribe::<_, _, C, DRIVER_NUM, { subscribe::CALLBACK }>(subscribe, &called)?; + + S::command(DRIVER_NUM, command::SET, 0, 0).to_result()?; + + loop { + S::yield_wait(); + if let Some(ret) = called.get() { + return ret; + } + } + }) + } + + /// Delete a key-value object by `key`. + pub fn delete(key: &[u8]) -> Result<(), ErrorCode> { + let called: Cell>> = Cell::new(None); + share::scope::< + ( + AllowRo<_, DRIVER_NUM, { allow_ro::KEY }>, + Subscribe<_, DRIVER_NUM, { subscribe::CALLBACK }>, + ), + _, + _, + >(|handle| { + let (allow_key, subscribe) = handle.split(); + + S::allow_ro::(allow_key, key)?; + + S::subscribe::<_, _, C, DRIVER_NUM, { subscribe::CALLBACK }>(subscribe, &called)?; + + S::command(DRIVER_NUM, command::DELETE, 0, 0).to_result()?; + + loop { + S::yield_wait(); + if let Some(ret) = called.get() { + return ret; + } + } + }) + } +} + +/// System call configuration trait for `KeyValue`. +pub trait Config: + platform::allow_ro::Config + platform::allow_rw::Config + platform::subscribe::Config +{ +} +impl + Config for T +{ +} + +// ----------------------------------------------------------------------------- +// Driver number and command IDs +// ----------------------------------------------------------------------------- + +const DRIVER_NUM: u32 = 0x50003; + +// Command IDs +#[allow(unused)] +mod command { + pub const DRIVER_CHECK: u32 = 0; + pub const GET: u32 = 1; + pub const SET: u32 = 2; + pub const DELETE: u32 = 3; +} + +#[allow(unused)] +mod subscribe { + pub const CALLBACK: u32 = 0; +} + +mod allow_ro { + pub const KEY: u32 = 0; + pub const VALUE_WRITE: u32 = 1; +} + +mod allow_rw { + pub const VALUE_READ: u32 = 0; +} diff --git a/src/lib.rs b/src/lib.rs index b45e2bfb..d86765b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -87,3 +87,7 @@ pub mod temperature { pub type Temperature = temperature::Temperature; pub use temperature::TemperatureListener; } +pub mod key_value { + use libtock_key_value as key_value; + pub type KeyValue = key_value::KeyValue; +} From f7092826a20bf75d198ac0ab233e2d84891e23f4 Mon Sep 17 00:00:00 2001 From: Brad Campbell Date: Tue, 1 Aug 2023 14:43:53 -0400 Subject: [PATCH 2/8] examples: add kv test app --- examples/kv.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 examples/kv.rs diff --git a/examples/kv.rs b/examples/kv.rs new file mode 100644 index 00000000..17bab114 --- /dev/null +++ b/examples/kv.rs @@ -0,0 +1,73 @@ +//! A key-value store example. Gets and sets key-value objects. + +#![no_main] +#![no_std] + +use core::fmt::Write; +use core::str; +use libtock::console::Console; + +use libtock::key_value::KeyValue; +use libtock::runtime::{set_main, stack_size}; + +set_main! {main} +stack_size! {0x200} + +/// Retrieve a key and insert the value into `value`. Then print the value +/// contents as a UTF-8 string or as hex values. +fn get_and_print(key: &[u8], value: &mut [u8]) { + match KeyValue::get(key, value) { + Ok(val_length) => { + let val_length: usize = val_length as usize; + writeln!(Console::writer(), "Got value len: {}", val_length).unwrap(); + + match str::from_utf8(&value[0..val_length]) { + Ok(val_str) => writeln!(Console::writer(), "Value: {}", val_str).unwrap(), + Err(_) => { + write!(Console::writer(), "Value: ").unwrap(); + for i in 0..val_length { + write!(Console::writer(), "{:02x}", value[i]).unwrap(); + } + write!(Console::writer(), "\n").unwrap(); + } + } + } + Err(_) => writeln!(Console::writer(), "error KV::get()",).unwrap(), + } +} + +fn main() { + // Check if there is key-value support on this board. + if KeyValue::exists() { + writeln!(Console::writer(), "KV available!").unwrap() + } else { + writeln!(Console::writer(), "ERR! KV unavailable").unwrap(); + } + + // Do a test query for key: a. + let key = "a"; + let mut value: [u8; 64] = [0; 64]; + get_and_print(key.as_bytes(), &mut value); + + // Now set, get, delete, then get the key: libtock-rs. + let set_key = "libtock-rs"; + let set_val = "kv test app"; + + match KeyValue::set(set_key.as_bytes(), set_val.as_bytes()) { + Ok(()) => { + writeln!(Console::writer(), "Successfully set the key-value").unwrap(); + } + Err(_) => writeln!(Console::writer(), "error KV::set()",).unwrap(), + } + + get_and_print(set_key.as_bytes(), &mut value); + + match KeyValue::delete(set_key.as_bytes()) { + Ok(()) => { + writeln!(Console::writer(), "Successfully deleted the key-value").unwrap(); + } + Err(_) => writeln!(Console::writer(), "error KV::delete()",).unwrap(), + } + + get_and_print(set_key.as_bytes(), &mut value); +} From 2c623c0399165a9084786a8f027c058c3fe47ba2 Mon Sep 17 00:00:00 2001 From: Brad Campbell Date: Thu, 17 Aug 2023 23:30:57 -0400 Subject: [PATCH 3/8] api: kv: add add/update --- apis/key_value/src/lib.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/apis/key_value/src/lib.rs b/apis/key_value/src/lib.rs index 0bc810a3..289aaf0a 100644 --- a/apis/key_value/src/lib.rs +++ b/apis/key_value/src/lib.rs @@ -51,7 +51,7 @@ impl KeyValue { } /// Set a key-value object for the `key`. - pub fn set(key: &[u8], value: &[u8]) -> Result<(), ErrorCode> { + fn insert(command_num: u32, key: &[u8], value: &[u8]) -> Result<(), ErrorCode> { let called: Cell>> = Cell::new(None); share::scope::< ( @@ -69,7 +69,7 @@ impl KeyValue { S::subscribe::<_, _, C, DRIVER_NUM, { subscribe::CALLBACK }>(subscribe, &called)?; - S::command(DRIVER_NUM, command::SET, 0, 0).to_result()?; + S::command(DRIVER_NUM, command_num, 0, 0).to_result()?; loop { S::yield_wait(); @@ -80,6 +80,21 @@ impl KeyValue { }) } + /// Set a key-value object for the `key`. + pub fn set(key: &[u8], value: &[u8]) -> Result<(), ErrorCode> { + Self::insert(command::SET, key, value) + } + + /// Set a key-value object for the `key`. + pub fn add(key: &[u8], value: &[u8]) -> Result<(), ErrorCode> { + Self::insert(command::ADD, key, value) + } + + /// Set a key-value object for the `key`. + pub fn update(key: &[u8], value: &[u8]) -> Result<(), ErrorCode> { + Self::insert(command::UPDATE, key, value) + } + /// Delete a key-value object by `key`. pub fn delete(key: &[u8]) -> Result<(), ErrorCode> { let called: Cell>> = Cell::new(None); @@ -132,6 +147,8 @@ mod command { pub const GET: u32 = 1; pub const SET: u32 = 2; pub const DELETE: u32 = 3; + pub const ADD: u32 = 4; + pub const UPDATE: u32 = 5; } #[allow(unused)] From 2d7e3fa2e682b89499bc051f1599a611cb7872b0 Mon Sep 17 00:00:00 2001 From: Brad Campbell Date: Wed, 10 Jan 2024 15:46:02 -0500 Subject: [PATCH 4/8] api: kv: add tests --- apis/key_value/src/lib.rs | 3 + apis/key_value/src/tests.rs | 227 ++++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 apis/key_value/src/tests.rs diff --git a/apis/key_value/src/lib.rs b/apis/key_value/src/lib.rs index 289aaf0a..8ac7e8c5 100644 --- a/apis/key_value/src/lib.rs +++ b/apis/key_value/src/lib.rs @@ -134,6 +134,9 @@ impl; + +fn _get(kernel: &fake::Kernel) -> Result { + kernel.add_expected_syscall(ExpectedSyscall::AllowRo { + driver_num: DRIVER_NUM, + buffer_num: allow_ro::KEY, + return_error: None, + }); + kernel.add_expected_syscall(ExpectedSyscall::AllowRw { + driver_num: DRIVER_NUM, + buffer_num: allow_rw::VALUE_READ, + return_error: None, + }); + kernel.add_expected_syscall(ExpectedSyscall::Subscribe { + driver_num: DRIVER_NUM, + subscribe_num: subscribe::CALLBACK, + skip_with_error: None, + }); + kernel.add_expected_syscall(ExpectedSyscall::Command { + driver_id: DRIVER_NUM, + command_id: command::GET, + argument0: 0, + argument1: 0, + override_return: Some(command_return::success()), + }); + + let mut buf = [0; 3]; + Kv::get("mykey".as_bytes(), &mut buf) +} + +fn _set(kernel: &fake::Kernel) -> Result<(), ErrorCode> { + kernel.add_expected_syscall(ExpectedSyscall::AllowRo { + driver_num: DRIVER_NUM, + buffer_num: allow_ro::KEY, + return_error: None, + }); + kernel.add_expected_syscall(ExpectedSyscall::AllowRo { + driver_num: DRIVER_NUM, + buffer_num: allow_ro::VALUE_WRITE, + return_error: None, + }); + kernel.add_expected_syscall(ExpectedSyscall::Subscribe { + driver_num: DRIVER_NUM, + subscribe_num: subscribe::CALLBACK, + skip_with_error: None, + }); + kernel.add_expected_syscall(ExpectedSyscall::Command { + driver_id: DRIVER_NUM, + command_id: command::SET, + argument0: 0, + argument1: 0, + override_return: Some(command_return::success()), + }); + + Kv::set("mykey".as_bytes(), b"hooray") +} + +fn _add(kernel: &fake::Kernel) -> Result<(), ErrorCode> { + kernel.add_expected_syscall(ExpectedSyscall::AllowRo { + driver_num: DRIVER_NUM, + buffer_num: allow_ro::KEY, + return_error: None, + }); + kernel.add_expected_syscall(ExpectedSyscall::AllowRo { + driver_num: DRIVER_NUM, + buffer_num: allow_ro::VALUE_WRITE, + return_error: None, + }); + kernel.add_expected_syscall(ExpectedSyscall::Subscribe { + driver_num: DRIVER_NUM, + subscribe_num: subscribe::CALLBACK, + skip_with_error: None, + }); + kernel.add_expected_syscall(ExpectedSyscall::Command { + driver_id: DRIVER_NUM, + command_id: command::ADD, + argument0: 0, + argument1: 0, + override_return: Some(command_return::success()), + }); + + Kv::add("mykey".as_bytes(), b"hooray2") +} + +fn _update(kernel: &fake::Kernel) -> Result<(), ErrorCode> { + kernel.add_expected_syscall(ExpectedSyscall::AllowRo { + driver_num: DRIVER_NUM, + buffer_num: allow_ro::KEY, + return_error: None, + }); + kernel.add_expected_syscall(ExpectedSyscall::AllowRo { + driver_num: DRIVER_NUM, + buffer_num: allow_ro::VALUE_WRITE, + return_error: None, + }); + kernel.add_expected_syscall(ExpectedSyscall::Subscribe { + driver_num: DRIVER_NUM, + subscribe_num: subscribe::CALLBACK, + skip_with_error: None, + }); + kernel.add_expected_syscall(ExpectedSyscall::Command { + driver_id: DRIVER_NUM, + command_id: command::UPDATE, + argument0: 0, + argument1: 0, + override_return: Some(command_return::success()), + }); + + Kv::update("mykey".as_bytes(), b"hooray3") +} + +fn _delete(kernel: &fake::Kernel) -> Result<(), ErrorCode> { + kernel.add_expected_syscall(ExpectedSyscall::AllowRo { + driver_num: DRIVER_NUM, + buffer_num: allow_ro::KEY, + return_error: None, + }); + kernel.add_expected_syscall(ExpectedSyscall::Subscribe { + driver_num: DRIVER_NUM, + subscribe_num: subscribe::CALLBACK, + skip_with_error: None, + }); + kernel.add_expected_syscall(ExpectedSyscall::Command { + driver_id: DRIVER_NUM, + command_id: command::DELETE, + argument0: 0, + argument1: 0, + override_return: Some(command_return::success()), + }); + + Kv::delete("mykey".as_bytes()) +} + +#[test] +fn no_driver() { + let _kernel = fake::Kernel::new(); + assert!(!Kv::exists()); +} + +#[test] +fn driver_check() { + let kernel = fake::Kernel::new(); + let driver = fake::KeyValue::new(); + kernel.add_driver(&driver); + + assert!(Kv::exists()); +} + +#[test] +fn get_fail() { + let kernel = fake::Kernel::new(); + let driver = fake::KeyValue::new(); + kernel.add_driver(&driver); + + assert_eq!(_get(&kernel), Err(ErrorCode::NoSupport)); +} + +#[test] +fn set_get() { + let kernel = fake::Kernel::new(); + let driver = fake::KeyValue::new(); + kernel.add_driver(&driver); + + assert_eq!(_set(&kernel), Ok(())); + assert_eq!(_get(&kernel), Ok(6)); +} + +#[test] +fn add() { + let kernel = fake::Kernel::new(); + let driver = fake::KeyValue::new(); + kernel.add_driver(&driver); + + assert_eq!(_add(&kernel), Ok(())); +} + +#[test] +fn add_fail() { + let kernel = fake::Kernel::new(); + let driver = fake::KeyValue::new(); + kernel.add_driver(&driver); + + assert_eq!(_set(&kernel), Ok(())); + assert_eq!(_add(&kernel), Err(ErrorCode::NoSupport)); +} + +#[test] +fn update() { + let kernel = fake::Kernel::new(); + let driver = fake::KeyValue::new(); + kernel.add_driver(&driver); + + assert_eq!(_set(&kernel), Ok(())); + assert_eq!(_update(&kernel), Ok(())); +} + +#[test] +fn update_fail() { + let kernel = fake::Kernel::new(); + let driver = fake::KeyValue::new(); + kernel.add_driver(&driver); + + assert_eq!(_update(&kernel), Err(ErrorCode::NoSupport)); +} + +#[test] +fn delete() { + let kernel = fake::Kernel::new(); + let driver = fake::KeyValue::new(); + kernel.add_driver(&driver); + + assert_eq!(_set(&kernel), Ok(())); + assert_eq!(_delete(&kernel), Ok(())); +} + +#[test] +fn delete_fail() { + let kernel = fake::Kernel::new(); + let driver = fake::KeyValue::new(); + kernel.add_driver(&driver); + + assert_eq!(_delete(&kernel), Err(ErrorCode::NoSupport)); +} From 15e16beafdee312831eca171ff10f29fb9717e40 Mon Sep 17 00:00:00 2001 From: Brad Campbell Date: Wed, 10 Jan 2024 15:46:33 -0500 Subject: [PATCH 5/8] unittest: add fake kv --- unittest/src/fake/key_value/mod.rs | 229 +++++++++++++++++++++++++++++ unittest/src/fake/mod.rs | 2 + 2 files changed, 231 insertions(+) create mode 100644 unittest/src/fake/key_value/mod.rs diff --git a/unittest/src/fake/key_value/mod.rs b/unittest/src/fake/key_value/mod.rs new file mode 100644 index 00000000..ec817032 --- /dev/null +++ b/unittest/src/fake/key_value/mod.rs @@ -0,0 +1,229 @@ +use libtock_platform::{CommandReturn, ErrorCode}; + +use core::cell::{Cell, RefCell}; +use std::collections::HashMap; +use std::str; + +use crate::{DriverInfo, DriverShareRef, RoAllowBuffer, RwAllowBuffer}; + +pub struct KeyValue { + buffer_in_key: Cell, + buffer_in_val: Cell, + + buffer_out_val: RefCell, + + share_ref: DriverShareRef, + + database: RefCell>, +} + +impl KeyValue { + pub fn new() -> std::rc::Rc { + std::rc::Rc::new(KeyValue { + buffer_in_key: Default::default(), + buffer_in_val: Default::default(), + buffer_out_val: Default::default(), + + share_ref: Default::default(), + + database: Default::default(), + }) + } +} + +impl crate::fake::SyscallDriver for KeyValue { + fn info(&self) -> DriverInfo { + DriverInfo::new(DRIVER_NUM).upcall_count(1) + } + + fn register(&self, share_ref: DriverShareRef) { + self.share_ref.replace(share_ref); + } + + fn allow_readonly( + &self, + buffer_num: u32, + buffer: RoAllowBuffer, + ) -> Result { + match buffer_num { + RO_ALLOW_KEY => Ok(self.buffer_in_key.replace(buffer)), + RO_ALLOW_VAL => Ok(self.buffer_in_val.replace(buffer)), + _ => Err((buffer, ErrorCode::Invalid)), + } + } + + fn allow_readwrite( + &self, + buffer_num: u32, + buffer: RwAllowBuffer, + ) -> Result { + match buffer_num { + RW_ALLOW_VAL => Ok(self.buffer_out_val.replace(buffer)), + _ => Err((buffer, ErrorCode::Invalid)), + } + } + + fn command(&self, command_id: u32, _argument0: u32, _argument1: u32) -> CommandReturn { + match command_id { + CMD_DRIVER_CHECK => crate::command_return::success(), + CMD_GET => { + let k = self.buffer_in_key.take(); + let k_str = str::from_utf8(&k).unwrap(); + + let db = self.database.take(); + match db.get(k_str) { + Some(val) => { + let cp_len = core::cmp::min(self.buffer_out_val.borrow().len(), val.len()); + self.buffer_out_val.borrow_mut()[..cp_len] + .copy_from_slice(&val.as_bytes()[..cp_len]); + + self.share_ref + .schedule_upcall(SUB_CALLBACK, (0, val.len() as u32, 0)) + .expect("Unable to schedule upcall {}"); + } + _ => { + self.share_ref + .schedule_upcall(SUB_CALLBACK, (ErrorCode::NoSupport as u32, 0, 0)) + .expect("Unable to schedule upcall {}"); + } + } + self.buffer_in_key.set(k); + self.database.replace(db); + + crate::command_return::success() + } + CMD_SET => { + let k = self.buffer_in_key.take(); + let k_str = str::from_utf8(&k).unwrap(); + let v = self.buffer_in_val.take(); + let v_str = str::from_utf8(&v).unwrap(); + + let mut db = self.database.take(); + db.insert(k_str.to_string(), v_str.to_string()); + + self.buffer_in_key.set(k); + self.buffer_in_val.set(v); + self.database.replace(db); + + self.share_ref + .schedule_upcall(SUB_CALLBACK, (0, 0, 0)) + .expect("Unable to schedule upcall {}"); + + crate::command_return::success() + } + CMD_ADD => { + let k = self.buffer_in_key.take(); + let k_str = str::from_utf8(&k).unwrap(); + let v = self.buffer_in_val.take(); + let v_str = str::from_utf8(&v).unwrap(); + + let mut db = self.database.take(); + + let mut found = false; + match db.get(k_str) { + Some(_val) => { + self.share_ref + .schedule_upcall(SUB_CALLBACK, (ErrorCode::NoSupport as u32, 0, 0)) + .expect("Unable to schedule upcall {}"); + found = true; + } + _ => {} + } + + if !found { + db.insert(k_str.to_string(), v_str.to_string()); + + self.share_ref + .schedule_upcall(SUB_CALLBACK, (0, 0, 0)) + .expect("Unable to schedule upcall {}"); + } + + self.buffer_in_key.set(k); + self.buffer_in_val.set(v); + self.database.replace(db); + + crate::command_return::success() + } + CMD_UPDATE => { + let k = self.buffer_in_key.take(); + let k_str = str::from_utf8(&k).unwrap(); + let v = self.buffer_in_val.take(); + let v_str = str::from_utf8(&v).unwrap(); + + let mut db = self.database.take(); + + let mut found = false; + match db.get(k_str) { + Some(_val) => { + found = true; + } + _ => { + self.share_ref + .schedule_upcall(SUB_CALLBACK, (ErrorCode::NoSupport as u32, 0, 0)) + .expect("Unable to schedule upcall {}"); + } + } + + if found { + db.insert(k_str.to_string(), v_str.to_string()); + + self.share_ref + .schedule_upcall(SUB_CALLBACK, (0, 0, 0)) + .expect("Unable to schedule upcall {}"); + } + + self.buffer_in_key.set(k); + self.buffer_in_val.set(v); + self.database.replace(db); + + crate::command_return::success() + } + CMD_DELETE => { + let k = self.buffer_in_key.take(); + let k_str = str::from_utf8(&k).unwrap(); + + let mut db = self.database.take(); + + match db.remove(k_str) { + Some(_val) => { + self.share_ref + .schedule_upcall(SUB_CALLBACK, (0, 0, 0)) + .expect("Unable to schedule upcall {}"); + } + _ => { + self.share_ref + .schedule_upcall(SUB_CALLBACK, (ErrorCode::NoSupport as u32, 0, 0)) + .expect("Unable to schedule upcall {}"); + } + } + + self.buffer_in_key.set(k); + self.database.replace(db); + + crate::command_return::success() + } + _ => crate::command_return::failure(ErrorCode::NoSupport), + } + } +} + +// ----------------------------------------------------------------------------- +// Driver number and command IDs +// ----------------------------------------------------------------------------- + +const DRIVER_NUM: u32 = 0x50003; + +// Command IDs + +const CMD_DRIVER_CHECK: u32 = 0; +const CMD_GET: u32 = 1; +const CMD_SET: u32 = 2; +const CMD_DELETE: u32 = 3; +const CMD_ADD: u32 = 4; +const CMD_UPDATE: u32 = 5; + +const RO_ALLOW_KEY: u32 = 0; +const RO_ALLOW_VAL: u32 = 1; +const RW_ALLOW_VAL: u32 = 0; + +const SUB_CALLBACK: u32 = 0; diff --git a/unittest/src/fake/mod.rs b/unittest/src/fake/mod.rs index 72d3f5b8..ba042ab0 100644 --- a/unittest/src/fake/mod.rs +++ b/unittest/src/fake/mod.rs @@ -18,6 +18,7 @@ mod buzzer; mod console; mod gpio; mod kernel; +mod key_value; mod leds; mod low_level_debug; mod ninedof; @@ -36,6 +37,7 @@ pub use buzzer::Buzzer; pub use console::Console; pub use gpio::{Gpio, GpioMode, InterruptEdge, PullMode}; pub use kernel::Kernel; +pub use key_value::KeyValue; pub use leds::Leds; pub use low_level_debug::{LowLevelDebug, Message}; pub use ninedof::{NineDof, NineDofData}; From 5c3cd84b97e1e48cc019a1bfb9e977b48c9d30ba Mon Sep 17 00:00:00 2001 From: Brad Campbell Date: Wed, 10 Jan 2024 23:53:57 -0500 Subject: [PATCH 6/8] unittest: fake kv: clippy fix --- unittest/src/fake/key_value/mod.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/unittest/src/fake/key_value/mod.rs b/unittest/src/fake/key_value/mod.rs index ec817032..dd53a0ac 100644 --- a/unittest/src/fake/key_value/mod.rs +++ b/unittest/src/fake/key_value/mod.rs @@ -120,14 +120,11 @@ impl crate::fake::SyscallDriver for KeyValue { let mut db = self.database.take(); let mut found = false; - match db.get(k_str) { - Some(_val) => { - self.share_ref - .schedule_upcall(SUB_CALLBACK, (ErrorCode::NoSupport as u32, 0, 0)) - .expect("Unable to schedule upcall {}"); - found = true; - } - _ => {} + if let Some(_val) = db.get(k_str) { + self.share_ref + .schedule_upcall(SUB_CALLBACK, (ErrorCode::NoSupport as u32, 0, 0)) + .expect("Unable to schedule upcall {}"); + found = true; } if !found { From 6839783f83940b7c2edf27e2cb77629ced1c635d Mon Sep 17 00:00:00 2001 From: Brad Campbell Date: Fri, 2 Feb 2024 11:38:02 -0500 Subject: [PATCH 7/8] cargo.toml: revert space removal --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ef430280..f38be9b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ version = "0.1.0" rust-version = "1.70" [dependencies] -libtock_adc = { path = "apis/adc"} +libtock_adc = { path = "apis/adc" } libtock_air_quality = { path = "apis/air_quality" } libtock_alarm = { path = "apis/alarm" } libtock_ambient_light = { path = "apis/ambient_light" } From 4a5aea5fa25345a26290bf62418d5f47f71ef1fc Mon Sep 17 00:00:00 2001 From: Brad Campbell Date: Fri, 2 Feb 2024 11:38:32 -0500 Subject: [PATCH 8/8] cargo.toml: add expected space --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f38be9b5..8885cdc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ libtock_console = { path = "apis/console" } libtock_debug_panic = { path = "panic_handlers/debug_panic" } libtock_gpio = { path = "apis/gpio" } libtock_i2c_master_slave = { path = "apis/i2c_master_slave" } -libtock_key_value = { path = "apis/key_value"} +libtock_key_value = { path = "apis/key_value" } libtock_leds = { path = "apis/leds" } libtock_low_level_debug = { path = "apis/low_level_debug" } libtock_ninedof = { path = "apis/ninedof" }