use crate::catalog::ValType;
use crate::value::IndexValue;
pub fn value_order_bytes(v: &IndexValue) -> Vec<u8> {
match v {
IndexValue::Str(s) => s.clone(),
IndexValue::I64(i) => ((*i as u64) ^ (1 << 63)).to_be_bytes().to_vec(),
IndexValue::F64(f) => {
let b = f.to_bits();
let m = if b >> 63 == 1 { !b } else { b | (1 << 63) };
m.to_be_bytes().to_vec()
}
}
}
pub fn seg_key(v: &IndexValue, row_key: &[u8]) -> Vec<u8> {
let vb = value_order_bytes(v);
let mut out = Vec::with_capacity(vb.len() + row_key.len() + 4);
frame_into(&mut out, &vb);
frame_into(&mut out, row_key);
out
}
pub fn decode_seg_key(ty: ValType, key: &[u8]) -> Option<(IndexValue, Vec<u8>)> {
let (vb, rest) = unframe(key)?;
let (row, tail) = unframe(rest)?;
if !tail.is_empty() {
return None;
}
let value = match ty {
ValType::Str => IndexValue::Str(vb),
ValType::I64 => {
let raw = u64::from_be_bytes(vb.try_into().ok()?);
IndexValue::I64((raw ^ (1 << 63)) as i64)
}
ValType::F64 => {
let m = u64::from_be_bytes(vb.try_into().ok()?);
let b = if m >> 63 == 1 { m & !(1 << 63) } else { !m };
IndexValue::F64(f64::from_bits(b))
}
_ => return None,
};
Some((value, row))
}
pub fn seg_bounds(min: &IndexValue, max: &IndexValue) -> (Vec<u8>, Vec<u8>) {
let mut lo = Vec::new();
frame_into(&mut lo, &value_order_bytes(min));
let mut hi = Vec::new();
frame_into(&mut hi, &value_order_bytes(max));
*hi.last_mut().expect("frame is never empty") = 0x01;
(lo, hi)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WindowShape {
PlainI64,
CompositeLed,
}
#[derive(Debug, Clone, Copy)]
pub struct WindowAudit {
pub boundary: i64,
pub shape: WindowShape,
pub cold_live: u64,
}
pub fn window_value_of(v: &IndexValue, shape: WindowShape) -> Option<i64> {
match (shape, v) {
(WindowShape::PlainI64, IndexValue::I64(i)) => Some(*i),
(WindowShape::CompositeLed, IndexValue::Str(b)) => {
let raw = u64::from_be_bytes(b.get(..8)?.try_into().ok()?);
Some((raw ^ (1 << 63)) as i64)
}
_ => None,
}
}
pub fn window_bound(target: i64, shape: WindowShape) -> IndexValue {
match shape {
WindowShape::PlainI64 => IndexValue::I64(target),
WindowShape::CompositeLed => {
IndexValue::Str(((target as u64) ^ (1 << 63)).to_be_bytes().to_vec())
}
}
}
pub fn encode_seg_values(values: &[Option<&[u8]>]) -> Vec<u8> {
if values.is_empty() {
return Vec::new();
}
let mut out = Vec::new();
out.extend_from_slice(&(values.len() as u32).to_le_bytes());
for v in values {
match v {
None => out.push(0),
Some(b) => {
out.push(1);
out.extend_from_slice(&(b.len() as u32).to_le_bytes());
out.extend_from_slice(b);
}
}
}
out
}
pub fn decode_seg_values(payload: &[u8]) -> Option<Vec<Option<Vec<u8>>>> {
if payload.is_empty() {
return Some(Vec::new());
}
let n = u32::from_le_bytes(payload.get(..4)?.try_into().ok()?) as usize;
let mut at = 4usize;
let mut out = Vec::with_capacity(n);
for _ in 0..n {
match payload.get(at)? {
0 => {
out.push(None);
at += 1;
}
1 => {
let len =
u32::from_le_bytes(payload.get(at + 1..at + 5)?.try_into().ok()?) as usize;
out.push(Some(payload.get(at + 5..at + 5 + len)?.to_vec()));
at += 5 + len;
}
_ => return None,
}
}
(at == payload.len()).then_some(out)
}
fn frame_into(out: &mut Vec<u8>, b: &[u8]) {
for &c in b {
if c == 0 {
out.push(0);
out.push(0xFF);
} else {
out.push(c);
}
}
out.push(0);
out.push(0);
}
fn unframe(b: &[u8]) -> Option<(Vec<u8>, &[u8])> {
let mut out = Vec::new();
let mut i = 0;
while i < b.len() {
if b[i] != 0 {
out.push(b[i]);
i += 1;
continue;
}
match b.get(i + 1)? {
0xFF => {
out.push(0);
i += 2;
}
0x00 => return Some((out, &b[i + 2..])),
_ => return None,
}
}
None
}
#[derive(Debug)]
pub struct ColdBloom {
bits: Vec<u64>,
k: u32,
}
impl ColdBloom {
pub fn new(expected_items: usize) -> Self {
let words = (expected_items.max(64) * 10 / 64).next_power_of_two();
Self { bits: vec![0u64; words], k: 7 }
}
pub fn insert(&mut self, item: &[u8]) {
let (h1, h2) = Self::hashes(item);
let nbits = (self.bits.len() * 64) as u64;
for i in 0..self.k as u64 {
let bit = h1.wrapping_add(i.wrapping_mul(h2)) % nbits;
self.bits[(bit / 64) as usize] |= 1 << (bit % 64);
}
}
pub fn contains(&self, item: &[u8]) -> bool {
let (h1, h2) = Self::hashes(item);
let nbits = (self.bits.len() * 64) as u64;
(0..self.k as u64).all(|i| {
let bit = h1.wrapping_add(i.wrapping_mul(h2)) % nbits;
self.bits[(bit / 64) as usize] & (1 << (bit % 64)) != 0
})
}
fn hashes(item: &[u8]) -> (u64, u64) {
let fnv = |seed: u64| {
let mut h = seed;
for &b in item {
h ^= b as u64;
h = h.wrapping_mul(0x100000001b3);
}
h
};
(fnv(0xcbf29ce484222325), fnv(0x84222325cbf29ce4) | 1)
}
}
#[cfg(test)]
#[path = "segcold_tests.rs"]
mod tests;