use crate::lazy::encoder::annotation_seq::{AnnotationSeq, AnnotationsVec};
use crate::lazy::encoder::value_writer::internal::{
EExpWriterInternal, FieldEncoder, MakeValueWriter,
};
use crate::lazy::encoder::write_as_ion::WriteAsIon;
use crate::lazy::text::raw::v1_1::reader::MacroIdLike;
use crate::raw_symbol_ref::AsRawSymbolRef;
use crate::{Decimal, Int, IonResult, IonType, RawSymbolRef, Timestamp, UInt};
pub(crate) mod internal {
use crate::lazy::expanded::template::Parameter;
use crate::raw_symbol_ref::AsRawSymbolRef;
use crate::{ContextWriter, IonResult};
pub trait MakeValueWriter: ContextWriter {
fn make_value_writer(&mut self) -> <Self as ContextWriter>::NestedValueWriter<'_>;
}
pub trait FieldEncoder {
fn encode_field_name(&mut self, name: impl AsRawSymbolRef) -> IonResult<()>;
}
pub trait EExpWriterInternal {
fn expect_next_parameter(&mut self) -> IonResult<&Parameter>;
}
}
pub trait ContextWriter {
type NestedValueWriter<'a>: ValueWriter
where
Self: 'a;
}
pub trait EExpWriter: SequenceWriter + EExpWriterInternal {
type ExprGroupWriter<'group>: SequenceWriter
where
Self: 'group;
fn invoked_macro(&self) -> MacroRef<'_>;
fn current_parameter(&self) -> Option<&Parameter>;
fn write_flex_uint(&mut self, _value: impl Into<UInt>) -> IonResult<()> {
todo!("currently only implemented for binary 1.1 to enable unit testing for the reader")
}
fn write_fixed_uint8(&mut self, _value: impl Into<u8>) -> IonResult<()> {
todo!("currently only implemented for binary 1.1 to enable unit testing for the reader")
}
fn expr_group_writer(&mut self) -> IonResult<Self::ExprGroupWriter<'_>>;
}
pub trait AnnotatableWriter {
type AnnotatedValueWriter<'a>: ValueWriter
where
Self: 'a;
fn with_annotations<'a>(
self,
annotations: impl AnnotationSeq<'a>,
) -> IonResult<Self::AnnotatedValueWriter<'a>>
where
Self: 'a;
}
pub trait ValueWriter: AnnotatableWriter + Sized {
type ListWriter: SequenceWriter<Resources = ()>;
type SExpWriter: SequenceWriter<Resources = ()>;
type StructWriter: StructWriter;
type EExpWriter: EExpWriter<Resources = ()>;
fn write_null(self, ion_type: IonType) -> IonResult<()>;
fn write_bool(self, value: bool) -> IonResult<()>;
fn write_i64(self, value: i64) -> IonResult<()>;
fn write_int(self, value: &Int) -> IonResult<()>;
fn write_f32(self, value: f32) -> IonResult<()>;
fn write_f64(self, value: f64) -> IonResult<()>;
fn write_decimal(self, value: &Decimal) -> IonResult<()>;
fn write_timestamp(self, value: &Timestamp) -> IonResult<()>;
fn write_string(self, value: impl AsRef<str>) -> IonResult<()>;
fn write_symbol(self, value: impl AsRawSymbolRef) -> IonResult<()>;
fn write_clob(self, value: impl AsRef<[u8]>) -> IonResult<()>;
fn write_blob(self, value: impl AsRef<[u8]>) -> IonResult<()>;
fn list_writer(self) -> IonResult<Self::ListWriter>;
fn sexp_writer(self) -> IonResult<Self::SExpWriter>;
fn struct_writer(self) -> IonResult<Self::StructWriter>;
fn eexp_writer<'a>(self, macro_id: impl MacroIdLike<'a>) -> IonResult<Self::EExpWriter>
where
Self: 'a;
fn write(self, value: impl WriteAsIon) -> IonResult<()> {
value.write_as_ion(self)
}
fn write_list<V: WriteAsIon, I: IntoIterator<Item = V>>(self, values: I) -> IonResult<()> {
let mut list = self.list_writer()?;
list.write_all(values)?;
list.close()
}
fn write_sexp<V: WriteAsIon, I: IntoIterator<Item = V>>(self, values: I) -> IonResult<()> {
let mut sexp = self.sexp_writer()?;
sexp.write_all(values)?;
sexp.close()
}
fn write_struct<K: AsRawSymbolRef, V: WriteAsIon, I: IntoIterator<Item = (K, V)>>(
self,
values: I,
) -> IonResult<()> {
let mut strukt = self.struct_writer()?;
strukt.write_all(values)?;
strukt.close()
}
}
macro_rules! delegate_value_writer_to {
() => {
$crate::lazy::encoder::value_writer::delegate_value_writer_to!(closure std::convert::identity);
};
($name:ident) => {
$crate::lazy::encoder::value_writer::delegate_value_writer_to!(closure |self_: Self| self_.$name);
};
(closure $f:expr) => {
$crate::lazy::encoder::value_writer::delegate_value_writer_to!(fallible closure |self_| {
let infallible_closure = $f;
$crate::IonResult::Ok(infallible_closure(self_))
});
};
(fallible closure $f:expr) => {
delegate::delegate! {
to {let f = $f; f(self)?} {
fn write_null(self, ion_type: IonType) -> IonResult<()>;
fn write_bool(self, value: bool) -> IonResult<()>;
fn write_i64(self, value: i64) -> IonResult<()>;
fn write_int(self, value: &Int) -> IonResult<()>;
fn write_f32(self, value: f32) -> IonResult<()>;
fn write_f64(self, value: f64) -> IonResult<()>;
fn write_decimal(self, value: &Decimal) -> IonResult<()>;
fn write_timestamp(self, value: &Timestamp) -> IonResult<()>;
fn write_string(self, value: impl AsRef<str>) -> IonResult<()>;
fn write_symbol(self, value: impl AsRawSymbolRef) -> IonResult<()>;
fn write_clob(self, value: impl AsRef<[u8]>) -> IonResult<()>;
fn write_blob(self, value: impl AsRef<[u8]>) -> IonResult<()>;
fn list_writer(self) -> IonResult<Self::ListWriter>;
fn sexp_writer(self) -> IonResult<Self::SExpWriter>;
fn struct_writer(self) -> IonResult<Self::StructWriter>;
fn eexp_writer<'a>(
self,
macro_id: impl MacroIdLike<'a>,
) -> IonResult<Self::EExpWriter> where Self: 'a;
}
}
};
}
macro_rules! delegate_value_writer_to_self {
() => {
$crate::lazy::encoder::value_writer::delegate_value_writer_to!();
};
}
use crate::lazy::encoder::value_writer_config::ValueWriterConfig;
use crate::lazy::expanded::macro_table::MacroRef;
use crate::lazy::expanded::template::Parameter;
pub(crate) use delegate_value_writer_to;
pub(crate) use delegate_value_writer_to_self;
pub struct FieldWriter<'field, StructWriterType> {
name: RawSymbolRef<'field>,
struct_writer: &'field mut StructWriterType,
#[allow(dead_code)]
value_writer_config: ValueWriterConfig,
}
impl<'field, StructWriterType> FieldWriter<'field, StructWriterType> {
pub(crate) fn new(
name: RawSymbolRef<'field>,
value_writer_config: ValueWriterConfig,
struct_writer: &'field mut StructWriterType,
) -> Self {
Self {
name,
struct_writer,
value_writer_config,
}
}
}
impl<StructWriterType: StructWriter> AnnotatableWriter for FieldWriter<'_, StructWriterType> {
type AnnotatedValueWriter<'a>
= AnnotatedFieldWriter<'a, StructWriterType>
where
Self: 'a;
fn with_annotations<'a>(
self,
annotations: impl AnnotationSeq<'a>,
) -> IonResult<Self::AnnotatedValueWriter<'a>>
where
Self: 'a,
{
Ok(AnnotatedFieldWriter::new(
self.name,
annotations,
self.struct_writer,
))
}
}
impl<'field, StructWriterType: StructWriter> ValueWriter for FieldWriter<'field, StructWriterType> {
type ListWriter =
<<StructWriterType as ContextWriter>::NestedValueWriter<'field> as ValueWriter>::ListWriter;
type SExpWriter =
<<StructWriterType as ContextWriter>::NestedValueWriter<'field> as ValueWriter>::SExpWriter;
type StructWriter =
<<StructWriterType as ContextWriter>::NestedValueWriter<'field> as ValueWriter>::StructWriter;
type EExpWriter =
<<StructWriterType as ContextWriter>::NestedValueWriter<'field> as ValueWriter>::EExpWriter;
delegate_value_writer_to!(fallible closure |self_: Self| {
self_.struct_writer.encode_field_name(self_.name)?;
let value_writer = self_.struct_writer.make_value_writer();
IonResult::Ok(value_writer)
});
}
pub struct AnnotatedFieldWriter<'field, StructWriterType> {
name: RawSymbolRef<'field>,
annotations: AnnotationsVec<'field>,
struct_writer: &'field mut StructWriterType,
}
impl<'field, StructWriterType: StructWriter> AnnotatedFieldWriter<'field, StructWriterType> {
pub(crate) fn new(
name: RawSymbolRef<'field>,
annotations: impl AnnotationSeq<'field>,
struct_writer: &'field mut StructWriterType,
) -> Self {
Self {
name,
annotations: annotations.into_annotations_vec(),
struct_writer,
}
}
}
impl<StructWriterType: StructWriter> AnnotatableWriter
for AnnotatedFieldWriter<'_, StructWriterType>
{
type AnnotatedValueWriter<'a>
= AnnotatedFieldWriter<'a, StructWriterType>
where
Self: 'a;
fn with_annotations<'a>(
self,
annotations: impl AnnotationSeq<'a>,
) -> IonResult<Self::AnnotatedValueWriter<'a>>
where
Self: 'a,
{
Ok(AnnotatedFieldWriter {
name: self.name,
annotations: annotations.into_annotations_vec(),
struct_writer: self.struct_writer,
})
}
}
impl<'field, StructWriterType: StructWriter> ValueWriter
for AnnotatedFieldWriter<'field, StructWriterType>
{
type ListWriter =
<<<StructWriterType as ContextWriter>::NestedValueWriter<'field> as AnnotatableWriter>::AnnotatedValueWriter<'field> as ValueWriter>::ListWriter;
type SExpWriter =
<<<StructWriterType as ContextWriter>::NestedValueWriter<'field> as AnnotatableWriter>::AnnotatedValueWriter<'field> as ValueWriter>::SExpWriter;
type StructWriter =
<<<StructWriterType as ContextWriter>::NestedValueWriter<'field> as AnnotatableWriter>::AnnotatedValueWriter<'field> as ValueWriter>::StructWriter;
type EExpWriter =
<<<StructWriterType as ContextWriter>::NestedValueWriter<'field> as AnnotatableWriter>::AnnotatedValueWriter<'field> as ValueWriter>::EExpWriter;
delegate_value_writer_to!(fallible closure |self_: Self| {
self_.struct_writer.encode_field_name(self_.name)?;
let value_writer = self_.struct_writer.make_value_writer().with_annotations(self_.annotations)?;
IonResult::Ok(value_writer)
});
}
pub trait StructWriter: FieldEncoder + MakeValueWriter + Sized {
fn write<A: AsRawSymbolRef, V: WriteAsIon>(
&mut self,
name: A,
value: V,
) -> IonResult<&mut Self> {
self.encode_field_name(name)?;
value.write_as_ion(self.make_value_writer())?;
Ok(self)
}
fn write_all<A: AsRawSymbolRef, V: WriteAsIon, I: IntoIterator<Item = (A, V)>>(
&mut self,
fields: I,
) -> IonResult<&mut Self> {
for field in fields {
self.write(field.0, field.1)?;
}
Ok(self)
}
fn field_writer<'a>(&'a mut self, name: impl Into<RawSymbolRef<'a>>) -> FieldWriter<'a, Self> {
FieldWriter::new(name.into(), self.config(), self)
}
fn close(self) -> IonResult<()>;
fn config(&self) -> ValueWriterConfig;
}
macro_rules! delegate_and_return_self {
() => {};
($value_type:ty => $method:ident, $($rest:tt)*) => {
fn $method(&mut self, value: $value_type) -> IonResult<&mut Self> {
self.value_writer().$method(value)?;
Ok(self)
}
delegate_and_return_self!($($rest)*);
};
}
pub trait SequenceWriter: MakeValueWriter {
type Resources;
fn value_writer(&mut self) -> Self::NestedValueWriter<'_> {
<Self as MakeValueWriter>::make_value_writer(self)
}
fn write<V: WriteAsIon>(&mut self, value: V) -> IonResult<&mut Self> {
value.write_as_ion(self.make_value_writer())?;
Ok(self)
}
fn write_all<V: WriteAsIon, I: IntoIterator<Item = V>>(
&mut self,
values: I,
) -> IonResult<&mut Self> {
for value in values {
self.write(value)?;
}
Ok(self)
}
fn close(self) -> IonResult<Self::Resources>;
delegate_and_return_self!(
IonType => write_null,
bool => write_bool,
i64 => write_i64,
&Int => write_int,
f32 => write_f32,
f64 => write_f64,
&Decimal => write_decimal,
&Timestamp => write_timestamp,
impl AsRef<str> => write_string,
impl AsRawSymbolRef => write_symbol,
impl AsRef<[u8]> => write_clob,
impl AsRef<[u8]> => write_blob,
);
fn list_writer(
&mut self,
) -> IonResult<<Self::NestedValueWriter<'_> as ValueWriter>::ListWriter> {
self.value_writer().list_writer()
}
fn sexp_writer(
&mut self,
) -> IonResult<<Self::NestedValueWriter<'_> as ValueWriter>::SExpWriter> {
self.value_writer().sexp_writer()
}
fn struct_writer(
&mut self,
) -> IonResult<<Self::NestedValueWriter<'_> as ValueWriter>::StructWriter> {
self.value_writer().struct_writer()
}
fn eexp_writer<'a>(
&'a mut self,
macro_id: impl MacroIdLike<'a>,
) -> IonResult<<Self::NestedValueWriter<'a> as ValueWriter>::EExpWriter> {
self.value_writer().eexp_writer(macro_id)
}
fn write_list<V: WriteAsIon, I: IntoIterator<Item = V>>(
&mut self,
values: I,
) -> IonResult<&mut Self> {
self.value_writer().write_list(values)?;
Ok(self)
}
fn write_sexp<V: WriteAsIon, I: IntoIterator<Item = V>>(
&mut self,
values: I,
) -> IonResult<&mut Self> {
self.value_writer().write_sexp(values)?;
Ok(self)
}
fn write_struct<K: AsRawSymbolRef, V: WriteAsIon, I: IntoIterator<Item = (K, V)>>(
&mut self,
fields: I,
) -> IonResult<&mut Self> {
self.value_writer().write_struct(fields)?;
Ok(self)
}
}
#[cfg(all(test, feature = "experimental-reader-writer"))]
mod tests {
use crate::symbol_ref::AsSymbolRef;
use crate::{ion_seq, v1_0, Element, IntoAnnotatedElement, SequenceWriter, Writer};
use crate::{AnnotatableWriter, IonResult, ValueWriter};
#[test]
fn save_and_reuse_symbol_id() -> IonResult<()> {
let mut writer = Writer::new(v1_0::Binary, vec![])?;
let name_symbol = writer
.value_writer()
.symbol_table()
.sid_for("name")
.unwrap();
writer
.write_symbol(name_symbol)?
.write_symbol(name_symbol)?
.value_writer()
.with_annotations(name_symbol)?
.write_symbol(name_symbol)?;
let bytes = writer.close()?;
let actual = Element::read_all(&bytes)?;
let expected = ion_seq!(
"name".as_symbol_ref()
"name".as_symbol_ref()
"name".as_symbol_ref().with_annotations(["name"])
);
assert_eq!(actual, expected);
Ok(())
}
}