use std::fmt;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct VortexSeed {
hi: u64,
lo: u64,
}
impl VortexSeed {
pub const fn new(hi: u64, lo: u64) -> Self {
Self { hi, lo }
}
pub const fn from_u64(val: u64) -> Self {
Self { hi: 0, lo: val }
}
pub const fn hi(&self) -> u64 {
self.hi
}
pub const fn lo(&self) -> u64 {
self.lo
}
pub const fn to_u64(&self) -> u64 {
self.hi ^ self.lo
}
pub const fn to_bytes(&self) -> [u8; 16] {
let hi = self.hi.to_be_bytes();
let lo = self.lo.to_be_bytes();
[
hi[0], hi[1], hi[2], hi[3], hi[4], hi[5], hi[6], hi[7], lo[0], lo[1], lo[2], lo[3],
lo[4], lo[5], lo[6], lo[7],
]
}
pub fn from_bytes(bytes: [u8; 16]) -> Self {
let hi = u64::from_be_bytes([
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
]);
let lo = u64::from_be_bytes([
bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
]);
Self { hi, lo }
}
}
impl fmt::Debug for VortexSeed {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "VortexSeed(0x{:016x}{:016x})", self.hi, self.lo)
}
}
impl fmt::Display for VortexSeed {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:016x}{:016x}", self.hi, self.lo)
}
}
impl From<u64> for VortexSeed {
fn from(val: u64) -> Self {
Self::from_u64(val)
}
}
pub struct SeedTree {
master: VortexSeed,
}
impl SeedTree {
pub const fn new(master: VortexSeed) -> Self {
Self { master }
}
pub fn derive(&self, domain: &str) -> VortexSeed {
let mut hash_lo: u64 = 14695981039346656037; let mut hash_hi: u64 = 6700417;
for byte in self.master.to_bytes() {
hash_lo ^= byte as u64;
hash_lo = hash_lo.wrapping_mul(1099511628211); hash_hi ^= byte as u64;
hash_hi = hash_hi.wrapping_mul(309485009821345068);
}
for byte in domain.as_bytes() {
hash_lo ^= *byte as u64;
hash_lo = hash_lo.wrapping_mul(1099511628211);
hash_hi ^= *byte as u64;
hash_hi = hash_hi.wrapping_mul(309485009821345068);
}
VortexSeed::new(hash_hi, hash_lo)
}
pub fn subtree(&self, domain: &str) -> SeedTree {
SeedTree::new(self.derive(domain))
}
pub const fn master(&self) -> VortexSeed {
self.master
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_seed_from_u64() {
let s = VortexSeed::from_u64(42);
assert_eq!(s.hi(), 0);
assert_eq!(s.lo(), 42);
assert_eq!(s.to_u64(), 42);
}
#[test]
fn test_seed_roundtrip_bytes() {
let s = VortexSeed::new(0xDEADBEEF_CAFEBABE, 0x12345678_9ABCDEF0);
let bytes = s.to_bytes();
let s2 = VortexSeed::from_bytes(bytes);
assert_eq!(s, s2);
}
#[test]
fn test_seed_display() {
let s = VortexSeed::new(0, 42);
let display = format!("{s}");
assert_eq!(display, "0000000000000000000000000000002a");
}
#[test]
fn test_derive_deterministic() {
let tree1 = SeedTree::new(VortexSeed::from_u64(42));
let tree2 = SeedTree::new(VortexSeed::from_u64(42));
assert_eq!(tree1.derive("fs"), tree2.derive("fs"));
assert_eq!(tree1.derive("net"), tree2.derive("net"));
assert_eq!(tree1.derive("clock"), tree2.derive("clock"));
}
#[test]
fn test_derive_different_domains_differ() {
let tree = SeedTree::new(VortexSeed::from_u64(42));
let domains = ["executor", "fs", "clock", "alloc", "net", "process"];
let seeds: Vec<VortexSeed> = domains.iter().map(|d| tree.derive(d)).collect();
for i in 0..seeds.len() {
for j in (i + 1)..seeds.len() {
assert_ne!(
seeds[i], seeds[j],
"domains '{}' and '{}' collided",
domains[i], domains[j]
);
}
}
}
#[test]
fn test_derive_different_master_seeds_differ() {
let tree1 = SeedTree::new(VortexSeed::from_u64(42));
let tree2 = SeedTree::new(VortexSeed::from_u64(43));
assert_ne!(tree1.derive("fs"), tree2.derive("fs"));
}
#[test]
fn test_subtree() {
let tree = SeedTree::new(VortexSeed::from_u64(42));
let fs_tree = tree.subtree("fs");
let wal = fs_tree.derive("wal");
let data = fs_tree.derive("data");
assert_ne!(wal, data);
let fs_tree2 = SeedTree::new(VortexSeed::from_u64(42)).subtree("fs");
assert_eq!(fs_tree.derive("wal"), fs_tree2.derive("wal"));
}
#[test]
fn test_adding_new_domain_doesnt_change_existing() {
let tree = SeedTree::new(VortexSeed::from_u64(0xDEADBEEF));
let fs_before = tree.derive("fs");
let net_before = tree.derive("net");
let _new_domain = tree.derive("some_new_subsystem");
assert_eq!(tree.derive("fs"), fs_before);
assert_eq!(tree.derive("net"), net_before);
}
#[test]
fn test_cross_platform_stability() {
let tree = SeedTree::new(VortexSeed::new(0, 0xDEADBEEF));
let fs = tree.derive("fs");
let net = tree.derive("net");
let fs_expected = tree.derive("fs");
let net_expected = tree.derive("net");
assert_eq!(fs, fs_expected);
assert_eq!(net, net_expected);
}
}