1use std::collections::HashMap;
6use std::fmt::Debug;
7use std::sync::Arc;
8
9use arrow_array::{ArrayRef, RecordBatch};
10use arrow_buffer::{Buffer, MutableBuffer};
11use arrow_data::UnsafeFlag;
12use arrow_schema::{ArrowError, SchemaRef};
13
14use crate::convert::MessageBuffer;
15use crate::reader::{MAX_PREALLOC_BYTES, RecordBatchDecoder, read_dictionary_impl};
16use crate::{CONTINUATION_MARKER, MessageHeader};
17
18#[derive(Debug, Default)]
22pub struct StreamDecoder {
23 schema: Option<SchemaRef>,
25 dictionaries: HashMap<i64, ArrayRef>,
27 state: DecoderState,
29 buf: MutableBuffer,
31 require_alignment: bool,
33 skip_validation: UnsafeFlag,
38}
39
40#[derive(Debug)]
41enum DecoderState {
42 Header {
44 buf: [u8; 4],
46 read: u8,
48 continuation: bool,
50 },
51 Message {
53 size: u32,
55 },
56 Body {
58 message: MessageBuffer,
60 },
61 Finished,
63}
64
65impl Default for DecoderState {
66 fn default() -> Self {
67 Self::Header {
68 buf: [0; 4],
69 read: 0,
70 continuation: false,
71 }
72 }
73}
74
75impl StreamDecoder {
76 pub fn new() -> Self {
78 Self::default()
79 }
80
81 pub fn with_require_alignment(mut self, require_alignment: bool) -> Self {
94 self.require_alignment = require_alignment;
95 self
96 }
97
98 pub fn schema(&self) -> Option<SchemaRef> {
100 self.schema.as_ref().map(|schema| schema.clone())
101 }
102
103 pub unsafe fn with_skip_validation(mut self, skip_validation: bool) -> Self {
113 unsafe { self.skip_validation.set(skip_validation) };
114 self
115 }
116
117 pub fn decode(&mut self, buffer: &mut Buffer) -> Result<Option<RecordBatch>, ArrowError> {
147 while !buffer.is_empty()
148 || matches!(
149 &self.state,
150 DecoderState::Body { message } if message.as_ref().bodyLength() == 0
151 )
152 {
153 match &mut self.state {
154 DecoderState::Header {
155 buf,
156 read,
157 continuation,
158 } => {
159 let offset_buf = &mut buf[*read as usize..];
160 let to_read = buffer.len().min(offset_buf.len());
161 offset_buf[..to_read].copy_from_slice(&buffer[..to_read]);
162 *read += to_read as u8;
163 buffer.advance(to_read);
164 if *read == 4 {
165 if !*continuation && buf == &CONTINUATION_MARKER {
166 *continuation = true;
167 *read = 0;
168 continue;
169 }
170 let size = u32::from_le_bytes(*buf);
171
172 if size == 0 {
173 self.state = DecoderState::Finished;
174 continue;
175 }
176 self.state = DecoderState::Message { size };
177 }
178 }
179 DecoderState::Message { size } => {
180 let len = *size as usize;
181 if self.buf.is_empty() && buffer.len() > len {
182 let message = MessageBuffer::try_new(buffer.slice_with_length(0, len))?;
183 self.state = DecoderState::Body { message };
184 buffer.advance(len);
185 continue;
186 }
187
188 reserve_declared(&mut self.buf, len)?;
189 let to_read = buffer.len().min(len - self.buf.len());
190 self.buf
191 .try_extend_from_slice(&buffer[..to_read])
192 .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
193 buffer.advance(to_read);
194 if self.buf.len() == len {
195 let message = MessageBuffer::try_new(std::mem::take(&mut self.buf).into())?;
196 self.state = DecoderState::Body { message };
197 }
198 }
199 DecoderState::Body { message } => {
200 let message = message.as_ref();
201 let body_length = message.bodyLength() as usize;
202
203 let body = if self.buf.is_empty() && buffer.len() >= body_length {
204 let body = buffer.slice_with_length(0, body_length);
205 buffer.advance(body_length);
206 body
207 } else {
208 reserve_declared(&mut self.buf, body_length)?;
209 let to_read = buffer.len().min(body_length - self.buf.len());
210 self.buf
211 .try_extend_from_slice(&buffer[..to_read])
212 .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
213 buffer.advance(to_read);
214
215 if self.buf.len() != body_length {
216 continue;
217 }
218 std::mem::take(&mut self.buf).into()
219 };
220
221 let version = message.version();
222 match message.header_type() {
223 MessageHeader::Schema => {
224 if self.schema.is_some() {
225 return Err(ArrowError::IpcError(
226 "Not expecting a schema when messages are read".to_string(),
227 ));
228 }
229
230 let ipc_schema = message.header_as_schema().ok_or_else(|| {
231 ArrowError::ParseError(
232 "Unable to read IPC message as schema".to_string(),
233 )
234 })?;
235 let schema = crate::convert::try_fb_to_schema(ipc_schema)?;
236 self.state = DecoderState::default();
237 self.schema = Some(Arc::new(schema));
238 }
239 MessageHeader::RecordBatch => {
240 let batch = message.header_as_record_batch().unwrap();
241 let schema = self.schema.clone().ok_or_else(|| {
242 ArrowError::IpcError("Missing schema".to_string())
243 })?;
244 let batch = RecordBatchDecoder::try_new(
245 &body,
246 batch,
247 schema,
248 &self.dictionaries,
249 &version,
250 )?
251 .with_require_alignment(self.require_alignment)
252 .with_skip_validation(self.skip_validation.clone())
253 .read_record_batch()?;
254 self.state = DecoderState::default();
255 return Ok(Some(batch));
256 }
257 MessageHeader::DictionaryBatch => {
258 let dictionary = message.header_as_dictionary_batch().unwrap();
259 let schema = self.schema.as_deref().ok_or_else(|| {
260 ArrowError::IpcError("Missing schema".to_string())
261 })?;
262 read_dictionary_impl(
263 &body,
264 dictionary,
265 schema,
266 &mut self.dictionaries,
267 &version,
268 self.require_alignment,
269 self.skip_validation.clone(),
270 )?;
271 self.state = DecoderState::default();
272 }
273 MessageHeader::NONE => {
274 self.state = DecoderState::default();
275 }
276 t => {
277 return Err(ArrowError::IpcError(format!(
278 "Message type unsupported by StreamDecoder: {t:?}"
279 )));
280 }
281 }
282 }
283 DecoderState::Finished => {
284 return Err(ArrowError::IpcError("Unexpected EOS".to_string()));
285 }
286 }
287 }
288 Ok(None)
289 }
290
291 pub fn finish(&mut self) -> Result<(), ArrowError> {
295 match self.state {
296 DecoderState::Finished
297 | DecoderState::Header {
298 read: 0,
299 continuation: false,
300 ..
301 } => Ok(()),
302 _ => Err(ArrowError::IpcError("Unexpected End of Stream".to_string())),
303 }
304 }
305}
306
307fn reserve_declared(buf: &mut MutableBuffer, len: usize) -> Result<(), ArrowError> {
311 if buf.is_empty() {
312 buf.try_reserve(len.min(MAX_PREALLOC_BYTES))
313 .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
314 }
315 Ok(())
316}
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321 use crate::writer::{IpcWriteOptions, StreamWriter};
322 use arrow_array::{
323 DictionaryArray, Int32Array, Int64Array, RecordBatch, RunArray, StringArray,
324 types::Int32Type,
325 };
326 use arrow_schema::{DataType, Field, Schema};
327
328 #[test]
331 fn test_eos() {
332 let schema = Arc::new(Schema::new(vec![
333 Field::new("int32", DataType::Int32, false),
334 Field::new("int64", DataType::Int64, false),
335 ]));
336
337 let input = RecordBatch::try_new(
338 schema.clone(),
339 vec![
340 Arc::new(Int32Array::from(vec![1, 2, 3])) as _,
341 Arc::new(Int64Array::from(vec![1, 2, 3])) as _,
342 ],
343 )
344 .unwrap();
345
346 let mut buf = Vec::with_capacity(1024);
347 let mut s = StreamWriter::try_new(&mut buf, &schema).unwrap();
348 s.write(&input).unwrap();
349 s.finish().unwrap();
350 drop(s);
351
352 let buffer = Buffer::from_vec(buf);
353
354 let mut b = buffer.slice_with_length(0, buffer.len() - 1);
355 let mut decoder = StreamDecoder::new();
356 let output = decoder.decode(&mut b).unwrap().unwrap();
357 assert_eq!(output, input);
358 assert_eq!(b.len(), 7); assert!(decoder.decode(&mut b).unwrap().is_none());
360
361 let err = decoder.finish().unwrap_err().to_string();
362 assert_eq!(err, "Ipc error: Unexpected End of Stream");
363 }
364
365 #[test]
366 fn test_schema() {
367 let schema = Arc::new(Schema::new(vec![
368 Field::new("int32", DataType::Int32, false),
369 Field::new("int64", DataType::Int64, false),
370 ]));
371
372 let mut buf = Vec::with_capacity(1024);
373 let mut s = StreamWriter::try_new(&mut buf, &schema).unwrap();
374 s.finish().unwrap();
375 drop(s);
376
377 let buffer = Buffer::from_vec(buf);
378
379 let mut b = buffer.slice_with_length(0, buffer.len() - 1);
380 let mut decoder = StreamDecoder::new();
381 let output = decoder.decode(&mut b).unwrap();
382 assert!(output.is_none());
383 let decoded_schema = decoder.schema().unwrap();
384 assert_eq!(schema, decoded_schema);
385
386 let err = decoder.finish().unwrap_err().to_string();
387 assert_eq!(err, "Ipc error: Unexpected End of Stream");
388 }
389
390 #[test]
391 fn test_schema_without_eos() {
392 let schema = Arc::new(Schema::new(vec![Field::new("id", DataType::Int32, false)]));
393
394 let mut buf = Vec::new();
395 let writer = StreamWriter::try_new(&mut buf, &schema).unwrap();
396 drop(writer);
398
399 let mut buffer = Buffer::from_vec(buf);
400 let mut decoder = StreamDecoder::new();
401 let output = decoder.decode(&mut buffer).unwrap();
402
403 assert!(output.is_none());
404 assert!(buffer.is_empty());
405 assert_eq!(decoder.schema(), Some(schema));
406 decoder.finish().unwrap();
407 }
408
409 #[test]
410 fn test_read_ree_dict_record_batches_from_buffer() {
411 let schema = Schema::new(vec![Field::new(
412 "test1",
413 DataType::RunEndEncoded(
414 Arc::new(Field::new(
415 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
416 DataType::Int32,
417 false,
418 )),
419 #[expect(deprecated)]
420 Arc::new(Field::new_dict(
421 Field::REE_VALUES_FIELD_DEFAULT_NAME,
422 DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8)),
423 true,
424 0,
425 false,
426 )),
427 ),
428 true,
429 )]);
430 let batch = RecordBatch::try_new(
431 schema.clone().into(),
432 vec![Arc::new(
433 RunArray::try_new(
434 &Int32Array::from(vec![1, 2, 3]),
435 &vec![Some("a"), None, Some("a")]
436 .into_iter()
437 .collect::<DictionaryArray<Int32Type>>(),
438 )
439 .expect("Failed to create RunArray"),
440 )],
441 )
442 .expect("Failed to create RecordBatch");
443
444 let mut buffer = vec![];
445 {
446 let mut writer = StreamWriter::try_new_with_options(
447 &mut buffer,
448 &schema,
449 IpcWriteOptions::default(),
450 )
451 .expect("Failed to create StreamWriter");
452 writer.write(&batch).expect("Failed to write RecordBatch");
453 writer.finish().expect("Failed to finish StreamWriter");
454 }
455
456 let mut decoder = StreamDecoder::new();
457 let buf = &mut Buffer::from(buffer.as_slice());
458 while let Some(batch) = decoder
459 .decode(buf)
460 .map_err(|e| {
461 ArrowError::ExternalError(format!("Failed to decode record batch: {e}").into())
462 })
463 .expect("Failed to decode record batch")
464 {
465 assert_eq!(batch, batch);
466 }
467
468 decoder.finish().expect("Failed to finish decoder");
469 }
470
471 #[test]
474 fn test_split_body_is_buffered_at_its_declared_size() {
475 let schema = Arc::new(Schema::new(vec![Field::new("s", DataType::Utf8, false)]));
476 let input = RecordBatch::try_new(
477 schema.clone(),
478 vec![Arc::new(StringArray::from_iter_values(
479 (0..7000).map(|i| format!("value{i:05}")),
480 )) as _],
481 )
482 .unwrap();
483
484 let mut stream = Vec::new();
485 let mut writer = StreamWriter::try_new(&mut stream, &schema).unwrap();
486 writer.write(&input).unwrap();
487 writer.finish().unwrap();
488 drop(writer);
489
490 let mut decoder = StreamDecoder::new();
491 let mut output = None;
492 for byte in stream.chunks(1) {
493 if let Some(batch) = decoder.decode(&mut Buffer::from(byte)).unwrap() {
494 output = Some(batch);
495 }
496 }
497 decoder.finish().unwrap();
498 let output = output.unwrap();
499 assert_eq!(output, input);
500
501 let held = output.column(0).to_data().buffers()[0].capacity();
502 assert!(
503 held <= stream.len(),
504 "decoded batch holds {held} bytes, more than the {} byte stream it came from",
505 stream.len()
506 );
507 }
508
509 #[test]
512 fn test_implausible_body_length_reserves_a_bounded_buffer() {
513 for body_length in [i64::MAX, 1 << 50] {
514 let mut fbb = flatbuffers::FlatBufferBuilder::new();
515 let mut message = crate::MessageBuilder::new(&mut fbb);
516 message.add_version(crate::MetadataVersion::V5);
517 message.add_header_type(MessageHeader::NONE);
518 message.add_bodyLength(body_length);
519 let root = message.finish();
520 fbb.finish(root, None);
521 let metadata = fbb.finished_data();
522
523 let mut stream = Vec::new();
524 stream.extend_from_slice(&CONTINUATION_MARKER);
525 stream.extend_from_slice(&(metadata.len() as i32).to_le_bytes());
526 stream.extend_from_slice(metadata);
527 stream.extend_from_slice(&[0xAB; 16]);
528
529 let mut decoder = StreamDecoder::new();
530 let decoded = decoder
531 .decode(&mut Buffer::from(stream.as_slice()))
532 .unwrap();
533 assert!(decoded.is_none(), "body_length {body_length}");
534 assert!(decoder.finish().is_err(), "body_length {body_length}");
535 }
536 }
537}