pub fn encode_comparator_ids(
btree_id: Option<&str>,
dup_id: Option<&str>,
) -> Vec<u8> {
if btree_id.is_none() && dup_id.is_none() {
return Vec::new();
}
let mut out = Vec::new();
for id in [btree_id, dup_id] {
let s = id.unwrap_or("");
out.extend_from_slice(&(s.len() as u16).to_le_bytes());
out.extend_from_slice(s.as_bytes());
}
out
}
pub fn decode_comparator_ids(
trailer: &[u8],
) -> (Option<String>, Option<String>) {
if trailer.is_empty() {
return (None, None);
}
let mut off = 0usize;
let mut read_one = || -> Option<String> {
if off + 2 > trailer.len() {
return None;
}
let len = u16::from_le_bytes([trailer[off], trailer[off + 1]]) as usize;
off += 2;
if len == 0 {
return Some(String::new());
}
if off + len > trailer.len() {
return None;
}
let s = String::from_utf8(trailer[off..off + len].to_vec()).ok();
off += len;
s
};
let btree = read_one().filter(|s| !s.is_empty());
let dup = read_one().filter(|s| !s.is_empty());
(btree, dup)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trip_both() {
let enc = encode_comparator_ids(Some("rev"), Some("le_u32"));
assert_eq!(
decode_comparator_ids(&enc),
(Some("rev".to_string()), Some("le_u32".to_string()))
);
}
#[test]
fn round_trip_btree_only() {
let enc = encode_comparator_ids(Some("rev"), None);
assert_eq!(
decode_comparator_ids(&enc),
(Some("rev".to_string()), None)
);
}
#[test]
fn round_trip_dup_only() {
let enc = encode_comparator_ids(None, Some("d"));
assert_eq!(decode_comparator_ids(&enc), (None, Some("d".to_string())));
}
#[test]
fn pre_dbi14_format_is_none_none() {
assert_eq!(decode_comparator_ids(&[]), (None, None));
assert!(encode_comparator_ids(None, None).is_empty());
}
#[test]
fn malformed_trailer_is_safe() {
let bad = vec![5u8, 0, b'x'];
let _ = decode_comparator_ids(&bad); }
#[test]
fn dbi15_master_nameln_data_layout_round_trips_to_replica_decode() {
let db_id: u64 = 42;
let mut data = db_id.to_le_bytes().to_vec();
data.extend_from_slice(&encode_comparator_ids(
Some("reverse"),
Some("le_u32"),
));
assert!(data.len() >= 8);
let decoded_id = u64::from_le_bytes(data[..8].try_into().unwrap());
assert_eq!(decoded_id, db_id);
let (btree, dup) = decode_comparator_ids(&data[8..]);
assert_eq!(btree.as_deref(), Some("reverse"));
assert_eq!(dup.as_deref(), Some("le_u32"));
}
}