fast-cache 0.1.0

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

impl RedisObjectBucket {
    #[inline(always)]
    pub(crate) fn sadd_existing_or_wrongtype_hashed(
        &mut self,
        key_hash: u64,
        key: &[u8],
        members: &[&[u8]],
    ) -> RedisObjectWriteAttempt {
        if members.is_empty() {
            return RedisObjectWriteAttempt::Complete(RedisObjectResult::Integer(0));
        }
        if let Some(slot) = self.sets.get_hashed(key_hash, key) {
            let set = self.set_slab.get_mut(slot).expect("set slab slot missing");
            let inserted = if let [member] = members {
                set.insert_slice(member) as usize
            } else {
                set.insert_many(members)
            };
            return RedisObjectWriteAttempt::Complete(RedisObjectResult::Integer(inserted as i64));
        }
        if self.has_non_set(key) {
            RedisObjectWriteAttempt::Complete(RedisObjectResult::WrongType)
        } else {
            RedisObjectWriteAttempt::Missing
        }
    }

    #[inline(always)]
    pub(crate) fn sadd_new_unchecked_hashed(
        &mut self,
        key_hash: u64,
        key: &[u8],
        members: &[&[u8]],
    ) -> RedisObjectResult {
        let mut set = SetObject::empty();
        let inserted = if let [member] = members {
            set.insert_slice(member) as usize
        } else {
            set.insert_many(members)
        };
        let slot = self.set_slab.insert(set);
        self.sets.insert_hashed(key_hash, key.to_vec(), slot);
        RedisObjectResult::Integer(inserted as i64)
    }

    pub(crate) fn srem(&mut self, key: &[u8], members: &[&[u8]]) -> (RedisObjectResult, bool) {
        if let Some(slot) = self.sets.get(key).copied() {
            let set = self.set_slab.get_mut(slot).expect("set slab slot missing");
            let removed = members.iter().filter(|member| set.remove(member)).count();
            let empty = set.is_empty();
            if empty {
                self.sets.remove(key);
                self.set_slab.remove(slot);
                self.expire_at_ms.remove(key);
            }
            return (RedisObjectResult::Integer(removed as i64), empty);
        }
        if self.has_non_set(key) {
            (RedisObjectResult::WrongType, false)
        } else {
            (RedisObjectResult::Integer(0), false)
        }
    }

    pub(crate) fn sismember(&self, key: &[u8], member: &[u8]) -> RedisObjectResult {
        match self.sets.get(key).copied() {
            Some(slot) => RedisObjectResult::Integer(
                self.set_slab
                    .get(slot)
                    .expect("set slab slot missing")
                    .contains(member) as i64,
            ),
            None if self.has_non_set(key) => RedisObjectResult::WrongType,
            None => RedisObjectResult::Integer(0),
        }
    }

    pub(crate) fn smismember(&self, key: &[u8], members: &[&[u8]]) -> RedisObjectResult {
        match self.sets.get(key).copied() {
            Some(slot) => {
                let set = self.set_slab.get(slot).expect("set slab slot missing");
                RedisObjectResult::IntegerArray(
                    members
                        .iter()
                        .map(|member| set.contains(member) as i64)
                        .collect(),
                )
            }
            None if self.has_non_set(key) => RedisObjectResult::WrongType,
            None => RedisObjectResult::IntegerArray(vec![0; members.len()]),
        }
    }

    pub(crate) fn sismember_visit(
        &self,
        key: &[u8],
        member: &[u8],
        write: impl FnOnce(i64),
    ) -> RedisObjectReadOutcome {
        match self.sets.get(key).copied() {
            Some(slot) => {
                write(
                    self.set_slab
                        .get(slot)
                        .expect("set slab slot missing")
                        .contains(member) as i64,
                );
                RedisObjectReadOutcome::Written
            }
            None if self.has_non_set(key) => RedisObjectReadOutcome::WrongType,
            None => RedisObjectReadOutcome::Missing,
        }
    }

    pub(crate) fn scard(&self, key: &[u8]) -> RedisObjectResult {
        match self.sets.get(key).copied() {
            Some(slot) => RedisObjectResult::Integer(
                self.set_slab
                    .get(slot)
                    .expect("set slab slot missing")
                    .len() as i64,
            ),
            None if self.has_non_set(key) => RedisObjectResult::WrongType,
            None => RedisObjectResult::Integer(0),
        }
    }

    pub(crate) fn scard_visit(
        &self,
        key: &[u8],
        write: impl FnOnce(i64),
    ) -> RedisObjectReadOutcome {
        match self.sets.get(key).copied() {
            Some(slot) => {
                write(
                    self.set_slab
                        .get(slot)
                        .expect("set slab slot missing")
                        .len() as i64,
                );
                RedisObjectReadOutcome::Written
            }
            None if self.has_non_set(key) => RedisObjectReadOutcome::WrongType,
            None => RedisObjectReadOutcome::Missing,
        }
    }

    pub(crate) fn smembers(&self, key: &[u8]) -> RedisObjectResult {
        match self.sets.get(key).copied() {
            Some(slot) => {
                let mut members = self
                    .set_slab
                    .get(slot)
                    .expect("set slab slot missing")
                    .iter()
                    .cloned()
                    .map(Some)
                    .collect::<Vec<_>>();
                members.sort();
                RedisObjectResult::Array(members)
            }
            None if self.has_non_set(key) => RedisObjectResult::WrongType,
            None => RedisObjectResult::Array(Vec::new()),
        }
    }

    pub(crate) fn set_members(&self, key: &[u8]) -> Result<Vec<Bytes>, ()> {
        match self.sets.get(key).copied() {
            Some(slot) => {
                let mut members = self
                    .set_slab
                    .get(slot)
                    .expect("set slab slot missing")
                    .iter()
                    .cloned()
                    .collect::<Vec<_>>();
                members.sort();
                Ok(members)
            }
            None if self.has_non_set(key) => Err(()),
            None => Ok(Vec::new()),
        }
    }

    pub(crate) fn spop(&mut self, key: &[u8], count: Option<usize>) -> (RedisObjectResult, bool) {
        if let Some(slot) = self.sets.get(key).copied() {
            let set = self.set_slab.get_mut(slot).expect("set slab slot missing");
            let requested = count.unwrap_or(1);
            let members = set.iter().take(requested).cloned().collect::<Vec<_>>();
            for member in &members {
                set.remove(member);
            }
            let empty = set.is_empty();
            if empty {
                self.sets.remove(key);
                self.set_slab.remove(slot);
                self.expire_at_ms.remove(key);
            }
            let result = if count.is_none() {
                RedisObjectResult::Bulk(members.into_iter().next())
            } else {
                RedisObjectResult::Array(members.into_iter().map(Some).collect())
            };
            return (result, empty);
        }
        if self.has_non_set(key) {
            (RedisObjectResult::WrongType, false)
        } else if count.is_some() {
            (RedisObjectResult::Array(Vec::new()), false)
        } else {
            (RedisObjectResult::Bulk(None), false)
        }
    }

    pub(crate) fn srandmember(&self, key: &[u8], count: Option<i64>) -> RedisObjectResult {
        match self.sets.get(key).copied() {
            Some(slot) => {
                let set = self.set_slab.get(slot).expect("set slab slot missing");
                if let Some(count) = count {
                    let members = set.iter().cloned().collect::<Vec<_>>();
                    if members.is_empty() {
                        return RedisObjectResult::Array(Vec::new());
                    }
                    let requested = count.unsigned_abs() as usize;
                    let values = if count >= 0 {
                        members.into_iter().take(requested).map(Some).collect()
                    } else {
                        (0..requested)
                            .map(|index| Some(members[index % members.len()].clone()))
                            .collect()
                    };
                    RedisObjectResult::Array(values)
                } else {
                    RedisObjectResult::Bulk(set.iter().next().cloned())
                }
            }
            None if self.has_non_set(key) => RedisObjectResult::WrongType,
            None => {
                if count.is_some() {
                    RedisObjectResult::Array(Vec::new())
                } else {
                    RedisObjectResult::Bulk(None)
                }
            }
        }
    }
}