bcp_decoder/
block_reader.rs1use bcp_types::fields::{
2 FieldWireType, decode_bytes_value, decode_field_header, decode_varint_value,
3};
4
5use crate::error::DecodeError;
6
7pub struct RawField<'a> {
21 pub field_id: u64,
22 pub wire_type: FieldWireType,
23 pub data: &'a [u8],
24}
25
26pub struct BlockReader<'a> {
50 buf: &'a [u8],
51 pos: usize,
52}
53
54impl<'a> BlockReader<'a> {
55 #[must_use]
60 pub fn new(buf: &'a [u8]) -> Self {
61 Self { buf, pos: 0 }
62 }
63
64 pub fn next_field(&mut self) -> Result<Option<RawField<'a>>, DecodeError> {
80 let remaining = &self.buf[self.pos..];
81 if remaining.is_empty() {
82 return Ok(None);
83 }
84
85 let (header, header_len) = decode_field_header(remaining)?;
86 let payload_buf = &remaining[header_len..];
87
88 let (data, payload_consumed) = match header.wire_type {
89 FieldWireType::Varint => {
90 let (_, n) = decode_varint_value(payload_buf)?;
94 (&payload_buf[..n], n)
95 }
96 FieldWireType::Bytes | FieldWireType::Nested => {
97 let (inner, n) = decode_bytes_value(payload_buf)?;
100 (inner, n)
101 }
102 };
103
104 self.pos += header_len + payload_consumed;
105
106 Ok(Some(RawField {
107 field_id: header.field_id,
108 wire_type: header.wire_type,
109 data,
110 }))
111 }
112
113 #[must_use]
115 pub fn position(&self) -> usize {
116 self.pos
117 }
118
119 #[must_use]
121 pub fn remaining(&self) -> &'a [u8] {
122 &self.buf[self.pos..]
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use bcp_types::fields::{encode_bytes_field, encode_nested_field, encode_varint_field};
130
131 #[test]
132 fn empty_buffer_returns_none() {
133 let mut reader = BlockReader::new(&[]);
134 assert!(reader.next_field().unwrap().is_none());
135 }
136
137 #[test]
138 fn reads_varint_field() {
139 let mut buf = Vec::new();
140 encode_varint_field(&mut buf, 1, 42);
141
142 let mut reader = BlockReader::new(&buf);
143 let field = reader.next_field().unwrap().unwrap();
144 assert_eq!(field.field_id, 1);
145 assert_eq!(field.wire_type, FieldWireType::Varint);
146
147 let (value, _) = decode_varint_value(field.data).unwrap();
149 assert_eq!(value, 42);
150
151 assert!(reader.next_field().unwrap().is_none());
152 }
153
154 #[test]
155 fn reads_bytes_field() {
156 let mut buf = Vec::new();
157 encode_bytes_field(&mut buf, 2, b"hello");
158
159 let mut reader = BlockReader::new(&buf);
160 let field = reader.next_field().unwrap().unwrap();
161 assert_eq!(field.field_id, 2);
162 assert_eq!(field.wire_type, FieldWireType::Bytes);
163 assert_eq!(field.data, b"hello");
164
165 assert!(reader.next_field().unwrap().is_none());
166 }
167
168 #[test]
169 fn reads_nested_field() {
170 let mut inner = Vec::new();
171 encode_varint_field(&mut inner, 1, 99);
172
173 let mut buf = Vec::new();
174 encode_nested_field(&mut buf, 3, &inner);
175
176 let mut reader = BlockReader::new(&buf);
177 let field = reader.next_field().unwrap().unwrap();
178 assert_eq!(field.field_id, 3);
179 assert_eq!(field.wire_type, FieldWireType::Nested);
180 assert_eq!(field.data, &inner);
181 }
182
183 #[test]
184 fn reads_multiple_fields_sequentially() {
185 let mut buf = Vec::new();
186 encode_varint_field(&mut buf, 1, 7);
187 encode_bytes_field(&mut buf, 2, b"world");
188 encode_varint_field(&mut buf, 3, 256);
189
190 let mut reader = BlockReader::new(&buf);
191
192 let f1 = reader.next_field().unwrap().unwrap();
193 assert_eq!(f1.field_id, 1);
194
195 let f2 = reader.next_field().unwrap().unwrap();
196 assert_eq!(f2.field_id, 2);
197 assert_eq!(f2.data, b"world");
198
199 let f3 = reader.next_field().unwrap().unwrap();
200 assert_eq!(f3.field_id, 3);
201
202 assert!(reader.next_field().unwrap().is_none());
203 assert_eq!(reader.position(), buf.len());
204 }
205
206 #[test]
207 fn position_tracks_correctly() {
208 let mut buf = Vec::new();
209 encode_varint_field(&mut buf, 1, 42);
210 encode_bytes_field(&mut buf, 2, b"hi");
211
212 let mut reader = BlockReader::new(&buf);
213 assert_eq!(reader.position(), 0);
214
215 reader.next_field().unwrap();
216 let mid = reader.position();
217 assert!(mid > 0 && mid < buf.len());
218
219 reader.next_field().unwrap();
220 assert_eq!(reader.position(), buf.len());
221 assert!(reader.remaining().is_empty());
222 }
223}