arrow_avro/reader/
block.rs1use crate::errors::AvroError;
21use crate::reader::vlq::VLQDecoder;
22
23#[derive(Debug, Default)]
27pub struct Block {
28 pub count: usize,
30 pub data: Vec<u8>,
32 pub sync: [u8; 16],
34}
35
36#[derive(Debug)]
38pub struct BlockDecoder {
39 state: BlockDecoderState,
40 in_progress: Block,
41 vlq_decoder: VLQDecoder,
42 bytes_remaining: usize,
43}
44
45#[derive(Debug)]
46pub(crate) enum BlockDecoderState {
47 Count,
48 Size,
49 Data,
50 Sync,
51 Finished,
52}
53
54impl Default for BlockDecoder {
55 fn default() -> Self {
56 Self {
57 state: BlockDecoderState::Count,
58 in_progress: Default::default(),
59 vlq_decoder: Default::default(),
60 bytes_remaining: 0,
61 }
62 }
63}
64
65impl BlockDecoder {
66 pub fn decode(&mut self, mut buf: &[u8]) -> Result<usize, AvroError> {
79 let max_read = buf.len();
80 while !buf.is_empty() {
81 match self.state {
82 BlockDecoderState::Count => {
83 if let Some(c) = self.vlq_decoder.long(&mut buf) {
84 self.in_progress.count = c.try_into().map_err(|_| {
85 AvroError::ParseError(format!(
86 "Block count cannot be negative, got {c}"
87 ))
88 })?;
89
90 self.state = BlockDecoderState::Size;
91 }
92 }
93 BlockDecoderState::Size => {
94 if let Some(c) = self.vlq_decoder.long(&mut buf) {
95 self.bytes_remaining = c.try_into().map_err(|_| {
96 AvroError::ParseError(format!("Block size cannot be negative, got {c}"))
97 })?;
98
99 self.in_progress
104 .data
105 .reserve(self.bytes_remaining.min(buf.len()));
106 self.state = BlockDecoderState::Data;
107 }
108 }
109 BlockDecoderState::Data => {
110 let to_read = self.bytes_remaining.min(buf.len());
111 self.in_progress.data.extend_from_slice(&buf[..to_read]);
112 buf = &buf[to_read..];
113 self.bytes_remaining -= to_read;
114 if self.bytes_remaining == 0 {
115 self.bytes_remaining = 16;
116 self.state = BlockDecoderState::Sync;
117 }
118 }
119 BlockDecoderState::Sync => {
120 let to_decode = buf.len().min(self.bytes_remaining);
121 let write = &mut self.in_progress.sync[16 - to_decode..];
122 write[..to_decode].copy_from_slice(&buf[..to_decode]);
123 self.bytes_remaining -= to_decode;
124 buf = &buf[to_decode..];
125 if self.bytes_remaining == 0 {
126 self.state = BlockDecoderState::Finished;
127 }
128 }
129 BlockDecoderState::Finished => return Ok(max_read - buf.len()),
130 }
131 }
132 Ok(max_read)
133 }
134
135 pub fn flush(&mut self) -> Option<Block> {
137 match self.state {
138 BlockDecoderState::Finished => {
139 self.state = BlockDecoderState::Count;
140 Some(std::mem::take(&mut self.in_progress))
141 }
142 _ => None,
143 }
144 }
145}
146
147#[cfg(feature = "async")]
148impl BlockDecoder {
149 pub(crate) fn state(&self) -> &BlockDecoderState {
150 &self.state
151 }
152
153 pub(crate) fn bytes_remaining(&self) -> usize {
154 self.bytes_remaining
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161
162 fn encode_long(value: i64, out: &mut Vec<u8>) {
164 let mut n = ((value << 1) ^ (value >> 63)) as u64;
165 while n >= 0x80 {
166 out.push((n as u8) | 0x80);
167 n >>= 7;
168 }
169 out.push(n as u8);
170 }
171
172 #[test]
173 fn test_oversized_block_size_bounds_reserve() {
174 let mut buf = Vec::new();
177 encode_long(1, &mut buf); encode_long(i64::MAX, &mut buf); buf.extend_from_slice(&[0u8; 8]); let mut decoder = BlockDecoder::default();
182 let read = decoder.decode(&buf).unwrap();
183
184 assert_eq!(read, buf.len(), "all available input should be consumed");
185 assert!(
186 decoder.in_progress.data.capacity() <= buf.len(),
187 "capacity {} must stay bounded by available input {}, not the advertised i64::MAX",
188 decoder.in_progress.data.capacity(),
189 buf.len(),
190 );
191 }
192
193 #[test]
194 fn test_negative_block_size_errors() {
195 let mut buf = Vec::new();
196 encode_long(1, &mut buf); encode_long(-1, &mut buf); let mut decoder = BlockDecoder::default();
200 let err = decoder.decode(&buf).unwrap_err();
201 assert!(
202 err.to_string().contains("Block size cannot be negative"),
203 "unexpected error: {err}",
204 );
205 }
206
207 #[test]
208 fn test_well_formed_block_round_trips() {
209 let payload = [1u8, 2, 3, 4];
211 let sync = [7u8; 16];
212 let mut buf = Vec::new();
213 encode_long(2, &mut buf); encode_long(payload.len() as i64, &mut buf); buf.extend_from_slice(&payload);
216 buf.extend_from_slice(&sync);
217
218 let mut decoder = BlockDecoder::default();
219 assert_eq!(decoder.decode(&buf).unwrap(), buf.len());
220 let block = decoder.flush().expect("a complete block");
221 assert_eq!(block.count, 2);
222 assert_eq!(block.data, payload);
223 assert_eq!(block.sync, sync);
224 }
225}