#![allow(deprecated)]
use crate::{fuse_contains_impl, fuse_from_impl, Filter};
use alloc::{boxed::Box, vec::Vec};
use core::convert::TryFrom;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "bincode")]
use bincode::{Decode, Encode};
#[deprecated(since = "0.8.0", note = "prefer using a `BinaryFuse32`")]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "bincode", derive(Encode, Decode))]
#[derive(Debug)]
pub struct Fuse32 {
pub seed: u64,
pub segment_length: usize,
pub fingerprints: Box<[u32]>,
}
impl Filter<u64> for Fuse32 {
fn contains(&self, key: &u64) -> bool {
fuse_contains_impl!(*key, self, fingerprint u32)
}
fn len(&self) -> usize {
self.fingerprints.len()
}
}
impl Fuse32 {
pub fn try_from_iterator<T>(keys: T) -> Result<Self, &'static str>
where
T: ExactSizeIterator<Item = u64> + Clone,
{
fuse_from_impl!(keys fingerprint u32, max iter 1_000)
}
}
impl TryFrom<&[u64]> for Fuse32 {
type Error = &'static str;
fn try_from(keys: &[u64]) -> Result<Self, Self::Error> {
Self::try_from_iterator(keys.iter().copied())
}
}
impl TryFrom<&Vec<u64>> for Fuse32 {
type Error = &'static str;
fn try_from(v: &Vec<u64>) -> Result<Self, Self::Error> {
Self::try_from_iterator(v.iter().copied())
}
}
impl TryFrom<Vec<u64>> for Fuse32 {
type Error = &'static str;
fn try_from(v: Vec<u64>) -> Result<Self, Self::Error> {
Self::try_from_iterator(v.iter().copied())
}
}
#[cfg(test)]
mod test {
use crate::{Filter, Fuse32};
use core::convert::TryFrom;
use alloc::vec::Vec;
use rand::Rng;
#[test]
fn test_initialization() {
const SAMPLE_SIZE: usize = 1_000_000;
let mut rng = rand::thread_rng();
let keys: Vec<u64> = (0..SAMPLE_SIZE).map(|_| rng.gen()).collect();
let filter = Fuse32::try_from(&keys).unwrap();
for key in keys {
assert!(filter.contains(&key));
}
}
#[test]
fn test_bits_per_entry() {
const SAMPLE_SIZE: usize = 1_000_000;
let mut rng = rand::thread_rng();
let keys: Vec<u64> = (0..SAMPLE_SIZE).map(|_| rng.gen()).collect();
let filter = Fuse32::try_from(&keys).unwrap();
let bpe = (filter.len() as f64) * 32.0 / (SAMPLE_SIZE as f64);
assert!(bpe < 36.404, "Bits per entry is {}", bpe);
}
#[test]
#[ignore]
fn test_false_positives() {
const SAMPLE_SIZE: usize = 1_000_000_000;
let mut rng = rand::thread_rng();
let keys: Vec<u64> = (0..SAMPLE_SIZE).map(|_| rng.gen()).collect();
let filter = Fuse32::try_from(&keys).unwrap();
let false_positives: usize = (0..SAMPLE_SIZE)
.map(|_| rng.gen())
.filter(|n| filter.contains(n))
.count();
let fp_rate: f64 = (false_positives * 100) as f64 / SAMPLE_SIZE as f64;
assert!(
fp_rate < 0.0000000000000001,
"False positive rate is {}",
fp_rate
);
}
#[test]
fn test_fail_construction() {
const SAMPLE_SIZE: usize = 1_000;
let mut rng = rand::thread_rng();
let keys: Vec<u64> = (0..SAMPLE_SIZE).map(|_| rng.gen()).collect();
let filter = Fuse32::try_from(&keys);
assert!(filter.expect_err("") == "Failed to construct fuse filter.");
}
}