bronzedb-util 0.1.0

util for bronzedb
Documentation
use libc::memcmp;
use std::cmp::{Eq, Ordering, PartialEq, PartialOrd};
use std::hash::{Hash, Hasher};
use std::mem::transmute;
use std::ops::Deref;
use std::os::raw::c_void;

pub type Value = Vec<u8>;
pub type Entry = (Key, Value);
pub type EntryRef<'a> = (&'a Key, &'a Value);

#[derive(Debug, Clone, Default)]
pub struct Key {
    data: Vec<u8>,
}

pub struct RawKey {
    data: [u8],
}

impl Deref for RawKey {
    type Target = [u8];
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl Deref for Key {
    type Target = Vec<u8>;
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl AsRef<[u8]> for Key {
    fn as_ref(&self) -> &[u8] {
        self.as_slice()
    }
}

impl From<&[u8]> for &RawKey {
    fn from(data: &[u8]) -> Self {
        unsafe { transmute(data) }
    }
}

impl From<Vec<u8>> for Key {
    fn from(data: Vec<u8>) -> Self {
        Self { data }
    }
}

impl PartialEq for RawKey {
    fn eq(&self, other: &Self) -> bool {
        self.len() == other.len()
            && unsafe {
                0 == memcmp(
                    &self.data as *const [u8] as *const c_void,
                    &other.data as *const [u8] as *const c_void,
                    self.len(),
                )
            }
    }
}

impl PartialOrd for RawKey {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        match unsafe {
            memcmp(
                &self.data as *const [u8] as *const c_void,
                &other.data as *const [u8] as *const c_void,
                self.len(),
            )
        } {
            x if x < 0 => Some(Ordering::Less),
            x if x > 0 => Some(Ordering::Greater),
            _ => {
                if self.len() == other.len() {
                    Some(Ordering::Equal)
                } else if self.len() < other.len() {
                    Some(Ordering::Less)
                } else {
                    Some(Ordering::Greater)
                }
            }
        }
    }
}

impl PartialEq for Key {
    fn eq(&self, other: &Self) -> bool {
        <RawKey as PartialEq>::eq(self.as_slice().into(), other.as_slice().into())
    }
}

impl PartialOrd for Key {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        <RawKey as PartialOrd>::partial_cmp(self.as_slice().into(), other.as_slice().into())
    }
}

impl Eq for Key {}

impl Hash for Key {
    fn hash<H: Hasher>(&self, state: &mut H) {
        <u8 as Hash>::hash_slice(self.as_slice(), state)
    }
}

#[cfg(test)]
mod tests {
    use std::cmp::Ordering::*;
    use std::cmp::PartialOrd;

    #[test]
    fn key_cmp() {
        for (former, latter, order) in vec![
            ("xixi", "haha", Greater),
            ("haa", "haha", Less),
            ("haha", "haha", Equal),
            ("hah", "haha", Less),
            ("hahah", "haha", Greater),
        ] {
            let former_key = former.to_owned().into_bytes();
            let latter_key = latter.to_owned().into_bytes();
            assert_eq!(order, former_key.partial_cmp(&latter_key).unwrap());
        }
    }
}