pub(crate) const DATA_U64_SIZE: usize = 4;
#[cfg(feature = "serde")]
pub(crate) const DATA_U8_SIZE: usize = 32;
#[cfg(feature = "serde")]
use bincode::Options;
#[cfg(feature = "rand")]
use rand_core::{OsRng, RngCore};
#[cfg(feature = "serde")]
use serde::Serialize;
#[cfg(feature = "serde")]
use sha2::Digest;
#[cfg(feature = "serde")]
use sha2::Sha256;
use std::cmp::Ordering;
use std::hash::Hash;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CKey {
pub(crate) data: [u64; DATA_U64_SIZE],
}
impl CKey {
#[cfg(feature = "serde")]
pub fn digest(data: impl AsRef<[u8]>) -> Self {
let mut hasher = Sha256::default();
hasher.update(data);
let hash = hasher.finalize();
bincode::deserialize(&hash).unwrap()
}
#[cfg(feature = "serde")]
pub fn serial<T>(v: T) -> Self
where
T: Serialize,
{
let data = bincode::serialize(&v).unwrap();
Self::digest(data)
}
#[cfg(feature = "rand")]
#[cfg(feature = "serde")]
pub fn rand() -> Self {
let mut hash = [0u8; DATA_U8_SIZE];
OsRng.fill_bytes(&mut hash);
bincode::deserialize(&hash).unwrap()
}
pub fn zero() -> Self {
Self::default()
}
pub fn unit() -> Self {
Self { data: [0, 0, 0, 1] }
}
pub fn last() -> Self {
Self {
data: [
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
],
}
}
pub fn halfway() -> Self {
Self {
data: [
0x8000000000000000,
0x0000000000000000,
0x0000000000000000,
0x0000000000000000,
],
}
}
pub fn inside(self, lower: CKey, upper: CKey) -> bool {
if lower == upper {
return true;
}
if self == lower {
return false;
}
if self == upper {
return true;
}
let lower_to_self = self - lower;
let lower_to_upper = upper - lower;
for i in 0..DATA_U64_SIZE {
if lower_to_self.data[i] > lower_to_upper.data[i] {
return false;
}
if lower_to_self.data[i] < lower_to_upper.data[i] {
return true;
}
}
true
}
pub fn incr(&mut self) {
*self = self.next();
}
pub fn decr(&mut self) {
*self = self.prev();
}
pub fn next(self) -> CKey {
self + Self::unit()
}
pub fn prev(self) -> CKey {
self - Self::unit()
}
pub fn parse(value: &str) -> Result<CKey, <Self as std::convert::TryFrom<&str>>::Error> {
if value.len() != 64 {
return Err(hex::FromHexError::InvalidStringLength);
}
Ok(CKey {
data: [
u64::from_str_radix(&value[0..16], 16).unwrap(),
u64::from_str_radix(&value[16..32], 16).unwrap(),
u64::from_str_radix(&value[32..48], 16).unwrap(),
u64::from_str_radix(&value[48..64], 16).unwrap(),
],
})
}
#[cfg(feature = "serde")]
pub fn set(data: impl AsRef<[u8]>) -> Self {
let unserializer = bincode::DefaultOptions::new()
.with_fixint_encoding()
.with_big_endian()
.allow_trailing_bytes();
if data.as_ref().len() < DATA_U8_SIZE {
let mut buf: Vec<u8> = Vec::new();
for byte in data.as_ref().iter() {
buf.push(*byte);
}
while buf.len() < DATA_U8_SIZE {
buf.push(0);
}
unserializer.deserialize(&buf).unwrap()
} else {
unserializer.deserialize(data.as_ref()).unwrap()
}
}
#[cfg(feature = "serde")]
pub fn bytes(&self) -> Vec<u8> {
let serializer = bincode::DefaultOptions::new()
.with_fixint_encoding()
.with_big_endian()
.allow_trailing_bytes();
serializer.serialize(&self).unwrap()
}
pub fn sort(v: &mut Vec<CKey>, start: CKey) {
v.sort_by(|a, b| {
if *a == *b {
Ordering::Equal
} else if a.inside(start, *b) {
Ordering::Less
} else {
Ordering::Greater
}
});
}
}
#[cfg(test)]
mod tests {
use super::CKey;
#[cfg(feature = "serde")]
use serde_json::json;
#[test]
fn test_ckey_inside() {
let k_zero = CKey::zero();
let k_unit = CKey::unit();
let k_halfway = CKey::halfway();
let k_last = CKey::last();
let k2 = CKey::from(0.2);
let k3 = CKey::from(0.3);
let k9 = CKey::from(0.9);
assert!(k3.inside(k2, k9));
assert!(!k2.inside(k3, k9));
assert!(k2.inside(k9, k3));
assert!(!k3.inside(k9, k2));
assert!(k3.inside(k2, k2));
assert!(k3.inside(k2, k3), "upper bound is included");
assert!(!k2.inside(k2, k3), "lower bound is excluded");
assert!(k_unit.inside(k_zero, k2));
assert!(k_zero.inside(k9, k_zero));
assert!(k_last.inside(k9, k_zero));
assert!(k_zero.inside(k_last, k_zero));
assert!(!k_last.inside(k_last, k_zero));
assert!(k_halfway.inside(k3, k9));
}
#[test]
fn test_ckey_next() {
assert_eq!(
"0000000000000000000000000000000000000000000000000000000000000001",
format!("{:?}", CKey::zero().next())
);
assert_eq!(
"0000000000000000000000000000000000000000000000000000000000000002",
format!("{:?}", CKey::unit().next())
);
assert_eq!(
"8000000000000000000000000000000000000000000000000000000000000001",
format!("{:?}", CKey::halfway().next())
);
assert_eq!(
"0000000000000000000000000000000000000000000000000000000000000000",
format!("{:?}", CKey::last().next())
);
}
#[test]
fn test_ckey_prev() {
assert_eq!(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
format!("{:?}", CKey::zero().prev())
);
assert_eq!(
"0000000000000000000000000000000000000000000000000000000000000000",
format!("{:?}", CKey::unit().prev())
);
assert_eq!(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
format!("{:?}", CKey::halfway().prev())
);
assert_eq!(
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
format!("{:?}", CKey::last().prev())
);
}
#[test]
fn test_ckey_sort() {
let k_zero = CKey::zero();
let k_unit = CKey::unit();
let k_halfway = CKey::halfway();
let k_last = CKey::last();
let k2 = CKey::from(0.2);
let k3 = CKey::from(0.3);
let k9 = CKey::from(0.9);
let mut sorted = vec![k2, k9, k3, k_halfway, k_unit, k_last, k_unit, k_zero];
CKey::sort(&mut sorted, k3);
assert_eq!(8, sorted.len());
assert_eq!(k_halfway, sorted[0]);
assert_eq!(k9, sorted[1]);
assert_eq!(k_last, sorted[2]);
assert_eq!(k_zero, sorted[3]);
assert_eq!(k_unit, sorted[4]);
assert_eq!(k_unit, sorted[5]);
assert_eq!(k2, sorted[6]);
assert_eq!(k3, sorted[7]);
}
#[cfg(feature = "serde")]
#[test]
fn test_json() {
let key_halfway = CKey::halfway();
let js_halfway = json!(&key_halfway).to_string();
assert_eq!("{\"data\":[9223372036854775808,0,0,0]}", js_halfway);
let key_from_js_halfway: CKey = serde_json::from_str(js_halfway.as_str()).unwrap();
assert_eq!(key_halfway, key_from_js_halfway);
}
#[cfg(feature = "serde")]
#[test]
fn test_set_bytes() {
for n in 0..100usize {
let mut v: Vec<u8> = Vec::new();
for i in 0..n {
v.push(i as u8);
}
let k = CKey::set(&v);
let bytes = k.bytes();
assert_eq!(32, bytes.len());
for i in 0..std::cmp::min(n, bytes.len()) {
assert_eq!(i, bytes[i] as usize);
}
}
}
}