use bumpalo::collections::Vec as BumpVec;
use bumpalo::Bump as BumpAllocator;
use ice_code::ice as cold_path;
use crate::binary::var_uint::VarUInt;
use crate::lazy::encoder::binary::v1_0::value_writer::{BinaryValueWriter_1_0, MAX_INLINE_LENGTH};
use crate::lazy::encoder::value_writer::internal::{FieldEncoder, MakeValueWriter};
use crate::lazy::encoder::value_writer::{SequenceWriter, StructWriter};
use crate::raw_symbol_ref::AsRawSymbolRef;
use crate::result::{EncodingError, IonFailure};
use crate::{
v1_0, ContextWriter, Encoding, IonError, IonResult, RawSymbolRef, SymbolId, ValueWriterConfig,
};
pub struct BinaryContainerWriter_1_0<'value, 'top> {
type_code: u8,
allocator: &'top BumpAllocator,
child_values_buffer: BumpVec<'top, u8>,
parent_buffer: &'value mut BumpVec<'top, u8>,
annotations: Option<BumpVec<'top, SymbolId>>,
}
impl<'value, 'top> BinaryContainerWriter_1_0<'value, 'top> {
pub fn new(
type_code: u8,
allocator: &'top BumpAllocator,
buffer: &'value mut BumpVec<'top, u8>,
) -> Self {
Self {
type_code,
allocator,
child_values_buffer: BumpVec::with_capacity_in(
DEFAULT_CONTAINER_BUFFER_SIZE,
allocator,
),
parent_buffer: buffer,
annotations: None,
}
}
pub fn with_annotations<S: AsRawSymbolRef, I: IntoIterator<Item = S>>(
mut self,
annotations: I,
) -> IonResult<Self> {
let iterator = annotations.into_iter();
let mut symbol_ids = BumpVec::with_capacity_in(iterator.size_hint().0, self.allocator);
for annotation in iterator {
let symbol_address = match annotation.as_raw_symbol_ref() {
RawSymbolRef::SymbolId(symbol_id) => symbol_id,
other_token => {
return cold_path! {
IonResult::encoding_error(
format!("binary Ion 1.0 only supports symbol ID annotations (received '{other_token:?}')")
)
}
}
};
symbol_ids.push(symbol_address);
}
self.annotations = if !symbol_ids.is_empty() {
Some(symbol_ids)
} else {
None
};
Ok(self)
}
pub fn child_values_buffer(&self) -> &[u8] {
self.child_values_buffer.as_slice()
}
pub fn end(mut self) -> IonResult<()> {
match self.annotations.take() {
None => self.write_unannotated_value_to_parent_buffer(),
Some(annotations) => self.write_annotated_value_to_parent_buffer(annotations),
}
}
pub fn write_annotated_value_to_parent_buffer(
&mut self,
annotations: BumpVec<'top, SymbolId>,
) -> IonResult<()> {
let mut encoded_sequence = BumpVec::new_in(self.allocator);
for annotation in annotations {
VarUInt::write_u64(&mut encoded_sequence, annotation as u64)?;
}
let mut encoded_sequence_length = BumpVec::new_in(self.allocator);
VarUInt::write_u64(&mut encoded_sequence_length, encoded_sequence.len() as u64)?;
let container_body_length = self.child_values_buffer.len();
let container_header_length = match container_body_length {
0..=MAX_INLINE_LENGTH => 1,
length => 1 + VarUInt::encoded_size_of(length as u64),
};
let envelope_length = encoded_sequence_length.len()
+ encoded_sequence.len()
+ container_header_length
+ container_body_length;
match envelope_length {
0..=MAX_INLINE_LENGTH => self.parent_buffer.push(0xE0u8 | envelope_length as u8),
_ => {
self.parent_buffer.push(0xEE); VarUInt::write_u64(self.parent_buffer, envelope_length as u64)?;
}
}
self.parent_buffer.extend_from_slices_copy(&[
encoded_sequence_length.as_slice(),
encoded_sequence.as_slice(),
]);
self.write_unannotated_value_to_parent_buffer()
}
pub fn write_unannotated_value_to_parent_buffer(&mut self) -> IonResult<()> {
let encoded_length = self.child_values_buffer.len();
match encoded_length {
0..=MAX_INLINE_LENGTH => {
let opcode = self.type_code | encoded_length as u8;
self.parent_buffer.push(opcode);
}
_ => {
let opcode = self.type_code | 0x0E; self.parent_buffer.push(opcode);
VarUInt::write_u64(self.parent_buffer, encoded_length as u64)?;
}
}
self.parent_buffer
.extend_from_slice_copy(self.child_values_buffer.as_slice());
Ok(())
}
}
const DEFAULT_CONTAINER_BUFFER_SIZE: usize = 512;
pub struct BinaryListWriter_1_0<'value, 'top> {
pub(crate) container_writer: BinaryContainerWriter_1_0<'value, 'top>,
}
impl<'value, 'top> BinaryListWriter_1_0<'value, 'top> {
pub(crate) fn with_container_writer(
container_writer: BinaryContainerWriter_1_0<'value, 'top>,
) -> Self {
Self { container_writer }
}
pub(crate) fn new(
allocator: &'top BumpAllocator,
buffer: &'value mut BumpVec<'top, u8>,
) -> Self {
const LIST_TYPE_CODE: u8 = 0xB0;
BinaryListWriter_1_0::with_container_writer(BinaryContainerWriter_1_0::new(
LIST_TYPE_CODE,
allocator,
buffer,
))
}
pub(crate) fn with_annotations<S: AsRawSymbolRef, I: IntoIterator<Item = S>>(
mut self,
annotations: I,
) -> IonResult<Self> {
self.container_writer = self.container_writer.with_annotations(annotations)?;
Ok(self)
}
}
impl<'top> ContextWriter for BinaryListWriter_1_0<'_, 'top> {
type NestedValueWriter<'a>
= BinaryValueWriter_1_0<'a, 'top>
where
Self: 'a;
}
impl MakeValueWriter for BinaryListWriter_1_0<'_, '_> {
fn make_value_writer(&mut self) -> Self::NestedValueWriter<'_> {
BinaryValueWriter_1_0::new(
self.container_writer.allocator,
&mut self.container_writer.child_values_buffer,
)
}
}
impl SequenceWriter for BinaryListWriter_1_0<'_, '_> {
type Resources = ();
fn close(self) -> IonResult<Self::Resources> {
self.container_writer.end()
}
}
impl<'top> ContextWriter for BinarySExpWriter_1_0<'_, 'top> {
type NestedValueWriter<'a>
= BinaryValueWriter_1_0<'a, 'top>
where
Self: 'a;
}
impl MakeValueWriter for BinarySExpWriter_1_0<'_, '_> {
fn make_value_writer(&mut self) -> Self::NestedValueWriter<'_> {
BinaryValueWriter_1_0::new(
self.container_writer.allocator,
&mut self.container_writer.child_values_buffer,
)
}
}
impl SequenceWriter for BinarySExpWriter_1_0<'_, '_> {
type Resources = ();
fn close(self) -> IonResult<Self::Resources> {
self.container_writer.end()
}
}
pub struct BinarySExpWriter_1_0<'value, 'top> {
container_writer: BinaryContainerWriter_1_0<'value, 'top>,
}
impl<'value, 'top> BinarySExpWriter_1_0<'value, 'top> {
pub(crate) fn with_container_writer(
container_writer: BinaryContainerWriter_1_0<'value, 'top>,
) -> Self {
Self { container_writer }
}
pub(crate) fn new(
allocator: &'top BumpAllocator,
buffer: &'value mut BumpVec<'top, u8>,
) -> Self {
const SEXP_TYPE_CODE: u8 = 0xC0;
let container_writer = BinaryContainerWriter_1_0::new(SEXP_TYPE_CODE, allocator, buffer);
Self::with_container_writer(container_writer)
}
pub(crate) fn with_annotations<S: AsRawSymbolRef, I: IntoIterator<Item = S>>(
mut self,
annotations: I,
) -> IonResult<Self> {
self.container_writer = self.container_writer.with_annotations(annotations)?;
Ok(self)
}
pub fn buffer(&self) -> &[u8] {
self.container_writer.child_values_buffer()
}
}
pub struct BinaryStructWriter_1_0<'value, 'top> {
container_writer: BinaryContainerWriter_1_0<'value, 'top>,
}
impl<'value, 'top> BinaryStructWriter_1_0<'value, 'top> {
pub(crate) fn with_container_writer(
container: BinaryContainerWriter_1_0<'value, 'top>,
) -> Self {
Self {
container_writer: container,
}
}
pub(crate) fn new(
allocator: &'top BumpAllocator,
buffer: &'value mut BumpVec<'top, u8>,
) -> Self {
const STRUCT_TYPE_CODE: u8 = 0xD0;
Self::with_container_writer(BinaryContainerWriter_1_0::new(
STRUCT_TYPE_CODE,
allocator,
buffer,
))
}
pub(crate) fn with_annotations<S: AsRawSymbolRef, I: IntoIterator<Item = S>>(
mut self,
annotations: I,
) -> IonResult<Self> {
self.container_writer = self.container_writer.with_annotations(annotations)?;
Ok(self)
}
pub fn buffer(&self) -> &[u8] {
self.container_writer.child_values_buffer()
}
}
impl FieldEncoder for BinaryStructWriter_1_0<'_, '_> {
fn encode_field_name(&mut self, name: impl AsRawSymbolRef) -> IonResult<()> {
let sid = match name.as_raw_symbol_ref() {
RawSymbolRef::SymbolId(sid) => sid,
other => {
return Err(IonError::Encoding(EncodingError::new(format!(
"the v1.0 raw binary writer only supports symbol ID struct field names, received {other:?}"
))));
}
};
VarUInt::write_u64(&mut self.container_writer.child_values_buffer, sid as u64)?;
Ok(())
}
}
impl<'top> ContextWriter for BinaryStructWriter_1_0<'_, 'top> {
type NestedValueWriter<'a>
= BinaryValueWriter_1_0<'a, 'top>
where
Self: 'a;
}
impl MakeValueWriter for BinaryStructWriter_1_0<'_, '_> {
fn make_value_writer(&mut self) -> Self::NestedValueWriter<'_> {
BinaryValueWriter_1_0::new(
self.container_writer.allocator,
&mut self.container_writer.child_values_buffer,
)
}
}
impl StructWriter for BinaryStructWriter_1_0<'_, '_> {
fn close(self) -> IonResult<()> {
self.container_writer.end()
}
fn config(&self) -> ValueWriterConfig {
v1_0::Binary::default_value_writer_config()
}
}