pub const LOG_PREFIX: &[u8] = b"L/";
pub const META_PREFIX: &[u8] = b"M/";
const META_PROMISE: &[u8] = b"M/promise";
const META_ACCEPTED_ROUND: &[u8] = b"M/accepted_round";
const META_DECIDED_IDX: &[u8] = b"M/decided_idx";
const META_COMPACTED_IDX: &[u8] = b"M/compacted_idx";
const META_SNAPSHOT: &[u8] = b"M/snapshot";
const META_STOPSIGN: &[u8] = b"M/stopsign";
#[must_use]
pub fn log_key(idx: u64) -> Vec<u8> {
let mut out = Vec::with_capacity(LOG_PREFIX.len() + 8);
out.extend_from_slice(LOG_PREFIX);
out.extend_from_slice(&idx.to_be_bytes());
out
}
#[must_use]
pub fn log_key_range() -> (Vec<u8>, Vec<u8>) {
(log_key(0), META_PREFIX.to_vec())
}
#[must_use]
pub fn meta_promise_key() -> Vec<u8> {
META_PROMISE.to_vec()
}
#[must_use]
pub fn meta_accepted_round_key() -> Vec<u8> {
META_ACCEPTED_ROUND.to_vec()
}
#[must_use]
pub fn meta_decided_idx_key() -> Vec<u8> {
META_DECIDED_IDX.to_vec()
}
#[must_use]
pub fn meta_compacted_idx_key() -> Vec<u8> {
META_COMPACTED_IDX.to_vec()
}
#[must_use]
pub fn meta_snapshot_key() -> Vec<u8> {
META_SNAPSHOT.to_vec()
}
#[must_use]
pub fn meta_stopsign_key() -> Vec<u8> {
META_STOPSIGN.to_vec()
}
pub fn parse_log_key(key: &[u8]) -> Option<u64> {
if !key.starts_with(LOG_PREFIX) || key.len() != LOG_PREFIX.len() + 8 {
return None;
}
let bytes = &key[LOG_PREFIX.len()..];
let mut buf = [0u8; 8];
buf.copy_from_slice(bytes);
Some(u64::from_be_bytes(buf))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn log_keys_iterate_in_index_order() {
let low = log_key(0x0000_0000_0000_00FF);
let high = log_key(0x0000_0000_0000_0100);
assert!(low < high, "log_key(255) < log_key(256) must hold");
}
#[test]
fn log_keys_have_log_prefix() {
assert!(log_key(0).starts_with(LOG_PREFIX));
assert!(log_key(u64::MAX).starts_with(LOG_PREFIX));
}
#[test]
fn meta_keys_have_meta_prefix() {
let keys = [
meta_promise_key(),
meta_accepted_round_key(),
meta_decided_idx_key(),
meta_compacted_idx_key(),
meta_snapshot_key(),
meta_stopsign_key(),
];
for key in &keys {
assert!(
key.starts_with(META_PREFIX),
"key {key:?} missing META_PREFIX"
);
}
}
#[test]
fn log_and_meta_prefixes_do_not_collide() {
assert_ne!(LOG_PREFIX[0], META_PREFIX[0]);
}
#[test]
fn log_key_round_trips_through_parse() {
for idx in [0_u64, 1, 255, 256, u64::MAX] {
let key = log_key(idx);
assert_eq!(parse_log_key(&key), Some(idx));
}
}
#[test]
fn parse_log_key_rejects_non_log_keys() {
assert!(parse_log_key(META_PREFIX).is_none());
assert!(parse_log_key(b"L/").is_none()); assert!(parse_log_key(&meta_promise_key()).is_none());
}
}