ion_rs/binary/
binary_writer.rs

1use crate::binary::raw_binary_writer::{RawBinaryWriter, RawBinaryWriterBuilder};
2use crate::constants::v1_0::system_symbol_ids;
3use crate::raw_symbol_token_ref::{AsRawSymbolTokenRef, RawSymbolTokenRef};
4use crate::result::{illegal_operation, IonResult};
5use crate::types::{Decimal, Int, IonType, SymbolId, Timestamp};
6use crate::writer::IonWriter;
7use crate::SymbolTable;
8use delegate::delegate;
9use std::io::Write;
10
11pub struct BinaryWriterBuilder {
12    // Nothing yet
13}
14
15impl BinaryWriterBuilder {
16    pub fn new() -> Self {
17        BinaryWriterBuilder {}
18    }
19
20    pub fn build<W: Write>(self, sink: W) -> IonResult<BinaryWriter<W>> {
21        let mut raw_writer = RawBinaryWriterBuilder::new().build(sink)?;
22        let symbol_table_writer = RawBinaryWriterBuilder::new().build(Vec::new())?;
23        // TODO: Track whether we've written an IVM and emit it at flush time instead
24        raw_writer.write_ion_version_marker(1, 0)?;
25        let binary_writer = BinaryWriter {
26            raw_writer,
27            symbol_table: Default::default(),
28            num_pending_symbols: 0,
29            symbol_table_writer,
30        };
31        Ok(binary_writer)
32    }
33}
34
35impl Default for BinaryWriterBuilder {
36    fn default() -> Self {
37        BinaryWriterBuilder::new()
38    }
39}
40
41/**
42 * An application-level binary Ion writer. This writer manages a symbol table and so can convert
43 * symbol IDs to their corresponding text.
44 */
45pub struct BinaryWriter<W: Write> {
46    raw_writer: RawBinaryWriter<W>,
47    symbol_table: SymbolTable,
48    // The number of symbols that have been added to the in-memory symbol table but
49    // whose definitions have not yet been written to the output stream.
50    num_pending_symbols: usize,
51    // The BinaryWriter uses the `symbol_table_writer` to encode local symbol tables to a buffer
52    // and then flush them to output before flushing the contents of the `raw_writer`. This guarantees
53    // that any symbols referenced in the `raw_writer`'s contents will be defined in the Ion stream
54    // before the reference appears.
55    symbol_table_writer: RawBinaryWriter<Vec<u8>>,
56}
57
58impl<W: Write> BinaryWriter<W> {
59    fn get_or_create_symbol_id(&mut self, text: &str) -> SymbolId {
60        if let Some(symbol_id) = self.symbol_table.sid_for(&text) {
61            // If the provided text is in the symbol table, use the associated symbol ID...
62            symbol_id
63        } else {
64            // ...otherwise, add it to the symbol table and return the new symbol ID.
65            self.num_pending_symbols += 1;
66            self.symbol_table.intern(text)
67        }
68    }
69
70    fn write_symbol_table_for_pending_symbols(&mut self) -> IonResult<()> {
71        let pending_symbols_starting_index = self.symbol_table.len() - self.num_pending_symbols;
72        let pending_symbols = self
73            .symbol_table
74            .symbols_tail(pending_symbols_starting_index);
75
76        self.symbol_table_writer
77            .add_annotation(system_symbol_ids::ION_SYMBOL_TABLE);
78        self.symbol_table_writer.step_in(IonType::Struct)?;
79
80        self.symbol_table_writer
81            .set_field_name(system_symbol_ids::IMPORTS);
82        self.symbol_table_writer
83            .write_symbol(system_symbol_ids::ION_SYMBOL_TABLE)?;
84
85        self.symbol_table_writer
86            .set_field_name(system_symbol_ids::SYMBOLS);
87        self.symbol_table_writer.step_in(IonType::List)?;
88        for symbol in pending_symbols {
89            match symbol.text() {
90                Some(text) => self.symbol_table_writer.write_string(text),
91                None => self.symbol_table_writer.write_null(IonType::Null),
92            }?;
93        }
94        self.symbol_table_writer.step_out()?; // End symbols list
95
96        self.symbol_table_writer.step_out()?; // End $ion_symbol_table::{...}
97        self.symbol_table_writer.flush()?;
98
99        // Write the symbol_table_writer's encoded bytes to the raw_writer's output
100        let bytes = &self.symbol_table_writer.output()[..];
101        self.raw_writer.output_mut().write_all(bytes)?;
102        self.symbol_table_writer.output_mut().clear();
103
104        Ok(())
105    }
106}
107
108impl<W: Write> IonWriter for BinaryWriter<W> {
109    type Output = W;
110
111    fn supports_text_symbol_tokens(&self) -> bool {
112        // The BinaryWriter can always write text field names, annotations, and symbols
113        // after first adding the provided text to the symbol table.
114        true
115    }
116
117    fn set_annotations<I, A>(&mut self, annotations: I)
118    where
119        A: AsRawSymbolTokenRef,
120        I: IntoIterator<Item = A>,
121    {
122        for annotation in annotations {
123            let symbol_id = match annotation.as_raw_symbol_token_ref() {
124                RawSymbolTokenRef::SymbolId(symbol_id) => {
125                    if self.symbol_table.sid_is_valid(symbol_id) {
126                        symbol_id
127                    } else {
128                        panic!("Cannot set symbol ID ${symbol_id} as annotation. It is undefined.");
129                    }
130                }
131                RawSymbolTokenRef::Text(text) => self.get_or_create_symbol_id(text),
132            };
133            self.raw_writer.add_annotation(symbol_id);
134        }
135    }
136
137    fn write_symbol<A: AsRawSymbolTokenRef>(&mut self, value: A) -> IonResult<()> {
138        let symbol_id = match value.as_raw_symbol_token_ref() {
139            RawSymbolTokenRef::SymbolId(symbol_id) => {
140                if self.symbol_table.sid_is_valid(symbol_id) {
141                    symbol_id
142                } else {
143                    return illegal_operation(format!(
144                        "Cannot write symbol ID ${symbol_id} as a symbol value. It is undefined."
145                    ));
146                }
147            }
148            RawSymbolTokenRef::Text(text) => self.get_or_create_symbol_id(text),
149        };
150        self.raw_writer.write_symbol(symbol_id)
151    }
152
153    fn set_field_name<A: AsRawSymbolTokenRef>(&mut self, name: A) {
154        let text = match name.as_raw_symbol_token_ref() {
155            RawSymbolTokenRef::SymbolId(symbol_id) => {
156                if self.symbol_table.sid_is_valid(symbol_id) {
157                    symbol_id
158                } else {
159                    panic!("Cannot set symbol ID ${symbol_id} as field name. It is undefined.");
160                }
161            }
162            RawSymbolTokenRef::Text(text) => self.get_or_create_symbol_id(text),
163        };
164        self.raw_writer.set_field_name(text);
165    }
166
167    fn flush(&mut self) -> IonResult<()> {
168        // Check to see if there are any pending symbols.
169        if self.num_pending_symbols > 0 {
170            self.write_symbol_table_for_pending_symbols()?;
171            self.num_pending_symbols = 0;
172        }
173        self.raw_writer.flush()
174    }
175
176    delegate! {
177        to self.raw_writer {
178            fn ion_version(&self) -> (u8, u8);
179            fn write_ion_version_marker(&mut self, major: u8, minor: u8) -> IonResult<()>;
180            fn write_null(&mut self, ion_type: IonType) -> IonResult<()>;
181            fn write_bool(&mut self, value: bool) -> IonResult<()>;
182            fn write_i64(&mut self, value: i64) -> IonResult<()>;
183            fn write_int(&mut self, value: &Int) -> IonResult<()>;
184            fn write_f32(&mut self, value: f32) -> IonResult<()>;
185            fn write_f64(&mut self, value: f64) -> IonResult<()>;
186            fn write_decimal(&mut self, value: &Decimal) -> IonResult<()>;
187            fn write_timestamp(&mut self, value: &Timestamp) -> IonResult<()>;
188            fn write_string<A: AsRef<str>>(&mut self, value: A) -> IonResult<()>;
189            fn write_clob<A: AsRef<[u8]>>(&mut self, value: A) -> IonResult<()>;
190            fn write_blob<A: AsRef<[u8]>>(&mut self, value: A) -> IonResult<()>;
191            fn step_in(&mut self, container_type: IonType) -> IonResult<()>;
192            fn parent_type(&self) -> Option<IonType>;
193            fn depth(&self) -> usize;
194            fn step_out(&mut self) -> IonResult<()>;
195            fn output(&self) -> &Self::Output;
196            fn output_mut(&mut self) -> &mut Self::Output;
197        }
198    }
199}
200
201#[cfg(test)]
202mod tests {
203    use super::*;
204    use crate::reader::ReaderBuilder;
205    use crate::stream_reader::IonReader;
206
207    use crate::StreamItem::Value;
208
209    #[test]
210    fn intern_field_names() -> IonResult<()> {
211        let mut buffer = Vec::new();
212        let mut binary_writer = BinaryWriterBuilder::new().build(&mut buffer)?;
213        binary_writer.step_in(IonType::Struct)?;
214        binary_writer.set_field_name("foo");
215        binary_writer.write_symbol("bar")?;
216        binary_writer.step_out()?;
217        binary_writer.flush()?;
218
219        let mut reader = ReaderBuilder::new().build(buffer)?;
220        assert_eq!(Value(IonType::Struct), reader.next()?);
221        reader.step_in()?;
222        assert_eq!(Value(IonType::Symbol), reader.next()?);
223        assert_eq!("foo", reader.field_name()?);
224        assert_eq!("bar", reader.read_symbol()?.text_or_error()?);
225
226        Ok(())
227    }
228
229    #[test]
230    fn intern_annotations() -> IonResult<()> {
231        let mut buffer = Vec::new();
232        let mut binary_writer = BinaryWriterBuilder::new().build(&mut buffer)?;
233        binary_writer.set_annotations(["foo", "bar"]);
234        binary_writer.write_i64(5)?;
235        binary_writer.flush()?;
236
237        let mut reader = ReaderBuilder::new().build(buffer)?;
238        assert_eq!(Value(IonType::Int), reader.next()?);
239        let mut annotations = reader.annotations();
240        assert_eq!("foo", annotations.next().unwrap()?);
241        assert_eq!("bar", annotations.next().unwrap()?);
242
243        Ok(())
244    }
245
246    #[test]
247    fn intern_symbols() -> IonResult<()> {
248        let mut buffer = Vec::new();
249        let mut binary_writer = BinaryWriterBuilder::new().build(&mut buffer)?;
250        binary_writer.write_symbol("foo")?;
251        binary_writer.write_symbol("bar")?;
252        binary_writer.write_symbol("baz")?;
253        binary_writer.flush()?;
254
255        let mut reader = ReaderBuilder::new().build(buffer)?;
256        assert_eq!(Value(IonType::Symbol), reader.next()?);
257        assert_eq!("foo", reader.read_symbol()?);
258        assert_eq!(Value(IonType::Symbol), reader.next()?);
259        assert_eq!("bar", reader.read_symbol()?);
260        assert_eq!(Value(IonType::Symbol), reader.next()?);
261        assert_eq!("baz", reader.read_symbol()?);
262
263        Ok(())
264    }
265}