use bumpalo::collections::Vec as BumpVec;
use bumpalo::Bump as BumpAllocator;
use delegate::delegate;
use std::io::Write;
use crate::lazy::encoder::binary::v1_0::value_writer::BinaryValueWriter_1_0;
use crate::lazy::encoder::private::Sealed;
use crate::lazy::encoder::value_writer::internal::MakeValueWriter;
use crate::lazy::encoder::value_writer::SequenceWriter;
use crate::lazy::encoder::write_as_ion::WriteAsIon;
use crate::lazy::encoder::writer::WriterMacroTable;
use crate::lazy::encoder::LazyRawWriter;
use crate::lazy::encoding::Encoding;
use crate::lazy::expanded::macro_table::EMPTY_MACRO_TABLE;
use crate::unsafe_helpers::{mut_ref_to_ptr, ptr_to_mut_ref, ptr_to_ref};
use crate::write_config::{WriteConfig, WriteConfigKind};
use crate::{ContextWriter, IonResult};
pub struct LazyRawBinaryWriter_1_0<W: Write> {
output: W,
allocator: BumpAllocator,
encoding_buffer_ptr: Option<*mut ()>,
}
const DEFAULT_BUMP_SIZE: usize = 16 * 1024;
impl<W: Write> LazyRawBinaryWriter_1_0<W> {
pub fn new(mut output: W) -> IonResult<Self> {
output.write_all(&[0xE0, 0x01, 0x00, 0xEA])?;
Ok(Self {
output,
allocator: BumpAllocator::with_capacity(DEFAULT_BUMP_SIZE),
encoding_buffer_ptr: None,
})
}
pub fn write<V: WriteAsIon>(&mut self, value: V) -> IonResult<&mut Self> {
value.write_as_ion(self.value_writer())?;
Ok(self)
}
pub fn flush(&mut self) -> IonResult<()> {
let Self {
output,
allocator,
encoding_buffer_ptr,
..
} = self;
if let Some(ptr) = encoding_buffer_ptr {
let encoding_buffer = unsafe { ptr_to_ref::<'_, BumpVec<'_, u8>>(*ptr).as_slice() };
output.write_all(encoding_buffer)?;
output.flush()?;
}
self.encoding_buffer_ptr = None;
allocator.reset();
Ok(())
}
fn get_or_allocate_encoding_buffer<'value, 'top>(
encoding_buffer_ptr: &'value mut Option<*mut ()>,
allocator: &'top BumpAllocator,
) -> &'value mut BumpVec<'top, u8> {
match encoding_buffer_ptr {
Some(ptr) => {
let new_ptr = *ptr;
unsafe { ptr_to_mut_ref::<'_, BumpVec<'_, u8>>(new_ptr) }
}
None => {
let encoding_buffer = allocator.alloc_with(|| BumpVec::<u8>::new_in(allocator));
let ptr = mut_ref_to_ptr(encoding_buffer);
*encoding_buffer_ptr = Some(ptr);
unsafe { ptr_to_mut_ref::<'_, BumpVec<'_, u8>>(encoding_buffer_ptr.unwrap()) }
}
}
}
pub(crate) fn value_writer(&mut self) -> BinaryValueWriter_1_0<'_, '_> {
let Self {
ref allocator,
ref mut encoding_buffer_ptr,
..
} = *self;
let top_level = Self::get_or_allocate_encoding_buffer(encoding_buffer_ptr, allocator);
let annotated_value_writer = BinaryValueWriter_1_0::new(allocator, top_level);
annotated_value_writer
}
}
impl<W: Write> Sealed for LazyRawBinaryWriter_1_0<W> {}
impl<W: Write> LazyRawWriter<W> for LazyRawBinaryWriter_1_0<W> {
fn new(output: W) -> IonResult<Self> {
Self::new(output)
}
fn build<E: Encoding>(config: WriteConfig<E>, output: W) -> IonResult<Self> {
match &config.kind {
WriteConfigKind::Text(_) => {
unreachable!("Text writer can not be created from binary encoding")
}
WriteConfigKind::Binary(_) => LazyRawBinaryWriter_1_0::new(output),
}
}
fn output(&self) -> &W {
&self.output
}
delegate! {
to self {
fn flush(&mut self) -> IonResult<()>;
}
}
fn output_mut(&mut self) -> &mut W {
&mut self.output
}
fn write_version_marker(&mut self) -> IonResult<()> {
self.output.write_all(&[0xE0, 0x01, 0x00, 0xEA])?;
Ok(())
}
fn macro_table(&self) -> &WriterMacroTable {
&EMPTY_MACRO_TABLE
}
fn macro_table_mut(&mut self) -> Option<&mut WriterMacroTable> {
None
}
}
impl<W: Write> ContextWriter for LazyRawBinaryWriter_1_0<W> {
type NestedValueWriter<'a>
= BinaryValueWriter_1_0<'a, 'a>
where
Self: 'a;
}
impl<W: Write> MakeValueWriter for LazyRawBinaryWriter_1_0<W> {
fn make_value_writer(&mut self) -> Self::NestedValueWriter<'_> {
self.value_writer()
}
}
impl<W: Write> SequenceWriter for LazyRawBinaryWriter_1_0<W> {
type Resources = W;
fn close(mut self) -> IonResult<Self::Resources> {
self.flush()?;
Ok(self.output)
}
}