ion_rs/text/
text_writer.rs1use crate::element::writer::TextKind;
2use crate::raw_symbol_token_ref::{AsRawSymbolTokenRef, RawSymbolTokenRef};
3use crate::result::IonResult;
4use crate::text::raw_text_writer::RawTextWriter;
5use crate::types::{Decimal, Timestamp};
6use crate::writer::IonWriter;
7use crate::{Int, IonType, RawTextWriterBuilder, SymbolTable};
8use delegate::delegate;
9use std::io::Write;
10
11pub struct TextWriterBuilder {
12 text_kind: TextKind,
13}
14
15impl TextWriterBuilder {
16 pub fn new(format: TextKind) -> TextWriterBuilder {
18 TextWriterBuilder { text_kind: format }
19 }
20
21 pub fn compact() -> TextWriterBuilder {
29 TextWriterBuilder {
30 text_kind: TextKind::Compact,
31 }
32 }
33
34 pub fn lines() -> TextWriterBuilder {
45 TextWriterBuilder {
46 text_kind: TextKind::Lines,
47 }
48 }
49
50 pub fn pretty() -> TextWriterBuilder {
68 TextWriterBuilder {
69 text_kind: TextKind::Pretty,
70 }
71 }
72
73 pub fn build<W: Write>(self, sink: W) -> IonResult<TextWriter<W>> {
76 let builder = match self.text_kind {
77 TextKind::Compact => RawTextWriterBuilder::default(),
78 TextKind::Pretty => RawTextWriterBuilder::pretty(),
79 TextKind::Lines => RawTextWriterBuilder::lines(),
80 };
81 let raw_writer = builder.build(sink)?;
82 let text_writer = TextWriter {
83 raw_writer,
84 symbol_table: SymbolTable::new(),
85 };
86 Ok(text_writer)
87 }
88}
89
90impl Default for TextWriterBuilder {
91 fn default() -> Self {
92 TextWriterBuilder::new(TextKind::Compact)
93 }
94}
95
96pub struct TextWriter<W: Write> {
102 raw_writer: RawTextWriter<W>,
103 symbol_table: SymbolTable,
104}
105
106impl<W: Write> IonWriter for TextWriter<W> {
107 type Output = W;
108
109 fn supports_text_symbol_tokens(&self) -> bool {
110 true
112 }
113
114 fn set_annotations<I, A>(&mut self, annotations: I)
115 where
116 A: AsRawSymbolTokenRef,
117 I: IntoIterator<Item = A>,
118 {
119 for annotation in annotations {
120 let raw_symbol_token_ref = match annotation.as_raw_symbol_token_ref() {
121 RawSymbolTokenRef::SymbolId(symbol_id) => {
122 match self.symbol_table.text_for(symbol_id) {
124 Some(text) => RawSymbolTokenRef::Text(text),
125 None => RawSymbolTokenRef::SymbolId(symbol_id),
126 }
127 }
128 text_token => text_token,
129 };
130 self.raw_writer.add_annotation(raw_symbol_token_ref);
131 }
132 }
133
134 fn write_symbol<A: AsRawSymbolTokenRef>(&mut self, value: A) -> IonResult<()> {
135 let raw_symbol_token_ref = match value.as_raw_symbol_token_ref() {
136 RawSymbolTokenRef::SymbolId(symbol_id) => {
137 match self.symbol_table.text_for(symbol_id) {
139 Some(text) => RawSymbolTokenRef::Text(text),
140 None => RawSymbolTokenRef::SymbolId(symbol_id),
141 }
142 }
143 text_token => text_token,
144 };
145 self.raw_writer.write_symbol(raw_symbol_token_ref)
146 }
147
148 fn set_field_name<A: AsRawSymbolTokenRef>(&mut self, name: A) {
149 let raw_symbol_token_ref = match name.as_raw_symbol_token_ref() {
150 RawSymbolTokenRef::SymbolId(symbol_id) => {
151 match self.symbol_table.text_for(symbol_id) {
153 Some(text) => RawSymbolTokenRef::Text(text),
154 None => RawSymbolTokenRef::SymbolId(symbol_id),
155 }
156 }
157 text_token => text_token,
158 };
159 self.raw_writer.set_field_name(raw_symbol_token_ref);
160 }
161
162 delegate! {
163 to self.raw_writer {
164 fn ion_version(&self) -> (u8, u8);
165 fn write_ion_version_marker(&mut self, major: u8, minor: u8) -> IonResult<()>;
166 fn write_null(&mut self, ion_type: IonType) -> IonResult<()>;
167 fn write_bool(&mut self, value: bool) -> IonResult<()>;
168 fn write_i64(&mut self, value: i64) -> IonResult<()>;
169 fn write_int(&mut self, value: &Int) -> IonResult<()>;
170 fn write_f32(&mut self, value: f32) -> IonResult<()>;
171 fn write_f64(&mut self, value: f64) -> IonResult<()>;
172 fn write_decimal(&mut self, value: &Decimal) -> IonResult<()>;
173 fn write_timestamp(&mut self, value: &Timestamp) -> IonResult<()>;
174 fn write_string<A: AsRef<str>>(&mut self, value: A) -> IonResult<()>;
175 fn write_clob<A: AsRef<[u8]>>(&mut self, value: A) -> IonResult<()>;
176 fn write_blob<A: AsRef<[u8]>>(&mut self, value: A) -> IonResult<()>;
177 fn step_in(&mut self, container_type: IonType) -> IonResult<()>;
178 fn parent_type(&self) -> Option<IonType>;
179 fn depth(&self) -> usize;
180 fn step_out(&mut self) -> IonResult<()>;
181 fn flush(&mut self) -> IonResult<()>;
182 fn output(&self) -> &Self::Output;
183 fn output_mut(&mut self) -> &mut Self::Output;
184 }
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191 use crate::reader::ReaderBuilder;
192 use crate::IonReader;
193 use crate::StreamItem::Value;
194
195 #[test]
196 fn resolve_symbol_ids() -> IonResult<()> {
197 let mut buffer = Vec::new();
201 let mut text_writer = TextWriterBuilder::default().build(&mut buffer)?;
202 text_writer.step_in(IonType::Struct)?;
205 text_writer.set_field_name(4);
206 text_writer.set_annotations([1]);
207 text_writer.write_symbol(5)?;
208 text_writer.step_out()?;
209 text_writer.flush()?;
210
211 let mut reader = ReaderBuilder::new().build(text_writer.output().as_slice())?;
212 assert_eq!(Value(IonType::Struct), reader.next()?);
213 reader.step_in()?;
214 assert_eq!(Value(IonType::Symbol), reader.next()?);
215 assert_eq!(1, reader.number_of_annotations());
216 assert_eq!("$ion", reader.annotations().next().unwrap()?);
218 assert_eq!("name", reader.field_name()?);
219 assert_eq!("version", reader.read_symbol()?);
220
221 Ok(())
222 }
223}