ion_rs/binary/
raw_binary_writer.rs

1use std::io::Write;
2use std::ops::Range;
3use std::{io, mem};
4
5use bytes::BufMut;
6use num_bigint::Sign;
7use num_traits::Zero;
8
9use crate::binary::constants::v1_0::IVM;
10use crate::binary::uint::DecodedUInt;
11use crate::binary::var_uint::VarUInt;
12use crate::raw_symbol_token_ref::{AsRawSymbolTokenRef, RawSymbolTokenRef};
13use crate::result::{illegal_operation, IonResult};
14use crate::types::{ContainerType, Decimal, SymbolId, Timestamp};
15use crate::writer::IonWriter;
16use crate::{Int, IonType};
17
18use super::decimal::DecimalBinaryEncoder;
19use super::timestamp::TimestampBinaryEncoder;
20use super::uint;
21
22pub struct RawBinaryWriterBuilder {
23    // Nothing yet
24}
25
26impl RawBinaryWriterBuilder {
27    pub fn new() -> Self {
28        RawBinaryWriterBuilder {}
29    }
30
31    /// Creates a new RawBinaryWriter that will write its encoded output to the provided
32    /// io::Write sink.
33    pub fn build<W: Write>(self, out: W) -> IonResult<RawBinaryWriter<W>> {
34        let mut levels = Vec::with_capacity(INITIAL_ENCODING_LEVELS_CAPACITY);
35        // Create an EncodingLevel to represent the top level. It has no annotations.
36        levels.push(EncodingLevel::new(ContainerType::TopLevel, None, 0, 0));
37        // Create an empty IoRange for top-level leading scalar values.
38        let mut io_ranges = Vec::with_capacity(INITIAL_IO_RANGE_CAPACITY);
39        io_ranges.push(0usize..0);
40        let raw_binary_writer = RawBinaryWriter {
41            buffer: Vec::with_capacity(INITIAL_ENCODING_BUFFER_CAPACITY),
42            io_ranges,
43            levels,
44            out,
45            annotations_all_levels: Vec::with_capacity(INITIAL_ANNOTATIONS_CAPACITY),
46            num_annotations_current_value: 0,
47            field_id: None,
48            contiguous_encoding: Vec::with_capacity(INITIAL_ENCODING_BUFFER_CAPACITY),
49        };
50
51        // Currently, this method cannot fail. However, the other builder APIs return an
52        // IonResult, so we've followed suit here.
53        Ok(raw_binary_writer)
54    }
55}
56
57impl Default for RawBinaryWriterBuilder {
58    fn default() -> Self {
59        RawBinaryWriterBuilder::new()
60    }
61}
62
63// Ion's length prefixing requires that elements in a stream be encoded out of order.
64// For example, to write the annotated list $ion::["foo", "bar"], the writer must:
65//   1. Encode "foo"
66//   2. Encode "bar"
67//   3. Use the combined length of "foo" and "bar" to encode the header for the list
68//   4. Encode the annotation sequence '$ion'
69//   5. Encode the length of the annotation sequence
70//   5. Use the combined length of 'foo' and the list to write the annotations wrapper
71//
72// The BinarySystemWriter encodes these out-of-order byte sequences in a temporary buffer and tracks
73// which slices of the buffer should be written out first by maintaining a queue of Range<usize>
74// entries. These entries are referred to as `IoRange`s, as they are the buffer ranges that
75// are actually sent to `io::write` whenever `flush()` is called.
76type IoRange = Range<usize>;
77
78// When encoding the above example data, the buffer with out-of-order byte sequences might look
79// like this:
80//
81// [offset] 0             4             8             12   13   14   15
82// buffer : e0 01 00 ea | 83 66 6f 6f | 83 62 61 72 | b8 | 81 | 81 | eb
83//          ^             ^             ^             ^    ^    ^    ^-- 11-byte annotation wrapper
84//          |             |             |             |    |    +------- Annotation seq length 1
85//          |             |             |             |    +------------ Annotation 1 ('$ion')
86//          |             |             |             +----------------- 8-byte list header
87//          |             |             +------------------------------- 3-byte string "bar"
88//          |             +--------------------------------------------- 3-byte string "foo"
89//          +----------------------------------------------------------- Ion 1.0 version marker
90//
91// Meanwhile, the writer's IoRange queue would look like this:
92//
93//     0..4, 15..16, 14..15, 13..14, 12..13, 4..12
94//
95// Ranges have inclusive starts and exclusive ends, so the range 14..15 includes a single byte at
96// index 14.
97//
98// When the writer's `flush()` method is called, each IoRange is turned into a slice of the buffer
99// and written to the io::Write sink.
100//
101//     e0 01 00 ea eb 81 81 b8 83 66 6f 6f 83 62 61 72
102
103// Stores information about each level into which the writer has stepped, including its
104// annotations, field_id, and container type.
105#[derive(Debug)]
106struct EncodingLevel {
107    container_type: ContainerType,
108    field_id: Option<SymbolId>,
109    // Annotations are stored in a common Vec on the BinarySystemWriter. Each EncodingLevel tracks
110    // how many annotations it had, allowing that Vec to be treated as a stack. Stepping into
111    // a new level pushes `num_annotations` symbol IDs onto the Vec and stepping out pops
112    // `num_annotations` back off the stack.
113    num_annotations: u8,
114    // Index of the IoRange for this container's type descriptor and length. When the writer
115    // steps out of this level, the type descriptor IoRange will be retrieved and populated.
116    td_io_range_index: usize,
117}
118
119impl EncodingLevel {
120    fn new(
121        container_type: ContainerType,
122        field_id: Option<SymbolId>,
123        num_annotations: u8,
124        td_io_range_index: usize,
125    ) -> EncodingLevel {
126        EncodingLevel {
127            container_type,
128            field_id,
129            num_annotations,
130            td_io_range_index,
131        }
132    }
133
134    // Visits all of the IoRanges belonging to this EncodingLevel and notes their total length.
135    // This length will be written out as a length prefix for the container.
136    fn calculate_final_size(&self, io_ranges: &mut [Range<usize>]) -> usize {
137        io_ranges[self.td_io_range_index..]
138            .iter()
139            .map(|r| r.len())
140            .sum()
141    }
142}
143
144/// A system-level streaming binary Ion writer. This writer does not provide symbol table
145/// management; symbol-related operations (e.g. setting field IDs and annotations or writing symbol
146/// values) require a valid symbol ID to be provided by the caller.
147///
148/// To produce a valid binary Ion stream, the writer MUST call
149/// [RawBinaryWriter::write_ion_version_marker] before writing any data.
150#[derive(Debug)]
151pub struct RawBinaryWriter<W: Write> {
152    // A byte buffer to encode individual components of the stream.
153    buffer: Vec<u8>,
154    // Slices of the buffer to write out in order when flush() is called.
155    io_ranges: Vec<IoRange>,
156    // Stack for tracking step_in/step_out
157    levels: Vec<EncodingLevel>,
158    // An io::Write implementation to be used as a sink for encoded data.
159    out: W,
160    // The field ID of the current value. If the writer is not in a struct, this will be None.
161    field_id: Option<SymbolId>,
162    // A Vec into which all EncodingLevels can store their annotations. Sharing this Vec avoids
163    // allocating new space for each container the writer steps into.
164    annotations_all_levels: Vec<SymbolId>,
165    // The number of annotations at the tail of `annotations_all_levels` belonging to the current
166    // value.
167    num_annotations_current_value: u8,
168    // Scratch space for the flush() method to rearrange the contents of `buffer` before writing
169    // the data to `out`.
170    contiguous_encoding: Vec<u8>,
171}
172
173// The largest possible 'L' (length) value that can be written directly in a type descriptor byte.
174// Larger length values will need to be written as a VarUInt following the type descriptor.
175pub(crate) const MAX_INLINE_LENGTH: usize = 13;
176
177// The number of IoRanges needed to write out an annotations wrapper, not including the IoRange
178// belonging to the wrapped value. (One IoRange for each of: the annotations sequence, the length
179// of the annotations sequence, and the annotations wrapper header.)
180const IO_RANGES_PER_ANNOTATION_WRAPPER: usize = 3;
181
182// These values are initial sizes for various `Vec`s that will be resized if necessary.
183const INITIAL_ENCODING_BUFFER_CAPACITY: usize = 8 * 1024;
184const INITIAL_ENCODING_LEVELS_CAPACITY: usize = 16;
185const INITIAL_IO_RANGE_CAPACITY: usize = 128;
186const INITIAL_ANNOTATIONS_CAPACITY: usize = 4;
187
188impl<W: Write> RawBinaryWriter<W> {
189    // Uses the provided closure to encode data to the buffer. Returns the range of the buffer
190    // now occupied by the encoded bytes.
191    #[inline]
192    fn encode_to_buffer(
193        &mut self,
194        mut encode_fn: impl FnMut(&mut Self) -> IonResult<()>,
195    ) -> IonResult<IoRange> {
196        let start = self.buffer.len();
197        encode_fn(self)?;
198        let end = self.buffer.len();
199        Ok(start..end)
200    }
201
202    // Returns true if the last container that the writer stepped into was a struct; false otherwise.
203    #[inline]
204    fn is_in_struct(&self) -> bool {
205        self.levels
206            .last()
207            .map(|level| level.container_type == ContainerType::Struct)
208            .unwrap_or(false)
209    }
210
211    // Modifies the last IoRange to include the next `number_of_bytes`.
212    // Used when writing scalars, which can always extend the most recent range instead of adding
213    // a new one.
214    #[inline]
215    fn extend_last_range(&mut self, number_of_bytes: usize) {
216        let last_range = self
217            .io_ranges
218            .last_mut()
219            .expect("io_ranges unexpectedly empty.");
220        last_range.end += number_of_bytes;
221    }
222
223    // Handles before-and-after tasks common to writing all non-container values, like encoding
224    // field IDs and annotation wrappers.
225    fn write_scalar(
226        &mut self,
227        mut write_fn: impl FnMut(&mut Vec<u8>) -> IonResult<()>,
228    ) -> IonResult<()> {
229        // If we're in a struct, encode the field ID first.
230        if self.is_in_struct() {
231            let field_id = self.expect_field_id()? as u64;
232            let bytes_written = VarUInt::write_u64(&mut self.buffer, field_id)?;
233            self.extend_last_range(bytes_written);
234            self.field_id = None;
235        }
236
237        if self.has_annotations() {
238            return self.encode_annotated_scalar(write_fn);
239        }
240
241        let encoded_range = self.encode_to_buffer(|writer| write_fn(&mut writer.buffer))?;
242        self.extend_last_range(encoded_range.len());
243
244        Ok(())
245    }
246
247    // Uses the provided closure to encode a scalar value, then encodes the annotation wrapper
248    // based on the encoded value's length and the configured annotations sequence.
249    fn encode_annotated_scalar(
250        &mut self,
251        mut scalar_write_fn: impl FnMut(&mut Vec<u8>) -> IonResult<()>,
252    ) -> IonResult<()> {
253        // Encode the scalar into the buffer, but do not push the IoRange yet.
254        let value_io_range: IoRange =
255            self.encode_to_buffer(|writer| scalar_write_fn(&mut writer.buffer))?;
256
257        // Create ranges that will ultimately point to the encoded components of the annotations
258        // wrapper for the value.
259        let mut header_io_range: Range<usize> = 0..0;
260        let mut annotations_seq_length_io_range: Range<usize> = 0..0;
261        let mut annotations_seq_io_range: Range<usize> = 0..0;
262
263        // Using the encoded length of the value, encode the annotations wrapper and populate
264        // the IO ranges we created above.
265        self.encode_annotation_wrapper(
266            &mut header_io_range,
267            &mut annotations_seq_length_io_range,
268            &mut annotations_seq_io_range,
269            value_io_range.len(),
270        )?;
271
272        // Push the IO ranges in the correct order so the encoded bytes will be written in the
273        // correct order when the user calls `flush()`.
274        self.io_ranges.extend_from_slice(&[
275            header_io_range,
276            annotations_seq_length_io_range,
277            annotations_seq_io_range,
278            value_io_range,
279        ]);
280
281        self.push_empty_io_range();
282
283        Ok(())
284    }
285
286    // Writes the annotations wrapper for a value of a given length. Callers should encode the
287    // value to the buffer, call this method with the value's encoded length, then push
288    // the populated IoRanges in the necessary order.
289    fn encode_annotation_wrapper(
290        &mut self,
291        header_io_range: &mut IoRange,
292        annotations_seq_length_io_range: &mut IoRange,
293        annotations_seq_io_range: &mut IoRange,
294        wrapped_value_length: usize,
295    ) -> IonResult<()> {
296        // Encode the sequence of annotations and make a note of the encoded length.
297        // The return value of mem::replace is the original range value, which is always 0..0.
298        // We can safely ignore it.
299        let _ = mem::replace(
300            annotations_seq_io_range,
301            self.encode_to_buffer(|writer| {
302                let range = writer.current_value_annotations_range();
303                let annotations = &writer.annotations_all_levels[range];
304                for annotation_id in annotations {
305                    VarUInt::write_u64(&mut writer.buffer, *annotation_id as u64)?;
306                }
307                Ok(())
308            })?,
309        );
310        let annotation_sequence_encoded_length = annotations_seq_io_range.len();
311
312        // Encode the length of the annotations sequence as a VarUInt.
313        let _ = mem::replace(
314            annotations_seq_length_io_range,
315            self.encode_to_buffer(|writer| {
316                let _num_bytes = VarUInt::write_u64(
317                    &mut writer.buffer,
318                    annotation_sequence_encoded_length as u64,
319                )?;
320                Ok(())
321            })?,
322        );
323
324        // The length of the wrapper is the sum total of:
325        // 1. The length of the encoded annotations sequence
326        // 2. The length of the VarUInt representation of #1 above.
327        // 3. The length of the value being annotated.
328        let wrapper_length = annotations_seq_io_range.len()
329            + annotations_seq_length_io_range.len()
330            + wrapped_value_length;
331
332        // Now that we know the wrapper length, encode the annotation wrapper header.
333        let _ = mem::replace(
334            header_io_range,
335            self.encode_to_buffer(|writer| {
336                let type_descriptor: u8;
337                if wrapper_length <= MAX_INLINE_LENGTH {
338                    // Use inline length encoding
339                    type_descriptor = 0xE0 | wrapper_length as u8;
340                    writer.buffer.push(type_descriptor);
341                } else {
342                    type_descriptor = 0xEE; // VarUInt length encoding
343                    writer.buffer.push(type_descriptor);
344                    VarUInt::write_u64(&mut writer.buffer, wrapper_length as u64)?;
345                }
346                Ok(())
347            })?,
348        );
349
350        self.clear_annotations();
351        Ok(())
352    }
353
354    // Returns the range of annotations in `annotations_all_levels` that belong to the current value.
355    // This function originally borrowed a slice of `annotations_all_levels`, but this lead to ownership
356    // conflicts; all of `self` would remain borrowed. Returning the range instead allows the compiler
357    // to see that only `self.annotations_all_levels` is being borrowed.
358    #[inline]
359    fn current_value_annotations_range(&self) -> Range<usize> {
360        let end = self.annotations_all_levels.len();
361        let start = end - self.num_annotations_current_value as usize;
362        start..end
363    }
364
365    #[inline]
366    pub fn clear_annotations(&mut self) {
367        if self.num_annotations_current_value > 0 {
368            let new_length =
369                self.annotations_all_levels.len() - self.num_annotations_current_value as usize;
370            self.annotations_all_levels.truncate(new_length);
371            self.num_annotations_current_value = 0;
372        }
373    }
374
375    #[inline]
376    pub fn has_annotations(&self) -> bool {
377        self.num_annotations_current_value > 0
378    }
379
380    pub fn write_symbol_id(&mut self, symbol_id: SymbolId) -> IonResult<()> {
381        self.write_scalar(|enc_buffer| {
382            const SYMBOL_BUFFER_SIZE: usize = mem::size_of::<u64>();
383            let mut buffer = [0u8; SYMBOL_BUFFER_SIZE];
384            let mut writer = io::Cursor::new(&mut buffer).writer();
385            let encoded_length = DecodedUInt::write_u64(&mut writer, symbol_id as u64)?;
386
387            let type_descriptor: u8;
388            if encoded_length <= MAX_INLINE_LENGTH {
389                type_descriptor = 0x70 | encoded_length as u8;
390                enc_buffer.push(type_descriptor);
391            } else {
392                type_descriptor = 0x7E;
393                enc_buffer.push(type_descriptor);
394                VarUInt::write_u64(enc_buffer, encoded_length as u64)?;
395            }
396            let raw_buffer = writer.into_inner().into_inner();
397            enc_buffer.extend_from_slice(&raw_buffer[..encoded_length]);
398            Ok(())
399        })
400    }
401
402    fn write_lob(enc_buffer: &mut Vec<u8>, value: &[u8], type_code: u8) -> IonResult<()> {
403        let encoded_length = value.len();
404        let type_descriptor: u8;
405        if encoded_length <= MAX_INLINE_LENGTH {
406            type_descriptor = type_code | encoded_length as u8;
407            enc_buffer.push(type_descriptor);
408        } else {
409            type_descriptor = type_code | 0x0E;
410            enc_buffer.push(type_descriptor);
411            VarUInt::write_u64(enc_buffer, encoded_length as u64)?;
412        }
413        enc_buffer.extend_from_slice(value);
414        Ok(())
415    }
416
417    // Creates an empty IoRange starting from the next unoccupied byte in the buffer.
418    fn push_empty_io_range(&mut self) {
419        let next_byte_index = self.buffer.len();
420        self.io_ranges.push(next_byte_index..next_byte_index);
421    }
422
423    pub fn set_field_id(&mut self, field_id: SymbolId) {
424        self.field_id = Some(field_id);
425    }
426
427    // Called when the writer is in a struct and a missing field ID is an error
428    fn expect_field_id(&self) -> IonResult<usize> {
429        match self.field_id {
430            Some(field_id) => Ok(field_id),
431            None => {
432                illegal_operation("`set_field_id()` must be called before each field in a struct.")
433            }
434        }
435    }
436
437    // When step_out() is called and the container has been written, this function uses the encoded
438    // length to write the container's annotations wrapper.
439    fn encode_container_annotations(
440        &mut self,
441        td_io_range_index: usize,
442        container_size: usize,
443    ) -> IonResult<()> {
444        // Create IoRanges that will ultimately point to the encoded components of the annotations
445        // wrapper for the value.
446        let mut header_io_range: Range<usize> = 0..0;
447        let mut annotations_seq_length_io_range: Range<usize> = 0..0;
448        let mut annotations_seq_io_range: Range<usize> = 0..0;
449
450        // Encode the annotation wrapper, populating the ranges above in the process.
451        self.encode_annotation_wrapper(
452            &mut header_io_range,
453            &mut annotations_seq_length_io_range,
454            &mut annotations_seq_io_range,
455            container_size,
456        )?;
457
458        // Populate each of the reserved annotation IO ranges using the results from above.
459        let header_io_range_index = td_io_range_index - IO_RANGES_PER_ANNOTATION_WRAPPER;
460        let _ = mem::replace(&mut self.io_ranges[header_io_range_index], header_io_range);
461
462        let annotations_seq_length_io_range_index = header_io_range_index + 1;
463        let _ = mem::replace(
464            &mut self.io_ranges[annotations_seq_length_io_range_index],
465            annotations_seq_length_io_range,
466        );
467
468        let annotations_seq_io_range_index = header_io_range_index + 2;
469        let _ = mem::replace(
470            &mut self.io_ranges[annotations_seq_io_range_index],
471            annotations_seq_io_range,
472        );
473
474        Ok(())
475    }
476
477    /// Returns a reference to the underlying io::Write implementation.
478    pub fn output(&self) -> &W {
479        &self.out
480    }
481
482    /// Returns a mutable reference to the underlying io::Write implementation. Modifying the
483    /// underlying sink is an inherently risky operation and can result in unexpected behavior.
484    /// It is not recommended for most use cases.
485    pub fn output_mut(&mut self) -> &mut W {
486        &mut self.out
487    }
488
489    fn reserve_io_ranges_for_annotations(&mut self) {
490        // Annotations type descriptor and wrapper length
491        self.push_empty_io_range();
492        // The VarUInt length of the encoded sequence of annotations
493        self.push_empty_io_range();
494        // The encoded sequence of annotations
495        self.push_empty_io_range();
496    }
497
498    pub fn add_annotation<A: AsRawSymbolTokenRef>(&mut self, annotation: A) {
499        let symbol_id = match annotation.as_raw_symbol_token_ref() {
500            RawSymbolTokenRef::SymbolId(symbol_id) => symbol_id,
501            RawSymbolTokenRef::Text(text) => panic!(
502                "The RawBinaryWriter can only accept symbol ID annotations, not text ('{text}')."
503            ),
504        };
505        self.annotations_all_levels.push(symbol_id);
506        self.num_annotations_current_value += 1;
507    }
508}
509
510impl<W: Write> IonWriter for RawBinaryWriter<W> {
511    type Output = W;
512
513    fn ion_version(&self) -> (u8, u8) {
514        (1, 0)
515    }
516
517    fn write_ion_version_marker(&mut self, major: u8, minor: u8) -> IonResult<()> {
518        if self.depth() > 0 {
519            return illegal_operation("can only write an IVM at the top level");
520        }
521        if major == 1 && minor == 0 {
522            return Ok(self.out.write_all(&IVM)?);
523        }
524        illegal_operation("Only Ion 1.0 is supported.")
525    }
526
527    fn supports_text_symbol_tokens(&self) -> bool {
528        // In Ion 1.0, the binary format requires that field names, annotations, and symbol values
529        // be encoded as symbol IDs. The raw writer does not have a symbol table and so cannot
530        // convert a String to a symbol ID.
531        false
532    }
533
534    fn set_annotations<I, A>(&mut self, annotations: I)
535    where
536        A: AsRawSymbolTokenRef,
537        I: IntoIterator<Item = A>,
538    {
539        self.clear_annotations();
540        for annotation in annotations {
541            self.add_annotation(annotation);
542        }
543    }
544
545    /// Writes an Ion null of the specified type.
546    fn write_null(&mut self, ion_type: IonType) -> IonResult<()> {
547        self.write_scalar(|enc_buffer| {
548            let byte: u8 = match ion_type {
549                IonType::Null => 0x0F,
550                IonType::Bool => 0x1F,
551                IonType::Int => 0x2F,
552                IonType::Float => 0x4F,
553                IonType::Decimal => 0x5F,
554                IonType::Timestamp => 0x6F,
555                IonType::Symbol => 0x7F,
556                IonType::String => 0x8F,
557                IonType::Clob => 0x9F,
558                IonType::Blob => 0xAF,
559                IonType::List => 0xBF,
560                IonType::SExp => 0xCF,
561                IonType::Struct => 0xDF,
562            };
563            enc_buffer.push(byte);
564            Ok(())
565        })
566    }
567
568    /// Writes an Ion boolean with the specified value.
569    fn write_bool(&mut self, value: bool) -> IonResult<()> {
570        self.write_scalar(|enc_buffer| {
571            let byte: u8 = if value { 0x11 } else { 0x10 };
572            enc_buffer.push(byte);
573            Ok(())
574        })
575    }
576
577    /// Writes an Ion integer with the specified value.
578    fn write_i64(&mut self, value: i64) -> IonResult<()> {
579        self.write_scalar(|enc_buffer| {
580            // Get the absolute value of the i64 and store it in a u64.
581            let magnitude: u64 = value.unsigned_abs();
582            let encoded = uint::encode_u64(magnitude);
583            let bytes_to_write = encoded.as_bytes();
584
585            // The encoded length will never be larger than 8 bytes, so it will
586            // always fit in the Int's type descriptor byte.
587            let encoded_length = bytes_to_write.len();
588            let type_descriptor: u8 = if value >= 0 {
589                0x20 | (encoded_length as u8)
590            } else {
591                0x30 | (encoded_length as u8)
592            };
593            enc_buffer.push(type_descriptor);
594            enc_buffer.extend_from_slice(bytes_to_write);
595
596            Ok(())
597        })
598    }
599
600    /// Writes an Ion integer with the specified value.
601    fn write_int(&mut self, value: &Int) -> IonResult<()> {
602        // If the `value` is an `i64`, use `write_i64` and return.
603        let value = match value {
604            Int::I64(i) => return self.write_i64(*i),
605            Int::BigInt(i) => i,
606        };
607
608        // From here on, `value` is a `BigInt`.
609        self.write_scalar(|enc_buffer| {
610            if value.is_zero() {
611                enc_buffer.push(0x20);
612                return Ok(());
613            }
614
615            let (sign, magnitude_be_bytes) = value.to_bytes_be();
616
617            let mut type_descriptor: u8 = match sign {
618                Sign::Plus | Sign::NoSign => 0x20,
619                Sign::Minus => 0x30,
620            };
621
622            let encoded_length = magnitude_be_bytes.len();
623            if encoded_length <= 13 {
624                type_descriptor |= encoded_length as u8;
625                enc_buffer.push(type_descriptor);
626            } else {
627                type_descriptor |= 0xEu8;
628                enc_buffer.push(type_descriptor);
629                VarUInt::write_u64(enc_buffer, encoded_length as u64)?;
630            }
631
632            enc_buffer.extend_from_slice(magnitude_be_bytes.as_slice());
633
634            Ok(())
635        })
636    }
637
638    /// Writes an Ion float with the specified value.
639    fn write_f32(&mut self, value: f32) -> IonResult<()> {
640        self.write_scalar(|enc_buffer| {
641            if value == 0f32 && !value.is_sign_negative() {
642                enc_buffer.push(0x40);
643                return Ok(());
644            }
645
646            enc_buffer.push(0x44);
647            enc_buffer.extend_from_slice(&value.to_be_bytes());
648            Ok(())
649        })
650    }
651
652    /// Writes an Ion float with the specified value.
653    fn write_f64(&mut self, value: f64) -> IonResult<()> {
654        self.write_scalar(|enc_buffer| {
655            if value == 0f64 && !value.is_sign_negative() {
656                enc_buffer.push(0x40);
657                return Ok(());
658            }
659
660            enc_buffer.push(0x48);
661            enc_buffer.extend_from_slice(&value.to_be_bytes());
662            Ok(())
663        })
664    }
665
666    /// Writes an Ion decimal with the specified value.
667    fn write_decimal(&mut self, value: &Decimal) -> IonResult<()> {
668        self.write_scalar(|enc_buffer| {
669            let _ = enc_buffer.encode_decimal_value(value)?;
670            Ok(())
671        })
672    }
673
674    /// Writes an Ion timestamp with the specified value.
675    fn write_timestamp(&mut self, value: &Timestamp) -> IonResult<()> {
676        self.write_scalar(|enc_buffer| {
677            let _ = enc_buffer.encode_timestamp_value(value)?;
678            Ok(())
679        })
680    }
681
682    fn write_symbol<A: AsRawSymbolTokenRef>(&mut self, value: A) -> IonResult<()> {
683        match value.as_raw_symbol_token_ref() {
684            RawSymbolTokenRef::SymbolId(sid) => self.write_symbol_id(sid),
685            RawSymbolTokenRef::Text(_text) => {
686                illegal_operation("The RawBinaryWriter cannot write text symbols.")
687            }
688        }
689    }
690
691    fn write_string<S: AsRef<str>>(&mut self, value: S) -> IonResult<()> {
692        self.write_scalar(|enc_buffer| {
693            let text: &str = value.as_ref();
694            let encoded_length = text.len(); // The number of utf8 bytes
695
696            let type_descriptor: u8;
697            if encoded_length <= MAX_INLINE_LENGTH {
698                type_descriptor = 0x80 | encoded_length as u8;
699                enc_buffer.push(type_descriptor);
700            } else {
701                type_descriptor = 0x8E;
702                enc_buffer.push(type_descriptor);
703                VarUInt::write_u64(enc_buffer, encoded_length as u64)?;
704            }
705            enc_buffer.extend_from_slice(text.as_bytes());
706            Ok(())
707        })
708    }
709
710    fn write_clob<A: AsRef<[u8]>>(&mut self, value: A) -> IonResult<()> {
711        self.write_scalar(|enc_buffer| {
712            let bytes: &[u8] = value.as_ref();
713            // The clob type descriptor's high nibble is type code 9
714            RawBinaryWriter::<W>::write_lob(enc_buffer, bytes, 0x90)
715        })
716    }
717
718    fn write_blob<A: AsRef<[u8]>>(&mut self, value: A) -> IonResult<()> {
719        self.write_scalar(|enc_buffer| {
720            let bytes: &[u8] = value.as_ref();
721            // The blob type descriptor's high nibble is type code 10
722            RawBinaryWriter::<W>::write_lob(enc_buffer, bytes, 0xA0)
723        })
724    }
725
726    /// Starts a container of the specified Ion type. If `ion_type` is not a List, SExpression,
727    /// or Struct, `step_in` will return an Err.
728    fn step_in(&mut self, ion_type: IonType) -> IonResult<()> {
729        use IonType::*;
730        let container_type = match ion_type {
731            List => ContainerType::List,
732            SExp => ContainerType::SExpression,
733            Struct => ContainerType::Struct,
734            _ => return illegal_operation("Cannot step into a scalar Ion type."),
735        };
736
737        // If this is a field in a struct, encode the field ID at the end of the last IO range.
738        if self.is_in_struct() {
739            let field_id_io_range = self.encode_to_buffer(|writer| {
740                let field_id = writer.expect_field_id()? as u64;
741                VarUInt::write_u64(&mut writer.buffer, field_id)?;
742                Ok(())
743            })?;
744            self.extend_last_range(field_id_io_range.len());
745        }
746
747        // If the container is annotated, reserve IO ranges to hold the annotations
748        // wrapper components that will ultimately precede the value.
749        if self.num_annotations_current_value > 0 {
750            self.reserve_io_ranges_for_annotations();
751        }
752
753        // An empty placeholder range that we'll fill in during step_out(). It will point to the
754        // type descriptor byte and any length bytes.
755        let header_io_range_index = self.io_ranges.len();
756        self.push_empty_io_range();
757
758        let new_encoding_level = EncodingLevel::new(
759            container_type,
760            self.field_id,
761            self.num_annotations_current_value,
762            header_io_range_index,
763        );
764        self.num_annotations_current_value = 0;
765        self.levels.push(new_encoding_level);
766
767        self.push_empty_io_range(); // Scalars can append to this
768        Ok(())
769    }
770
771    fn set_field_name<A: AsRawSymbolTokenRef>(&mut self, name: A) {
772        if self.parent_type() != Some(IonType::Struct) {
773            panic!("Attempted to set field name when the writer was not in a struct.");
774        }
775        match name.as_raw_symbol_token_ref() {
776            RawSymbolTokenRef::SymbolId(sid) => self.set_field_id(sid),
777            RawSymbolTokenRef::Text(text) => panic!(
778                "The RawBinaryWriter can only accept Symbol ID field names, not text ('{text}')."
779            ),
780        }
781    }
782
783    fn parent_type(&self) -> Option<IonType> {
784        // `self.levels` always has at least one value: the top level.
785        // This means we can `unwrap()` the last value safely.
786        match self.levels.last().unwrap().container_type {
787            ContainerType::TopLevel => None,
788            ContainerType::Struct => Some(IonType::Struct),
789            ContainerType::List => Some(IonType::List),
790            ContainerType::SExpression => Some(IonType::SExp),
791        }
792    }
793
794    fn depth(&self) -> usize {
795        // The top level is always present
796        self.levels.len() - 1
797    }
798
799    /// Ends the current container. If the writer is at the top level, `step_out` will return an Err.
800    fn step_out(&mut self) -> IonResult<()> {
801        if self.levels.len() <= 1 {
802            return illegal_operation(
803                "Cannot call step_out() unless the writer is positioned within a container.",
804            );
805        }
806        self.clear_annotations();
807        let container = self.levels.pop().unwrap();
808        self.num_annotations_current_value = container.num_annotations;
809        self.field_id = container.field_id;
810        let container_size = container.calculate_final_size(&mut self.io_ranges);
811
812        use crate::types::ContainerType::*;
813        let mut type_descriptor: u8 = match container.container_type {
814            List => 0xB0,
815            SExpression => 0xC0,
816            Struct => 0xD0,
817            _ => return illegal_operation("Cannot step into a scalar Ion type."),
818        };
819
820        // Encode the type descriptor byte, and optional length
821        let header_io_range = self.encode_to_buffer(|writer| {
822            if container_size <= MAX_INLINE_LENGTH {
823                type_descriptor |= container_size as u8;
824                writer.buffer.push(type_descriptor);
825            } else {
826                type_descriptor |= 0x0E; // VarUInt encoding
827                writer.buffer.push(type_descriptor);
828                VarUInt::write_u64(&mut writer.buffer, container_size as u64)?;
829            }
830            Ok(())
831        })?;
832
833        // Now that we know how large the container's header is, add its length to the
834        // calculated container size.
835        let container_size = container_size + header_io_range.len();
836
837        // Retrieve this container's header byte range from io_ranges
838        let td_io_range = self
839            .io_ranges
840            .get_mut(container.td_io_range_index)
841            .expect("Missing type descriptor IO range for {}");
842
843        // Update the IO range to point to the bytes we just encoded
844        let _ = mem::replace(td_io_range, header_io_range);
845
846        // If this container had annotations, retrieve the IO ranges that were reserved to store
847        // them and use them to encode the annotations wrapper.
848        if container.num_annotations > 0 {
849            self.encode_container_annotations(container.td_io_range_index, container_size)?;
850        }
851
852        // Create an empty IO Range that will hold the bytes of any scalar values that will follow
853        // now that we've stepped out.
854        self.push_empty_io_range();
855
856        Ok(())
857    }
858
859    /// Writes any buffered data to the sink. This method can only be called when the writer is at
860    /// the top level.
861    fn flush(&mut self) -> IonResult<()> {
862        if self.depth() > 0 {
863            return illegal_operation(
864                "Cannot call flush() while the writer is positioned within a container.",
865            );
866        }
867
868        // We don't call finalize() on the top level because it has no length prefix.
869        // Instead, its io_range represents the bytes of any leading scalar values.
870
871        // For each io_range in order, copy the specified bytes into a contiguous buffer that
872        // we'll write to output.
873
874        for io_range in self.io_ranges.drain(..) {
875            self.contiguous_encoding
876                .extend_from_slice(&self.buffer[io_range]);
877        }
878
879        // TODO: When io::Write#is_write_vectored[1] or trait specialization[2] stabilize,
880        //      we can use vectored writes instead of making a contiguous encoding
881        //      buffer.
882        //      [1] https://github.com/rust-lang/rust/issues/69941
883        //      [2] https://github.com/rust-lang/rust/issues/31844
884
885        self.out.write_all(self.contiguous_encoding.as_slice())?;
886
887        self.contiguous_encoding.clear();
888        self.push_empty_io_range();
889
890        Ok(())
891    }
892
893    fn output(&self) -> &Self::Output {
894        &self.out
895    }
896
897    fn output_mut(&mut self) -> &mut Self::Output {
898        &mut self.out
899    }
900}
901
902#[cfg(test)]
903mod writer_tests {
904    use std::fmt::Debug;
905
906    use crate::StreamItem;
907
908    use rstest::*;
909
910    use super::*;
911    use crate::raw_symbol_token::{local_sid_token, RawSymbolToken};
912    use crate::reader::{Reader, ReaderBuilder};
913    use crate::types::{Blob, Clob, Symbol};
914    use crate::IonReader;
915    use num_bigint::BigInt;
916    use num_traits::Float;
917    use std::convert::TryInto;
918    use std::str::FromStr;
919
920    type TestWriter<'a> = RawBinaryWriter<&'a mut Vec<u8>>;
921    type TestReader<'a> = Reader<'a>;
922
923    /// A reusable test outline for verifying BinarySystemWriter behavior.
924    fn binary_writer_test(
925        mut write_fn: impl FnMut(&mut TestWriter) -> IonResult<()>,
926        mut read_fn: impl FnMut(&mut TestReader) -> IonResult<()>,
927    ) -> IonResult<()> {
928        // Create a BinarySystemWriter that writes to a byte vector.
929        let mut buffer = vec![];
930        let mut writer = RawBinaryWriterBuilder::new().build(&mut buffer)?;
931        writer.write_ion_version_marker(1, 0)?;
932
933        // Call the user's writing function
934        write_fn(&mut writer)?;
935        writer.flush()?;
936
937        // Create a BinaryReader that reads from the BinarySystemWriter's output.
938        let data = buffer.as_slice();
939        let mut reader = ReaderBuilder::new().build(data)?;
940
941        // Call the user's verification function
942        read_fn(&mut reader)
943    }
944
945    /// A reusable test outline for verifying BinarySystemWriter scalar encoding behavior.
946    fn binary_writer_scalar_test<T, U>(
947        values: &[T],
948        ion_type: IonType,
949        mut write_fn: impl FnMut(&mut TestWriter, &T) -> IonResult<()>,
950        mut read_fn: impl FnMut(&mut TestReader) -> IonResult<U>,
951    ) -> IonResult<()>
952    where
953        T: Debug,
954        U: std::cmp::PartialEq<T> + Debug,
955    {
956        binary_writer_test(
957            |writer| {
958                for value in values {
959                    write_fn(writer, value)?;
960                }
961                Ok(())
962            },
963            |reader| {
964                for value in values {
965                    assert_eq!(reader.next()?, StreamItem::Value(ion_type));
966                    let reader_value = read_fn(reader)?;
967                    assert_eq!(
968                        reader_value, *value,
969                        "Value read back in (left) was not equal to the original value (right)"
970                    );
971                }
972                Ok(())
973            },
974        )
975    }
976
977    #[test]
978    fn binary_writer_nulls() -> IonResult<()> {
979        let ion_types = &[
980            IonType::Null,
981            IonType::Bool,
982            IonType::Int,
983            IonType::Float,
984            IonType::Decimal,
985            IonType::Timestamp,
986            IonType::Symbol,
987            IonType::String,
988            IonType::Clob,
989            IonType::Blob,
990            IonType::List,
991            IonType::SExp,
992            IonType::Struct,
993        ];
994
995        binary_writer_test(
996            |writer| {
997                for ion_type in ion_types {
998                    writer.write_null(*ion_type)?;
999                }
1000                Ok(())
1001            },
1002            |reader| {
1003                for ion_type in ion_types {
1004                    assert_eq!(reader.next()?, StreamItem::Null(*ion_type));
1005                }
1006                Ok(())
1007            },
1008        )
1009    }
1010
1011    #[test]
1012    fn binary_writer_bools() -> IonResult<()> {
1013        binary_writer_scalar_test(
1014            &[true, false],
1015            IonType::Bool,
1016            |writer, v| writer.write_bool(*v),
1017            |reader| reader.read_bool(),
1018        )
1019    }
1020
1021    #[test]
1022    fn binary_writer_ints() -> IonResult<()> {
1023        binary_writer_scalar_test(
1024            &[-24_601, -17, -1, 0, 1, 17, 24_601],
1025            IonType::Int,
1026            |writer, v| writer.write_i64(*v),
1027            |reader| reader.read_i64(),
1028        )
1029    }
1030
1031    #[test]
1032    fn binary_writer_floats() -> IonResult<()> {
1033        binary_writer_scalar_test(
1034            &[-24.601, -1.7, -1.0, -0.0, 0.0, 1.0, 1.7, 24.601],
1035            IonType::Float,
1036            |writer, v| writer.write_f64(*v),
1037            |reader| reader.read_f64(),
1038        )
1039    }
1040
1041    #[rstest]
1042    #[case::year(Timestamp::with_year(2021).build().unwrap())]
1043    #[case::year_month(Timestamp::with_year(2021).with_month(1).build().unwrap())]
1044    #[case::year_month_day(Timestamp::with_ymd(2021, 1, 8).build().unwrap())]
1045    #[case::ymd_hm_unknown(Timestamp::with_ymd(2021, 1, 8).with_hour_and_minute(14, 12).build_at_unknown_offset().unwrap())]
1046    #[case::ymd_hm_est(Timestamp::with_ymd(2021, 1, 8).with_hour_and_minute(14, 12).build_at_offset(-5 * 60).unwrap())]
1047    #[case::ymd_hms_unknown(Timestamp::with_ymd(2021, 1, 8).with_hms(14, 12, 36).build_at_unknown_offset().unwrap())]
1048    #[case::ymd_hms_est(Timestamp::with_ymd(2021, 1, 8).with_hms(14, 12, 36).build_at_offset(-5 * 60).unwrap())]
1049    #[case::ymd_hms_millis_unknown(Timestamp::with_ymd(2021, 1, 8).with_hms(14, 12, 36).with_milliseconds(888).build_at_unknown_offset().unwrap())]
1050    #[case::ymd_hms_millis_est(Timestamp::with_ymd(2021, 1, 8).with_hms(14, 12, 36).with_milliseconds(888).build_at_offset(-5 * 60).unwrap())]
1051    #[case::ymd_hms_nanos_unknown(Timestamp::with_ymd(2021, 1, 8).with_hms(14, 12, 36).with_nanoseconds(888888888).build_at_unknown_offset().unwrap())]
1052    #[case::ymd_hms_nanos_est(Timestamp::with_ymd(2021, 1, 8).with_hms(14, 12, 36).with_nanoseconds(888888888).build_at_offset(-5 * 60).unwrap())]
1053    fn binary_writer_timestamps(#[case] timestamp: Timestamp) -> IonResult<()> {
1054        binary_writer_scalar_test(
1055            &[timestamp],
1056            IonType::Timestamp,
1057            |writer, v| writer.write_timestamp(v),
1058            |reader| reader.read_timestamp(),
1059        )
1060    }
1061
1062    #[rstest]
1063    #[case(24.601)]
1064    #[case(-24.601)]
1065    #[case(1.7)]
1066    #[case(-1.7)]
1067    #[case(1.0)]
1068    #[case(-1.0)]
1069    #[case::positive_zero(0.0)]
1070    #[case::negative_zero(f64::neg_zero())]
1071    fn binary_writer_decimals(#[case] value: f64) -> IonResult<()> {
1072        let decimal: Decimal = value.try_into().unwrap();
1073        binary_writer_scalar_test(
1074            &[decimal],
1075            IonType::Decimal,
1076            |writer, v| writer.write_decimal(v),
1077            |reader| reader.read_decimal(),
1078        )
1079    }
1080
1081    #[test]
1082    fn binary_writer_symbols() -> IonResult<()> {
1083        let symbol_ids: Vec<RawSymbolToken> = [0, 5, 10, 31, 111, 556, 1024, 74_991, 111_448]
1084            .iter()
1085            .map(|sid| local_sid_token(*sid))
1086            .collect();
1087        binary_writer_scalar_test(
1088            symbol_ids.as_slice(),
1089            IonType::Symbol,
1090            |writer, v| writer.write_symbol_id(v.local_sid().unwrap()),
1091            |reader| reader.read_raw_symbol(),
1092        )
1093    }
1094
1095    #[test]
1096    fn binary_writer_strings() -> IonResult<()> {
1097        binary_writer_scalar_test(
1098            &["", "foo", "bar", "baz", "quux", "Winnipeg", "😂😂😂"],
1099            IonType::String,
1100            |writer, v| writer.write_string(*v),
1101            |reader| reader.read_string(),
1102        )
1103    }
1104
1105    #[test]
1106    fn binary_writer_lobs() -> IonResult<()> {
1107        let values: Vec<&[u8]> = ["", "foo", "bar", "baz", "quux", "Winnipeg", "😂😂😂"]
1108            .iter()
1109            .map(|s| s.as_bytes())
1110            .collect();
1111
1112        let clobs: Vec<Clob> = values.iter().map(|b| Clob::from(*b)).collect();
1113        let blobs: Vec<Blob> = values.iter().map(|b| Blob::from(*b)).collect();
1114
1115        binary_writer_scalar_test(
1116            clobs.as_slice(),
1117            IonType::Clob,
1118            |writer, v| writer.write_clob(v),
1119            |reader| reader.read_clob(),
1120        )?;
1121
1122        binary_writer_scalar_test(
1123            blobs.as_slice(),
1124            IonType::Blob,
1125            |writer, v| writer.write_blob(v),
1126            |reader| reader.read_blob(),
1127        )
1128    }
1129
1130    fn expect_scalar<T: Debug, U: PartialEq<T> + Debug>(
1131        reader: &mut TestReader,
1132        ion_type: IonType,
1133        mut read_fn: impl FnMut(&mut TestReader) -> IonResult<U>,
1134        expected_value: T,
1135    ) {
1136        let next = reader.next().unwrap_or_else(|_| {
1137            panic!("Expected to read {expected_value:?}, but the stream was empty.")
1138        });
1139        assert_eq!(next, StreamItem::Value(ion_type));
1140        let value = read_fn(reader)
1141            .unwrap_or_else(|_| panic!("Failed to read in expected value: {expected_value:?}"));
1142        assert_eq!(value, expected_value);
1143    }
1144
1145    fn expect_bool(reader: &mut TestReader, value: bool) {
1146        expect_scalar(reader, IonType::Bool, |r| r.read_bool(), value);
1147    }
1148
1149    fn expect_integer(reader: &mut TestReader, value: i64) {
1150        expect_scalar(reader, IonType::Int, |r| r.read_i64(), value);
1151    }
1152
1153    fn expect_big_integer(reader: &mut TestReader, value: &BigInt) {
1154        expect_scalar(
1155            reader,
1156            IonType::Int,
1157            |r| r.read_int(),
1158            Int::BigInt(value.clone()),
1159        );
1160    }
1161
1162    fn expect_float(reader: &mut TestReader, value: f64) {
1163        expect_scalar(reader, IonType::Float, |r| r.read_f64(), value);
1164    }
1165
1166    fn expect_symbol_id(reader: &mut TestReader, value: SymbolId) {
1167        expect_scalar(
1168            reader,
1169            IonType::Symbol,
1170            |r| r.read_raw_symbol(),
1171            local_sid_token(value),
1172        );
1173    }
1174
1175    fn expect_string(reader: &mut TestReader, value: &str) {
1176        expect_scalar(reader, IonType::String, |r| r.read_string(), value);
1177    }
1178
1179    fn expect_null(reader: &mut TestReader) {
1180        assert_eq!(
1181            reader.next().expect("Failed to read null."),
1182            StreamItem::Null(IonType::Null)
1183        );
1184    }
1185
1186    fn expect_container(reader: &mut TestReader, ion_type: IonType) {
1187        assert_eq!(
1188            reader.next().expect("Failed to read container."),
1189            StreamItem::Value(ion_type)
1190        );
1191    }
1192
1193    fn expect_list(reader: &mut TestReader) {
1194        expect_container(reader, IonType::List);
1195    }
1196
1197    fn expect_s_expression(reader: &mut TestReader) {
1198        expect_container(reader, IonType::SExp);
1199    }
1200
1201    fn expect_struct(reader: &mut TestReader) {
1202        expect_container(reader, IonType::Struct);
1203    }
1204
1205    fn expect_field_name(reader: &TestReader, field_name: &str) {
1206        assert!(reader.field_name().is_ok());
1207        assert_eq!(reader.field_name().unwrap(), field_name);
1208    }
1209
1210    fn expect_annotations(reader: &TestReader, annotations: &[&str]) {
1211        assert_eq!(
1212            reader
1213                .annotations()
1214                .map(|opt| opt.expect("Annotation with unknown text."))
1215                .collect::<Vec<Symbol>>()
1216                .as_slice(),
1217            annotations
1218        );
1219    }
1220
1221    fn write_lst<W: Write>(writer: &mut RawBinaryWriter<W>, symbols: &[&str]) -> IonResult<()> {
1222        // $ion_symbol_table::{symbols: ["your", "strings", "here"]}
1223        writer.set_annotations([3]); // $ion_symbol_table
1224        writer.step_in(IonType::Struct)?;
1225        writer.set_field_id(7); // symbols
1226        writer.step_in(IonType::List)?;
1227        for symbol in symbols {
1228            writer.write_string(symbol)?;
1229        }
1230        writer.step_out()?;
1231        writer.step_out()?;
1232        Ok(())
1233    }
1234
1235    #[test]
1236    fn binary_writer_large_integers() -> IonResult<()> {
1237        // 11 byte UInt
1238        let big_positive = BigInt::from_str("123456789123456789123456789").unwrap();
1239        // 19 byte UInt
1240        let very_big_positive =
1241            BigInt::from_str("123456789123456789123456789123456789123456789").unwrap();
1242        let big_negative = -big_positive.clone();
1243        let very_big_negative = -very_big_positive.clone();
1244        binary_writer_test(
1245            |writer| {
1246                writer.write_int(&Int::BigInt(BigInt::zero()))?;
1247                writer.write_int(&Int::BigInt(big_positive.clone()))?;
1248                writer.write_int(&Int::BigInt(very_big_positive.clone()))?;
1249                writer.write_int(&Int::BigInt(big_negative.clone()))?;
1250                writer.write_int(&Int::BigInt(very_big_negative.clone()))?;
1251                Ok(())
1252            },
1253            |reader| {
1254                expect_big_integer(reader, &BigInt::zero());
1255                expect_big_integer(reader, &big_positive);
1256                expect_big_integer(reader, &very_big_positive);
1257                expect_big_integer(reader, &big_negative);
1258                expect_big_integer(reader, &very_big_negative);
1259                Ok(())
1260            },
1261        )
1262    }
1263
1264    #[test]
1265    fn binary_writer_mixed_scalars() -> IonResult<()> {
1266        // The tests above write streams containing a single type of Ion value. This test writes
1267        // a mix.
1268        binary_writer_test(
1269            |writer| {
1270                writer.write_i64(42)?;
1271                writer.write_string("Hello")?;
1272                writer.write_symbol_id(12)?;
1273                writer.write_f32(2.5)?;
1274                writer.write_f64(7.5)?;
1275                writer.write_bool(false)
1276            },
1277            |reader| {
1278                expect_integer(reader, 42);
1279                expect_string(reader, "Hello");
1280                expect_symbol_id(reader, 12);
1281                expect_float(reader, 2.5);
1282                expect_float(reader, 7.5);
1283                expect_bool(reader, false);
1284                Ok(())
1285            },
1286        )
1287    }
1288
1289    #[test]
1290    fn binary_writer_annotated_scalars() -> IonResult<()> {
1291        binary_writer_test(
1292            |writer| {
1293                write_lst(writer, &["foo", "bar", "baz", "quux", "quuz", "waldo"])?;
1294
1295                writer.set_annotations([10]);
1296                writer.write_bool(true)?;
1297
1298                writer.set_annotations([11, 12]);
1299                writer.write_i64(42)?;
1300
1301                writer.set_annotations([13, 14, 15]);
1302                writer.write_string("Hello")
1303            },
1304            |reader| {
1305                expect_bool(reader, true);
1306                expect_annotations(reader, &["foo"]);
1307
1308                expect_integer(reader, 42);
1309                expect_annotations(reader, &["bar", "baz"]);
1310
1311                expect_string(reader, "Hello");
1312                expect_annotations(reader, &["quux", "quuz", "waldo"]);
1313                Ok(())
1314            },
1315        )
1316    }
1317
1318    #[test]
1319    fn binary_writer_annotated_containers() -> IonResult<()> {
1320        binary_writer_test(
1321            |writer| {
1322                write_lst(
1323                    writer,
1324                    &["foo", "bar", "baz", "quux", "quuz", "waldo", "gary"],
1325                )?;
1326
1327                // foo::(true)
1328                writer.set_annotations([10]);
1329                writer.step_in(IonType::SExp)?;
1330                writer.write_bool(true)?;
1331                writer.step_out()?;
1332
1333                // bar::baz::[11]
1334                writer.set_annotations([11, 12]);
1335                writer.step_in(IonType::List)?;
1336                writer.write_i64(11)?;
1337                writer.step_out()?;
1338
1339                // quux::quuz::waldo::{gary: "foo"}
1340                writer.set_annotations([13, 14, 15]);
1341                writer.step_in(IonType::Struct)?;
1342                writer.set_field_id(16);
1343                writer.write_string("foo")?;
1344                writer.step_out()
1345            },
1346            |reader| {
1347                expect_s_expression(reader);
1348                expect_annotations(reader, &["foo"]);
1349                reader.step_in()?;
1350                expect_bool(reader, true);
1351                reader.step_out()?;
1352
1353                expect_list(reader);
1354                expect_annotations(reader, &["bar", "baz"]);
1355                reader.step_in()?;
1356                expect_integer(reader, 11);
1357                reader.step_out()?;
1358
1359                expect_struct(reader);
1360                expect_annotations(reader, &["quux", "quuz", "waldo"]);
1361                reader.step_in()?;
1362                expect_string(reader, "foo");
1363                expect_field_name(reader, "gary");
1364                reader.step_out()?;
1365                Ok(())
1366            },
1367        )
1368    }
1369
1370    #[test]
1371    fn binary_writer_nested_annotated_containers() -> IonResult<()> {
1372        binary_writer_test(
1373            |writer| {
1374                write_lst(writer, &["foo", "bar", "baz", "quux"])?;
1375                // foo::{bar: baz::[quux::"quuz"]]}
1376                writer.set_annotations([10]);
1377                writer.step_in(IonType::Struct)?;
1378                writer.set_field_id(11);
1379                writer.set_annotations([12]);
1380                writer.step_in(IonType::List)?;
1381                writer.set_annotations([13]);
1382                writer.write_string("quuz")?;
1383                writer.step_out()?; // End of list
1384                writer.step_out() // End of struct
1385            },
1386            |reader| {
1387                expect_struct(reader);
1388                expect_annotations(reader, &["foo"]);
1389                reader.step_in()?;
1390                expect_list(reader);
1391                expect_field_name(reader, "bar");
1392                expect_annotations(reader, &["baz"]);
1393                reader.step_in()?;
1394                expect_string(reader, "quuz");
1395                expect_annotations(reader, &["quux"]);
1396                reader.step_out()?;
1397                reader.step_out()?;
1398                Ok(())
1399            },
1400        )
1401    }
1402
1403    #[test]
1404    fn binary_writer_list() -> IonResult<()> {
1405        binary_writer_test(
1406            |writer| {
1407                // [42, "Hello"]
1408                writer.step_in(IonType::List)?;
1409                writer.write_i64(42)?;
1410                writer.write_string("Hello")?;
1411                writer.step_out()
1412            },
1413            |reader| {
1414                expect_list(reader);
1415                reader.step_in()?;
1416                expect_integer(reader, 42);
1417                expect_string(reader, "Hello");
1418                reader.step_out()
1419            },
1420        )
1421    }
1422
1423    #[test]
1424    fn binary_writer_nested_list() -> IonResult<()> {
1425        binary_writer_test(
1426            |writer| {
1427                // [42, ["Hello"], "foo"]
1428                writer.step_in(IonType::List)?;
1429                writer.write_i64(42)?;
1430                writer.step_in(IonType::List)?;
1431                writer.write_string("Hello")?;
1432                writer.step_out()?;
1433                writer.write_string("foo")?;
1434                writer.step_out()
1435            },
1436            |reader| {
1437                expect_list(reader);
1438                reader.step_in()?;
1439                expect_integer(reader, 42);
1440                expect_list(reader);
1441                reader.step_in()?;
1442                expect_string(reader, "Hello");
1443                reader.step_out()?;
1444                expect_string(reader, "foo");
1445                reader.step_out()
1446            },
1447        )
1448    }
1449
1450    #[test]
1451    fn binary_writer_nested_structs() -> IonResult<()> {
1452        binary_writer_test(
1453            |writer| {
1454                write_lst(writer, &["foo", "bar", "baz", "quux"])?;
1455
1456                // {foo: true, bar: {quux: 7}, baz: null}
1457                writer.step_in(IonType::Struct)?;
1458                writer.set_field_id(10);
1459                writer.write_bool(true)?;
1460                writer.set_field_id(11);
1461                writer.step_in(IonType::Struct)?;
1462                writer.set_field_id(13);
1463                writer.write_i64(7)?;
1464                writer.step_out()?; // End of nested struct
1465                writer.set_field_id(12);
1466                writer.write_null(IonType::Null)?;
1467                writer.step_out() // End of top-level struct
1468            },
1469            |reader| {
1470                expect_struct(reader);
1471                reader.step_in()?;
1472                expect_bool(reader, true);
1473                expect_field_name(reader, "foo");
1474                expect_struct(reader);
1475                expect_field_name(reader, "bar");
1476                reader.step_in()?;
1477                expect_integer(reader, 7);
1478                expect_field_name(reader, "quux");
1479                reader.step_out()?;
1480                expect_null(reader);
1481                expect_field_name(reader, "baz");
1482                reader.step_out()
1483            },
1484        )
1485    }
1486}