use std::io::Write;
use delegate::delegate;
use crate::lazy::encoder::text::v1_0::value_writer::TextValueWriter_1_0;
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, TextEncoding_1_0};
use crate::lazy::expanded::macro_table::EMPTY_MACRO_TABLE;
use crate::text::whitespace_config::{
WhitespaceConfig, COMPACT_WHITESPACE_CONFIG, LINES_WHITESPACE_CONFIG, PRETTY_WHITESPACE_CONFIG,
};
use crate::types::ParentType;
use crate::write_config::WriteConfigKind;
use crate::{ContextWriter, IonResult, TextFormat, WriteConfig};
pub struct LazyRawTextWriter_1_0<W: Write> {
pub(crate) output: W,
pub(crate) whitespace_config: &'static WhitespaceConfig,
}
impl<W: Write> LazyRawTextWriter_1_0<W> {
pub fn new(output: W) -> IonResult<Self> {
<Self as LazyRawWriter<W>>::new(output)
}
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<()> {
self.output.flush()?;
Ok(())
}
#[inline]
fn value_writer(&mut self) -> TextValueWriter_1_0<'_, W> {
TextValueWriter_1_0::new(
self,
0,
"", ParentType::TopLevel,
)
}
}
impl<W: Write> SequenceWriter for LazyRawTextWriter_1_0<W> {
type Resources = W;
fn close(mut self) -> IonResult<Self::Resources> {
self.flush()?;
Ok(self.output)
}
}
impl<W: Write> ContextWriter for LazyRawTextWriter_1_0<W> {
type NestedValueWriter<'a>
= TextValueWriter_1_0<'a, W>
where
Self: 'a;
}
impl<W: Write> MakeValueWriter for LazyRawTextWriter_1_0<W> {
fn make_value_writer(&mut self) -> Self::NestedValueWriter<'_> {
self.value_writer()
}
}
impl<W: Write> LazyRawWriter<W> for LazyRawTextWriter_1_0<W> {
fn new(output: W) -> IonResult<Self> {
Self::build(
WriteConfig::<TextEncoding_1_0>::new(TextFormat::default()),
output,
)
}
fn build<E: Encoding>(config: WriteConfig<E>, output: W) -> IonResult<Self> {
match &config.kind {
WriteConfigKind::Text(text_config) => {
let whitespace_config = match text_config.text_kind {
TextFormat::Compact => &COMPACT_WHITESPACE_CONFIG,
TextFormat::Lines => &LINES_WHITESPACE_CONFIG,
TextFormat::Pretty => &PRETTY_WHITESPACE_CONFIG,
};
Ok(LazyRawTextWriter_1_0 {
output,
whitespace_config,
})
}
WriteConfigKind::Binary(_) => {
unreachable!("Binary writer can not be created from text encoding")
}
}
}
delegate! {
to self {
fn flush(&mut self) -> IonResult<()>;
}
}
fn output(&self) -> &W {
&self.output
}
fn output_mut(&mut self) -> &mut W {
&mut self.output
}
fn macro_table(&self) -> &WriterMacroTable {
&EMPTY_MACRO_TABLE
}
fn macro_table_mut(&mut self) -> Option<&mut WriterMacroTable> {
None
}
fn write_version_marker(&mut self) -> IonResult<()> {
let space_between = self.whitespace_config.space_between_top_level_values;
write!(self.output, "$ion_1_0{space_between}")?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::element::reader::ElementReader;
use crate::lazy::encoder::text::v1_0::writer::LazyRawTextWriter_1_0;
use crate::{v1_1, Annotatable, IonData, IonResult, Reader, SequenceWriter};
#[test]
fn write_annotated_values() -> IonResult<()> {
const NO_ANNOTATIONS: [&str; 0] = [];
let mut writer = LazyRawTextWriter_1_0::new(vec![])?;
writer
.write(1)?
.write(2.annotated_with(NO_ANNOTATIONS))?
.write(3.annotated_with("foo"))?
.write(4.annotated_with(["foo", "bar", "baz"]))?;
let encoded_bytes = writer.close()?;
let encoded_text = String::from_utf8(encoded_bytes).unwrap();
println!("{encoded_text}");
let expected_ion = r#"
1
2 // An explicitly empty annotations sequence results in an unannotated value
foo::3
foo::bar::baz::4
"#;
let mut reader = Reader::new(v1_1::Text, encoded_text)?;
let actual = reader.read_all_elements()?;
let mut reader = Reader::new(v1_1::Text, expected_ion)?;
let expected = reader.read_all_elements()?;
assert!(IonData::eq(&expected, &actual));
Ok(())
}
}