Skip to content

Commit

Permalink
Simplifies the ValueWriter trait family (#732)
Browse files Browse the repository at this point in the history
* Adds traits: `ListFn`, `SExpFn`, `StructFn`, `MacroArgsFn`, removing
  several lifetimes from trait method signatures and associated types.
* Removes superfluous `ContainerValues` family of 1.0 writer types.
  • Loading branch information
zslayton committed Apr 2, 2024
1 parent 652122e commit ca3ef27
Show file tree
Hide file tree
Showing 10 changed files with 402 additions and 454 deletions.
19 changes: 0 additions & 19 deletions src/lazy/encoder/binary/mod.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,2 @@
pub mod v1_0;
pub mod v1_1;

/// Takes a series of `TYPE => METHOD` pairs, generating a function for each that calls the host
/// type's `encode_annotated` method to encode an annotations sequence and then delegates encoding
/// the value to the corresponding value writer method.
// This macro is used in the v1_0 and v1_1 binary writer implementations, which both define an
// `encode_annotated` method. That method is not codified (for example: in a trait); this relies
// solely on convention between the two.
macro_rules! annotate_and_delegate {
// End of iteration
() => {};
// Recurses one argument pair at a time
($value_type:ty => $method:ident, $($rest:tt)*) => {
fn $method(self, value: $value_type) -> IonResult<()> {
self.encode_annotated(|value_writer| value_writer.$method(value))
}
annotate_and_delegate!($($rest)*);
};
}
pub(crate) use annotate_and_delegate;
216 changes: 50 additions & 166 deletions src/lazy/encoder/binary/v1_0/container_writers.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
use bumpalo::collections::Vec as BumpVec;
use bumpalo::Bump as BumpAllocator;

use crate::binary::var_uint::VarUInt;
use crate::lazy::encoder::binary::v1_0::value_writer::{
BinaryAnnotatableValueWriter_1_0, MAX_INLINE_LENGTH,
};
use crate::lazy::encoder::binary::v1_0::value_writer::BinaryAnnotatableValueWriter_1_0;
use crate::lazy::encoder::value_writer::internal::MakeValueWriter;
use crate::lazy::encoder::value_writer::{SequenceWriter, StructWriter};
use crate::lazy::encoder::write_as_ion::WriteAsIon;
use crate::raw_symbol_token_ref::AsRawSymbolTokenRef;
use crate::result::EncodingError;
use crate::{IonError, IonResult, RawSymbolTokenRef};
use bumpalo::collections::Vec as BumpVec;
use bumpalo::Bump as BumpAllocator;
use delegate::delegate;

/// A helper type that holds fields and logic that is common to [`BinaryListWriter_1_0`],
/// [`BinarySExpWriter_1_0`], and [`BinaryStructWriter_1_0`].
Expand All @@ -22,43 +20,31 @@ pub struct BinaryContainerWriter_1_0<'value, 'top> {
// The buffer containing the parent's encoded body. When this list writer is finished encoding
// its own data, a header will be written to the parent and then the list body will be copied
// over.
parent_buffer: &'value mut BumpVec<'top, u8>,
buffer: &'value mut BumpVec<'top, u8>,
}

impl<'value, 'top> BinaryContainerWriter_1_0<'value, 'top> {
pub fn new(
type_code: u8,
allocator: &'top BumpAllocator,
parent_buffer: &'value mut BumpVec<'top, u8>,
buffer: &'value mut BumpVec<'top, u8>,
) -> Self {
Self {
type_code,
allocator,
parent_buffer,
buffer,
}
}

pub fn write_values<'a, F>(mut self, write_fn: F) -> IonResult<()>
where
'top: 'a,
F: FnOnce(BinaryContainerValuesWriter_1_0<'a>) -> IonResult<BumpVec<'a, u8>>,
{
let container_values_writer = BinaryContainerValuesWriter_1_0::new(self.allocator);
let encoded_values = write_fn(container_values_writer)?;
self.write_header_and_encoded_body(encoded_values.as_slice())
pub fn write<V: WriteAsIon>(&mut self, value: V) -> IonResult<&mut Self> {
let annotated_value_writer =
BinaryAnnotatableValueWriter_1_0::new(self.allocator, self.buffer);
value.write_as_ion(annotated_value_writer)?;
Ok(self)
}

fn write_header_and_encoded_body(&mut self, body: &[u8]) -> IonResult<()> {
let body_length = body.len();
if body_length <= MAX_INLINE_LENGTH {
let type_descriptor = self.type_code | (body_length as u8);
self.parent_buffer.push(type_descriptor);
} else {
self.parent_buffer.push(self.type_code | 0xE);
VarUInt::write_u64(&mut self.parent_buffer, body_length as u64)?;
}
self.parent_buffer.extend_from_slice_copy(body);
Ok(())
pub fn buffer(&self) -> &[u8] {
self.buffer.as_slice()
}
}

Expand All @@ -72,108 +58,48 @@ pub struct BinaryContainerValuesWriter_1_0<'value> {
// reallocations/copies.
const DEFAULT_CONTAINER_BUFFER_SIZE: usize = 512;

impl<'value> BinaryContainerValuesWriter_1_0<'value> {
pub fn new(allocator: &'value BumpAllocator) -> Self {
let buffer = BumpVec::with_capacity_in(DEFAULT_CONTAINER_BUFFER_SIZE, allocator);
Self { allocator, buffer }
}

pub fn write<V: WriteAsIon>(&mut self, value: V) -> IonResult<&mut Self> {
let annotated_value_writer =
BinaryAnnotatableValueWriter_1_0::new(self.allocator, &mut self.buffer);
value.write_as_ion(annotated_value_writer)?;
Ok(self)
}
}

pub struct BinaryListValuesWriter_1_0<'value> {
values_writer: BinaryContainerValuesWriter_1_0<'value>,
}

impl<'value> BinaryListValuesWriter_1_0<'value> {
pub fn new(values_writer: BinaryContainerValuesWriter_1_0<'value>) -> Self {
Self { values_writer }
}
pub fn write<V: WriteAsIon>(&mut self, value: V) -> IonResult<&mut Self> {
self.values_writer.write(value)?;
Ok(self)
}
}

impl<'value> MakeValueWriter for BinaryListValuesWriter_1_0<'value> {
type ValueWriter<'a> = BinaryAnnotatableValueWriter_1_0<'a, 'value> where Self: 'a;

fn make_value_writer(&mut self) -> Self::ValueWriter<'_> {
BinaryAnnotatableValueWriter_1_0::new(
self.values_writer.allocator,
&mut self.values_writer.buffer,
)
}
}

impl<'value> SequenceWriter for BinaryListValuesWriter_1_0<'value> {
delegate! {
to self {
fn write<V: WriteAsIon>(&mut self, value: V) -> IonResult<&mut Self>;
}
}
}

pub struct BinaryListWriter_1_0<'value, 'top> {
container_writer: BinaryContainerWriter_1_0<'value, 'top>,
pub(crate) container_writer: BinaryContainerWriter_1_0<'value, 'top>,
}

impl<'value, 'top> BinaryListWriter_1_0<'value, 'top> {
pub fn new(container_writer: BinaryContainerWriter_1_0<'value, 'top>) -> Self {
Self { container_writer }
}

pub fn write_values<'a, F>(self, write_fn: F) -> IonResult<()>
where
'top: 'a,
F: FnOnce(&mut BinaryListValuesWriter_1_0<'a>) -> IonResult<()>,
{
self.container_writer
.write_values(|container_values_writer| {
let mut list_values_writer =
BinaryListValuesWriter_1_0::new(container_values_writer);
write_fn(&mut list_values_writer)?;
Ok(list_values_writer.values_writer.buffer)
})
pub fn buffer(&self) -> &[u8] {
self.container_writer.buffer()
}
}

pub struct BinarySExpValuesWriter_1_0<'value> {
values_writer: BinaryContainerValuesWriter_1_0<'value>,
}
impl<'value, 'top> MakeValueWriter for BinaryListWriter_1_0<'value, 'top> {
type ValueWriter<'a> = BinaryAnnotatableValueWriter_1_0<'a, 'top> where Self: 'a;

impl<'value> BinarySExpValuesWriter_1_0<'value> {
pub fn new(values_writer: BinaryContainerValuesWriter_1_0<'value>) -> Self {
Self { values_writer }
}
pub fn write<V: WriteAsIon>(&mut self, value: V) -> IonResult<&mut Self> {
self.values_writer.write(value)?;
Ok(self)
fn make_value_writer(&mut self) -> Self::ValueWriter<'_> {
BinaryAnnotatableValueWriter_1_0::new(
self.container_writer.allocator,
self.container_writer.buffer,
)
}
}

impl<'value> MakeValueWriter for BinarySExpValuesWriter_1_0<'value> {
type ValueWriter<'a> = BinaryAnnotatableValueWriter_1_0<'a, 'value> where Self: 'a;
impl<'value, 'top> SequenceWriter for BinaryListWriter_1_0<'value, 'top> {
// All default methods
}

impl<'value, 'top> MakeValueWriter for BinarySExpWriter_1_0<'value, 'top> {
type ValueWriter<'a> = BinaryAnnotatableValueWriter_1_0<'a, 'top> where Self: 'a;

fn make_value_writer(&mut self) -> Self::ValueWriter<'_> {
BinaryAnnotatableValueWriter_1_0::new(
self.values_writer.allocator,
&mut self.values_writer.buffer,
self.container_writer.allocator,
self.container_writer.buffer,
)
}
}

impl<'value> SequenceWriter for BinarySExpValuesWriter_1_0<'value> {
delegate! {
to self {
fn write<V: WriteAsIon>(&mut self, value: V) -> IonResult<&mut Self>;
}
}
impl<'value, 'top> SequenceWriter for BinarySExpWriter_1_0<'value, 'top> {
// All default methods
}

pub struct BinarySExpWriter_1_0<'value, 'top> {
Expand All @@ -187,33 +113,29 @@ impl<'value, 'top> BinarySExpWriter_1_0<'value, 'top> {
}
}

pub fn write_values<'a, F>(self, write_fn: F) -> IonResult<()>
where
'top: 'a,
F: FnOnce(&mut BinarySExpValuesWriter_1_0<'a>) -> IonResult<()>,
{
self.container_writer
.write_values(|container_values_writer| {
let mut sexp_values_writer =
BinarySExpValuesWriter_1_0::new(container_values_writer);
write_fn(&mut sexp_values_writer)?;
Ok(sexp_values_writer.values_writer.buffer)
})
pub fn buffer(&self) -> &[u8] {
self.container_writer.buffer()
}
}

pub struct BinaryStructFieldsWriter_1_0<'value> {
container_values_writer: BinaryContainerValuesWriter_1_0<'value>,
pub struct BinaryStructWriter_1_0<'value, 'top> {
container_writer: BinaryContainerWriter_1_0<'value, 'top>,
}

impl<'value> BinaryStructFieldsWriter_1_0<'value> {
pub fn new(container_values_writer: BinaryContainerValuesWriter_1_0<'value>) -> Self {
impl<'value, 'top> BinaryStructWriter_1_0<'value, 'top> {
pub fn new(container: BinaryContainerWriter_1_0<'value, 'top>) -> Self {
Self {
container_values_writer,
container_writer: container,
}
}

pub fn write<A: AsRawSymbolTokenRef, V: WriteAsIon>(
pub fn buffer(&self) -> &[u8] {
self.container_writer.buffer()
}
}

impl<'value, 'top> StructWriter for BinaryStructWriter_1_0<'value, 'top> {
fn write<A: AsRawSymbolTokenRef, V: WriteAsIon>(
&mut self,
name: A,
value: V,
Expand All @@ -227,48 +149,10 @@ impl<'value> BinaryStructFieldsWriter_1_0<'value> {
))));
}
};
VarUInt::write_u64(&mut self.container_values_writer.buffer, sid as u64)?;
VarUInt::write_u64(&mut self.container_writer.buffer, sid as u64)?;

// Write the field value
self.container_values_writer.write(value)?;
self.container_writer.write(value)?;
Ok(self)
}
}

impl<'value> StructWriter for BinaryStructFieldsWriter_1_0<'value> {
delegate! {
to self {
fn write<A: AsRawSymbolTokenRef, V: WriteAsIon>(
&mut self,
name: A,
value: V,
) -> IonResult<&mut Self>;
}
}
}

pub struct BinaryStructWriter_1_0<'value, 'top> {
container_writer: BinaryContainerWriter_1_0<'value, 'top>,
}

impl<'value, 'top> BinaryStructWriter_1_0<'value, 'top> {
pub fn new(container: BinaryContainerWriter_1_0<'value, 'top>) -> Self {
Self {
container_writer: container,
}
}

pub fn write_fields<'a, F>(self, write_fn: F) -> IonResult<()>
where
'top: 'a,
F: FnOnce(&mut BinaryStructFieldsWriter_1_0<'a>) -> IonResult<()>,
{
self.container_writer
.write_values(|container_values_writer| {
let mut struct_fields_writer =
BinaryStructFieldsWriter_1_0::new(container_values_writer);
write_fn(&mut struct_fields_writer)?;
Ok(struct_fields_writer.container_values_writer.buffer)
})
}
}
Loading

0 comments on commit ca3ef27

Please sign in to comment.