1use crate::error::{Error, Result};
7use std::fmt;
8
9pub type BtiResult<T> = Result<T>;
11
12#[derive(Debug, Clone)]
14pub enum BtiError {
15 Parse(String),
17 InvalidNodeStructure(String),
19 NavigationError(String),
21 InvalidNodeType(u8),
23 MaxDepthExceeded(usize),
25 InvalidByteComparableKey(String),
27 CorruptedTrie(String),
29 MissingComponent(String),
31}
32
33impl fmt::Display for BtiError {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 match self {
36 BtiError::Parse(msg) => write!(f, "BTI parse error: {}", msg),
37 BtiError::InvalidNodeStructure(msg) => write!(f, "Invalid BTI node structure: {}", msg),
38 BtiError::NavigationError(msg) => write!(f, "BTI navigation error: {}", msg),
39 BtiError::InvalidNodeType(node_type) => {
40 write!(f, "Invalid BTI trie node type: 0x{:02X}", node_type)
41 }
42 BtiError::MaxDepthExceeded(depth) => {
43 write!(f, "BTI trie depth exceeded maximum: {}", depth)
44 }
45 BtiError::InvalidByteComparableKey(key) => {
46 write!(f, "Invalid byte-comparable key: {}", key)
47 }
48 BtiError::CorruptedTrie(msg) => {
49 write!(f, "Corrupted BTI trie structure: {}", msg)
50 }
51 BtiError::MissingComponent(component) => {
52 write!(f, "Missing BTI component: {}", component)
53 }
54 }
55 }
56}
57
58impl std::error::Error for BtiError {}
59
60impl From<BtiError> for Error {
61 fn from(err: BtiError) -> Self {
62 Error::Parse(format!("BTI error: {}", err))
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum BtiNodeType {
69 PayloadOnly,
71 Single,
73 Sparse,
75 Dense,
77}
78
79impl BtiNodeType {
80 pub fn expected_children_range(&self) -> (usize, Option<usize>) {
82 match self {
83 BtiNodeType::PayloadOnly => (0, Some(0)),
84 BtiNodeType::Single => (1, Some(1)),
85 BtiNodeType::Sparse => (2, Some(256)), BtiNodeType::Dense => (1, Some(256)), }
88 }
89}
90
91impl fmt::Display for BtiNodeType {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 match self {
94 BtiNodeType::PayloadOnly => write!(f, "PayloadOnly"),
95 BtiNodeType::Single => write!(f, "Single"),
96 BtiNodeType::Sparse => write!(f, "Sparse"),
97 BtiNodeType::Dense => write!(f, "Dense"),
98 }
99 }
100}
101
102#[derive(Debug, Clone, PartialEq, Eq)]
112pub struct SizedPointer {
113 pub distance: u64,
115}
116
117#[cfg(target_pointer_width = "64")]
125const _: () = assert!(std::mem::size_of::<SizedPointer>() == 8);
126
127impl SizedPointer {
128 pub fn new(distance: u64) -> Self {
130 Self { distance }
131 }
132}
133
134#[derive(Debug, Clone, PartialEq, Eq)]
136pub struct Transition {
137 pub byte: u8,
139 pub child: SizedPointer,
141}
142
143#[cfg(target_pointer_width = "64")]
151const _: () = assert!(std::mem::size_of::<Transition>() == 16);
152
153impl Transition {
154 pub fn new(byte: u8, child: SizedPointer) -> Self {
155 Self { byte, child }
156 }
157}
158
159#[derive(Debug, Clone, PartialEq, Eq)]
161pub struct PayloadRef {
162 pub offset: u64,
164 pub length: u32,
166 pub checksum: Option<u32>,
168}
169
170#[cfg(target_pointer_width = "64")]
177const _: () = assert!(std::mem::size_of::<PayloadRef>() == 24);
178
179impl PayloadRef {
180 pub fn new(offset: u64, length: u32) -> Self {
181 Self {
182 offset,
183 length,
184 checksum: None,
185 }
186 }
187
188 pub fn with_checksum(mut self, checksum: u32) -> Self {
189 self.checksum = Some(checksum);
190 self
191 }
192}
193
194#[derive(Debug, Clone)]
196pub struct BtiNode {
197 pub node_type: BtiNodeType,
199 pub level: u16,
201 pub key_prefix: Vec<u8>,
203 pub data: BtiNodeData,
205}
206
207#[derive(Debug, Clone)]
209pub enum BtiNodeData {
210 PayloadOnly { payload: PayloadRef },
212
213 Single { transition: Transition },
215
216 Sparse { transitions: Vec<Transition> },
218
219 Dense {
221 start_byte: u8,
223 children: Vec<Option<SizedPointer>>,
233 },
234}
235
236impl BtiNode {
237 pub fn payload_only(level: u16, key_prefix: Vec<u8>, payload: PayloadRef) -> Self {
239 Self {
240 node_type: BtiNodeType::PayloadOnly,
241 level,
242 key_prefix,
243 data: BtiNodeData::PayloadOnly { payload },
244 }
245 }
246
247 pub fn single(level: u16, key_prefix: Vec<u8>, transition: Transition) -> Self {
249 Self {
250 node_type: BtiNodeType::Single,
251 level,
252 key_prefix,
253 data: BtiNodeData::Single { transition },
254 }
255 }
256
257 pub fn sparse(level: u16, key_prefix: Vec<u8>, mut transitions: Vec<Transition>) -> Self {
259 transitions.sort_by_key(|t| t.byte);
261
262 Self {
263 node_type: BtiNodeType::Sparse,
264 level,
265 key_prefix,
266 data: BtiNodeData::Sparse { transitions },
267 }
268 }
269
270 pub fn dense(
276 level: u16,
277 key_prefix: Vec<u8>,
278 start_byte: u8,
279 children: Vec<Option<SizedPointer>>,
280 ) -> Self {
281 Self {
282 node_type: BtiNodeType::Dense,
283 level,
284 key_prefix,
285 data: BtiNodeData::Dense {
286 start_byte,
287 children,
288 },
289 }
290 }
291
292 pub fn find_child(&self, byte: u8) -> Option<&SizedPointer> {
294 match &self.data {
295 BtiNodeData::PayloadOnly { .. } => None,
296
297 BtiNodeData::Single { transition } => {
298 if transition.byte == byte {
299 Some(&transition.child)
300 } else {
301 None
302 }
303 }
304
305 BtiNodeData::Sparse { transitions } => {
306 transitions
308 .binary_search_by_key(&byte, |t| t.byte)
309 .ok()
310 .map(|idx| &transitions[idx].child)
311 }
312
313 BtiNodeData::Dense {
314 start_byte,
315 children,
316 } => {
317 if byte >= *start_byte && (byte as usize) < (*start_byte as usize + children.len())
318 {
319 let index = byte as usize - *start_byte as usize;
320 children.get(index).and_then(|slot| slot.as_ref())
323 } else {
324 None
325 }
326 }
327 }
328 }
329
330 pub fn get_payload(&self) -> Option<&PayloadRef> {
332 match &self.data {
333 BtiNodeData::PayloadOnly { payload } => Some(payload),
334 _ => None,
335 }
336 }
337
338 pub fn is_leaf(&self) -> bool {
340 matches!(self.data, BtiNodeData::PayloadOnly { .. })
341 }
342
343 pub fn child_count(&self) -> usize {
345 match &self.data {
346 BtiNodeData::PayloadOnly { .. } => 0,
347 BtiNodeData::Single { .. } => 1,
348 BtiNodeData::Sparse { transitions } => transitions.len(),
349 BtiNodeData::Dense { children, .. } => children.len(),
350 }
351 }
352
353 pub fn validate(&self) -> BtiResult<()> {
355 let expected_range = self.node_type.expected_children_range();
356 let child_count = self.child_count();
357
358 if child_count < expected_range.0 {
360 return Err(BtiError::InvalidNodeStructure(format!(
361 "Node type {} has {} children, expected at least {}",
362 self.node_type, child_count, expected_range.0
363 ))
364 .into());
365 }
366
367 if let Some(max) = expected_range.1 {
368 if child_count > max {
369 return Err(BtiError::InvalidNodeStructure(format!(
370 "Node type {} has {} children, expected at most {}",
371 self.node_type, child_count, max
372 ))
373 .into());
374 }
375 }
376
377 match &self.data {
379 BtiNodeData::Sparse { transitions } => {
380 for window in transitions.windows(2) {
382 if window[0].byte >= window[1].byte {
383 return Err(BtiError::InvalidNodeStructure(
384 "Sparse node transitions not sorted".to_string(),
385 )
386 .into());
387 }
388 }
389 }
390
391 BtiNodeData::Dense {
392 start_byte,
393 children,
394 } => {
395 let end_byte = *start_byte as usize + children.len();
397 if end_byte > 256 {
398 return Err(BtiError::InvalidNodeStructure(
399 "Dense node range overflows byte values".to_string(),
400 )
401 .into());
402 }
403 }
404
405 _ => {} }
407
408 Ok(())
409 }
410}
411
412#[cfg(test)]
413mod tests {
414 use super::*;
415
416 #[test]
417 fn test_sized_pointer() {
418 let small = SizedPointer::new(100);
421 assert_eq!(small.distance, 100);
422
423 let large = SizedPointer::new(0x10000);
424 assert_eq!(large.distance, 0x10000);
425 }
426
427 #[test]
428 fn test_node_creation() {
429 let payload = PayloadRef::new(1000, 50);
430 let node = BtiNode::payload_only(0, b"test".to_vec(), payload);
431
432 assert_eq!(node.node_type, BtiNodeType::PayloadOnly);
433 assert_eq!(node.level, 0);
434 assert_eq!(node.key_prefix, b"test");
435 assert!(node.is_leaf());
436 assert_eq!(node.child_count(), 0);
437 }
438
439 #[test]
440 fn test_sparse_node_search() {
441 let transitions = vec![
442 Transition::new(b'a', SizedPointer::new(100)),
443 Transition::new(b'm', SizedPointer::new(200)),
444 Transition::new(b'z', SizedPointer::new(300)),
445 ];
446
447 let node = BtiNode::sparse(1, Vec::new(), transitions);
448
449 assert!(node.find_child(b'a').is_some());
450 assert!(node.find_child(b'm').is_some());
451 assert!(node.find_child(b'z').is_some());
452 assert!(node.find_child(b'b').is_none());
453
454 assert_eq!(node.child_count(), 3);
455 }
456
457 #[test]
458 fn test_dense_node_lookup() {
459 let children = vec![
460 Some(SizedPointer::new(100)),
461 Some(SizedPointer::new(200)),
462 Some(SizedPointer::new(300)),
463 ];
464
465 let node = BtiNode::dense(1, Vec::new(), b'a', children);
466
467 assert!(node.find_child(b'a').is_some());
468 assert!(node.find_child(b'b').is_some());
469 assert!(node.find_child(b'c').is_some());
470 assert!(node.find_child(b'd').is_none());
471 assert!(node.find_child(b'@').is_none()); }
473
474 #[test]
481 fn test_dense_node_offset_zero_child_distinct_from_no_transition() {
482 let children = vec![
487 Some(SizedPointer::new(0)), None, Some(SizedPointer::new(300)),
490 ];
491 let node = BtiNode::dense(1, Vec::new(), b'a', children);
492
493 let a = node.find_child(b'a');
494 assert!(a.is_some(), "offset-0 child must be found, not dropped");
495 assert_eq!(
496 a.unwrap().distance,
497 0,
498 "the real child at absolute offset 0 must be returned"
499 );
500 assert!(
501 node.find_child(b'b').is_none(),
502 "no-transition slot must return None"
503 );
504 assert!(node.find_child(b'c').is_some());
505 assert_eq!(node.child_count(), 3);
507 }
508
509 #[test]
510 fn test_node_validation() {
511 let payload_node = BtiNode::payload_only(0, Vec::new(), PayloadRef::new(0, 10));
513 assert!(payload_node.validate().is_ok());
514
515 let _invalid_sparse = BtiNode::sparse(
517 1,
518 Vec::new(),
519 vec![Transition::new(b'a', SizedPointer::new(100))],
520 );
521 }
524}