const DATA_U64_SIZE: usize = 4;
const DATA_U8_SIZE: usize = 32;
const ONE_I128: i128 = 0x1_0000_0000_0000_0000;
const ONE_F64: f64 = ONE_I128 as f64;
use rand_core::{OsRng, RngCore};
use serde::{Deserialize, Serialize};
use sha2::Digest;
use sha2::Sha256;
use std::cmp::Ordering;
use std::fmt::Formatter;
use std::num::Wrapping;
#[derive(Default, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub struct CKey {
data: [u64; DATA_U64_SIZE],
}
impl CKey {
pub fn new_digest(data: impl AsRef<[u8]>) -> Self {
let mut hasher = Sha256::default();
hasher.update(data);
let hash = hasher.finalize();
bincode::deserialize(&hash).unwrap()
}
pub fn new_rand() -> Self {
let mut hash = [0u8; DATA_U8_SIZE];
OsRng.fill_bytes(&mut hash);
bincode::deserialize(&hash).unwrap()
}
pub fn new_zero() -> Self {
Self::default()
}
pub fn new_unit() -> Self {
Self { data: [0, 0, 0, 1] }
}
pub fn new_last() -> Self {
Self {
data: [
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
],
}
}
pub fn new_half() -> 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::new_unit()
}
pub fn prev(self) -> CKey {
self - Self::new_unit()
}
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
}
});
}
}
impl From<f64> for CKey {
fn from(f: f64) -> CKey {
let f_mod_1: f64 = if f < 0.0 {
1.0 - ((-f).fract())
} else {
f.fract()
};
let v = (ONE_F64 * f_mod_1) as u64;
CKey { data: [v, v, v, v] }
}
}
impl From<u32> for CKey {
fn from(u: u32) -> CKey {
let v = (u as u64) << 32;
CKey { data: [v, v, v, v] }
}
}
impl From<u64> for CKey {
fn from(u: u64) -> CKey {
CKey { data: [u, u, u, u] }
}
}
impl From<CKey> for f64 {
fn from(k: CKey) -> f64 {
(k.data[0] as f64) / ONE_F64
}
}
impl From<CKey> for u32 {
fn from(k: CKey) -> u32 {
(k.data[0] >> 32) as u32
}
}
impl From<CKey> for u64 {
fn from(k: CKey) -> u64 {
k.data[0]
}
}
impl std::convert::TryFrom<&str> for CKey {
type Error = hex::FromHexError;
fn try_from(value: &str) -> Result<CKey, Self::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(),
],
})
}
}
impl std::convert::TryFrom<String> for CKey {
type Error = hex::FromHexError;
fn try_from(value: String) -> Result<CKey, Self::Error> {
Self::try_from(value.as_str())
}
}
impl From<CKey> for String {
fn from(k: CKey) -> String {
format!("{}", k)
}
}
impl std::ops::Add<CKey> for CKey {
type Output = Self;
fn add(self, other: CKey) -> CKey {
let mut old_carry = 0;
let mut ret: CKey = CKey::default();
for i in 0..DATA_U64_SIZE {
let j = DATA_U64_SIZE - i - 1;
let (v, new_carry) = match self.data[j].checked_add(other.data[j]) {
Some(v1) => match v1.checked_add(old_carry) {
Some(v2) => (v2, 0),
None => ((Wrapping(v1) + Wrapping(old_carry)).0, 1),
},
None => (
(Wrapping(self.data[j]) + Wrapping(other.data[j]) + Wrapping(old_carry)).0,
1,
),
};
ret.data[j] = v;
old_carry = new_carry;
}
ret
}
}
impl std::ops::Sub<CKey> for CKey {
type Output = Self;
fn sub(self, other: CKey) -> CKey {
let mut old_carry = 0;
let mut ret: CKey = CKey::default();
for i in 0..DATA_U64_SIZE {
let j = DATA_U64_SIZE - i - 1;
let (v, new_carry) = match self.data[j].checked_sub(other.data[j]) {
Some(v1) => match v1.checked_sub(old_carry) {
Some(v2) => (v2, 0),
None => ((Wrapping(v1) - Wrapping(old_carry)).0, 1),
},
None => (
(Wrapping(self.data[j]) - Wrapping(other.data[j]) - Wrapping(old_carry)).0,
1,
),
};
ret.data[j] = v;
old_carry = new_carry;
}
ret
}
}
impl std::ops::Add<f64> for CKey {
type Output = Self;
fn add(self, delta: f64) -> CKey {
let other = CKey::from(delta);
self + other
}
}
impl std::ops::Sub<f64> for CKey {
type Output = Self;
fn sub(self, delta: f64) -> CKey {
let other = CKey::from(delta);
self - other
}
}
impl std::ops::Add<u32> for CKey {
type Output = Self;
fn add(self, delta: u32) -> CKey {
let other = CKey::from(delta);
self + other
}
}
impl std::ops::Sub<u32> for CKey {
type Output = Self;
fn sub(self, delta: u32) -> CKey {
let other = CKey::from(delta);
self - other
}
}
impl std::ops::Add<u64> for CKey {
type Output = Self;
fn add(self, delta: u64) -> CKey {
let other = CKey::from(delta);
self + other
}
}
impl std::ops::Sub<u64> for CKey {
type Output = Self;
fn sub(self, delta: u64) -> CKey {
let other = CKey::from(delta);
self - other
}
}
impl std::fmt::Debug for CKey {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(
f,
"{:016x}{:016x}{:016x}{:016x}",
self.data[0], self.data[1], self.data[2], self.data[3]
)
}
}
impl std::fmt::Display for CKey {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:0.9}", f64::from(*self))
}
}
#[cfg(test)]
mod tests {
use super::CKey;
#[test]
fn test_ckey_inside() {
let k_zero = CKey::new_zero();
let k_unit = CKey::new_unit();
let k_half = CKey::new_half();
let k_last = CKey::new_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_half.inside(k3, k9));
}
#[test]
fn test_ckey_next() {
assert_eq!(
"0000000000000000000000000000000000000000000000000000000000000001",
format!("{:?}", CKey::new_zero().next())
);
assert_eq!(
"0000000000000000000000000000000000000000000000000000000000000002",
format!("{:?}", CKey::new_unit().next())
);
assert_eq!(
"8000000000000000000000000000000000000000000000000000000000000001",
format!("{:?}", CKey::new_half().next())
);
assert_eq!(
"0000000000000000000000000000000000000000000000000000000000000000",
format!("{:?}", CKey::new_last().next())
);
}
#[test]
fn test_ckey_prev() {
assert_eq!(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
format!("{:?}", CKey::new_zero().prev())
);
assert_eq!(
"0000000000000000000000000000000000000000000000000000000000000000",
format!("{:?}", CKey::new_unit().prev())
);
assert_eq!(
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
format!("{:?}", CKey::new_half().prev())
);
assert_eq!(
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
format!("{:?}", CKey::new_last().prev())
);
}
#[test]
fn test_fmt_display() {
assert_eq!("0.000000000", format!("{}", CKey::new_zero()));
assert_eq!("0.000000000", format!("{}", CKey::new_unit()));
assert_eq!("0.500000000", format!("{}", CKey::new_half()));
assert_eq!("1.000000000", format!("{}", CKey::new_last()));
}
#[test]
fn test_ckey_add() {
assert_eq!(
"0.300000000",
format!("{}", CKey::from(0.1) + CKey::from(0.2))
);
assert_eq!(
"0.000000000",
format!("{}", CKey::from(0.5) + CKey::from(0.5))
);
assert_eq!(
"0.100000000",
format!("{}", CKey::from(0.8) + CKey::from(0.3))
);
assert_eq!(
"0.300000000",
format!("{}", CKey::from(1.1) + CKey::from(0.2))
);
assert_eq!(
"0.400000000",
format!("{}", CKey::from(-0.1) + CKey::from(0.5))
);
}
#[test]
fn test_ckey_sub() {
assert_eq!(
"0.300000000",
format!("{}", CKey::from(0.4) - CKey::from(0.1))
);
assert_eq!(
"0.000000000",
format!("{}", CKey::from(0.9) - CKey::from(0.9))
);
assert_eq!(
"0.900000000",
format!("{}", CKey::from(0.2) - CKey::from(0.3))
);
assert_eq!(
"0.800000000",
format!("{}", CKey::from(1.1) - CKey::from(1.3))
);
assert_eq!(
"0.900000000",
format!("{}", CKey::from(0.2) - CKey::from(-0.7))
);
}
#[test]
fn test_ckey_sort() {
let k_zero = CKey::new_zero();
let k_unit = CKey::new_unit();
let k_half = CKey::new_half();
let k_last = CKey::new_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_half, k_unit, k_last, k_unit, k_zero];
CKey::sort(&mut sorted, k3);
assert_eq!(8, sorted.len());
assert_eq!(k_half, 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]);
}
}