1use std::io::{self, Read, Write};
10
11const MAGIC: &[u8; 8] = b"FTKEYS\0\0";
12const VERSION: u32 = 1;
13
14#[derive(Debug, thiserror::Error)]
16pub enum KeyTableError {
17 #[error("key table I/O failed")]
19 Io(#[from] io::Error),
20 #[error("not a key table")]
22 Magic,
23 #[error("key table version {found}, expected {expected}")]
25 Version {
26 found: u32,
28 expected: u32,
30 },
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Default)]
35pub struct KeyTable {
36 pairs: Vec<(u64, u32)>,
37}
38
39impl KeyTable {
40 #[must_use]
42 pub fn new(mut pairs: Vec<(u64, u32)>) -> Self {
43 pairs.sort_unstable();
44 pairs.dedup();
45 Self { pairs }
46 }
47
48 #[must_use]
50 pub fn get(&self, key: u64) -> Option<u32> {
51 self.pairs
52 .binary_search_by_key(&key, |(k, _)| *k)
53 .ok()
54 .and_then(|i| self.pairs.get(i))
55 .map(|(_, o)| *o)
56 }
57
58 #[must_use]
60 pub fn len(&self) -> usize {
61 self.pairs.len()
62 }
63
64 #[must_use]
66 pub fn is_empty(&self) -> bool {
67 self.pairs.is_empty()
68 }
69
70 pub fn write_to(&self, out: &mut impl Write) -> Result<(), KeyTableError> {
76 out.write_all(MAGIC)?;
77 out.write_all(&VERSION.to_le_bytes())?;
78 let len = u64::try_from(self.pairs.len()).map_err(|_| io::Error::other("too many keys"))?;
79 out.write_all(&len.to_le_bytes())?;
80 for (key, ordinal) in &self.pairs {
81 out.write_all(&key.to_le_bytes())?;
82 out.write_all(&ordinal.to_le_bytes())?;
83 }
84 Ok(())
85 }
86
87 pub fn read_from(input: &mut impl Read) -> Result<Self, KeyTableError> {
93 let mut magic = [0_u8; 8];
94 input.read_exact(&mut magic)?;
95 if &magic != MAGIC {
96 return Err(KeyTableError::Magic);
97 }
98 let mut word = [0_u8; 4];
99 input.read_exact(&mut word)?;
100 let version = u32::from_le_bytes(word);
101 if version != VERSION {
102 return Err(KeyTableError::Version {
103 found: version,
104 expected: VERSION,
105 });
106 }
107 let mut long = [0_u8; 8];
108 input.read_exact(&mut long)?;
109 let len = usize::try_from(u64::from_le_bytes(long))
110 .map_err(|_| io::Error::other("key table too large"))?;
111 let mut pairs = Vec::with_capacity(len);
112 for _ in 0..len {
113 input.read_exact(&mut long)?;
114 input.read_exact(&mut word)?;
115 pairs.push((u64::from_le_bytes(long), u32::from_le_bytes(word)));
116 }
117 Ok(Self { pairs })
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::{KeyTable, KeyTableError};
124
125 #[test]
126 fn the_table_answers_by_key_and_round_trips() {
127 let keys = KeyTable::new(vec![(829, 0), (12_251_526, 1), (2_798_745, 1), (829, 0)]);
128 assert_eq!(keys.len(), 3);
129 assert_eq!(keys.get(2_798_745), Some(1));
130 assert_eq!(keys.get(1), None);
131 let mut bytes = Vec::new();
132 keys.write_to(&mut bytes).expect("writes");
133 assert_eq!(
134 KeyTable::read_from(&mut bytes.as_slice()).expect("reads"),
135 keys
136 );
137 assert!(matches!(
138 KeyTable::read_from(&mut b"XXXXXXXX\0\0\0\0".as_slice()),
139 Err(KeyTableError::Magic)
140 ));
141 }
142}