fast-cache 0.1.0

Embedded-first thread-per-core in-memory cache with optional Redis-compatible server
Documentation
use super::*;

impl SetObject {
    pub(super) fn empty() -> Self {
        Self::Small(SmallSetEntries::new())
    }

    pub(super) fn map_with_capacity(capacity: usize) -> Self {
        let mut set = FastHashSet::default();
        set.reserve(capacity);
        Self::Map(set)
    }

    pub(super) fn insert_many(&mut self, members: &[&[u8]]) -> usize {
        let mut inserted = 0usize;
        for member in members {
            if self.insert_slice(member) {
                inserted += 1;
            }
        }
        inserted
    }

    pub(super) fn insert_slice(&mut self, member: &[u8]) -> bool {
        match self {
            Self::Small(entries) => {
                if entries
                    .first()
                    .is_some_and(|existing| existing.as_slice() == member)
                {
                    return false;
                }
                if entries.iter().any(|existing| existing.as_slice() == member) {
                    return false;
                }
                if entries.len() < SMALL_SET_INLINE {
                    entries.push(member.to_vec());
                    return true;
                }

                let capacity = entries.len() + 1;
                let old_entries = std::mem::take(entries);
                *self = Self::map_with_capacity(capacity);
                let Self::Map(set) = self else {
                    unreachable!("set promotion did not create map state");
                };
                for old_member in old_entries {
                    set.insert(old_member);
                }
                set.insert(member.to_vec())
            }
            Self::Map(set) => set.insert(member.to_vec()),
        }
    }

    pub(super) fn remove(&mut self, member: &[u8]) -> bool {
        match self {
            Self::Small(entries) => {
                let Some(index) = entries
                    .iter()
                    .position(|existing| existing.as_slice() == member)
                else {
                    return false;
                };
                entries.remove(index);
                true
            }
            Self::Map(set) => set.remove(member),
        }
    }

    pub(super) fn contains(&self, member: &[u8]) -> bool {
        match self {
            Self::Small(entries) => entries.iter().any(|existing| existing.as_slice() == member),
            Self::Map(set) => set.contains(member),
        }
    }

    pub(super) fn len(&self) -> usize {
        match self {
            Self::Small(entries) => entries.len(),
            Self::Map(set) => set.len(),
        }
    }

    pub(super) fn is_empty(&self) -> bool {
        match self {
            Self::Small(entries) => entries.is_empty(),
            Self::Map(set) => set.is_empty(),
        }
    }

    pub(super) fn iter(&self) -> impl Iterator<Item = &Bytes> {
        enum SetIter<'a> {
            Small(std::slice::Iter<'a, Bytes>),
            Map(std::collections::hash_set::Iter<'a, Bytes>),
        }

        impl<'a> Iterator for SetIter<'a> {
            type Item = &'a Bytes;

            fn next(&mut self) -> Option<Self::Item> {
                match self {
                    Self::Small(iter) => iter.next(),
                    Self::Map(iter) => iter.next(),
                }
            }
        }

        match self {
            Self::Small(entries) => SetIter::Small(entries.iter()),
            Self::Map(set) => SetIter::Map(set.iter()),
        }
    }
}