scepter 0.1.5

Composable primitives for planet-scale time-series routing, indexing, and aggregation.
Documentation
/// A value that can encode itself into bytes whose ordering preserves the
/// value's logical ordering.
pub trait LexicographicKey {
    /// Appends this value's order-preserving encoding to `out`.
    fn encode_key(&self, out: &mut Vec<u8>);

    /// Returns this value's order-preserving byte encoding.
    fn encoded_key(&self) -> Vec<u8> {
        let mut out = Vec::new();
        self.encode_key(&mut out);
        out
    }
}

impl LexicographicKey for str {
    fn encode_key(&self, out: &mut Vec<u8>) {
        out.extend_from_slice(self.as_bytes());
    }
}

impl LexicographicKey for String {
    fn encode_key(&self, out: &mut Vec<u8>) {
        self.as_str().encode_key(out);
    }
}

impl LexicographicKey for u64 {
    fn encode_key(&self, out: &mut Vec<u8>) {
        out.extend_from_slice(&self.to_be_bytes());
    }
}

impl LexicographicKey for i64 {
    fn encode_key(&self, out: &mut Vec<u8>) {
        let sortable = (*self as u64) ^ (1_u64 << 63);
        sortable.encode_key(out);
    }
}

impl LexicographicKey for f64 {
    fn encode_key(&self, out: &mut Vec<u8>) {
        let bits = self.to_bits();
        let sortable = if bits & (1_u64 << 63) == 0 {
            bits + (1_u64 << 63)
        } else {
            !bits
        };
        sortable.encode_key(out);
    }
}

impl LexicographicKey for bool {
    fn encode_key(&self, out: &mut Vec<u8>) {
        out.push(u8::from(*self));
    }
}

/// Encodes compound keys with field separators so target and metric tuples can
/// be routed with byte-range comparisons.
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct KeyEncoder {
    bytes: Vec<u8>,
}

impl KeyEncoder {
    /// Creates an empty compound-key encoder.
    pub fn new() -> Self {
        Self::default()
    }

    /// Appends one field to the compound key.
    pub fn push_field<K: LexicographicKey + ?Sized>(&mut self, field: &K) -> &mut Self {
        if !self.bytes.is_empty() {
            self.bytes.push(0);
        }
        field.encode_key(&mut self.bytes);
        self
    }

    /// Finishes encoding and returns the owned byte key.
    pub fn finish(self) -> Vec<u8> {
        self.bytes
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn compound_keys_preserve_field_order() {
        let a = KeyEncoder::new()
            .push_field("ComputeTask")
            .push_field("aa")
            .push_field(&7_u64)
            .clone()
            .finish();
        let b = KeyEncoder::new()
            .push_field("ComputeTask")
            .push_field("aa")
            .push_field(&8_u64)
            .clone()
            .finish();

        assert!(a < b);
    }

    #[test]
    fn signed_integers_sort_by_numeric_order() {
        assert!((-1_i64).encoded_key() < 1_i64.encoded_key());
    }

    #[test]
    fn floats_sort_by_numeric_order() {
        assert!((-10.0_f64).encoded_key() < 0.0_f64.encoded_key());
        assert!(0.0_f64.encoded_key() < 10.0_f64.encoded_key());
    }
}