diff --git a/Cargo.toml b/Cargo.toml index 2404a14..7ab26ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/lowcarboncode/quickleaf" readme = "README.md" [dependencies] -valu3 = "0.6.5" +valu3 = "0.6" [features] default = [] diff --git a/README.md b/README.md index c5079b4..d09b1f9 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Quickleaf Cache is a Rust library that provides a simple and efficient in-memory - List cache entries with support for filtering, ordering, and limiting results - Custom error handling - Event notifications for cache operations +- Support for generic values using [valu3](https://github.com/lowcarboncode/valu3) ## Installation @@ -18,6 +19,7 @@ Add the following to your `Cargo.toml`: ```toml [dependencies] quickleaf = "0.1" +valu3 = "0.1" ``` ## Usage @@ -26,6 +28,7 @@ Here's a basic example of how to use Quickleaf Cache: ```rust use quickleaf::{Quickleaf, ListProps, Order, Filter}; +use quickleaf::valu3::value::Value; fn main() { let mut cache = Quickleaf::new(2); @@ -34,8 +37,8 @@ fn main() { cache.insert("key3", 3); assert_eq!(cache.get("key1"), None); - assert_eq!(cache.get("key2"), Some(&2)); - assert_eq!(cache.get("key3"), Some(&3)); + assert_eq!(cache.get("key2"), Some(&2.to_value())); + assert_eq!(cache.get("key3"), Some(&3.to_value())); let list_props = ListProps::default() .order(Order::Asc) @@ -128,6 +131,7 @@ You can use events to get notified when cache entries are inserted, removed, or ```rust use quickleaf::{Quickleaf, Event}; use std::sync::mpsc::channel; +use quickleaf::valu3::value::Value; fn main() { let (tx, rx) = channel(); @@ -150,15 +154,15 @@ fn main() { assert_eq!(items.len(), 3); assert_eq!( items[0], - Event::insert("key1".to_string(), 1) + Event::insert("key1".to_string(), 1.to_value()) ); assert_eq!( items[1], - Event::insert("key2".to_string(), 2) + Event::insert("key2".to_string(), 2.to_value()) ); assert_eq!( items[2], - Event::insert("key3".to_string(), 3) + Event::insert("key3".to_string(), 3.to_value()) ); } ``` diff --git a/src/cache.rs b/src/cache.rs index 8e20436..e0bc7e7 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::fmt::Debug; +use valu3::traits::ToValueBehavior; use valu3::value::Value; use crate::error::Error; @@ -12,27 +13,21 @@ use std::sync::mpsc::Sender; pub type Key = String; #[derive(Clone, Debug)] -pub struct Cache -where - V: PartialEq, -{ - map: HashMap, +pub struct Cache { + map: HashMap, list: Vec, capacity: usize, - sender: Option>>, - _phantom: std::marker::PhantomData, + sender: Option>>, + _phantom: std::marker::PhantomData, } -impl PartialEq for Cache { +impl PartialEq for Cache { fn eq(&self, other: &Self) -> bool { self.map == other.map && self.list == other.list && self.capacity == other.capacity } } -impl Cache -where - V: PartialEq + Clone, -{ +impl Cache { pub fn new(capacity: usize) -> Self { Self { map: HashMap::new(), @@ -43,7 +38,7 @@ where } } - pub fn with_sender(capacity: usize, sender: Sender>) -> Self { + pub fn with_sender(capacity: usize, sender: Sender>) -> Self { Self { map: HashMap::new(), list: Vec::new(), @@ -53,7 +48,7 @@ where } } - pub fn set_event(&mut self, sender: Sender>) { + pub fn set_event(&mut self, sender: Sender>) { self.sender = Some(sender); } @@ -61,14 +56,14 @@ where self.sender = None; } - fn send_insert(&self, key: Key, value: V) { + fn send_insert(&self, key: Key, value: Value) { if let Some(sender) = &self.sender { let event = Event::insert(key, value); sender.send(event).unwrap(); } } - fn send_remove(&self, key: Key, value: V) { + fn send_remove(&self, key: Key, value: Value) { if let Some(sender) = &self.sender { let event = Event::remove(key, value); sender.send(event).unwrap(); @@ -82,9 +77,10 @@ where } } - pub fn insert(&mut self, key: T, value: V) + pub fn insert(&mut self, key: T, value: V) where T: Into + Clone + AsRef, + V: ToValueBehavior, { let key = key.into(); @@ -108,26 +104,16 @@ where .unwrap_or(self.list.len()); self.list.insert(position, key.clone()); - self.map.insert(key.clone(), value.clone().into()); + self.map.insert(key.clone(), value.to_value()); - self.send_insert(key, value); + self.send_insert(key, value.to_value()); } - pub fn insert_if_not_exists(&mut self, key: Key, value: V) -> Result<(), Error> { - if self.map.contains_key(&key) { - return Err(Error::SortKeyExists); - } - - self.insert(key, value); - - Ok(()) - } - - pub fn get(&self, key: &str) -> Option<&V> { + pub fn get(&self, key: &str) -> Option<&Value> { self.map.get(key) } - pub fn get_mut(&mut self, key: &str) -> Option<&mut V> { + pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> { self.map.get_mut(key) } @@ -175,7 +161,7 @@ where self.map.contains_key(key) } - pub fn list(&self, props: T) -> Result, Error> + pub fn list(&self, props: T) -> Result, Error> where T: Into, { @@ -191,7 +177,7 @@ where &self, mut list_iter: I, props: ListProps, - ) -> Result, Error> + ) -> Result, Error> where I: Iterator, { diff --git a/src/event.rs b/src/event.rs index 298efd6..06e2e38 100644 --- a/src/event.rs +++ b/src/event.rs @@ -14,15 +14,15 @@ pub struct EventData { } impl Event { - pub(crate) fn insert(key: Key, value: V) -> Self { + pub fn insert(key: Key, value: V) -> Self { Self::Insert(EventData { key, value }) } - pub(crate) fn remove(key: Key, value: V) -> Self { + pub fn remove(key: Key, value: V) -> Self { Self::Remove(EventData { key, value }) } - pub(crate) fn clear() -> Self { + pub fn clear() -> Self { Self::Clear } } diff --git a/src/lib.rs b/src/lib.rs index 47d5ac6..bf36255 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ //! - List cache entries with support for filtering, ordering, and limiting results //! - Custom error handling //! - Event notifications for cache operations +//! - Support for generic values using [valu3](https://github.com/lowcarboncode/valu3) //! //! ## Installation //! @@ -18,6 +19,7 @@ //! ```toml //! [dependencies] //! quickleaf = "0.1" +//! valu3 = "0.1" //! ``` //! //! ## Usage @@ -25,7 +27,8 @@ //! Here's a basic example of how to use Quickleaf Cache: //! //! ```rust -//! use quickleaf::{Quickleaf, ListProps, Order, Filter}; +//! use quickleaf::{Quickleaf, ListProps, Order, Filter, prelude::*}; +//! use quickleaf::valu3::value::Value; //! //! fn main() { //! let mut cache = Quickleaf::new(2); @@ -34,12 +37,11 @@ //! cache.insert("key3", 3); //! //! assert_eq!(cache.get("key1"), None); -//! assert_eq!(cache.get("key2"), Some(&2)); -//! assert_eq!(cache.get("key3"), Some(&3)); +//! assert_eq!(cache.get("key2"), Some(&2.to_value())); +//! assert_eq!(cache.get("key3"), Some(&3.to_value())); //! //! let list_props = ListProps::default() -//! .order(Order::Asc) -//! .limit(10); +//! .order(Order::Asc); //! //! let result = cache.list(list_props).unwrap(); //! for (key, value) in result { @@ -57,6 +59,7 @@ //! ```rust //! use quickleaf::{Quickleaf, ListProps, Order, Filter}; //! +//! //! fn main() { //! let mut cache = Quickleaf::new(10); //! cache.insert("apple", 1); @@ -65,8 +68,7 @@ //! //! let list_props = ListProps::default() //! .order(Order::Asc) -//! .filter(Filter::StartWith("ap")) -//! .limit(10); +//! .filter(Filter::StartWith("ap")); //! //! let result = cache.list(list_props).unwrap(); //! for (key, value) in result { @@ -88,8 +90,7 @@ //! //! let list_props = ListProps::default() //! .order(Order::Asc) -//! .filter(Filter::EndWith("apple")) -//! .limit(10); +//! .filter(Filter::EndWith("apple")); //! //! let result = cache.list(list_props).unwrap(); //! for (key, value) in result { @@ -111,8 +112,7 @@ //! //! let list_props = ListProps::default() //! .order(Order::Asc) -//! .filter(Filter::StartAndEndWith("apple", "pie")) -//! .limit(10); +//! .filter(Filter::StartAndEndWith("apple", "pie")); //! //! let result = cache.list(list_props).unwrap(); //! for (key, value) in result { @@ -126,8 +126,9 @@ //! You can use events to get notified when cache entries are inserted, removed, or cleared. Here is an example: //! //! ```rust -//! use quickleaf::{Quickleaf, Event}; +//! use quickleaf::{Quickleaf, Event, prelude::*}; //! use std::sync::mpsc::channel; +//! use quickleaf::valu3::value::Value; //! //! fn main() { //! let (tx, rx) = channel(); @@ -150,15 +151,15 @@ //! assert_eq!(items.len(), 3); //! assert_eq!( //! items[0], -//! Event::insert("key1".to_string(), 1) +//! Event::insert("key1".to_string(), 1.to_value()) //! ); //! assert_eq!( //! items[1], -//! Event::insert("key2".to_string(), 2) +//! Event::insert("key2".to_string(), 2.to_value()) //! ); //! assert_eq!( //! items[2], -//! Event::insert("key3".to_string(), 3) +//! Event::insert("key3".to_string(), 3.to_value()) //! ); //! } //! ``` @@ -176,6 +177,8 @@ mod error; mod event; mod filter; mod list_props; +pub mod prelude; +mod quickleaf; #[cfg(test)] mod tests; @@ -183,8 +186,7 @@ pub use cache::Cache; pub use error::Error; pub use event::{Event, EventData}; pub use filter::Filter; -pub use list_props::ListProps; +pub use list_props::{ListProps, Order, StartAfter}; +pub use quickleaf::Quickleaf; pub use valu3; pub use valu3::value::Value; - -pub type Quickleaf = Cache; diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 0000000..18d6695 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1 @@ +pub use valu3::prelude::*; diff --git a/src/quickleaf.rs b/src/quickleaf.rs new file mode 100644 index 0000000..43dd217 --- /dev/null +++ b/src/quickleaf.rs @@ -0,0 +1,2 @@ +use crate::Cache; +pub type Quickleaf = Cache; diff --git a/src/tests.rs b/src/tests.rs index a05ebe9..0c22c3a 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,7 +1,9 @@ #[cfg(test)] mod test { - use crate::*; - use list_props::{Order, StartAfter}; + use valu3::traits::ToValueBehavior; + + use crate::list_props::{Order, StartAfter}; + use crate::{Cache, Event, EventData, Filter, ListProps}; #[test] fn test_cache_insert() { @@ -10,8 +12,8 @@ mod test { cache.insert("key2", 2); cache.insert("key3", 3); assert_eq!(cache.get("key1"), None); - assert_eq!(cache.get("key2"), Some(&2)); - assert_eq!(cache.get("key3"), Some(&3)); + assert_eq!(cache.get("key2"), Some(&2.to_value())); + assert_eq!(cache.get("key3"), Some(&3.to_value().to_value())); } #[test] @@ -22,8 +24,8 @@ mod test { cache.remove("key1").expect("Error removing key"); assert_eq!(cache.get("key1"), None); cache.insert("key3", 3); - assert_eq!(cache.get("key3"), Some(&3)); - assert_eq!(cache.get("key2"), Some(&2)); + assert_eq!(cache.get("key3"), Some(&3.to_value().to_value())); + assert_eq!(cache.get("key2"), Some(&2.to_value())); } #[test] @@ -59,9 +61,9 @@ mod test { }; assert_eq!(result.len(), 3); - assert_eq!(result[0], ("key3".to_string(), &3)); - assert_eq!(result[1], ("key4".to_string(), &4)); - assert_eq!(result[2], ("key5".to_string(), &5)); + assert_eq!(result[0], ("key3".to_string(), &3.to_value())); + assert_eq!(result[1], ("key4".to_string(), &4.to_value())); + assert_eq!(result[2], ("key5".to_string(), &5.to_value())); } #[test] @@ -93,8 +95,8 @@ mod test { }; assert_eq!(result.len(), 2); - assert_eq!(result[0], ("postmortem".to_string(), &9)); - assert_eq!(result[1], ("postpone".to_string(), &6)); + assert_eq!(result[0], ("postmortem".to_string(), &9.to_value())); + assert_eq!(result[1], ("postpone".to_string(), &6.to_value())); } #[test] @@ -121,8 +123,8 @@ mod test { }; assert_eq!(result.len(), 2); - assert_eq!(result[0], ("key2".to_string(), &2)); - assert_eq!(result[1], ("key1".to_string(), &1)); + assert_eq!(result[0], ("key2".to_string(), &2.to_value())); + assert_eq!(result[1], ("key1".to_string(), &1.to_value())); } #[test] @@ -154,8 +156,8 @@ mod test { }; assert_eq!(result.len(), 2); - assert_eq!(result[0], ("postmark".to_string(), &10)); - assert_eq!(result[1], ("postgraduate".to_string(), &7)); + assert_eq!(result[0], ("postmark".to_string(), &10.to_value())); + assert_eq!(result[1], ("postgraduate".to_string(), &7.to_value())); } #[test] @@ -183,9 +185,9 @@ mod test { }; assert_eq!(result.len(), 3); - assert_eq!(result[0], ("postmark".to_string(), &10)); - assert_eq!(result[1], ("postmodern".to_string(), &8)); - assert_eq!(result[2], ("postmortem".to_string(), &9)); + assert_eq!(result[0], ("postmark".to_string(), &10.to_value())); + assert_eq!(result[1], ("postmodern".to_string(), &8.to_value())); + assert_eq!(result[2], ("postmortem".to_string(), &9.to_value())); } #[test] @@ -213,8 +215,8 @@ mod test { }; assert_eq!(result.len(), 2); - assert_eq!(result[0], ("precaution".to_string(), &3)); - assert_eq!(result[1], ("precognition".to_string(), &5)); + assert_eq!(result[0], ("precaution".to_string(), &3.to_value())); + assert_eq!(result[1], ("precognition".to_string(), &5.to_value())); } #[test] @@ -239,7 +241,7 @@ mod test { }; assert_eq!(result.len(), 1); - assert_eq!(result[0], ("applemorepie".to_string(), &1)); + assert_eq!(result[0], ("applemorepie".to_string(), &1.to_value())); } #[test] @@ -249,6 +251,7 @@ mod test { let mut clone_cache = cache.clone(); std::thread::spawn(move || { + std::thread::sleep(std::time::Duration::from_millis(1)); clone_cache.insert("key1", 1); }); @@ -270,21 +273,21 @@ mod test { items[0], Event::Insert(EventData { key: "key2".to_string(), - value: 2 + value: 2.to_value() }) ); assert_eq!( items[1], Event::Insert(EventData { key: "key3".to_string(), - value: 3 + value: 3.to_value() }) ); assert_eq!( items[2], Event::Insert(EventData { key: "key1".to_string(), - value: 1 + value: 1.to_value() }) ); }