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)]
104pub struct SizedPointer {
105 pub distance: u64,
107 pub size: u8,
109}
110
111impl SizedPointer {
112 pub fn new(distance: u64) -> Self {
114 let size = if distance <= 0xFF {
115 1
116 } else if distance <= 0xFFFF {
117 2
118 } else if distance <= 0xFFFF_FFFF {
119 4
120 } else {
121 8
122 };
123
124 Self { distance, size }
125 }
126
127 pub fn to_bytes(&self) -> Vec<u8> {
129 match self.size {
130 1 => vec![self.distance as u8],
131 2 => (self.distance as u16).to_be_bytes().to_vec(),
132 4 => (self.distance as u32).to_be_bytes().to_vec(),
133 8 => self.distance.to_be_bytes().to_vec(),
134 _ => panic!("Invalid pointer size: {}", self.size),
135 }
136 }
137
138 pub fn from_bytes(data: &[u8], size: u8) -> BtiResult<Self> {
140 let distance = match size {
141 1 if !data.is_empty() => data[0] as u64,
142 2 if data.len() >= 2 => u16::from_be_bytes([data[0], data[1]]) as u64,
143 4 if data.len() >= 4 => u32::from_be_bytes([data[0], data[1], data[2], data[3]]) as u64,
144 8 if data.len() >= 8 => u64::from_be_bytes([
145 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
146 ]),
147 _ => {
148 return Err(BtiError::Parse(format!(
149 "Invalid pointer size {} or insufficient data",
150 size
151 ))
152 .into());
153 }
154 };
155
156 Ok(Self { distance, size })
157 }
158}
159
160#[derive(Debug, Clone, PartialEq, Eq)]
162pub struct Transition {
163 pub byte: u8,
165 pub child: SizedPointer,
167}
168
169impl Transition {
170 pub fn new(byte: u8, child: SizedPointer) -> Self {
171 Self { byte, child }
172 }
173}
174
175#[derive(Debug, Clone, PartialEq, Eq)]
177pub struct PayloadRef {
178 pub offset: u64,
180 pub length: u32,
182 pub checksum: Option<u32>,
184}
185
186impl PayloadRef {
187 pub fn new(offset: u64, length: u32) -> Self {
188 Self {
189 offset,
190 length,
191 checksum: None,
192 }
193 }
194
195 pub fn with_checksum(mut self, checksum: u32) -> Self {
196 self.checksum = Some(checksum);
197 self
198 }
199}
200
201#[derive(Debug, Clone)]
203pub struct BtiNode {
204 pub node_type: BtiNodeType,
206 pub level: u16,
208 pub key_prefix: Vec<u8>,
210 pub data: BtiNodeData,
212}
213
214#[derive(Debug, Clone)]
216pub enum BtiNodeData {
217 PayloadOnly { payload: PayloadRef },
219
220 Single { transition: Transition },
222
223 Sparse { transitions: Vec<Transition> },
225
226 Dense {
228 start_byte: u8,
230 children: Vec<Option<SizedPointer>>,
240 },
241}
242
243impl BtiNode {
244 pub fn payload_only(level: u16, key_prefix: Vec<u8>, payload: PayloadRef) -> Self {
246 Self {
247 node_type: BtiNodeType::PayloadOnly,
248 level,
249 key_prefix,
250 data: BtiNodeData::PayloadOnly { payload },
251 }
252 }
253
254 pub fn single(level: u16, key_prefix: Vec<u8>, transition: Transition) -> Self {
256 Self {
257 node_type: BtiNodeType::Single,
258 level,
259 key_prefix,
260 data: BtiNodeData::Single { transition },
261 }
262 }
263
264 pub fn sparse(level: u16, key_prefix: Vec<u8>, mut transitions: Vec<Transition>) -> Self {
266 transitions.sort_by_key(|t| t.byte);
268
269 Self {
270 node_type: BtiNodeType::Sparse,
271 level,
272 key_prefix,
273 data: BtiNodeData::Sparse { transitions },
274 }
275 }
276
277 pub fn dense(
283 level: u16,
284 key_prefix: Vec<u8>,
285 start_byte: u8,
286 children: Vec<Option<SizedPointer>>,
287 ) -> Self {
288 Self {
289 node_type: BtiNodeType::Dense,
290 level,
291 key_prefix,
292 data: BtiNodeData::Dense {
293 start_byte,
294 children,
295 },
296 }
297 }
298
299 pub fn find_child(&self, byte: u8) -> Option<&SizedPointer> {
301 match &self.data {
302 BtiNodeData::PayloadOnly { .. } => None,
303
304 BtiNodeData::Single { transition } => {
305 if transition.byte == byte {
306 Some(&transition.child)
307 } else {
308 None
309 }
310 }
311
312 BtiNodeData::Sparse { transitions } => {
313 transitions
315 .binary_search_by_key(&byte, |t| t.byte)
316 .ok()
317 .map(|idx| &transitions[idx].child)
318 }
319
320 BtiNodeData::Dense {
321 start_byte,
322 children,
323 } => {
324 if byte >= *start_byte && (byte as usize) < (*start_byte as usize + children.len())
325 {
326 let index = byte as usize - *start_byte as usize;
327 children.get(index).and_then(|slot| slot.as_ref())
330 } else {
331 None
332 }
333 }
334 }
335 }
336
337 pub fn get_transitions(&self) -> Vec<&Transition> {
339 match &self.data {
340 BtiNodeData::PayloadOnly { .. } => Vec::new(),
341 BtiNodeData::Single { transition } => vec![transition],
342 BtiNodeData::Sparse { transitions } => transitions.iter().collect(),
343 BtiNodeData::Dense {
344 start_byte: _,
345 children: _,
346 } => {
347 Vec::new() }
352 }
353 }
354
355 pub fn get_payload(&self) -> Option<&PayloadRef> {
357 match &self.data {
358 BtiNodeData::PayloadOnly { payload } => Some(payload),
359 _ => None,
360 }
361 }
362
363 pub fn is_leaf(&self) -> bool {
365 matches!(self.data, BtiNodeData::PayloadOnly { .. })
366 }
367
368 pub fn child_count(&self) -> usize {
370 match &self.data {
371 BtiNodeData::PayloadOnly { .. } => 0,
372 BtiNodeData::Single { .. } => 1,
373 BtiNodeData::Sparse { transitions } => transitions.len(),
374 BtiNodeData::Dense { children, .. } => children.len(),
375 }
376 }
377
378 pub fn validate(&self) -> BtiResult<()> {
380 let expected_range = self.node_type.expected_children_range();
381 let child_count = self.child_count();
382
383 if child_count < expected_range.0 {
385 return Err(BtiError::InvalidNodeStructure(format!(
386 "Node type {} has {} children, expected at least {}",
387 self.node_type, child_count, expected_range.0
388 ))
389 .into());
390 }
391
392 if let Some(max) = expected_range.1 {
393 if child_count > max {
394 return Err(BtiError::InvalidNodeStructure(format!(
395 "Node type {} has {} children, expected at most {}",
396 self.node_type, child_count, max
397 ))
398 .into());
399 }
400 }
401
402 match &self.data {
404 BtiNodeData::Sparse { transitions } => {
405 for window in transitions.windows(2) {
407 if window[0].byte >= window[1].byte {
408 return Err(BtiError::InvalidNodeStructure(
409 "Sparse node transitions not sorted".to_string(),
410 )
411 .into());
412 }
413 }
414 }
415
416 BtiNodeData::Dense {
417 start_byte,
418 children,
419 } => {
420 let end_byte = *start_byte as usize + children.len();
422 if end_byte > 256 {
423 return Err(BtiError::InvalidNodeStructure(
424 "Dense node range overflows byte values".to_string(),
425 )
426 .into());
427 }
428 }
429
430 _ => {} }
432
433 Ok(())
434 }
435}
436
437#[derive(Debug, Clone)]
439pub struct TrieNavigator {
440 pub current_offset: u64,
442 pub path: Vec<u8>,
444 pub visited_offsets: std::collections::HashSet<u64>,
446}
447
448impl TrieNavigator {
449 pub fn new(root_offset: u64) -> Self {
451 Self {
452 current_offset: root_offset,
453 path: Vec::new(),
454 visited_offsets: std::collections::HashSet::new(),
455 }
456 }
457
458 pub fn navigate_to_child(&mut self, byte: u8, child_pointer: &SizedPointer) -> BtiResult<()> {
460 let target_offset = self.current_offset + child_pointer.distance;
461
462 if self.visited_offsets.contains(&target_offset) {
464 return Err(
465 BtiError::NavigationError("Cycle detected in trie navigation".to_string()).into(),
466 );
467 }
468
469 self.visited_offsets.insert(self.current_offset);
470 self.current_offset = target_offset;
471 self.path.push(byte);
472
473 Ok(())
474 }
475
476 pub fn current_path(&self) -> &[u8] {
478 &self.path
479 }
480
481 pub fn reset(&mut self, root_offset: u64) {
483 self.current_offset = root_offset;
484 self.path.clear();
485 self.visited_offsets.clear();
486 }
487}
488
489#[cfg(test)]
490mod tests {
491 use super::*;
492
493 #[test]
494 fn test_sized_pointer() {
495 let small = SizedPointer::new(100);
496 assert_eq!(small.size, 1);
497 assert_eq!(small.to_bytes(), vec![100]);
498
499 let large = SizedPointer::new(0x10000);
500 assert_eq!(large.size, 4);
501 assert_eq!(large.to_bytes(), vec![0x00, 0x01, 0x00, 0x00]);
502 }
503
504 #[test]
505 fn test_node_creation() {
506 let payload = PayloadRef::new(1000, 50);
507 let node = BtiNode::payload_only(0, b"test".to_vec(), payload);
508
509 assert_eq!(node.node_type, BtiNodeType::PayloadOnly);
510 assert_eq!(node.level, 0);
511 assert_eq!(node.key_prefix, b"test");
512 assert!(node.is_leaf());
513 assert_eq!(node.child_count(), 0);
514 }
515
516 #[test]
517 fn test_sparse_node_search() {
518 let transitions = vec![
519 Transition::new(b'a', SizedPointer::new(100)),
520 Transition::new(b'm', SizedPointer::new(200)),
521 Transition::new(b'z', SizedPointer::new(300)),
522 ];
523
524 let node = BtiNode::sparse(1, Vec::new(), transitions);
525
526 assert!(node.find_child(b'a').is_some());
527 assert!(node.find_child(b'm').is_some());
528 assert!(node.find_child(b'z').is_some());
529 assert!(node.find_child(b'b').is_none());
530
531 assert_eq!(node.child_count(), 3);
532 }
533
534 #[test]
535 fn test_dense_node_lookup() {
536 let children = vec![
537 Some(SizedPointer::new(100)),
538 Some(SizedPointer::new(200)),
539 Some(SizedPointer::new(300)),
540 ];
541
542 let node = BtiNode::dense(1, Vec::new(), b'a', children);
543
544 assert!(node.find_child(b'a').is_some());
545 assert!(node.find_child(b'b').is_some());
546 assert!(node.find_child(b'c').is_some());
547 assert!(node.find_child(b'd').is_none());
548 assert!(node.find_child(b'@').is_none()); }
550
551 #[test]
558 fn test_dense_node_offset_zero_child_distinct_from_no_transition() {
559 let children = vec![
564 Some(SizedPointer::new(0)), None, Some(SizedPointer::new(300)),
567 ];
568 let node = BtiNode::dense(1, Vec::new(), b'a', children);
569
570 let a = node.find_child(b'a');
571 assert!(a.is_some(), "offset-0 child must be found, not dropped");
572 assert_eq!(
573 a.unwrap().distance,
574 0,
575 "the real child at absolute offset 0 must be returned"
576 );
577 assert!(
578 node.find_child(b'b').is_none(),
579 "no-transition slot must return None"
580 );
581 assert!(node.find_child(b'c').is_some());
582 assert_eq!(node.child_count(), 3);
584 }
585
586 #[test]
587 fn test_node_validation() {
588 let payload_node = BtiNode::payload_only(0, Vec::new(), PayloadRef::new(0, 10));
590 assert!(payload_node.validate().is_ok());
591
592 let _invalid_sparse = BtiNode::sparse(
594 1,
595 Vec::new(),
596 vec![Transition::new(b'a', SizedPointer::new(100))],
597 );
598 }
601
602 #[test]
603 fn test_trie_navigator() {
604 let mut nav = TrieNavigator::new(1000);
605 assert_eq!(nav.current_offset, 1000);
606 assert_eq!(nav.current_path(), &[] as &[u8]);
607
608 let pointer = SizedPointer::new(100);
609 nav.navigate_to_child(b'a', &pointer).unwrap();
610
611 assert_eq!(nav.current_offset, 1100);
612 assert_eq!(nav.current_path(), b"a");
613 }
614}