#![deny(missing_debug_implementations)]
#![deny(missing_docs)]
#![deny(unused_results)]
#![deny(dead_code)]
#![doc(html_root_url = "https://docs.rs/minisketch_rs/0.1.9")]
pub mod examples;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::ops::BitXorAssign;
#[derive(Debug)]
pub struct MinisketchError(String);
impl MinisketchError {
pub fn new(msg: &str) -> Self {
MinisketchError(msg.to_owned())
}
}
impl Error for MinisketchError {}
impl Display for MinisketchError {
fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
write!(f, "MinisketchError({})", self.0)
}
}
#[doc(hidden)]
mod ffi {
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
unsafe impl Send for minisketch {}
}
pub struct Minisketch {
inner: *mut ffi::minisketch,
bits: u32,
implementation: u32,
capacity: usize,
}
impl Minisketch {
pub fn try_new(
bits: u32,
implementation: u32,
capacity: usize,
) -> Result<Self, MinisketchError> {
let inner = unsafe { ffi::minisketch_create(bits, implementation, capacity) };
if !inner.is_null() {
Ok(Minisketch {
inner,
bits,
implementation,
capacity,
})
} else {
Err(MinisketchError::new("Unsupported minisketch parameters"))
}
}
pub fn bits_supported(bits: u32) -> bool {
let res = unsafe { ffi::minisketch_bits_supported(bits) };
res != 0
}
pub fn implementation_max() -> u32 {
unsafe { ffi::minisketch_implementation_max() }
}
pub fn bits(&self) -> u32 {
unsafe { ffi::minisketch_bits(self.inner) }
}
pub fn capacity(&self) -> usize {
unsafe { ffi::minisketch_capacity(self.inner) }
}
pub fn implementation(&self) -> u32 {
unsafe { ffi::minisketch_implementation(self.inner) }
}
pub fn serialized_size(&self) -> usize {
unsafe { ffi::minisketch_serialized_size(self.inner) }
}
pub fn add(&mut self, element: u64) {
unsafe { ffi::minisketch_add_uint64(self.inner, element) }
}
pub fn set_seed(&mut self, seed: u64) {
unsafe { ffi::minisketch_set_seed(self.inner, seed) }
}
pub fn merge(&mut self, other: &Self) -> Result<usize, MinisketchError> {
let capacity = unsafe { ffi::minisketch_merge(self.inner, other.inner) };
if capacity == 0 {
Err(MinisketchError::new("Merge is failed"))
} else {
Ok(capacity)
}
}
pub fn decode(&self, elements: &mut [u64]) -> Result<usize, MinisketchError> {
let result =
unsafe { ffi::minisketch_decode(self.inner, elements.len(), elements.as_mut_ptr()) };
if result == -1 {
Err(MinisketchError::new("Sketch decoding failed"))
} else {
Ok(result as usize)
}
}
pub fn deserialize(&mut self, buf: &[u8]) {
unsafe { ffi::minisketch_deserialize(self.inner, buf.as_ptr()) }
}
pub fn serialize(&self, buf: &mut [u8]) -> Result<(), MinisketchError> {
let size = self.serialized_size();
if size < buf.len() {
return Err(MinisketchError::new("Invalid size of the output buffer"));
}
unsafe { ffi::minisketch_serialize(self.inner, buf.as_mut_ptr()) }
Ok(())
}
}
impl Debug for Minisketch {
fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
write!(
f,
"Minisketch {{ bits = {}, implementation = {}, capacity = {} }}",
self.bits(),
self.implementation(),
self.capacity(),
)
}
}
#[doc(hidden)]
impl Drop for Minisketch {
fn drop(&mut self) {
unsafe {
ffi::minisketch_destroy(self.inner);
}
}
}
#[doc(hidden)]
impl Clone for Minisketch {
fn clone(&self) -> Self {
let inner = unsafe { ffi::minisketch_clone(self.inner) };
Minisketch {
inner,
bits: self.bits,
implementation: self.implementation,
capacity: self.capacity,
}
}
}
impl BitXorAssign for Minisketch {
fn bitxor_assign(&mut self, rhs: Minisketch) {
let _ = self.merge(&rhs);
}
}
#[cfg(test)]
mod tests {
use crate::*;
fn validate_elements(elements: &[u64]) {
let mut differences = Vec::from(elements);
differences.sort();
assert_eq!(differences[0], 3_000);
assert_eq!(differences[1], 3_001);
assert_eq!(differences[2], 3_010);
assert_eq!(differences[3], 3_011);
}
#[test]
pub fn test_sanity_check() {
use ffi::*;
unsafe {
let sketch_a = minisketch_create(12, 0, 4);
for i in 3_000..3_010 {
minisketch_add_uint64(sketch_a, i as u64);
}
let sersize = minisketch_serialized_size(sketch_a);
assert_eq!(sersize, 12 * 4 / 8);
let mut buf_a = vec![0u8; sersize];
minisketch_serialize(sketch_a, buf_a.as_mut_slice().as_mut_ptr());
minisketch_destroy(sketch_a);
let sketch_b = minisketch_create(12, 0, 4);
for i in 3_002..3_012 {
minisketch_add_uint64(sketch_b, i as u64);
}
{
let sketch_a = minisketch_create(12, 0, 4); minisketch_deserialize(sketch_a, buf_a.as_ptr());
let _ = minisketch_merge(sketch_b, sketch_a);
let mut differences = [0u64; 4];
let num_differences = minisketch_decode(sketch_b, 4, differences.as_mut_ptr());
minisketch_destroy(sketch_a);
minisketch_destroy(sketch_b);
assert!(num_differences > 0);
validate_elements(&differences[..]);
}
};
}
#[test]
pub fn sanity_check_rust_types() {
let mut sketch_a = Minisketch::try_new(12, 0, 4).unwrap();
assert_eq!(sketch_a.bits(), 12);
assert_eq!(sketch_a.implementation(), 0);
assert_eq!(sketch_a.capacity(), 4);
for i in 3_000..3_010 {
sketch_a.add(i);
}
let sersize = sketch_a.serialized_size();
assert_eq!(sersize, 12 * 4 / 8);
let mut buf_a = vec![0u8; sersize];
sketch_a.serialize(buf_a.as_mut_slice()).unwrap();
let mut sketch_b = Minisketch::try_new(12, 0, 4).unwrap();
for i in 3_002..3_012 {
sketch_b.add(i);
}
{
let mut sketch_b = sketch_b.clone();
let mut sketch_a = Minisketch::try_new(12, 0, 4).unwrap();
sketch_a.deserialize(&buf_a);
let _ = sketch_b.merge(&sketch_a).unwrap();
let mut differences = [0u64; 4];
let num_differences = sketch_b.decode(&mut differences[..]).unwrap();
assert!(num_differences > 0);
validate_elements(&differences[..]);
}
{
let mut sketch_b = sketch_b.clone();
let mut sketch_a = Minisketch::try_new(12, 0, 4).unwrap();
sketch_a.deserialize(&buf_a);
sketch_b ^= sketch_a;
let mut differences = [0u64; 4];
let num_differences = sketch_b.decode(&mut differences[..]).unwrap();
assert!(num_differences > 0);
validate_elements(&differences[..]);
}
}
}