//! Thread-safe native collections, caches, and hierarchical token buckets.

#![allow(clippy::missing_errors_doc)] // Result shapes are fixed by the compatibility map.
#![allow(clippy::missing_panics_doc)] // Infallible mapped accessors mirror C# exception behavior.
#![allow(clippy::must_use_candidate)] // Attributes are not part of the mapped C# surface.
#![allow(clippy::needless_pass_by_value)] // Owned parameters preserve the mapped signatures.
#![allow(clippy::similar_names)] // Paired dictionary keys intentionally have parallel names.
#![allow(clippy::type_complexity)] // Callback signatures mirror the mapped generic delegates.
#![allow(clippy::cast_possible_truncation)] // Floating duration conversion follows TimeSpan.
#![allow(clippy::assigning_clones)] // Option replacement preserves mapped null/default values.
#![allow(clippy::return_self_not_must_use)] // Properties do not carry Rust-only attributes.

use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::{Arc, Mutex, RwLock};
use std::time::{Duration, Instant};

use crate::Error;
use crate::compat::IEqualityComparer;

fn mutex<T>(lock: &Mutex<T>) -> Result<std::sync::MutexGuard<'_, T>, Error> {
    lock.lock().map_err(|_| Error::InvalidOperation)
}

fn read<T>(lock: &RwLock<T>) -> Result<std::sync::RwLockReadGuard<'_, T>, Error> {
    lock.read().map_err(|_| Error::InvalidOperation)
}

fn write<T>(lock: &RwLock<T>) -> Result<std::sync::RwLockWriteGuard<'_, T>, Error> {
    lock.write().map_err(|_| Error::InvalidOperation)
}

/// Eviction policy used by [`CacheDictionary`].
pub trait ICacheDictionaryRemovalStrategy<TKey>: Send + Sync {
    fn initialize(&self, max_size: i32) -> Result<(), Error>;
    fn key_added(&self, key: TKey) -> Result<(), Error>;
    fn key_removed(&self, key: TKey) -> Result<(), Error>;
    fn key_accessed(&self, key: TKey) -> Result<(), Error>;
    fn clear(&self) -> Result<(), Error>;
    fn get_key_to_remove(&self) -> Result<TKey, Error>;
}

macro_rules! removal_strategy {
    ($name:ident, $remove:expr, $track_access:expr, $reserve_capacity:expr) => {
        /// Recency-based cache removal policy.
        pub struct $name<TKey> {
            items: Mutex<Vec<TKey>>,
        }

        impl<TKey: Clone + PartialEq + Send> $name<TKey> {
            pub fn new() -> Result<Self, Error> {
                Ok(Self {
                    items: Mutex::new(Vec::new()),
                })
            }
            pub fn initialize(&self, max_size: i32) -> Result<(), Error> {
                <Self as ICacheDictionaryRemovalStrategy<TKey>>::initialize(self, max_size)
            }
            pub fn key_added(&self, key: TKey) -> Result<(), Error> {
                <Self as ICacheDictionaryRemovalStrategy<TKey>>::key_added(self, key)
            }
            pub fn key_removed(&self, key: TKey) -> Result<(), Error> {
                <Self as ICacheDictionaryRemovalStrategy<TKey>>::key_removed(self, key)
            }
            pub fn key_accessed(&self, key: TKey) -> Result<(), Error> {
                <Self as ICacheDictionaryRemovalStrategy<TKey>>::key_accessed(self, key)
            }
            pub fn clear(&self) -> Result<(), Error> {
                <Self as ICacheDictionaryRemovalStrategy<TKey>>::clear(self)
            }
            pub fn get_key_to_remove(&self) -> Result<TKey, Error> {
                <Self as ICacheDictionaryRemovalStrategy<TKey>>::get_key_to_remove(self)
            }
        }

        impl<TKey: Clone + PartialEq + Send> ICacheDictionaryRemovalStrategy<TKey> for $name<TKey> {
            fn initialize(&self, max_size: i32) -> Result<(), Error> {
                let mut items = mutex(&self.items)?;
                *items = if $reserve_capacity {
                    Vec::with_capacity(usize::try_from(max_size).map_err(|_| Error::Argument)?)
                } else {
                    Vec::new()
                };
                Ok(())
            }
            fn key_added(&self, key: TKey) -> Result<(), Error> {
                mutex(&self.items)?.push(key);
                Ok(())
            }
            fn key_removed(&self, key: TKey) -> Result<(), Error> {
                let mut items = mutex(&self.items)?;
                if let Some(index) = items.iter().position(|item| item == &key) {
                    items.remove(index);
                }
                Ok(())
            }
            fn key_accessed(&self, key: TKey) -> Result<(), Error> {
                if !$track_access {
                    return Ok(());
                }
                let mut items = mutex(&self.items)?;
                if let Some(index) = items.iter().position(|item| item == &key) {
                    items.remove(index);
                }
                items.push(key);
                Ok(())
            }
            fn clear(&self) -> Result<(), Error> {
                mutex(&self.items)?.clear();
                Ok(())
            }
            fn get_key_to_remove(&self) -> Result<TKey, Error> {
                let mut items = mutex(&self.items)?;
                if items.is_empty() {
                    return Err(Error::IndexOutOfRange);
                }
                let index = ($remove)(items.len());
                Ok(items.remove(index))
            }
        }
    };
}

removal_strategy!(EmptyRemovalStrategy, |_| 0, false, false);
removal_strategy!(LruRemovalStrategy, |_| 0, true, true);
removal_strategy!(MruRemovalStrategy, |length: usize| length - 1, true, true);

/// Fixed-capacity dictionary with a pluggable eviction policy.
pub struct CacheDictionary<TKey, TValue> {
    data: RwLock<Vec<(TKey, Option<TValue>)>>,
    max_size: usize,
    removal_strategy: Arc<dyn ICacheDictionaryRemovalStrategy<TKey>>,
}

impl<TKey: Clone + PartialEq, TValue: Clone + PartialEq> CacheDictionary<TKey, TValue> {
    pub fn new(
        max_size: i32,
        removal_strategy: Box<dyn ICacheDictionaryRemovalStrategy<TKey>>,
    ) -> Result<Self, Error> {
        if max_size == 0 {
            return Err(Error::Argument);
        }
        removal_strategy.initialize(max_size)?;
        Ok(Self {
            data: RwLock::new(Vec::new()),
            max_size: usize::try_from(max_size).unwrap_or(usize::MAX),
            removal_strategy: Arc::from(removal_strategy),
        })
    }

    pub fn add_with_t_key_t_value(&self, key: TKey, value: Option<TValue>) -> Result<(), Error> {
        let eviction = {
            let data = read(&self.data)?;
            if data.iter().any(|(candidate, _)| candidate == &key) {
                return Err(Error::Argument);
            }
            (data.len() == self.max_size)
                .then(|| self.removal_strategy.get_key_to_remove())
                .transpose()?
        };
        if let Some(eviction) = eviction {
            let removed = {
                let mut data = write(&self.data)?;
                data.iter()
                    .position(|(candidate, _)| candidate == &eviction)
                    .map(|index| data.remove(index))
            };
            if removed.is_none() {
                return Err(Error::InvalidOperation);
            }
        }
        write(&self.data)?.push((key.clone(), value));
        self.removal_strategy.key_added(key)
    }

    pub fn add_with_key_value_pair(&self, item: (TKey, Option<TValue>)) -> Result<(), Error> {
        self.add_with_t_key_t_value(item.0, item.1)
    }
    pub fn contains_key(&self, key: TKey) -> Result<bool, Error> {
        Ok(read(&self.data)?
            .iter()
            .any(|(candidate, _)| candidate == &key))
    }
    pub fn keys(&self) -> Vec<TKey> {
        read(&self.data)
            .expect("cache lock poisoned")
            .iter()
            .map(|(key, _)| key.clone())
            .collect()
    }
    pub fn values(&self) -> Vec<Option<TValue>> {
        read(&self.data)
            .expect("cache lock poisoned")
            .iter()
            .map(|(_, value)| value.clone())
            .collect()
    }
    pub fn remove_with_t_key(&self, key: TKey) -> Result<bool, Error> {
        let removed = {
            let mut data = write(&self.data)?;
            data.iter()
                .position(|(candidate, _)| candidate == &key)
                .map(|index| data.remove(index))
                .is_some()
        };
        if removed {
            self.removal_strategy.key_removed(key)?;
        }
        Ok(removed)
    }
    pub fn try_get_value(&self, key: TKey, value: &mut Option<TValue>) -> bool {
        let found = read(&self.data).ok().and_then(|data| {
            data.iter()
                .find(|(candidate, _)| candidate == &key)
                .map(|(_, value)| value.clone())
        });
        if let Some(found) = found {
            *value = found;
            let _ = self.removal_strategy.key_accessed(key);
            true
        } else {
            *value = None;
            false
        }
    }
    pub fn item(&self, key: Option<TKey>) -> Option<TValue> {
        let key = key?;
        let value = read(&self.data)
            .ok()?
            .iter()
            .find(|(candidate, _)| candidate == &key)?
            .1
            .clone();
        let _ = self.removal_strategy.key_accessed(key);
        value
    }
    pub fn set_item(&mut self, key: Option<TKey>, value: Option<TValue>) {
        let Some(key) = key else {
            return;
        };
        let mut data = self.data.write().expect("cache lock poisoned");
        if let Some((_, stored)) = data.iter_mut().find(|(candidate, _)| candidate == &key) {
            *stored = value;
        } else {
            data.push((key.clone(), value));
        }
        drop(data);
        let _ = self.removal_strategy.key_accessed(key);
    }
    pub fn clear(&self) -> Result<(), Error> {
        write(&self.data)?.clear();
        self.removal_strategy.clear()
    }
    pub fn contains(&self, item: (TKey, Option<TValue>)) -> Result<bool, Error> {
        Ok(read(&self.data)?.contains(&item))
    }
    pub fn copy_to(
        &self,
        array: &mut [(TKey, Option<TValue>)],
        array_index: i32,
    ) -> Result<(), Error> {
        let index = usize::try_from(array_index).map_err(|_| Error::IndexOutOfRange)?;
        let data = read(&self.data)?;
        if array.len().saturating_sub(index) < data.len() {
            return Err(Error::Argument);
        }
        array[index..index + data.len()].clone_from_slice(&data);
        Ok(())
    }
    pub fn count(&self) -> i32 {
        i32::try_from(read(&self.data).expect("cache lock poisoned").len()).unwrap_or(i32::MAX)
    }
    pub const fn is_read_only(&self) -> bool {
        false
    }
    pub fn remove_with_key_value_pair(&self, item: (TKey, Option<TValue>)) -> Result<bool, Error> {
        let removed = {
            let mut data = write(&self.data)?;
            data.iter()
                .position(|entry| entry == &item)
                .map(|index| data.remove(index))
                .is_some()
        };
        if removed {
            self.removal_strategy.key_removed(item.0)?;
        }
        Ok(removed)
    }
    pub fn get_enumerator(
        &self,
    ) -> Result<Box<dyn Iterator<Item = (TKey, Option<TValue>)> + '_>, Error> {
        let snapshot = read(&self.data)?.clone();
        Ok(Box::new(CacheDictionaryCacheDictionaryEnumerator::new(
            snapshot,
            Arc::clone(&self.removal_strategy),
        )))
    }
}

/// Stateful enumerator matching the nested C# surface.
pub struct CacheDictionaryCacheDictionaryEnumerator<TKey, TValue> {
    entries: Vec<(TKey, Option<TValue>)>,
    index: Mutex<Option<usize>>,
    strategy: Arc<dyn ICacheDictionaryRemovalStrategy<TKey>>,
    disposed: AtomicBool,
}
impl<TKey: Clone, TValue: Clone> CacheDictionaryCacheDictionaryEnumerator<TKey, TValue> {
    fn new(
        entries: Vec<(TKey, Option<TValue>)>,
        strategy: Arc<dyn ICacheDictionaryRemovalStrategy<TKey>>,
    ) -> Self {
        Self {
            entries,
            index: Mutex::new(None),
            strategy,
            disposed: AtomicBool::new(false),
        }
    }
    pub fn dispose(&self) -> Result<(), Error> {
        self.disposed.store(true, Ordering::Release);
        *mutex(&self.index)? = None;
        Ok(())
    }
    pub fn move_next(&self) -> Result<bool, Error> {
        if self.disposed.load(Ordering::Acquire) {
            return Err(Error::InvalidOperation);
        }
        let mut index = mutex(&self.index)?;
        let next = index.map_or(0, |value| value + 1);
        *index = Some(next);
        Ok(next < self.entries.len())
    }
    pub fn reset(&self) -> Result<(), Error> {
        if self.disposed.load(Ordering::Acquire) {
            return Err(Error::InvalidOperation);
        }
        *mutex(&self.index)? = None;
        Ok(())
    }
    pub fn current(&self) -> (TKey, Option<TValue>) {
        assert!(
            !self.disposed.load(Ordering::Acquire),
            "enumerator was disposed"
        );
        let index = self
            .index
            .lock()
            .expect("enumerator lock poisoned")
            .expect("enumeration has not started");
        let item = self.entries[index].clone();
        let _ = self.strategy.key_accessed(item.0.clone());
        item
    }
}

impl<TKey: Clone, TValue: Clone> Iterator
    for CacheDictionaryCacheDictionaryEnumerator<TKey, TValue>
{
    type Item = (TKey, Option<TValue>);

    fn next(&mut self) -> Option<Self::Item> {
        self.move_next().ok().filter(|advanced| *advanced)?;
        Some(self.current())
    }
}

/// Two-key synchronized dictionary.
pub struct DoubleDictionary<TKey1, TKey2, TValue> {
    data: RwLock<(Vec<(TKey1, Option<TValue>)>, Vec<(TKey2, Option<TValue>)>)>,
}
impl<TKey1: Clone + PartialEq, TKey2: Clone + PartialEq, TValue: Clone + PartialEq>
    DoubleDictionary<TKey1, TKey2, TValue>
{
    pub fn new_with_constructor() -> Result<Self, Error> {
        Ok(Self {
            data: RwLock::new((Vec::new(), Vec::new())),
        })
    }
    pub fn new_with_int32(capacity: i32) -> Result<Self, Error> {
        let cap = usize::try_from(capacity).map_err(|_| Error::Argument)?;
        Ok(Self {
            data: RwLock::new((Vec::with_capacity(cap), Vec::with_capacity(cap))),
        })
    }
    pub fn add(&self, key1: TKey1, key2: TKey2, value: Option<TValue>) -> Result<(), Error> {
        let mut data = write(&self.data)?;
        let first = data.0.iter().position(|(key, _)| key == &key1);
        let second = data.1.iter().position(|(key, _)| key == &key2);
        if first.is_some() != second.is_some() {
            return Err(Error::Argument);
        }
        if let Some(index) = first {
            data.0[index].1 = value.clone();
            data.1[second.expect("paired key")].1 = value;
        } else {
            data.0.push((key1, value.clone()));
            data.1.push((key2, value));
        }
        Ok(())
    }
    pub fn clear(&self) -> Result<(), Error> {
        let mut data = write(&self.data)?;
        data.0.clear();
        data.1.clear();
        Ok(())
    }
    pub fn contains_key_with_t_key1(&self, key: TKey1) -> Result<bool, Error> {
        Ok(read(&self.data)?.0.iter().any(|(item, _)| item == &key))
    }
    pub fn contains_key_with_t_key2(&self, key: TKey2) -> Result<bool, Error> {
        Ok(read(&self.data)?.1.iter().any(|(item, _)| item == &key))
    }
    pub fn try_get_value_with_t_key1_t_value(
        &self,
        key: TKey1,
        value: &mut Option<TValue>,
    ) -> bool {
        let found = read(&self.data).ok().and_then(|data| {
            data.0
                .iter()
                .find(|(item, _)| item == &key)
                .map(|(_, value)| value.clone())
        });
        if let Some(found) = found {
            *value = found;
            true
        } else {
            *value = None;
            false
        }
    }
    pub fn try_get_value_with_t_key2_t_value(
        &self,
        key: TKey2,
        value: &mut Option<TValue>,
    ) -> bool {
        let found = read(&self.data).ok().and_then(|data| {
            data.1
                .iter()
                .find(|(item, _)| item == &key)
                .map(|(_, value)| value.clone())
        });
        if let Some(found) = found {
            *value = found;
            true
        } else {
            *value = None;
            false
        }
    }
    pub fn count(&self) -> i32 {
        i32::try_from(read(&self.data).expect("dictionary lock poisoned").0.len())
            .unwrap_or(i32::MAX)
    }
    pub fn remove_with_t_key1_t_key2(&self, key1: TKey1, key2: TKey2) -> Result<bool, Error> {
        let mut data = write(&self.data)?;
        if let Some(index) = data.0.iter().position(|(key, _)| key == &key1) {
            data.0.remove(index);
        }
        Ok(data
            .1
            .iter()
            .position(|(key, _)| key == &key2)
            .map(|index| data.1.remove(index))
            .is_some())
    }
    pub fn remove_with_t_key1(&self, key1: TKey1) -> Result<bool, Error> {
        let mut data = write(&self.data)?;
        let Some(index) = data.0.iter().position(|(key, _)| key == &key1) else {
            return Ok(false);
        };
        let Some(value) = data.0[index].1.as_ref() else {
            return Ok(false);
        };
        let Some(other) = data
            .1
            .iter()
            .position(|(_, candidate)| candidate.as_ref() == Some(value))
        else {
            return Ok(false);
        };
        data.0.remove(index);
        data.1.remove(other);
        Ok(true)
    }
    pub fn remove_with_t_key2(&self, key2: TKey2) -> Result<bool, Error> {
        let mut data = write(&self.data)?;
        let Some(index) = data.1.iter().position(|(key, _)| key == &key2) else {
            return Ok(false);
        };
        let Some(value) = data.1[index].1.as_ref() else {
            return Ok(false);
        };
        let Some(other) = data
            .0
            .iter()
            .position(|(_, candidate)| candidate.as_ref() == Some(value))
        else {
            return Ok(false);
        };
        data.1.remove(index);
        data.0.remove(other);
        Ok(true)
    }
    pub fn dispose(&self) -> Result<(), Error> {
        Ok(())
    }
    pub fn find_value(
        &self,
        predicate: Box<dyn Fn(&Option<TValue>) -> bool + Send + Sync>,
    ) -> Result<Option<TValue>, Error> {
        let snapshot: Vec<_> = read(&self.data)?
            .0
            .iter()
            .map(|(_, value)| value.clone())
            .collect();
        Ok(snapshot
            .into_iter()
            .find(|value| predicate(value))
            .flatten())
    }
    pub fn find_all(
        &self,
        predicate: Box<dyn Fn(&Option<TValue>) -> bool + Send + Sync>,
    ) -> Result<Vec<Option<TValue>>, Error> {
        let snapshot: Vec<_> = read(&self.data)?
            .0
            .iter()
            .map(|(_, value)| value.clone())
            .collect();
        Ok(snapshot
            .into_iter()
            .filter(|value| predicate(value))
            .collect())
    }
    pub fn for_each_with_action(
        &self,
        action: Box<dyn Fn((TKey1, Option<TValue>)) + Send + Sync>,
    ) -> Result<(), Error> {
        let snapshot = read(&self.data)?.0.clone();
        for entry in snapshot {
            action(entry);
        }
        Ok(())
    }
    pub fn for_each_with_action_4dc2e201(
        &self,
        action: Box<dyn Fn((TKey2, Option<TValue>)) + Send + Sync>,
    ) -> Result<(), Error> {
        let snapshot = read(&self.data)?.1.clone();
        for entry in snapshot {
            action(entry);
        }
        Ok(())
    }
    pub fn for_each_with_action_b56adc7f(
        &self,
        action: Box<dyn Fn(Option<TValue>) + Send + Sync>,
    ) -> Result<(), Error> {
        let snapshot: Vec<_> = read(&self.data)?
            .0
            .iter()
            .map(|(_, value)| value.clone())
            .collect();
        for value in snapshot {
            action(value);
        }
        Ok(())
    }
    pub fn remove_all(
        &self,
        predicate: Box<dyn Fn(&Option<TValue>) -> bool + Send + Sync>,
    ) -> Result<i32, Error> {
        let (first, second) = read(&self.data)?.clone();
        let first_remove: Vec<_> = first
            .iter()
            .filter(|(_, value)| predicate(value))
            .cloned()
            .collect();
        let second_remove: Vec<_> = second
            .iter()
            .filter(|(_, value)| predicate(value))
            .cloned()
            .collect();
        let mut data = write(&self.data)?;
        let mut removed = 0;
        for entry in first_remove {
            if let Some(index) = data.0.iter().position(|candidate| candidate == &entry) {
                data.0.remove(index);
                removed += 1;
            }
        }
        for entry in second_remove {
            if let Some(index) = data.1.iter().position(|candidate| candidate == &entry) {
                data.1.remove(index);
            }
        }
        Ok(removed)
    }
}

/// Injectable monotonic clock for deterministic cache and throttling tests.
pub trait MonotonicClock: Send + Sync {
    fn now(&self) -> Duration;
}
struct SystemClock {
    start: Instant,
}
impl SystemClock {
    fn new() -> Self {
        Self {
            start: Instant::now(),
        }
    }
}
impl MonotonicClock for SystemClock {
    fn now(&self) -> Duration {
        self.start.elapsed()
    }
}

#[derive(Clone)]
struct ExpiringEntry<TKey, TValue> {
    key: TKey,
    value: Option<TValue>,
    expires: i128,
    sliding: Option<i128>,
}
struct ExpiringState<TKey, TValue> {
    entries: Vec<ExpiringEntry<TKey, TValue>>,
}

/// Thread-safe absolute and sliding-expiration cache.
pub struct ExpiringCache<TKey, TValue> {
    state: Mutex<ExpiringState<TKey, TValue>>,
    clock: Arc<dyn MonotonicClock>,
}
impl<TKey: Clone + PartialEq, TValue: Clone> ExpiringCache<TKey, TValue> {
    pub fn new() -> Result<Self, Error> {
        Self::new_with_clock(Arc::new(SystemClock::new()))
    }
    pub fn new_with_clock(clock: Arc<dyn MonotonicClock>) -> Result<Self, Error> {
        Ok(Self {
            state: Mutex::new(ExpiringState {
                entries: Vec::new(),
            }),
            clock,
        })
    }
    fn now(&self) -> i128 {
        i128::try_from(self.clock.now().as_nanos()).unwrap_or(i128::MAX)
    }
    fn prune(&self, state: &mut ExpiringState<TKey, TValue>) {
        let now = self.now();
        state.entries.retain(|entry| entry.expires >= now);
    }
    fn add_duration(
        &self,
        key: TKey,
        value: Option<TValue>,
        duration: i128,
        sliding: bool,
    ) -> Result<bool, Error> {
        let mut state = mutex(&self.state)?;
        self.prune(&mut state);
        if state.entries.iter().any(|entry| entry.key == key) {
            return Ok(false);
        }
        state.entries.push(ExpiringEntry {
            key,
            value,
            expires: self.now().saturating_add(duration),
            sliding: sliding.then_some(duration),
        });
        Ok(true)
    }
    pub fn add_with_t_key_t_value_double(
        &self,
        key: TKey,
        value: Option<TValue>,
        expiration_seconds: f64,
    ) -> Result<bool, Error> {
        self.add_duration(key, value, seconds_to_nanos(expiration_seconds)?, false)
    }
    pub fn add_with_t_key_t_value_time_span(
        &self,
        key: TKey,
        value: Option<TValue>,
        sliding_expiration: Duration,
    ) -> Result<bool, Error> {
        self.add_duration(
            key,
            value,
            i128::try_from(sliding_expiration.as_nanos()).unwrap_or(i128::MAX),
            true,
        )
    }
    fn update_duration(
        &self,
        key: TKey,
        value: Option<TValue>,
        duration: i128,
        sliding: bool,
    ) -> Result<bool, Error> {
        let mut state = mutex(&self.state)?;
        self.prune(&mut state);
        let Some(entry) = state.entries.iter_mut().find(|entry| entry.key == key) else {
            return Ok(false);
        };
        entry.value = value;
        entry.expires = self.now().saturating_add(duration);
        entry.sliding = sliding.then_some(duration);
        Ok(true)
    }
    pub fn add_or_update_with_t_key_t_value_double(
        &self,
        key: TKey,
        value: Option<TValue>,
        expiration_seconds: f64,
    ) -> Result<bool, Error> {
        if self.update_with_t_key_t_value_double(key.clone(), value.clone(), expiration_seconds)? {
            Ok(false)
        } else {
            self.add_with_t_key_t_value_double(key, value, expiration_seconds)
        }
    }
    pub fn add_or_update_with_t_key_t_value_time_span(
        &self,
        key: TKey,
        value: Option<TValue>,
        sliding_expiration: Duration,
    ) -> Result<bool, Error> {
        if self.update_with_t_key_t_value_time_span(
            key.clone(),
            value.clone(),
            sliding_expiration,
        )? {
            Ok(false)
        } else {
            self.add_with_t_key_t_value_time_span(key, value, sliding_expiration)
        }
    }
    pub fn clear(&self) -> Result<(), Error> {
        mutex(&self.state)?.entries.clear();
        Ok(())
    }
    pub fn contains(&self, key: TKey) -> Result<bool, Error> {
        let mut state = mutex(&self.state)?;
        self.prune(&mut state);
        Ok(state.entries.iter().any(|entry| entry.key == key))
    }
    pub fn count(&self) -> i32 {
        let mut state = self.state.lock().expect("cache lock poisoned");
        self.prune(&mut state);
        i32::try_from(state.entries.len()).unwrap_or(i32::MAX)
    }
    pub fn item(&self, key: TKey) -> Option<TValue> {
        let mut state = self.state.lock().ok()?;
        self.prune(&mut state);
        let entry = state.entries.iter_mut().find(|entry| entry.key == key)?;
        if let Some(window) = entry.sliding {
            entry.expires = self.now().saturating_add(window);
        }
        entry.value.clone()
    }
    pub fn remove(&self, key: TKey) -> Result<bool, Error> {
        let mut state = mutex(&self.state)?;
        self.prune(&mut state);
        if let Some(index) = state.entries.iter().position(|entry| entry.key == key) {
            state.entries.remove(index);
            Ok(true)
        } else {
            Ok(false)
        }
    }
    pub fn try_get_value(&self, key: TKey, value: &mut Option<TValue>) -> bool {
        let Ok(mut state) = self.state.lock() else {
            *value = None;
            return false;
        };
        self.prune(&mut state);
        let Some(entry) = state.entries.iter_mut().find(|entry| entry.key == key) else {
            *value = None;
            return false;
        };
        if let Some(window) = entry.sliding {
            entry.expires = self.now().saturating_add(window);
        }
        *value = entry.value.clone();
        true
    }
    pub fn update_with_t_key_t_value(
        &self,
        key: TKey,
        value: Option<TValue>,
    ) -> Result<bool, Error> {
        let mut state = mutex(&self.state)?;
        self.prune(&mut state);
        let Some(entry) = state.entries.iter_mut().find(|entry| entry.key == key) else {
            return Ok(false);
        };
        entry.value = value;
        if let Some(window) = entry.sliding {
            entry.expires = self.now().saturating_add(window);
        }
        Ok(true)
    }
    pub fn update_with_t_key_t_value_double(
        &self,
        key: TKey,
        value: Option<TValue>,
        expiration_seconds: f64,
    ) -> Result<bool, Error> {
        self.update_duration(key, value, seconds_to_nanos(expiration_seconds)?, false)
    }
    pub fn update_with_t_key_t_value_time_span(
        &self,
        key: TKey,
        value: Option<TValue>,
        sliding_expiration: Duration,
    ) -> Result<bool, Error> {
        self.update_duration(
            key,
            value,
            i128::try_from(sliding_expiration.as_nanos()).unwrap_or(i128::MAX),
            true,
        )
    }
    pub fn copy_to(
        &self,
        array: &mut [(TKey, Option<TValue>)],
        start_index: i32,
    ) -> Result<(), Error> {
        let index = usize::try_from(start_index).map_err(|_| Error::Argument)?;
        let mut state = mutex(&self.state)?;
        self.prune(&mut state);
        if index >= array.len() || array.len().saturating_sub(index) < state.entries.len() {
            return Err(Error::Argument);
        }
        for (target, entry) in array[index..].iter_mut().zip(&state.entries) {
            *target = (entry.key.clone(), entry.value.clone());
        }
        Ok(())
    }
    pub fn dispose(&self) -> Result<(), Error> {
        Ok(())
    }
}

fn seconds_to_nanos(seconds: f64) -> Result<i128, Error> {
    if !seconds.is_finite() {
        return Err(Error::Argument);
    }
    Ok((seconds * 1_000_000_000.0) as i128)
}

/// Dictionary associating each key with an ordered collection of values.
pub struct MultiValueDictionary<TKey, TValue> {
    data: RwLock<Vec<(TKey, Vec<Option<TValue>>)>>,
    version: AtomicU64,
}
impl<TKey: Clone + PartialEq, TValue: Clone + PartialEq> MultiValueDictionary<TKey, TValue> {
    pub fn new_with_constructor() -> Result<Self, Error> {
        Ok(Self {
            data: RwLock::new(Vec::new()),
            version: AtomicU64::new(0),
        })
    }
    pub fn new_with_int32(capacity: i32) -> Result<Self, Error> {
        let capacity = usize::try_from(capacity).map_err(|_| Error::Argument)?;
        Ok(Self {
            data: RwLock::new(Vec::with_capacity(capacity)),
            version: AtomicU64::new(0),
        })
    }
    pub fn new_with_i_equality_comparer(_: IEqualityComparer<TKey>) -> Result<Self, Error> {
        Self::new_with_constructor()
    }
    pub fn new_with_int32_i_equality_comparer(
        capacity: i32,
        _: IEqualityComparer<TKey>,
    ) -> Result<Self, Error> {
        Self::new_with_int32(capacity)
    }
    pub fn new_with_i_enumerable(
        enumerable: Box<dyn Iterator<Item = (TKey, Vec<Option<TValue>>)>>,
    ) -> Result<Self, Error> {
        let result = Self::new_with_constructor()?;
        for (key, values) in enumerable {
            result.add_values(key, values)?;
        }
        Ok(result)
    }
    pub fn new_with_i_enumerable_i_equality_comparer(
        enumerable: Box<dyn Iterator<Item = (TKey, Vec<Option<TValue>>)>>,
        _: IEqualityComparer<TKey>,
    ) -> Result<Self, Error> {
        Self::new_with_i_enumerable(enumerable)
    }
    pub fn add(&self, key: TKey, value: Option<TValue>) -> Result<(), Error> {
        let mut data = write(&self.data)?;
        if let Some((_, values)) = data.iter_mut().find(|(candidate, _)| candidate == &key) {
            values.push(value);
        } else {
            data.push((key, vec![value]));
        }
        self.version.fetch_add(1, Ordering::AcqRel);
        Ok(())
    }
    pub fn add_range(
        &self,
        key: TKey,
        values: Box<dyn Iterator<Item = Option<TValue>>>,
    ) -> Result<(), Error> {
        self.add_values(key, values.collect())
    }
    fn add_values(&self, key: TKey, values: Vec<Option<TValue>>) -> Result<(), Error> {
        let mut data = write(&self.data)?;
        if let Some((_, stored)) = data.iter_mut().find(|(candidate, _)| candidate == &key) {
            stored.extend(values);
        } else {
            data.push((key, values));
        }
        self.version.fetch_add(1, Ordering::AcqRel);
        Ok(())
    }
    pub fn remove_with_t_key(&self, key: TKey) -> Result<bool, Error> {
        let mut data = write(&self.data)?;
        let removed = data
            .iter()
            .position(|(candidate, _)| candidate == &key)
            .map(|index| data.remove(index))
            .is_some();
        if removed {
            self.version.fetch_add(1, Ordering::AcqRel);
        }
        Ok(removed)
    }
    pub fn remove_with_t_key_t_value(
        &self,
        key: TKey,
        value: Option<TValue>,
    ) -> Result<bool, Error> {
        let mut data = write(&self.data)?;
        let Some(entry) = data.iter().position(|(candidate, _)| candidate == &key) else {
            return Ok(false);
        };
        let Some(index) = data[entry]
            .1
            .iter()
            .position(|candidate| candidate == &value)
        else {
            return Ok(false);
        };
        data[entry].1.remove(index);
        if data[entry].1.is_empty() {
            data.remove(entry);
        }
        self.version.fetch_add(1, Ordering::AcqRel);
        Ok(true)
    }
    pub fn contains(&self, key: TKey, value: Option<TValue>) -> Result<bool, Error> {
        Ok(read(&self.data)?
            .iter()
            .find(|(candidate, _)| candidate == &key)
            .is_some_and(|(_, values)| values.contains(&value)))
    }
    pub fn contains_value(&self, value: Option<TValue>) -> Result<bool, Error> {
        Ok(read(&self.data)?
            .iter()
            .any(|(_, values)| values.contains(&value)))
    }
    pub fn clear(&self) -> Result<(), Error> {
        write(&self.data)?.clear();
        self.version.fetch_add(1, Ordering::AcqRel);
        Ok(())
    }
    pub fn contains_key(&self, key: TKey) -> Result<bool, Error> {
        Ok(read(&self.data)?
            .iter()
            .any(|(candidate, _)| candidate == &key))
    }
    pub fn keys(&self) -> Box<dyn Iterator<Item = TKey> + '_> {
        Box::new(
            read(&self.data)
                .expect("dictionary lock poisoned")
                .iter()
                .map(|(key, _)| key.clone())
                .collect::<Vec<_>>()
                .into_iter(),
        )
    }
    pub fn try_get_value(&self, key: TKey, value: &mut Option<Vec<Option<TValue>>>) -> bool {
        *value = read(&self.data).ok().and_then(|data| {
            data.iter()
                .find(|(candidate, _)| candidate == &key)
                .map(|(_, values)| values.clone())
        });
        value.is_some()
    }
    pub fn values(&self) -> Box<dyn Iterator<Item = Vec<Option<TValue>>> + '_> {
        Box::new(
            read(&self.data)
                .expect("dictionary lock poisoned")
                .iter()
                .map(|(_, values)| values.clone())
                .collect::<Vec<_>>()
                .into_iter(),
        )
    }
    pub fn item(&self, key: TKey) -> Vec<Option<TValue>> {
        read(&self.data)
            .expect("dictionary lock poisoned")
            .iter()
            .find(|(candidate, _)| candidate == &key)
            .expect("key not found")
            .1
            .clone()
    }
    pub fn count(&self) -> i32 {
        i32::try_from(read(&self.data).expect("dictionary lock poisoned").len()).unwrap_or(i32::MAX)
    }
    pub fn get_enumerator(
        &self,
    ) -> Result<Box<dyn Iterator<Item = (TKey, Vec<Option<TValue>>)> + '_>, Error> {
        let data = read(&self.data)?;
        let expected_version = self.version.load(Ordering::Acquire);
        let snapshot = data.clone();
        Ok(Box::new(MultiValueIterator {
            inner: snapshot.into_iter(),
            version: &self.version,
            expected_version,
        }))
    }

    pub fn create_with_method<TValueCollection: crate::compat::Collection<TValue> + Default>()
    -> Result<MultiValueDictionary<TKey, Option<TValue>>, Error> {
        let _ = TValueCollection::default();
        MultiValueDictionary::new_with_constructor()
    }
    pub fn create_with_int32<TValueCollection: crate::compat::Collection<TValue> + Default>(
        capacity: i32,
    ) -> Result<MultiValueDictionary<TKey, Option<TValue>>, Error> {
        let _ = TValueCollection::default();
        MultiValueDictionary::new_with_int32(capacity)
    }
    pub fn create_with_i_equality_comparer<
        TValueCollection: crate::compat::Collection<TValue> + Default,
    >(
        _: IEqualityComparer<TKey>,
    ) -> Result<MultiValueDictionary<TKey, Option<TValue>>, Error> {
        Self::create_with_method::<TValueCollection>()
    }
    pub fn create_with_int32_i_equality_comparer<
        TValueCollection: crate::compat::Collection<TValue> + Default,
    >(
        capacity: i32,
        _: IEqualityComparer<TKey>,
    ) -> Result<MultiValueDictionary<TKey, Option<TValue>>, Error> {
        Self::create_with_int32::<TValueCollection>(capacity)
    }
    pub fn create_with_func<TValueCollection: crate::compat::Collection<TValue>>(
        collection_factory: Box<dyn Fn() -> TValueCollection + Send + Sync>,
    ) -> Result<MultiValueDictionary<TKey, Option<TValue>>, Error> {
        let _ = collection_factory();
        MultiValueDictionary::new_with_constructor()
    }
    pub fn create_with_int32_func<TValueCollection: crate::compat::Collection<TValue>>(
        capacity: i32,
        collection_factory: Box<dyn Fn() -> TValueCollection + Send + Sync>,
    ) -> Result<MultiValueDictionary<TKey, Option<TValue>>, Error> {
        let _ = collection_factory();
        MultiValueDictionary::new_with_int32(capacity)
    }
    pub fn create_with_i_equality_comparer_func<
        TValueCollection: crate::compat::Collection<TValue>,
    >(
        _: IEqualityComparer<TKey>,
        collection_factory: Box<dyn Fn() -> TValueCollection + Send + Sync>,
    ) -> Result<MultiValueDictionary<TKey, Option<TValue>>, Error> {
        Self::create_with_func(collection_factory)
    }
    pub fn create_with_int32_i_equality_comparer_func<
        TValueCollection: crate::compat::Collection<TValue>,
    >(
        capacity: i32,
        _: IEqualityComparer<TKey>,
        collection_factory: Box<dyn Fn() -> TValueCollection + Send + Sync>,
    ) -> Result<MultiValueDictionary<TKey, Option<TValue>>, Error> {
        Self::create_with_int32_func(capacity, collection_factory)
    }
    pub fn create_with_i_enumerable<
        TValueCollection: crate::compat::Collection<TValue> + Default,
    >(
        enumerable: Box<dyn Iterator<Item = (TKey, Vec<Option<TValue>>)>>,
    ) -> Result<MultiValueDictionary<TKey, Option<TValue>>, Error> {
        let result = Self::create_with_method::<TValueCollection>()?;
        for (key, values) in enumerable {
            result.add_values(key, values.into_iter().map(Some).collect())?;
        }
        Ok(result)
    }
    pub fn create_with_i_enumerable_i_equality_comparer<
        TValueCollection: crate::compat::Collection<TValue> + Default,
    >(
        enumerable: Box<dyn Iterator<Item = (TKey, Vec<Option<TValue>>)>>,
        _: IEqualityComparer<TKey>,
    ) -> Result<MultiValueDictionary<TKey, Option<TValue>>, Error> {
        Self::create_with_i_enumerable::<TValueCollection>(enumerable)
    }
    pub fn create_with_i_enumerable_func<TValueCollection: crate::compat::Collection<TValue>>(
        enumerable: Box<dyn Iterator<Item = (TKey, Vec<Option<TValue>>)>>,
        factory: Box<dyn Fn() -> TValueCollection + Send + Sync>,
    ) -> Result<MultiValueDictionary<TKey, Option<TValue>>, Error> {
        let result = Self::create_with_func(factory)?;
        for (key, values) in enumerable {
            result.add_values(key, values.into_iter().map(Some).collect())?;
        }
        Ok(result)
    }
    pub fn create_with_i_enumerable_i_equality_comparer_func<
        TValueCollection: crate::compat::Collection<TValue>,
    >(
        enumerable: Box<dyn Iterator<Item = (TKey, Vec<Option<TValue>>)>>,
        _: IEqualityComparer<TKey>,
        factory: Box<dyn Fn() -> TValueCollection + Send + Sync>,
    ) -> Result<MultiValueDictionary<TKey, Option<TValue>>, Error> {
        Self::create_with_i_enumerable_func(enumerable, factory)
    }
}

struct MultiValueIterator<'a, TKey, TValue> {
    inner: std::vec::IntoIter<(TKey, Vec<Option<TValue>>)>,
    version: &'a AtomicU64,
    expected_version: u64,
}

impl<TKey, TValue> Iterator for MultiValueIterator<'_, TKey, TValue> {
    type Item = (TKey, Vec<Option<TValue>>);

    fn next(&mut self) -> Option<Self::Item> {
        assert_eq!(
            self.version.load(Ordering::Acquire),
            self.expected_version,
            "collection was modified during enumeration"
        );
        self.inner.next()
    }
}

#[derive(Clone)]
pub struct TokenBucket {
    state: Arc<Mutex<TokenState>>,
    parent: Option<Box<TokenBucket>>,
    clock: Arc<dyn MonotonicClock>,
}
struct TokenState {
    max_burst: i32,
    tokens_per_ms: i32,
    content: i32,
    last_drip: i32,
}
impl TokenBucket {
    pub fn new(parent: TokenBucket, max_burst: i32, drip_rate: i32) -> Result<Self, Error> {
        Self::new_with_clock(
            Some(parent),
            max_burst,
            drip_rate,
            Arc::new(SystemClock::new()),
        )
    }
    pub fn new_root(max_burst: i32, drip_rate: i32) -> Result<Self, Error> {
        Self::new_with_clock(None, max_burst, drip_rate, Arc::new(SystemClock::new()))
    }
    pub fn new_with_clock(
        parent: Option<TokenBucket>,
        max_burst: i32,
        drip_rate: i32,
        clock: Arc<dyn MonotonicClock>,
    ) -> Result<Self, Error> {
        let now = tick_count(clock.as_ref());
        let bucket = Self {
            state: Arc::new(Mutex::new(TokenState {
                max_burst: max_burst.max(0),
                tokens_per_ms: 0,
                content: 0,
                last_drip: now,
            })),
            parent: parent.map(Box::new),
            clock,
        };
        {
            let mut state = mutex(&bucket.state)?;
            set_drip_rate_state(&mut state, drip_rate);
        }
        Ok(bucket)
    }
    pub fn remove_tokens_with_int32(&self, amount: i32) -> Result<bool, Error> {
        let mut drip = false;
        self.remove_tokens_with_int32_boolean(amount, &mut drip)
    }
    pub fn remove_tokens_with_int32_boolean(
        &self,
        amount: i32,
        drip_succeeded: &mut bool,
    ) -> Result<bool, Error> {
        let infinite = mutex(&self.state)?.max_burst == 0;
        if infinite {
            *drip_succeeded = true;
            return Ok(true);
        }
        let mut state = mutex(&self.state)?;
        *drip_succeeded = drip(&mut state, tick_count(self.clock.as_ref()));
        if state.content.wrapping_sub(amount) < 0 {
            return Ok(false);
        }
        if let Some(parent) = &self.parent
            && !parent.remove_tokens_with_int32(amount)?
        {
            return Ok(false);
        }
        state.content = state.content.wrapping_sub(amount);
        Ok(true)
    }
    pub fn parent(&self) -> TokenBucket {
        self.parent
            .as_deref()
            .expect("root token bucket has no parent")
            .clone()
    }
    pub fn max_burst(&self) -> i32 {
        self.state.lock().expect("bucket lock poisoned").max_burst
    }
    pub fn set_max_burst(&mut self, value: i32) {
        self.state.lock().expect("bucket lock poisoned").max_burst = value.max(0);
    }
    pub fn drip_rate(&self) -> i32 {
        self.state
            .lock()
            .expect("bucket lock poisoned")
            .tokens_per_ms
            .wrapping_mul(1000)
    }
    pub fn set_drip_rate(&mut self, value: i32) {
        set_drip_rate_state(&mut self.state.lock().expect("bucket lock poisoned"), value);
    }
    pub fn content(&self) -> i32 {
        self.state.lock().expect("bucket lock poisoned").content
    }
}
fn set_drip_rate_state(state: &mut TokenState, value: i32) {
    state.tokens_per_ms = if value == 0 {
        0
    } else if value / 1000 <= 0 {
        1
    } else {
        value / 1000
    };
}
fn tick_count(clock: &dyn MonotonicClock) -> i32 {
    let masked = clock.now().as_millis() % 2_147_483_648_u128;
    i32::try_from(masked).expect("masked tick count fits in i32")
}

fn drip(state: &mut TokenState, now: i32) -> bool {
    if state.tokens_per_ms == 0 {
        state.content = state.max_burst;
        return true;
    }
    let delta = now.wrapping_sub(state.last_drip);
    if delta <= 0 {
        if delta < 0 {
            state.last_drip = now;
        }
        return false;
    }
    let drip_amount = delta.wrapping_mul(state.tokens_per_ms);
    state.content = state.content.wrapping_add(drip_amount).min(state.max_burst);
    state.last_drip = now;
    true
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::panic::{AssertUnwindSafe, catch_unwind};
    use std::sync::Barrier;
    use std::thread;
    struct ManualClock(AtomicU64);
    impl ManualClock {
        fn new() -> Self {
            Self(AtomicU64::new(0))
        }
        fn advance(&self, millis: u64) {
            self.0.fetch_add(millis, Ordering::SeqCst);
        }
    }
    impl MonotonicClock for ManualClock {
        fn now(&self) -> Duration {
            Duration::from_millis(self.0.load(Ordering::SeqCst))
        }
    }

    #[test]
    fn cache_dictionary_lru_and_replacement_behave_like_reference() {
        let cache =
            CacheDictionary::new(2, Box::new(LruRemovalStrategy::<i32>::new().unwrap())).unwrap();
        cache.add_with_t_key_t_value(1, Some("one")).unwrap();
        cache.add_with_t_key_t_value(2, Some("two")).unwrap();
        assert_eq!(cache.item(Some(1)), Some("one"));
        cache.add_with_t_key_t_value(3, Some("three")).unwrap();
        assert!(!cache.contains_key(2).unwrap());
        assert!(cache.contains_key(1).unwrap());
        assert_eq!(
            cache.add_with_t_key_t_value(1, Some("again")),
            Err(Error::Argument)
        );

        let nullable =
            CacheDictionary::new(1, Box::new(EmptyRemovalStrategy::<i32>::new().unwrap())).unwrap();
        nullable.add_with_t_key_t_value(9, None::<i32>).unwrap();
        let mut value = Some(42);
        assert!(nullable.try_get_value(9, &mut value));
        assert_eq!(value, None);

        let enumerated =
            CacheDictionary::new(2, Box::new(LruRemovalStrategy::<i32>::new().unwrap())).unwrap();
        enumerated.add_with_t_key_t_value(1, Some(1)).unwrap();
        enumerated.add_with_t_key_t_value(2, Some(2)).unwrap();
        let mut entries = enumerated.get_enumerator().unwrap();
        assert_eq!(entries.next(), Some((1, Some(1))));
        enumerated.add_with_t_key_t_value(3, Some(3)).unwrap();
        assert!(!enumerated.contains_key(2).unwrap());
    }

    #[test]
    fn double_and_multi_value_dictionaries_preserve_pairs_and_duplicates() {
        let double = DoubleDictionary::new_with_constructor().unwrap();
        double.add(1, "a", Some(10)).unwrap();
        let mut value = None;
        assert!(double.try_get_value_with_t_key2_t_value("a", &mut value));
        assert_eq!(value, Some(10));
        assert!(double.remove_with_t_key1(1).unwrap());
        assert_eq!(double.count(), 0);
        let multi = MultiValueDictionary::new_with_constructor().unwrap();
        multi.add("key", Some(1)).unwrap();
        multi.add("key", Some(1)).unwrap();
        multi.add("key", Some(2)).unwrap();
        assert_eq!(multi.item("key"), vec![Some(1), Some(1), Some(2)]);
        assert!(multi.remove_with_t_key_t_value("key", Some(1)).unwrap());
        assert_eq!(multi.item("key"), vec![Some(1), Some(2)]);

        multi
            .add_range("empty", Box::new(std::iter::empty()))
            .unwrap();
        assert!(multi.contains_key("empty").unwrap());
        let mut enumerator = multi.get_enumerator().unwrap();
        multi.add("later", Some(3)).unwrap();
        assert!(catch_unwind(AssertUnwindSafe(|| enumerator.next())).is_err());
    }

    #[test]
    fn double_dictionary_callbacks_are_reentrant_and_run_without_collection_locks() {
        let dictionary = Arc::new(DoubleDictionary::new_with_constructor().unwrap());
        dictionary.add(1, "one", Some(10)).unwrap();
        dictionary.add(2, "two", Some(20)).unwrap();

        let observer = Arc::clone(&dictionary);
        dictionary
            .for_each_with_action_b56adc7f(Box::new(move |_| {
                assert_eq!(observer.count(), 2);
            }))
            .unwrap();

        let mut nullable = Some(1);
        dictionary.add(3, "three", None).unwrap();
        assert!(dictionary.try_get_value_with_t_key1_t_value(3, &mut nullable));
        assert_eq!(nullable, None);
    }

    #[test]
    fn expiration_and_sliding_access_use_the_injected_clock_without_sleep() {
        let clock = Arc::new(ManualClock::new());
        let cache = ExpiringCache::new_with_clock(clock.clone()).unwrap();
        cache
            .add_with_t_key_t_value_time_span("sliding", Some(7), Duration::from_millis(10))
            .unwrap();
        clock.advance(8);
        assert_eq!(cache.item("sliding"), Some(7));
        clock.advance(8);
        assert!(cache.contains("sliding").unwrap());
        clock.advance(3);
        assert!(!cache.contains("sliding").unwrap());
    }

    #[test]
    fn hierarchical_token_bucket_refills_and_rolls_back_deterministically() {
        let clock = Arc::new(ManualClock::new());
        let parent = TokenBucket::new_with_clock(None, 10, 1000, clock.clone()).unwrap();
        let child =
            TokenBucket::new_with_clock(Some(parent.clone()), 20, 2000, clock.clone()).unwrap();
        clock.advance(10);
        assert!(child.remove_tokens_with_int32(8).unwrap());
        assert_eq!(child.content(), 12);
        assert_eq!(parent.content(), 2);
        assert!(!child.remove_tokens_with_int32(5).unwrap());
        assert_eq!(child.content(), 12);
    }

    #[test]
    fn concurrent_cache_and_bucket_operations_preserve_atomic_invariants_without_sleep() {
        const WORKERS: usize = 16;
        let clock = Arc::new(ManualClock::new());
        let cache = Arc::new(ExpiringCache::new_with_clock(clock.clone()).unwrap());
        let start = Arc::new(Barrier::new(WORKERS));
        let handles: Vec<_> = (0..WORKERS)
            .map(|value| {
                let cache = Arc::clone(&cache);
                let start = Arc::clone(&start);
                thread::spawn(move || {
                    start.wait();
                    cache
                        .add_with_t_key_t_value_double("one-key", Some(value), 60.0)
                        .unwrap()
                })
            })
            .collect();
        let successful_adds = handles
            .into_iter()
            .map(|handle| handle.join().unwrap())
            .filter(|success| *success)
            .count();
        assert_eq!(successful_adds, 1);
        assert_eq!(cache.count(), 1);

        let bucket = Arc::new(TokenBucket::new_with_clock(None, 10, 1000, clock.clone()).unwrap());
        clock.advance(10);
        let start = Arc::new(Barrier::new(WORKERS));
        let handles: Vec<_> = (0..WORKERS)
            .map(|_| {
                let bucket = Arc::clone(&bucket);
                let start = Arc::clone(&start);
                thread::spawn(move || {
                    start.wait();
                    bucket.remove_tokens_with_int32(1).unwrap()
                })
            })
            .collect();
        let successful_removals = handles
            .into_iter()
            .map(|handle| handle.join().unwrap())
            .filter(|success| *success)
            .count();
        assert_eq!(successful_removals, 10);
        assert_eq!(bucket.content(), 0);
    }
}
