pingora_cache/
variance.rsuse std::{borrow::Cow, collections::BTreeMap};
use blake2::Digest;
use crate::key::{Blake2b128, HashBinary};
pub struct VarianceBuilder<'a> {
values: BTreeMap<Cow<'a, str>, Cow<'a, [u8]>>,
}
impl<'a> VarianceBuilder<'a> {
pub fn new() -> Self {
VarianceBuilder {
values: BTreeMap::new(),
}
}
pub fn add_value(&mut self, name: &'a str, value: &'a (impl AsRef<[u8]> + ?Sized)) {
self.values
.insert(name.into(), Cow::Borrowed(value.as_ref()));
}
pub fn add_owned_value(&mut self, name: &'a str, value: Vec<u8>) {
self.values.insert(name.into(), Cow::Owned(value));
}
pub fn has_variance(&self) -> bool {
!self.values.is_empty()
}
pub fn finalize(self) -> Option<HashBinary> {
const SALT: &[u8; 1] = &[0u8; 1];
if self.has_variance() {
let mut hash = Blake2b128::new();
for (name, value) in self.values.iter() {
hash.update(name.as_bytes());
hash.update(SALT);
hash.update(value);
hash.update(SALT);
}
Some(hash.finalize().into())
} else {
None
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_basic() {
let key_empty = VarianceBuilder::new().finalize();
assert_eq!(None, key_empty);
let mut key_value = VarianceBuilder::new();
key_value.add_value("a", "a");
let key_value = key_value.finalize();
let mut key_owned_value = VarianceBuilder::new();
key_owned_value.add_owned_value("a", "a".as_bytes().to_vec());
let key_owned_value = key_owned_value.finalize();
assert_ne!(key_empty, key_value);
assert_ne!(key_empty, key_owned_value);
assert_eq!(key_value, key_owned_value);
}
#[test]
fn test_value_ordering() {
let mut key_abc = VarianceBuilder::new();
key_abc.add_value("a", "a");
key_abc.add_value("b", "b");
key_abc.add_value("c", "c");
let key_abc = key_abc.finalize().unwrap();
let mut key_bac = VarianceBuilder::new();
key_bac.add_value("b", "b");
key_bac.add_value("a", "a");
key_bac.add_value("c", "c");
let key_bac = key_bac.finalize().unwrap();
let mut key_cba = VarianceBuilder::new();
key_cba.add_value("c", "c");
key_cba.add_value("b", "b");
key_cba.add_value("a", "a");
let key_cba = key_cba.finalize().unwrap();
assert_eq!(key_abc, key_bac);
assert_eq!(key_abc, key_cba);
}
#[test]
fn test_value_overriding() {
let mut key_a = VarianceBuilder::new();
key_a.add_value("a", "a");
let key_a = key_a.finalize().unwrap();
let mut key_b = VarianceBuilder::new();
key_b.add_value("a", "b");
key_b.add_value("a", "a");
let key_b = key_b.finalize().unwrap();
assert_eq!(key_a, key_b);
}
}