use bumpalo::collections::Vec as BumpVec;
use bumpalo::Bump as BumpAllocator;
use crate::lazy::encoder::binary::v1_1::value_writer::{
BinaryEExpParameterValueWriter_1_1, BinaryValueWriter_1_1,
};
use crate::lazy::encoder::binary::v1_1::{flex_sym::FlexSym, flex_uint::FlexUInt};
use crate::lazy::encoder::value_writer::internal::{
EExpWriterInternal, FieldEncoder, MakeValueWriter,
};
use crate::lazy::encoder::value_writer::{EExpWriter, SequenceWriter, StructWriter};
use crate::lazy::encoder::value_writer_config::ValueWriterConfig;
use crate::lazy::encoder::write_as_ion::WriteAsIon;
use crate::lazy::expanded::macro_table::MacroRef;
use crate::lazy::expanded::template::{Parameter, SignatureIterator};
use crate::raw_symbol_ref::AsRawSymbolRef;
use crate::{v1_1, ContextWriter, Encoding, IonResult, MacroTable, UInt};
pub(crate) struct BinaryContainerWriter_1_1<'value, 'top> {
allocator: &'top BumpAllocator,
encoder: ContainerEncodingKind<'value, 'top>,
value_writer_config: ValueWriterConfig,
macros: &'value MacroTable,
}
enum ContainerEncodingKind<'value, 'top> {
Delimited(DelimitedEncoder<'value, 'top>),
LengthPrefixed(LengthPrefixedEncoder<'value, 'top>),
}
impl<'top> ContainerEncodingKind<'_, 'top> {
fn target_buffer(&mut self) -> &mut BumpVec<'top, u8> {
match self {
ContainerEncodingKind::Delimited(encoder) => encoder.buffer,
ContainerEncodingKind::LengthPrefixed(encoder) => &mut encoder.child_values_buffer,
}
}
}
struct DelimitedEncoder<'value, 'top> {
buffer: &'value mut BumpVec<'top, u8>,
}
struct LengthPrefixedEncoder<'value, 'top> {
type_code: u8,
flex_len_type_code: u8,
parent_buffer: &'value mut BumpVec<'top, u8>,
child_values_buffer: BumpVec<'top, u8>,
}
impl<'value, 'top> BinaryContainerWriter_1_1<'value, 'top> {
const DELIMITED_END_OPCODE: u8 = 0xF0;
pub fn new_delimited(
start_opcode: u8,
allocator: &'top BumpAllocator,
buffer: &'value mut BumpVec<'top, u8>,
write_options: ValueWriterConfig,
macros: &'value MacroTable,
) -> Self {
buffer.push(start_opcode);
let encoder = ContainerEncodingKind::Delimited(DelimitedEncoder { buffer });
Self {
allocator,
encoder,
value_writer_config: write_options,
macros,
}
}
pub fn new_length_prefixed(
type_code: u8,
flex_len_type_code: u8,
allocator: &'top BumpAllocator,
buffer: &'value mut BumpVec<'top, u8>,
write_options: ValueWriterConfig,
macros: &'value MacroTable,
) -> Self {
const DEFAULT_CAPACITY: usize = 512;
let encoder = ContainerEncodingKind::LengthPrefixed(LengthPrefixedEncoder {
type_code,
flex_len_type_code,
parent_buffer: buffer,
child_values_buffer: BumpVec::with_capacity_in(DEFAULT_CAPACITY, allocator),
});
Self {
allocator,
encoder,
value_writer_config: write_options,
macros,
}
}
pub fn allocator(&self) -> &'top BumpAllocator {
self.allocator
}
pub fn child_values_buffer(&mut self) -> &'_ mut BumpVec<'top, u8> {
self.encoder.target_buffer()
}
pub fn config(&self) -> ValueWriterConfig {
self.value_writer_config
}
fn value_writer<'a>(&'a mut self) -> BinaryValueWriter_1_1<'a, 'top> {
let value_writer_config = self.config();
let macros = self.macros;
BinaryValueWriter_1_1::new(
self.allocator,
self.child_values_buffer(),
value_writer_config,
macros,
)
}
#[inline]
pub fn write<V: WriteAsIon>(&mut self, value: V) -> IonResult<&mut Self> {
let value_writer = self.value_writer();
value.write_as_ion(value_writer)?;
Ok(self)
}
pub fn end(self) -> IonResult<()> {
match self.encoder {
ContainerEncodingKind::Delimited(encoder) => {
encoder.buffer.push(Self::DELIMITED_END_OPCODE)
}
ContainerEncodingKind::LengthPrefixed(encoder) => {
let encoded_length = encoder.child_values_buffer.len();
match encoded_length {
0..=15 => {
let opcode = encoder.type_code | encoded_length as u8;
encoder.parent_buffer.push(opcode);
}
_ => {
let opcode = encoder.flex_len_type_code;
encoder.parent_buffer.push(opcode);
FlexUInt::write(encoder.parent_buffer, encoded_length)?;
}
}
encoder
.parent_buffer
.extend_from_slice_copy(encoder.child_values_buffer.as_slice());
}
}
Ok(())
}
}
pub struct BinaryListWriter_1_1<'value, 'top> {
pub(crate) container_writer: BinaryContainerWriter_1_1<'value, 'top>,
}
impl<'value, 'top> BinaryListWriter_1_1<'value, 'top> {
pub(crate) fn with_container_writer(
container_writer: BinaryContainerWriter_1_1<'value, 'top>,
) -> Self {
Self { container_writer }
}
pub(crate) fn new_delimited(
allocator: &'top BumpAllocator,
buffer: &'value mut BumpVec<'top, u8>,
value_writer_config: ValueWriterConfig,
macros: &'value MacroTable,
) -> Self {
const DELIMITED_LIST_OPCODE: u8 = 0xF1;
let container_writer = BinaryContainerWriter_1_1::new_delimited(
DELIMITED_LIST_OPCODE,
allocator,
buffer,
value_writer_config,
macros,
);
Self::with_container_writer(container_writer)
}
pub(crate) fn new_length_prefixed(
allocator: &'top BumpAllocator,
buffer: &'value mut BumpVec<'top, u8>,
value_writer_config: ValueWriterConfig,
macros: &'value MacroTable,
) -> Self {
const LENGTH_PREFIXED_LIST_TYPE_CODE: u8 = 0xB0;
const LENGTH_PREFIXED_FLEX_LEN_LIST_TYPE_CODE: u8 = 0xFB;
let container_writer = BinaryContainerWriter_1_1::new_length_prefixed(
LENGTH_PREFIXED_LIST_TYPE_CODE,
LENGTH_PREFIXED_FLEX_LEN_LIST_TYPE_CODE,
allocator,
buffer,
value_writer_config,
macros,
);
Self::with_container_writer(container_writer)
}
}
impl<'top> ContextWriter for BinaryListWriter_1_1<'_, 'top> {
type NestedValueWriter<'a>
= BinaryValueWriter_1_1<'a, 'top>
where
Self: 'a;
}
impl MakeValueWriter for BinaryListWriter_1_1<'_, '_> {
fn make_value_writer(&mut self) -> Self::NestedValueWriter<'_> {
self.container_writer.value_writer()
}
}
impl SequenceWriter for BinaryListWriter_1_1<'_, '_> {
type Resources = ();
fn write<V: WriteAsIon>(&mut self, value: V) -> IonResult<&mut Self> {
self.container_writer.write(value)?;
Ok(self)
}
fn close(self) -> IonResult<Self::Resources> {
self.container_writer.end()
}
}
pub struct BinarySExpWriter_1_1<'value, 'top> {
pub(crate) container_writer: BinaryContainerWriter_1_1<'value, 'top>,
}
impl<'value, 'top> BinarySExpWriter_1_1<'value, 'top> {
pub(crate) fn with_container_writer(
container_writer: BinaryContainerWriter_1_1<'value, 'top>,
) -> Self {
Self { container_writer }
}
pub(crate) fn new_delimited(
allocator: &'top BumpAllocator,
buffer: &'value mut BumpVec<'top, u8>,
value_writer_config: ValueWriterConfig,
macros: &'value MacroTable,
) -> Self {
const DELIMITED_SEXP_OPCODE: u8 = 0xF2;
let container_writer = BinaryContainerWriter_1_1::new_delimited(
DELIMITED_SEXP_OPCODE,
allocator,
buffer,
value_writer_config,
macros,
);
Self::with_container_writer(container_writer)
}
pub(crate) fn new_length_prefixed(
allocator: &'top BumpAllocator,
buffer: &'value mut BumpVec<'top, u8>,
value_writer_config: ValueWriterConfig,
macros: &'value MacroTable,
) -> Self {
const LENGTH_PREFIXED_SEXP_TYPE_CODE: u8 = 0xC0;
const LENGTH_PREFIXED_FLEX_LEN_SEXP_TYPE_CODE: u8 = 0xFC;
let container_writer = BinaryContainerWriter_1_1::new_length_prefixed(
LENGTH_PREFIXED_SEXP_TYPE_CODE,
LENGTH_PREFIXED_FLEX_LEN_SEXP_TYPE_CODE,
allocator,
buffer,
value_writer_config,
macros,
);
Self::with_container_writer(container_writer)
}
}
impl<'top> ContextWriter for BinarySExpWriter_1_1<'_, 'top> {
type NestedValueWriter<'a>
= BinaryValueWriter_1_1<'a, 'top>
where
Self: 'a;
}
impl MakeValueWriter for BinarySExpWriter_1_1<'_, '_> {
fn make_value_writer(&mut self) -> Self::NestedValueWriter<'_> {
let value_writer_config = self.container_writer.config();
let macros = self.container_writer.macros;
BinaryValueWriter_1_1::new(
self.container_writer.allocator(),
self.container_writer.child_values_buffer(),
value_writer_config,
macros,
)
}
}
impl SequenceWriter for BinarySExpWriter_1_1<'_, '_> {
type Resources = ();
fn write<V: WriteAsIon>(&mut self, value: V) -> IonResult<&mut Self> {
self.container_writer.write(value)?;
Ok(self)
}
fn close(self) -> IonResult<Self::Resources> {
self.container_writer.end()
}
}
pub struct BinaryStructWriter_1_1<'value, 'top> {
flex_uint_encoding: bool,
container_writer: BinaryContainerWriter_1_1<'value, 'top>,
}
impl<'value, 'top> BinaryStructWriter_1_1<'value, 'top> {
pub(crate) fn new_length_prefixed(
allocator: &'top BumpAllocator,
buffer: &'value mut BumpVec<'top, u8>,
value_writer_config: ValueWriterConfig,
macros: &'value MacroTable,
) -> Self {
const LENGTH_PREFIXED_STRUCT_TYPE_CODE: u8 = 0xD0;
const LENGTH_PREFIXED_FLEX_LEN_STRUCT_TYPE_CODE: u8 = 0xFD;
let container_writer = BinaryContainerWriter_1_1::new_length_prefixed(
LENGTH_PREFIXED_STRUCT_TYPE_CODE,
LENGTH_PREFIXED_FLEX_LEN_STRUCT_TYPE_CODE,
allocator,
buffer,
value_writer_config,
macros,
);
Self {
flex_uint_encoding: true,
container_writer,
}
}
pub(crate) fn new_delimited(
allocator: &'top BumpAllocator,
buffer: &'value mut BumpVec<'top, u8>,
value_writer_config: ValueWriterConfig,
macros: &'value MacroTable,
) -> Self {
const DELIMITED_STRUCT_OPCODE: u8 = 0xF3;
let container_writer = BinaryContainerWriter_1_1::new_delimited(
DELIMITED_STRUCT_OPCODE,
allocator,
buffer,
value_writer_config,
macros,
);
Self {
flex_uint_encoding: false,
container_writer,
}
}
pub(crate) fn fields_buffer(&mut self) -> &'_ mut BumpVec<'top, u8> {
self.container_writer.child_values_buffer()
}
}
impl FieldEncoder for BinaryStructWriter_1_1<'_, '_> {
#[inline]
fn encode_field_name(&mut self, name: impl AsRawSymbolRef) -> IonResult<()> {
use crate::raw_symbol_ref::RawSymbolRef::*;
let name_ref = name.as_raw_symbol_ref();
match (self.flex_uint_encoding, name_ref) {
(true, SymbolId(sid)) if sid > 0 => {
return FlexUInt::write(self.fields_buffer(), sid).map(|_| ());
}
(true, _) => {
self.fields_buffer().push(0x01);
self.flex_uint_encoding = false;
}
_ => {}
}
FlexSym::encode_symbol(self.fields_buffer(), name_ref);
Ok(())
}
}
impl<'top> ContextWriter for BinaryStructWriter_1_1<'_, 'top> {
type NestedValueWriter<'a>
= BinaryValueWriter_1_1<'a, 'top>
where
Self: 'a;
}
impl MakeValueWriter for BinaryStructWriter_1_1<'_, '_> {
fn make_value_writer(&mut self) -> Self::NestedValueWriter<'_> {
self.container_writer.value_writer()
}
}
impl StructWriter for BinaryStructWriter_1_1<'_, '_> {
fn close(mut self) -> IonResult<()> {
if let ContainerEncodingKind::Delimited(_) = &mut self.container_writer.encoder {
self.fields_buffer().push(0x01);
}
self.container_writer.end()
}
fn config(&self) -> ValueWriterConfig {
v1_1::Binary::default_value_writer_config()
}
}
pub struct BinaryEExpWriter_1_1<'value, 'top> {
allocator: &'top BumpAllocator,
buffer: &'value mut BumpVec<'top, u8>,
value_writer_config: ValueWriterConfig,
macros: &'value MacroTable,
signature_iter: SignatureIterator<'value>,
}
impl<'value, 'top> BinaryEExpWriter_1_1<'value, 'top> {
pub fn new(
allocator: &'top BumpAllocator,
buffer: &'value mut BumpVec<'top, u8>,
value_writer_config: ValueWriterConfig,
macros: &'value MacroTable,
invoked_macro: MacroRef<'value>,
) -> Self {
let signature_iter = invoked_macro.iter_signature();
Self {
allocator,
buffer,
value_writer_config,
macros,
signature_iter,
}
}
}
impl<'top> ContextWriter for BinaryEExpWriter_1_1<'_, 'top> {
type NestedValueWriter<'a>
= BinaryEExpParameterValueWriter_1_1<'a, 'top>
where
Self: 'a;
}
impl MakeValueWriter for BinaryEExpWriter_1_1<'_, '_> {
fn make_value_writer(&mut self) -> Self::NestedValueWriter<'_> {
let param = self.signature_iter.expect_next_parameter().ok();
BinaryEExpParameterValueWriter_1_1::new(
self.allocator,
self.buffer,
self.value_writer_config,
self.macros,
param,
)
}
}
impl SequenceWriter for BinaryEExpWriter_1_1<'_, '_> {
type Resources = ();
fn close(self) -> IonResult<Self::Resources> {
Ok(())
}
}
impl<'top> EExpWriterInternal for BinaryEExpWriter_1_1<'_, 'top> {
fn expect_next_parameter(&mut self) -> IonResult<&Parameter> {
self.signature_iter.expect_next_parameter()
}
}
impl<'top> EExpWriter for BinaryEExpWriter_1_1<'_, 'top> {
type ExprGroupWriter<'group>
= BinaryExprGroupWriter<'group, 'top>
where
Self: 'group;
fn invoked_macro(&self) -> MacroRef<'_> {
self.signature_iter.parent_macro()
}
fn current_parameter(&self) -> Option<&Parameter> {
self.signature_iter.current_parameter()
}
fn write_flex_uint(&mut self, value: impl Into<UInt>) -> IonResult<()> {
FlexUInt::write(self.buffer, value)?;
Ok(())
}
fn write_fixed_uint8(&mut self, value: impl Into<u8>) -> IonResult<()> {
self.buffer.push(value.into());
Ok(())
}
fn expr_group_writer(&mut self) -> IonResult<Self::ExprGroupWriter<'_>> {
let param = self
.signature_iter
.expect_next_parameter()
.and_then(|p| p.expect_variadic())?;
let writer = BinaryExprGroupWriter::new(
self.allocator,
self.buffer,
self.value_writer_config,
self.macros,
param,
);
Ok(writer)
}
}
pub struct BinaryExprGroupWriter<'group, 'top> {
allocator: &'top BumpAllocator,
buffer: &'group mut BumpVec<'top, u8>,
value_writer_config: ValueWriterConfig,
macros: &'group MacroTable,
_parameter: &'group Parameter,
}
impl<'group, 'top> BinaryExprGroupWriter<'group, 'top> {
fn new(
allocator: &'top BumpAllocator,
buffer: &'group mut BumpVec<'top, u8>,
value_writer_config: ValueWriterConfig,
macros: &'group MacroTable,
parameter: &'group Parameter,
) -> Self {
Self {
allocator,
buffer,
value_writer_config,
macros,
_parameter: parameter,
}
}
}
impl<'top> ContextWriter for BinaryExprGroupWriter<'_, 'top> {
type NestedValueWriter<'a>
= BinaryValueWriter_1_1<'a, 'top>
where
Self: 'a;
}
impl MakeValueWriter for BinaryExprGroupWriter<'_, '_> {
fn make_value_writer(&mut self) -> Self::NestedValueWriter<'_> {
BinaryValueWriter_1_1::new(
self.allocator,
self.buffer,
self.value_writer_config,
self.macros,
)
}
}
impl SequenceWriter for BinaryExprGroupWriter<'_, '_> {
type Resources = ();
fn close(self) -> IonResult<Self::Resources> {
Ok(())
}
}