1use std::{iter::FusedIterator, marker::PhantomData};
2
3use lxdb_format::{AdjacencyRecord, BinaryRecord, FormatError, RelationRecord, TokenRecord};
4
5#[derive(Debug, Clone)]
7pub struct RecordIter<'a, T> {
8 bytes: &'a [u8],
9 cursor: usize,
10 marker: PhantomData<T>,
11}
12
13impl<'a, T> RecordIter<'a, T>
14where
15 T: BinaryRecord,
16{
17 pub(crate) const fn new(bytes: &'a [u8]) -> Self {
18 Self { bytes, cursor: 0, marker: PhantomData }
19 }
20
21 fn remaining(&self) -> usize {
22 (self.bytes.len() - self.cursor) / T::SIZE
23 }
24}
25
26impl<T> Iterator for RecordIter<'_, T>
27where
28 T: BinaryRecord,
29{
30 type Item = Result<T, FormatError>;
31
32 fn next(&mut self) -> Option<Self::Item> {
33 if self.cursor >= self.bytes.len() {
34 return None;
35 }
36
37 let end = self.cursor + T::SIZE;
38
39 let record = T::decode(&self.bytes[self.cursor..end]);
40
41 self.cursor = end;
42
43 Some(record)
44 }
45
46 fn size_hint(&self) -> (usize, Option<usize>) {
47 let remaining = self.remaining();
48
49 (remaining, Some(remaining))
50 }
51}
52
53impl<T> ExactSizeIterator for RecordIter<'_, T>
54where
55 T: BinaryRecord,
56{
57 fn len(&self) -> usize {
58 self.remaining()
59 }
60}
61
62impl<T> FusedIterator for RecordIter<'_, T> where T: BinaryRecord {}
63
64pub type TokenRecordIter<'a> = RecordIter<'a, TokenRecord>;
65
66pub type RelationRecordIter<'a> = RecordIter<'a, RelationRecord>;
67
68pub type AdjacencyRecordIter<'a> = RecordIter<'a, AdjacencyRecord>;
69
70#[cfg(test)]
71mod tests {
72 use lxdb_format::{RelationRecord, TokenRecord};
73
74 use super::RecordIter;
75
76 #[test]
77 fn iterates_over_token_records() {
78 let first = TokenRecord::new(0, 0, 4);
79
80 let second = TokenRecord::new(1, 4, 8);
81
82 let mut bytes = Vec::new();
83
84 bytes.extend_from_slice(&first.encode());
85 bytes.extend_from_slice(&second.encode());
86
87 let mut records = RecordIter::<TokenRecord>::new(&bytes);
88
89 assert_eq!(records.len(), 2);
90
91 let decoded_first =
92 records.next().expect("first record should exist").expect("first record should decode");
93
94 assert_eq!(decoded_first, first);
95 assert_eq!(records.len(), 1);
96
97 let decoded_second = records
98 .next()
99 .expect("second record should exist")
100 .expect("second record should decode");
101
102 assert_eq!(decoded_second, second);
103 assert_eq!(records.len(), 0);
104 assert!(records.next().is_none());
105 assert!(records.next().is_none());
106 }
107
108 #[test]
109 fn uses_the_same_iterator_for_relation_records() {
110 let relation = RelationRecord::new(7, 2, 5, 0.75);
111
112 let bytes = relation.encode();
113
114 let mut records = RecordIter::<RelationRecord>::new(&bytes);
115
116 let decoded = records
117 .next()
118 .expect("relation record should exist")
119 .expect("relation record should decode");
120
121 assert_eq!(decoded.id(), relation.id());
122 assert_eq!(decoded.source(), relation.source());
123 assert_eq!(decoded.target(), relation.target());
124
125 assert_eq!(decoded.weight().to_bits(), relation.weight().to_bits(),);
126
127 assert!(records.next().is_none());
128 }
129
130 #[test]
131 fn empty_record_iterator_is_fused() {
132 let mut records = RecordIter::<TokenRecord>::new(&[]);
133
134 assert_eq!(records.len(), 0);
135 assert!(records.next().is_none());
136 assert!(records.next().is_none());
137 }
138}