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 }
25
26impl RawBinaryWriterBuilder {
27 pub fn new() -> Self {
28 RawBinaryWriterBuilder {}
29 }
30
31 pub fn build<W: Write>(self, out: W) -> IonResult<RawBinaryWriter<W>> {
34 let mut levels = Vec::with_capacity(INITIAL_ENCODING_LEVELS_CAPACITY);
35 levels.push(EncodingLevel::new(ContainerType::TopLevel, None, 0, 0));
37 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 Ok(raw_binary_writer)
54 }
55}
56
57impl Default for RawBinaryWriterBuilder {
58 fn default() -> Self {
59 RawBinaryWriterBuilder::new()
60 }
61}
62
63type IoRange = Range<usize>;
77
78#[derive(Debug)]
106struct EncodingLevel {
107 container_type: ContainerType,
108 field_id: Option<SymbolId>,
109 num_annotations: u8,
114 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 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#[derive(Debug)]
151pub struct RawBinaryWriter<W: Write> {
152 buffer: Vec<u8>,
154 io_ranges: Vec<IoRange>,
156 levels: Vec<EncodingLevel>,
158 out: W,
160 field_id: Option<SymbolId>,
162 annotations_all_levels: Vec<SymbolId>,
165 num_annotations_current_value: u8,
168 contiguous_encoding: Vec<u8>,
171}
172
173pub(crate) const MAX_INLINE_LENGTH: usize = 13;
176
177const IO_RANGES_PER_ANNOTATION_WRAPPER: usize = 3;
181
182const 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 #[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 #[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 #[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 fn write_scalar(
226 &mut self,
227 mut write_fn: impl FnMut(&mut Vec<u8>) -> IonResult<()>,
228 ) -> IonResult<()> {
229 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 fn encode_annotated_scalar(
250 &mut self,
251 mut scalar_write_fn: impl FnMut(&mut Vec<u8>) -> IonResult<()>,
252 ) -> IonResult<()> {
253 let value_io_range: IoRange =
255 self.encode_to_buffer(|writer| scalar_write_fn(&mut writer.buffer))?;
256
257 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 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 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 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 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 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 let wrapper_length = annotations_seq_io_range.len()
329 + annotations_seq_length_io_range.len()
330 + wrapped_value_length;
331
332 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 type_descriptor = 0xE0 | wrapper_length as u8;
340 writer.buffer.push(type_descriptor);
341 } else {
342 type_descriptor = 0xEE; 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 #[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 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 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 fn encode_container_annotations(
440 &mut self,
441 td_io_range_index: usize,
442 container_size: usize,
443 ) -> IonResult<()> {
444 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 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 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 pub fn output(&self) -> &W {
479 &self.out
480 }
481
482 pub fn output_mut(&mut self) -> &mut W {
486 &mut self.out
487 }
488
489 fn reserve_io_ranges_for_annotations(&mut self) {
490 self.push_empty_io_range();
492 self.push_empty_io_range();
494 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 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 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 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 fn write_i64(&mut self, value: i64) -> IonResult<()> {
579 self.write_scalar(|enc_buffer| {
580 let magnitude: u64 = value.unsigned_abs();
582 let encoded = uint::encode_u64(magnitude);
583 let bytes_to_write = encoded.as_bytes();
584
585 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 fn write_int(&mut self, value: &Int) -> IonResult<()> {
602 let value = match value {
604 Int::I64(i) => return self.write_i64(*i),
605 Int::BigInt(i) => i,
606 };
607
608 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 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 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 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 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(); 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 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 RawBinaryWriter::<W>::write_lob(enc_buffer, bytes, 0xA0)
723 })
724 }
725
726 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 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 self.num_annotations_current_value > 0 {
750 self.reserve_io_ranges_for_annotations();
751 }
752
753 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(); 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 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 self.levels.len() - 1
797 }
798
799 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 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; writer.buffer.push(type_descriptor);
828 VarUInt::write_u64(&mut writer.buffer, container_size as u64)?;
829 }
830 Ok(())
831 })?;
832
833 let container_size = container_size + header_io_range.len();
836
837 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 let _ = mem::replace(td_io_range, header_io_range);
845
846 if container.num_annotations > 0 {
849 self.encode_container_annotations(container.td_io_range_index, container_size)?;
850 }
851
852 self.push_empty_io_range();
855
856 Ok(())
857 }
858
859 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 for io_range in self.io_ranges.drain(..) {
875 self.contiguous_encoding
876 .extend_from_slice(&self.buffer[io_range]);
877 }
878
879 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 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 let mut buffer = vec![];
930 let mut writer = RawBinaryWriterBuilder::new().build(&mut buffer)?;
931 writer.write_ion_version_marker(1, 0)?;
932
933 write_fn(&mut writer)?;
935 writer.flush()?;
936
937 let data = buffer.as_slice();
939 let mut reader = ReaderBuilder::new().build(data)?;
940
941 read_fn(&mut reader)
943 }
944
945 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 writer.set_annotations([3]); writer.step_in(IonType::Struct)?;
1225 writer.set_field_id(7); 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 let big_positive = BigInt::from_str("123456789123456789123456789").unwrap();
1239 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 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 writer.set_annotations([10]);
1329 writer.step_in(IonType::SExp)?;
1330 writer.write_bool(true)?;
1331 writer.step_out()?;
1332
1333 writer.set_annotations([11, 12]);
1335 writer.step_in(IonType::List)?;
1336 writer.write_i64(11)?;
1337 writer.step_out()?;
1338
1339 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 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()?; writer.step_out() },
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 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 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 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()?; writer.set_field_id(12);
1466 writer.write_null(IonType::Null)?;
1467 writer.step_out() },
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}