ion_binary_rs/
ion_encoder.rs

1use crate::binary_encoder::{
2    encode_blob, encode_bool, encode_datetime, encode_decimal, encode_float64, encode_integer,
3    encode_null, encode_uint, encode_varuint, ION_LEN_ON_HEADER_WHEN_EXTRA_LEN_FIELD_REQUIRED,
4};
5use crate::binary_parser_types::{SystemSymbolIds, SYSTEM_SYMBOL_TABLE};
6use crate::symbol_table::SymbolContext;
7use crate::IonValue;
8use num_bigint::{BigInt, BigUint};
9use std::collections::HashMap;
10use std::convert::TryFrom;
11
12/// Allows to binary encode one or multiple IonValue.
13///
14/// Given how Ion format works there are two methods in order to use
15/// this utility.
16///
17/// - `add` allows to add IonValue to the buffer to later encoding.
18/// - `encode` takes all biffered values and encodes them, generating
19/// the symbol's table and the ion header. It returns a Vec<u8>.
20///
21/// ```rust,no_run
22///
23/// use ion_binary_rs::{IonEncoder, IonParser, IonValue};
24/// use std::collections::HashMap;
25///
26/// let mut ion_struct = HashMap::new();
27///
28/// ion_struct.insert("Model".to_string(), IonValue::String("CLK 350".to_string()));
29/// ion_struct.insert("Type".to_string(), IonValue::String("Sedan".to_string()));
30/// ion_struct.insert("Color".to_string(), IonValue::String("White".to_string()));
31/// ion_struct.insert(
32///     "VIN".to_string(),
33///     IonValue::String("1C4RJFAG0FC625797".to_string()),
34/// );
35/// ion_struct.insert("Make".to_string(), IonValue::String("Mercedes".to_string()));
36/// ion_struct.insert("Year".to_string(), IonValue::Integer(2019));
37///
38/// let ion_value = IonValue::Struct(ion_struct);
39///
40/// let mut encoder = IonEncoder::new();
41///
42/// encoder.add(ion_value.clone());
43/// let bytes = encoder.encode();
44///
45/// let resulting_ion_value = IonParser::new(&bytes[..]).consume_value().unwrap().0;
46///
47/// assert_eq!(ion_value, resulting_ion_value);
48/// ```
49#[derive(Debug)]
50pub struct IonEncoder {
51    current_buffer: Vec<IonValue>,
52    symbol_table: SymbolContext,
53}
54
55impl Default for IonEncoder {
56    fn default() -> Self {
57        Self::new()
58    }
59}
60
61impl IonEncoder {
62    pub fn new() -> IonEncoder {
63        IonEncoder {
64            current_buffer: vec![],
65            symbol_table: SymbolContext::new(),
66        }
67    }
68
69    pub fn add(&mut self, value: IonValue) {
70        self.current_buffer.push(value);
71    }
72
73    pub fn encode(&mut self) -> Vec<u8> {
74        let mut values = vec![];
75
76        values.append(&mut self.current_buffer);
77
78        let mut values_buffer: Vec<u8> = values
79            .into_iter()
80            .flat_map(|value| self.encode_value(&value))
81            .collect();
82
83        let mut symbol_table = self.encode_current_symbol_table();
84
85        let mut buffer = IonEncoder::get_ion_1_0_header();
86
87        buffer.append(&mut symbol_table);
88        buffer.append(&mut values_buffer);
89
90        buffer
91    }
92
93    fn get_ion_1_0_header() -> Vec<u8> {
94        vec![0xE0, 0x01, 0x00, 0xEA]
95    }
96
97    pub(crate) fn encode_value(&mut self, value: &IonValue) -> Vec<u8> {
98        match value {
99            IonValue::Null(value) => encode_null(value),
100            IonValue::Bool(value) => encode_bool(value),
101            IonValue::Integer(value) => encode_integer(&BigInt::from(*value)),
102            IonValue::BigInteger(value) => encode_integer(value),
103            IonValue::Float(value) => encode_float64(value),
104            IonValue::Decimal(value) => encode_decimal(value),
105            IonValue::String(value) => encode_blob(8, value.as_bytes()),
106            IonValue::Clob(value) => encode_blob(9, value),
107            IonValue::Blob(value) => encode_blob(10, value),
108            IonValue::DateTime(value) => encode_datetime(value),
109            IonValue::List(value) => self.encode_list(value, false),
110            IonValue::SExpr(value) => self.encode_list(value, true),
111            IonValue::Symbol(symbol) => self.encode_symbol(symbol),
112            IonValue::Struct(value) => self.encode_struct(value),
113            IonValue::Annotation(annotations, value) => self.encode_annotation(annotations, value),
114        }
115    }
116
117    pub(crate) fn encode_symbol(&mut self, symbol: &str) -> Vec<u8> {
118        let mut buffer: Vec<u8> = vec![];
119
120        let mut header: u8 = 0x70;
121
122        let id = self.symbol_table.insert_symbol(symbol);
123
124        let mut id_bytes = encode_uint(&BigUint::from(id));
125        let id_bytes_len = id_bytes.len();
126        let has_len_field = id_bytes_len >= ION_LEN_ON_HEADER_WHEN_EXTRA_LEN_FIELD_REQUIRED.into();
127
128        if has_len_field {
129            header += ION_LEN_ON_HEADER_WHEN_EXTRA_LEN_FIELD_REQUIRED;
130            buffer.push(header);
131            let mut id_bytes_len_bytes = encode_varuint(&id_bytes_len.to_be_bytes());
132            buffer.append(&mut id_bytes_len_bytes);
133        } else {
134            header += u8::try_from(id_bytes_len).unwrap();
135            buffer.push(header);
136        };
137
138        buffer.append(&mut id_bytes);
139
140        buffer
141    }
142
143    pub(crate) fn encode_list(&mut self, values: &[IonValue], is_sexp: bool) -> Vec<u8> {
144        let mut buffer: Vec<u8> = vec![];
145
146        for value in values {
147            let mut bytes = self.encode_value(value);
148
149            buffer.append(&mut bytes);
150        }
151
152        let buffer_len = buffer.len();
153        let has_len_field = buffer_len >= ION_LEN_ON_HEADER_WHEN_EXTRA_LEN_FIELD_REQUIRED.into();
154
155        let mut header: u8 = if is_sexp { 0xC0 } else { 0xB0 };
156
157        if has_len_field {
158            header += ION_LEN_ON_HEADER_WHEN_EXTRA_LEN_FIELD_REQUIRED;
159        } else {
160            header += u8::try_from(buffer_len).unwrap();
161        }
162
163        let mut buffer = if has_len_field {
164            let mut buffer_len_bytes = encode_varuint(&buffer_len.to_be_bytes());
165            buffer_len_bytes.append(&mut buffer);
166            buffer_len_bytes
167        } else {
168            buffer
169        };
170
171        buffer.insert(0, header);
172
173        buffer
174    }
175
176    pub(crate) fn encode_annotation(
177        &mut self,
178        annotations: &[String],
179        value: &IonValue,
180    ) -> Vec<u8> {
181        let mut annot_buffer: Vec<u8> = vec![];
182
183        for annot in annotations {
184            let annot_symbol = self.symbol_table.insert_symbol(annot);
185            let mut annot_symbol_bytes = encode_varuint(&annot_symbol.to_be_bytes());
186            annot_buffer.append(&mut annot_symbol_bytes);
187        }
188
189        let mut annot_len_bytes = encode_varuint(&annot_buffer.len().to_be_bytes());
190
191        let mut value_bytes = self.encode_value(value);
192
193        annot_len_bytes.append(&mut annot_buffer);
194
195        let mut buffer = annot_len_bytes;
196
197        buffer.append(&mut value_bytes);
198
199        let len = buffer.len();
200        let has_len_field = len >= ION_LEN_ON_HEADER_WHEN_EXTRA_LEN_FIELD_REQUIRED.into();
201
202        let mut header = 0xE0;
203
204        let mut final_buffer: Vec<u8> = vec![];
205
206        if has_len_field {
207            header += ION_LEN_ON_HEADER_WHEN_EXTRA_LEN_FIELD_REQUIRED;
208            final_buffer.push(header);
209            let mut len_bytes = encode_varuint(&len.to_be_bytes());
210            final_buffer.append(&mut len_bytes);
211        } else {
212            header += u8::try_from(len).unwrap();
213            final_buffer.push(header);
214        }
215
216        final_buffer.append(&mut buffer);
217
218        final_buffer
219    }
220
221    pub(crate) fn encode_struct(&mut self, value: &HashMap<String, IonValue>) -> Vec<u8> {
222        let mut content_buffer: Vec<u8> = vec![];
223
224        for (key, value) in value {
225            let symbol = self.symbol_table.insert_symbol(key);
226            let mut symbol_bytes = encode_varuint(&symbol.to_be_bytes());
227            let mut value_bytes = self.encode_value(value);
228            content_buffer.append(&mut symbol_bytes);
229            content_buffer.append(&mut value_bytes);
230        }
231
232        let content_len = content_buffer.len();
233        let has_len_field = content_len >= ION_LEN_ON_HEADER_WHEN_EXTRA_LEN_FIELD_REQUIRED.into();
234
235        let mut header = 0xD0;
236
237        let mut buffer: Vec<u8> = vec![];
238
239        if has_len_field {
240            header += ION_LEN_ON_HEADER_WHEN_EXTRA_LEN_FIELD_REQUIRED;
241            buffer.push(header);
242            let mut content_len_bytes = encode_varuint(&content_len.to_be_bytes());
243            buffer.append(&mut content_len_bytes);
244        } else {
245            header += u8::try_from(content_len).unwrap();
246            buffer.push(header);
247        }
248
249        buffer.append(&mut content_buffer);
250
251        buffer
252    }
253
254    pub(crate) fn encode_current_symbol_table(&mut self) -> Vec<u8> {
255        let symbols = self.symbol_table.dump_all_local_symbols();
256
257        let symbols = IonValue::List(symbols.into_iter().map(IonValue::String).collect());
258
259        let mut annotation_struct = HashMap::new();
260
261        let symbols_symbol = SYSTEM_SYMBOL_TABLE[SystemSymbolIds::Symbols as usize].to_string();
262        let local_table_annotation_symbol =
263            SYSTEM_SYMBOL_TABLE[SystemSymbolIds::IonSymbolTable as usize].to_string();
264
265        annotation_struct.insert(symbols_symbol, symbols);
266
267        let annotation_struct = IonValue::Struct(annotation_struct);
268
269        let annotation = IonValue::Annotation(
270            vec![local_table_annotation_symbol],
271            Box::new(annotation_struct),
272        );
273
274        self.encode_value(&annotation)
275    }
276}