use std::io::{self, Read, Write};
use whasher::{GxPapayaSet, new_papaya_set};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum SetOperation {
Sadd = 0,
Srem = 1,
Spop = 2,
Smove = 3,
Srandmember = 4,
Smembers = 5,
Sinter = 6,
Sunion = 7,
Sdiff = 8,
Sinterstore = 9,
Sunionstore = 10,
Sdiffstore = 11,
Sismember = 12,
Scard = 13,
}
pub struct SetObject {
pub set: GxPapayaSet<Vec<u8>>,
}
impl SetObject {
pub fn new() -> Self {
Self {
set: new_papaya_set(),
}
}
pub fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self> {
let mut buf = Vec::new();
reader.read_to_end(&mut buf)?;
let items: Vec<Vec<u8>> =
bitcode::decode(&buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let set = new_papaya_set();
let pin = set.pin();
for item in items {
pin.insert(item);
}
drop(pin);
Ok(Self { set })
}
pub fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
let pin = self.set.pin();
let mut items = Vec::with_capacity(pin.len());
for item in pin.iter() {
items.push(item.clone());
}
let bytes = bitcode::encode(&items);
writer.write_all(&bytes)
}
pub fn operate(&self, op: SetOperation, key: &[u8]) -> bool {
let pin = self.set.pin();
match op {
SetOperation::Sadd => pin.insert(key.to_vec()),
SetOperation::Srem => pin.remove(key),
SetOperation::Sismember => pin.contains(key),
_ => false,
}
}
pub fn count(&self) -> usize {
self.set.pin().len()
}
}
impl Default for SetObject {
fn default() -> Self {
Self::new()
}
}
impl SetObject {
pub fn get_keys(&self) -> Vec<Vec<u8>> {
let pin = self.set.pin();
pin.iter().cloned().collect()
}
pub fn pop(&self) -> Option<Vec<u8>> {
let pin = self.set.pin();
let len = pin.len();
if len == 0 {
return None;
}
let item = pin.iter().nth(fastrand::usize(..len)).cloned()?;
pin.remove(&item);
Some(item)
}
pub fn random_member(&self) -> Option<Vec<u8>> {
let pin = self.set.pin();
let len = pin.len();
if len == 0 {
return None;
}
pin.iter().nth(fastrand::usize(..len)).cloned()
}
}