http_streams_core/
arrow_format.rs1use crate::content_type::ContentType;
4use crate::error::{StreamError, StreamErrorKind};
5use crate::format::{
6 DecodeOptions, IdentityParser, ItemEncoder, StreamFormat, StreamFormatDecode,
7 StreamFormatEncode,
8};
9use crate::arrow_ipc_codec::ArrowIpcCodec;
10use arrow::array::RecordBatch;
11use arrow::datatypes::{Schema, SchemaRef};
12use arrow::error::ArrowError;
13use arrow::ipc::writer::{
14 write_message, DictionaryTracker, IpcDataGenerator, IpcWriteContext, IpcWriteOptions,
15};
16use bytes::{BufMut, BytesMut};
17use std::io::Write;
18use std::sync::Arc;
19
20const ARROW_CONTENT_TYPE: &str = "application/vnd.apache.arrow.stream";
21
22const CONTINUATION_MARKER: [u8; 4] = [0xff; 4];
24const TOTAL_LEN: [u8; 4] = [0; 4];
25
26#[derive(Debug, Clone)]
32pub struct ArrowRecordBatchIpcStreamFormat {
33 schema: SchemaRef,
34 options: IpcWriteOptions,
35}
36
37impl ArrowRecordBatchIpcStreamFormat {
38 pub fn new(schema: Arc<Schema>) -> Self {
40 Self::with_options(schema, IpcWriteOptions::default())
41 }
42
43 pub fn with_options(schema: Arc<Schema>, options: IpcWriteOptions) -> Self {
45 Self { schema, options }
46 }
47
48 pub fn for_decoding() -> Self {
54 Self::new(Arc::new(Schema::empty()))
55 }
56}
57
58impl crate::format::DefaultFormat for ArrowRecordBatchIpcStreamFormat {
59 fn default_format() -> Self {
61 Self::for_decoding()
62 }
63}
64
65impl StreamFormat for ArrowRecordBatchIpcStreamFormat {
66 fn format_name(&self) -> &'static str {
67 "arrow"
68 }
69
70 fn default_content_type(&self) -> &'static str {
71 ARROW_CONTENT_TYPE
72 }
73
74 fn accepts_content_type(&self, ct: &ContentType<'_>) -> bool {
75 ct.matches(ARROW_CONTENT_TYPE)
76 }
77}
78
79fn arrow_error(err: ArrowError) -> StreamError {
80 StreamError::new(StreamErrorKind::CodecError, Some(Box::new(err)), None)
81}
82
83pub struct ArrowIpcEncoder {
88 schema: SchemaRef,
89 options: IpcWriteOptions,
90 data_gen: IpcDataGenerator,
91 dictionary_tracker: DictionaryTracker,
92 write_context: IpcWriteContext,
93}
94
95impl ItemEncoder<RecordBatch> for ArrowIpcEncoder {
96 fn encode(
97 &mut self,
98 item: &RecordBatch,
99 index: u64,
100 buf: &mut BytesMut,
101 ) -> Result<(), StreamError> {
102 let mut writer = buf.writer();
103
104 if index == 0 {
106 let encoded = self.data_gen.schema_to_bytes_with_dictionary_tracker(
107 &self.schema,
108 &mut self.dictionary_tracker,
109 &self.options,
110 );
111 write_message(&mut writer, encoded, &self.options).map_err(arrow_error)?;
112 }
113
114 let (encoded_dictionaries, encoded_message) = self
115 .data_gen
116 .encode(
117 item,
118 &mut self.dictionary_tracker,
119 &self.options,
120 &mut self.write_context,
121 )
122 .map_err(arrow_error)?;
123
124 for encoded_dictionary in encoded_dictionaries {
125 write_message(&mut writer, encoded_dictionary, &self.options).map_err(arrow_error)?;
126 }
127
128 write_message(&mut writer, encoded_message, &self.options).map_err(arrow_error)?;
129 writer.flush().map_err(|err| {
130 StreamError::new(StreamErrorKind::CodecError, Some(Box::new(err)), None)
131 })
132 }
133
134 fn epilogue(&mut self, buf: &mut BytesMut) -> Result<(), StreamError> {
137 buf.extend_from_slice(&CONTINUATION_MARKER);
138 buf.extend_from_slice(&TOTAL_LEN);
139 Ok(())
140 }
141}
142
143impl StreamFormatEncode<RecordBatch> for ArrowRecordBatchIpcStreamFormat {
144 type Encoder = ArrowIpcEncoder;
145
146 fn encoder(&self) -> Self::Encoder {
147 ArrowIpcEncoder {
148 schema: self.schema.clone(),
149 options: self.options.clone(),
150 data_gen: IpcDataGenerator::default(),
151 dictionary_tracker: DictionaryTracker::new(false),
152 write_context: IpcWriteContext::default(),
153 }
154 }
155}
156
157impl StreamFormatDecode<RecordBatch> for ArrowRecordBatchIpcStreamFormat {
158 type Frame = Result<RecordBatch, StreamError>;
159 type Framer = ArrowIpcCodec;
160 type Parser = IdentityParser;
161
162 fn framer(&self, options: &DecodeOptions) -> Self::Framer {
163 ArrowIpcCodec::new_with_max_length(options.max_obj_len)
164 }
165
166 fn parser(&self) -> Self::Parser {
167 IdentityParser
168 }
169}