use libdictenstein::{Dictionary, DictionaryValue, MappedDictionary, SyncStrategy};
#[derive(Debug, Clone)]
pub struct LazyInitDefault<D> {
inner: D,
}
impl<D> LazyInitDefault<D> {
#[inline]
pub fn new(dict: D) -> Self {
Self { inner: dict }
}
#[inline]
pub fn into_inner(self) -> D {
self.inner
}
#[inline]
pub fn inner(&self) -> &D {
&self.inner
}
}
impl<D> Dictionary for LazyInitDefault<D>
where
D: Dictionary,
{
type Node = D::Node;
#[inline]
fn root(&self) -> Self::Node {
self.inner.root()
}
#[inline]
fn len(&self) -> Option<usize> {
self.inner.len()
}
#[inline]
fn contains(&self, term: &str) -> bool {
self.inner.contains(term)
}
#[inline]
fn sync_strategy(&self) -> SyncStrategy {
self.inner.sync_strategy()
}
}
impl<D, V> MappedDictionary for LazyInitDefault<D>
where
D: MappedDictionary<Value = V>,
V: DictionaryValue + Default,
{
type Value = V;
#[inline(always)]
fn get_value(&self, term: &str) -> Option<Self::Value> {
if let Some(value) = self.inner.get_value(term) {
return Some(value);
}
if self.inner.contains(term) {
return Some(V::default());
}
None
}
#[inline]
fn contains_with_value<F>(&self, term: &str, predicate: F) -> bool
where
F: Fn(&Self::Value) -> bool,
{
if self.inner.contains_with_value(term, &predicate) {
return true;
}
if self.inner.contains(term) {
let default_value = V::default();
return predicate(&default_value);
}
false
}
}
#[derive(Debug, Clone)]
pub struct LazyInitFn<D, V> {
inner: D,
initializer: fn() -> V,
}
impl<D, V> LazyInitFn<D, V> {
#[inline]
pub fn new(dict: D, initializer: fn() -> V) -> Self {
Self {
inner: dict,
initializer,
}
}
#[inline]
pub fn into_inner(self) -> D {
self.inner
}
#[inline]
pub fn inner(&self) -> &D {
&self.inner
}
}
impl<D, V> Dictionary for LazyInitFn<D, V>
where
D: Dictionary,
V: DictionaryValue,
{
type Node = D::Node;
#[inline]
fn root(&self) -> Self::Node {
self.inner.root()
}
#[inline]
fn len(&self) -> Option<usize> {
self.inner.len()
}
#[inline]
fn contains(&self, term: &str) -> bool {
self.inner.contains(term)
}
#[inline]
fn sync_strategy(&self) -> SyncStrategy {
self.inner.sync_strategy()
}
}
impl<D, V> MappedDictionary for LazyInitFn<D, V>
where
D: MappedDictionary<Value = V>,
V: DictionaryValue,
{
type Value = V;
#[inline]
fn get_value(&self, term: &str) -> Option<Self::Value> {
if let Some(value) = self.inner.get_value(term) {
return Some(value);
}
if self.inner.contains(term) {
return Some((self.initializer)());
}
None
}
#[inline]
fn contains_with_value<F>(&self, term: &str, predicate: F) -> bool
where
F: Fn(&Self::Value) -> bool,
{
if self.inner.contains_with_value(term, &predicate) {
return true;
}
if self.inner.contains(term) {
let value = (self.initializer)();
return predicate(&value);
}
false
}
}
#[derive(Clone)]
pub struct LazyInit<D, F> {
inner: D,
initializer: F,
}
impl<D, F> LazyInit<D, F> {
#[inline]
pub fn new(dict: D, initializer: F) -> Self {
Self {
inner: dict,
initializer,
}
}
#[inline]
pub fn into_inner(self) -> D {
self.inner
}
#[inline]
pub fn inner(&self) -> &D {
&self.inner
}
}
impl<D, F> Dictionary for LazyInit<D, F>
where
D: Dictionary,
{
type Node = D::Node;
#[inline]
fn root(&self) -> Self::Node {
self.inner.root()
}
#[inline]
fn len(&self) -> Option<usize> {
self.inner.len()
}
#[inline]
fn contains(&self, term: &str) -> bool {
self.inner.contains(term)
}
#[inline]
fn sync_strategy(&self) -> SyncStrategy {
self.inner.sync_strategy()
}
}
impl<D, F, V> MappedDictionary for LazyInit<D, F>
where
D: MappedDictionary<Value = V>,
F: Fn() -> V,
V: DictionaryValue,
{
type Value = V;
#[inline]
fn get_value(&self, term: &str) -> Option<Self::Value> {
if let Some(value) = self.inner.get_value(term) {
return Some(value);
}
if self.inner.contains(term) {
return Some((self.initializer)());
}
None
}
#[inline]
fn contains_with_value<F2>(&self, term: &str, predicate: F2) -> bool
where
F2: Fn(&Self::Value) -> bool,
{
if self.inner.contains_with_value(term, &predicate) {
return true;
}
if self.inner.contains(term) {
let value = (self.initializer)();
return predicate(&value);
}
false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "pathmap-backend")]
use libdictenstein::pathmap::PathMapDictionary;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
#[test]
#[cfg(feature = "pathmap-backend")]
fn test_lazy_init_default() {
let dict = PathMapDictionary::<i32>::from_terms(["foo", "bar", "baz"]);
let lazy = LazyInitDefault::new(dict);
assert_eq!(lazy.get_value("foo"), Some(0));
assert_eq!(lazy.get_value("bar"), Some(0));
assert_eq!(lazy.get_value("missing"), None);
}
#[test]
#[cfg(feature = "pathmap-backend")]
fn test_lazy_init_default_with_some_values() {
let dict = PathMapDictionary::from_terms_with_values([
("foo", 42),
("bar", 0), ]);
dict.insert("baz");
let lazy = LazyInitDefault::new(dict);
assert_eq!(lazy.get_value("foo"), Some(42));
assert_eq!(lazy.get_value("bar"), Some(0));
assert_eq!(lazy.get_value("baz"), Some(0));
assert_eq!(lazy.get_value("missing"), None);
}
#[test]
#[cfg(feature = "pathmap-backend")]
fn test_lazy_init_fn() {
static COUNTER: AtomicUsize = AtomicUsize::new(100);
fn increment_counter() -> usize {
COUNTER.fetch_add(1, Ordering::SeqCst)
}
let dict = PathMapDictionary::from_terms_with_values([("foo", 42), ("bar", 99)]);
let lazy = LazyInitFn::new(dict, increment_counter);
let val1 = lazy.get_value("foo");
let val2 = lazy.get_value("bar");
assert_eq!(val1, Some(42));
assert_eq!(val2, Some(99));
assert_eq!(COUNTER.load(Ordering::SeqCst), 100);
}
#[test]
#[cfg(feature = "pathmap-backend")]
fn test_lazy_init_closure() {
let context = "user_123";
let dict = PathMapDictionary::<String>::new();
dict.insert("setting1");
dict.insert("setting2");
let lazy = LazyInit::new(dict, || format!("default_for_{}", context));
assert_eq!(lazy.get_value("setting1"), Some("".to_string())); assert_eq!(lazy.get_value("setting2"), Some("".to_string())); assert_eq!(lazy.get_value("missing"), None);
}
#[test]
#[cfg(feature = "pathmap-backend")]
fn test_lazy_init_with_counter() {
let counter = Arc::new(AtomicUsize::new(0));
let counter_clone = Arc::clone(&counter);
let dict = PathMapDictionary::from_terms_with_values([("foo", 10), ("bar", 20)]);
let lazy = LazyInit::new(dict, move || counter_clone.fetch_add(1, Ordering::SeqCst));
let val1 = lazy.get_value("foo").expect("expected Some value in test");
let val2 = lazy.get_value("bar").expect("expected Some value in test");
assert_eq!(val1, 10);
assert_eq!(val2, 20);
assert_eq!(counter.load(Ordering::SeqCst), 0);
}
#[test]
#[cfg(feature = "pathmap-backend")]
fn test_lazy_init_contains_with_value() {
let dict = PathMapDictionary::from_terms(["foo", "bar"]);
let lazy = LazyInitDefault::<PathMapDictionary<i32>>::new(dict);
assert!(lazy.contains_with_value("foo", |v| *v == 0));
assert!(!lazy.contains_with_value("foo", |v| *v == 1));
assert!(!lazy.contains_with_value("missing", |v| *v == 0));
}
}