use core::borrow::Borrow;
use core::hash::{Hash, Hasher};
use crate::buf::{Bindable, Buf, Visit};
use crate::endian::{ByteOrder, Native};
use crate::error::Error;
use crate::pointer::{DefaultSize, Size};
use crate::sip::SipHasher13;
use crate::swiss::map::{RawTable, RawTableRef};
use crate::ZeroCopy;
pub struct Set<'a, T> {
key: u64,
table: RawTable<'a, T>,
buf: &'a Buf,
}
impl<T> Set<'_, T>
where
T: ZeroCopy,
{
pub fn contains<Q>(&self, value: &Q) -> Result<bool, Error>
where
Q: ?Sized + Visit,
Q::Target: Eq + Hash,
T: Visit,
T::Target: Borrow<Q::Target>,
{
let hash = value.visit(self.buf, |k| self.hash(k))?;
let entry = self.table.find(hash, |e| {
value.visit(self.buf, |b| e.visit(self.buf, |a| a.borrow() == b))?
})?;
Ok(entry.is_some())
}
fn hash<H>(&self, value: &H) -> u64
where
H: ?Sized + Hash,
{
let mut hasher = SipHasher13::new_with_keys(0, self.key);
value.hash(&mut hasher);
hasher.finish()
}
}
impl<T, E, O> Bindable for SetRef<T, E, O>
where
T: ZeroCopy,
E: ByteOrder,
O: Size,
{
type Bound<'a>
= Set<'a, T>
where
Self: 'a;
#[inline]
fn bind(self, buf: &Buf) -> Result<Self::Bound<'_>, Error> {
Ok(Set {
key: self.key,
table: self.table.bind(buf)?,
buf,
})
}
}
#[derive(Debug, ZeroCopy)]
#[repr(C)]
#[zero_copy(crate)]
pub struct SetRef<T, E = Native, O = DefaultSize>
where
T: ZeroCopy,
E: ByteOrder,
O: Size,
{
key: u64,
table: RawTableRef<T, E, O>,
}
impl<T, E, O> SetRef<T, E, O>
where
T: ZeroCopy,
E: ByteOrder,
O: Size,
{
#[cfg(feature = "alloc")]
pub(crate) fn new(key: u64, table: RawTableRef<T, E, O>) -> Self {
Self { key, table }
}
pub fn contains<Q>(&self, buf: &Buf, key: &Q) -> Result<bool, Error>
where
Q: ?Sized + Visit,
Q::Target: Eq + Hash,
T: Visit,
T::Target: Borrow<Q::Target>,
{
let hash = key.visit(buf, |key| self.hash(key))?;
let entry = self.table.find(buf, hash, |e| {
key.visit(buf, |b| e.visit(buf, |a| a.borrow() == b))?
})?;
Ok(entry.is_some())
}
fn hash<H>(&self, value: &H) -> u64
where
H: ?Sized + Hash,
{
let mut hasher = SipHasher13::new_with_keys(0, self.key);
value.hash(&mut hasher);
hasher.finish()
}
}