1use std::io;
18use std::marker::PhantomData;
19
20use crate::lazy::decoder::{Decoder, LazyRawValueExpr, RawValueExpr};
21use crate::lazy::encoder::annotation_seq::AnnotationsVec;
22use crate::lazy::encoder::value_writer::{SequenceWriter, StructWriter, ValueWriter};
23use crate::lazy::encoding::Encoding;
24use crate::lazy::expanded::macro_evaluator::RawEExpression;
25use crate::lazy::text::raw::v1_1::arg_group::{EExpArg, EExpArgExpr};
26use crate::lazy::value::LazyValue;
27use crate::lazy::value_ref::ValueRef;
28use crate::v1_0::RawValueRef;
29use crate::{
30 Blob, Clob, Decimal, Element, Int, IonResult, IonType, LazyList, LazyRawFieldExpr,
31 LazyRawFieldName, LazyRawSequence, LazyRawStruct, LazyRawValue, LazySExp, LazyStruct, Null,
32 RawSymbolRef, Symbol, SymbolRef, Timestamp, Value, WriteConfig,
33};
34
35pub trait WriteAsIon {
38 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()>;
40
41 fn encode_as<E: Encoding, C: Into<WriteConfig<E>>>(&self, config: C) -> IonResult<E::Output>
60 where
61 for<'a> &'a Self: WriteAsIon,
62 {
63 config.into().encode(self)
64 }
65
66 fn encode_to<E: Encoding, C: Into<WriteConfig<E>>, W: io::Write>(
69 &self,
70 config: C,
71 output: W,
72 ) -> IonResult<W>
73 where
74 for<'a> &'a Self: WriteAsIon,
75 {
76 config.into().encode_to(self, output)
77 }
78}
79
80impl WriteAsIon for Element {
81 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
82 if self.annotations().is_empty() {
83 self.value().write_as_ion(writer)
84 } else {
85 self.value()
86 .write_as_ion(writer.with_annotations(self.annotations().as_ref())?)
87 }
88 }
89}
90
91macro_rules! impl_write_as_ion_value {
94 () => {};
96 ($target_type:ty => $method:ident with $self:ident as $value:expr, $($rest:tt)*) => {
98 impl WriteAsIon for $target_type {
99 #[inline]
100 fn write_as_ion<V: ValueWriter>(&$self, writer: V) -> IonResult<()> {
101 writer.$method($value)
102 }
103 }
104 impl_write_as_ion_value!($($rest)*);
105 };
106 ($target_type:ty => $method:ident, $($rest:tt)*) => {
108 impl WriteAsIon for $target_type {
109 #[inline]
110 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
111 writer.$method(self)
112 }
113 }
114 impl_write_as_ion_value!($($rest)*);
115 };
116}
117
118impl_write_as_ion_value!(
124 Null => write_null with self as self.0,
125 bool => write_bool with self as *self,
126 i16 => write_i64 with self as *self as i64,
127 i32 => write_i64 with self as *self as i64,
128 i64 => write_i64 with self as *self,
129 isize => write_i64 with self as *self as i64,
130 u16 => write_i64 with self as i64::from(*self),
131 u32 => write_i64 with self as i64::from(*self),
132 u64 => write_int with self as &Int::from(*self),
133 usize => write_int with self as &Int::from(*self),
134 f32 => write_f32 with self as *self,
135 f64 => write_f64 with self as *self,
136 Int => write_int,
137 Decimal => write_decimal,
138 Timestamp => write_timestamp,
139 Symbol => write_symbol,
140 &str => write_string,
141 String => write_string,
142 &[u8] => write_blob,
143 Blob => write_blob,
144 Clob => write_clob,
145);
146
147impl WriteAsIon for RawSymbolRef<'_> {
148 #[inline]
149 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
150 writer.write_symbol(self)
151 }
152}
153
154impl WriteAsIon for SymbolRef<'_> {
155 #[inline]
156 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
157 writer.write_symbol(self)
158 }
159}
160
161impl<const N: usize> WriteAsIon for [u8; N] {
162 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
163 writer.write_blob(self)
164 }
165}
166
167impl<T: WriteAsIon> WriteAsIon for &T {
168 #[inline]
169 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
170 (*self).write_as_ion(writer)
171 }
172}
173
174macro_rules! impl_write_as_ion_value_for_iterable {
175 ($iterable:ty, $item:ident $(, const $n:ident: $n_type:ty)?) => {
176 impl<'a, $item $(, const $n: $n_type)?> WriteAsIon for $iterable
177 where
178 $item: WriteAsIon + 'a,
179 {
180 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
181 writer.write_list(self.into_iter())
182 }
183 }
184 };
185}
186
187impl_write_as_ion_value_for_iterable!(Vec<T>, T);
188impl_write_as_ion_value_for_iterable!(&[T], T);
189impl_write_as_ion_value_for_iterable!([T; N], T, const N: usize);
190
191#[allow(dead_code)]
193pub trait WriteAsSExp<T>: Sized
194where
195 T: WriteAsIon,
196{
197 #[allow(clippy::wrong_self_convention)]
201 fn as_sexp(self) -> SExpTypeHint<Self, T>;
204}
205macro_rules! impl_write_as_sexp_for_iterable {
206 ($iterable:ty, $item:ident $(, const $n:ident: $n_type:ty)?) => {
207 impl<$item $(, const $n: $n_type)?> WriteAsSExp<$item> for $iterable
208 where
209 $item: WriteAsIon,
210 {
211 fn as_sexp(self) -> SExpTypeHint<Self, T> {
212 SExpTypeHint::new(self)
213 }
214 }
215 };
216}
217
218impl_write_as_sexp_for_iterable!(Vec<T>, T);
219impl_write_as_sexp_for_iterable!(&[T], T);
220impl_write_as_sexp_for_iterable!([T; N], T, const N: usize);
221
222pub struct SExpTypeHint<S, T> {
228 values: S,
229 spooky: PhantomData<T>,
230}
231
232#[allow(dead_code)] impl<S, T> SExpTypeHint<S, T> {
234 pub fn new(values: S) -> Self {
235 Self {
236 values,
237 spooky: PhantomData,
238 }
239 }
240}
241
242macro_rules! impl_write_as_ion_value_for_sexp_type_hint {
243 ($iterable:ty, $item:ident $(, const $n:ident: $n_type:ty)?) => {
244 impl<$item $(, const $n: $n_type)?> WriteAsIon for SExpTypeHint<$iterable, $item>
245 where
246 $item: WriteAsIon,
247 for<'a> &'a $item: WriteAsIon,
248 {
249 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
250 writer.write_sexp((&self.values).into_iter())
251 }
252 }
253 };
254}
255
256impl_write_as_ion_value_for_sexp_type_hint!(Vec<T>, T);
257impl_write_as_ion_value_for_sexp_type_hint!(&[T], T);
258impl_write_as_ion_value_for_sexp_type_hint!([T; N], T, const N: usize);
259
260impl WriteAsIon for Value {
261 fn write_as_ion<V: ValueWriter>(&self, value_writer: V) -> IonResult<()> {
262 use Value::*;
263 match self {
264 Null(i) => value_writer.write_null(*i),
265 Bool(b) => value_writer.write_bool(*b),
266 Int(i) => value_writer.write_int(i),
267 Float(f) => value_writer.write_f64(*f),
268 Decimal(d) => value_writer.write_decimal(d),
269 Timestamp(t) => value_writer.write_timestamp(t),
270 Symbol(s) => value_writer.write_symbol(s),
271 String(s) => value_writer.write_string(s),
272 Clob(c) => value_writer.write_clob(c),
273 Blob(b) => value_writer.write_blob(b),
274 List(l) => value_writer.write_list(l),
275 SExp(s) => value_writer.write_sexp(s),
276 Struct(s) => value_writer.write_struct(s.iter()),
277 }
278 }
279}
280
281impl<D: Decoder> WriteAsIon for LazyValue<'_, D> {
282 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
283 if self.has_annotations() {
284 let mut annotations = AnnotationsVec::new();
285 for annotation in self.annotations() {
286 annotations.push(annotation?.into());
287 }
288 self.read()?
289 .write_as_ion(writer.with_annotations(annotations)?)
290 } else {
291 self.read()?.write_as_ion(writer)
292 }
293 }
294}
295
296impl<D: Decoder> WriteAsIon for RawValueRef<'_, D> {
297 fn write_as_ion<V: ValueWriter>(&self, value_writer: V) -> IonResult<()> {
298 use RawValueRef::*;
299 match self {
300 Null(i) => value_writer.write_null(*i),
301 Bool(b) => value_writer.write_bool(*b),
302 Int(i) => value_writer.write_int(i),
303 Float(f) => value_writer.write_f64(*f),
304 Decimal(d) => value_writer.write_decimal(d),
305 Timestamp(t) => value_writer.write_timestamp(t),
306 Symbol(s) => value_writer.write_symbol(s),
307 String(s) => value_writer.write_string(s.text()),
308 Clob(c) => value_writer.write_clob(c.data()),
309 Blob(b) => value_writer.write_blob(b.data()),
310 List(l) => {
311 let mut list_writer = value_writer.list_writer()?;
312 for value_result in l.iter() {
313 list_writer.write(WriteableRawValueExpr::<'_, D>::new(value_result?))?;
314 }
315 list_writer.close()
316 }
317 SExp(s) => {
318 let mut sexp_writer = value_writer.sexp_writer()?;
319 for value_result in s.iter() {
320 sexp_writer.write(WriteableRawValueExpr::<'_, D>::new(value_result?))?;
321 }
322 sexp_writer.close()
323 }
324 Struct(s) => {
325 let mut struct_writer = value_writer.struct_writer()?;
326 for field_result in s.iter() {
327 let field: LazyRawFieldExpr<'_, D> = field_result?;
328 match field {
329 LazyRawFieldExpr::NameValue(name, value) => {
330 struct_writer.write(name.read()?, WriteableRawValue::new(value))?;
331 }
332 LazyRawFieldExpr::NameEExp(name, eexp) => {
333 struct_writer.write(name.read()?, WriteableEExp::new(eexp))?;
334 }
335 LazyRawFieldExpr::EExp(_eexp) => {
336 todo!("Writing e-expressions in field name position during transcription.");
337 }
338 }
339 }
340 struct_writer.close()
341 }
342 }
343 }
344}
345
346pub struct WriteableRawValue<'a, D: Decoder, RawValue: LazyRawValue<'a, D>> {
348 raw_value: RawValue,
349 spooky: PhantomData<&'a D>,
350}
351
352impl<'a, D: Decoder, RawValue: LazyRawValue<'a, D>> WriteableRawValue<'a, D, RawValue> {
353 pub fn new(raw_value: RawValue) -> Self {
354 Self {
355 raw_value,
356 spooky: PhantomData,
357 }
358 }
359}
360
361impl<'a, D: Decoder, RawValue: LazyRawValue<'a, D>> WriteAsIon
362 for WriteableRawValue<'a, D, RawValue>
363{
364 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
365 if self.raw_value.has_annotations() {
366 let mut annotations = AnnotationsVec::new();
367 for annotation in self.raw_value.annotations() {
368 annotations.push(annotation?);
369 }
370 self.raw_value
371 .read()?
372 .write_as_ion(writer.with_annotations(annotations)?)
373 } else {
374 self.raw_value.read()?.write_as_ion(writer)
375 }
376 }
377}
378
379pub struct WriteableEExp<'a, D: Decoder<EExp<'a> = RawEExp>, RawEExp: RawEExpression<'a, D> + 'a> {
381 raw_eexp: RawEExp,
382 spooky: PhantomData<&'a D>,
383}
384
385impl<'a, D: Decoder<EExp<'a> = RawEExp>, RawEExp: RawEExpression<'a, D> + 'a>
386 WriteableEExp<'a, D, RawEExp>
387{
388 pub fn new(raw_eexp: RawEExp) -> Self {
389 Self {
390 raw_eexp,
391 spooky: PhantomData,
392 }
393 }
394}
395
396impl<'a, D: Decoder<EExp<'a> = RawEExp>, RawEExp: RawEExpression<'a, D> + 'a> WriteAsIon
397 for WriteableEExp<'a, D, RawEExp>
398{
399 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
400 let id = self.raw_eexp.id();
401 let mut eexp_writer = writer.eexp_writer(id)?;
402 for arg_result in self.raw_eexp.raw_arguments() {
403 let arg = arg_result?;
404 eexp_writer.write(WriteableEExpArg::<'_, D>::new(arg))?;
405 }
406 eexp_writer.close()
407 }
408}
409
410pub struct WriteableEExpArg<'a, D: Decoder> {
412 arg_expr: EExpArg<'a, D>,
413 spooky: PhantomData<&'a D>,
414}
415
416impl<'a, D: Decoder> WriteableEExpArg<'a, D> {
417 pub fn new(arg_expr: EExpArg<'a, D>) -> Self {
418 Self {
419 arg_expr,
420 spooky: PhantomData,
421 }
422 }
423}
424
425impl<D: Decoder> WriteAsIon for WriteableEExpArg<'_, D> {
426 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
427 use EExpArgExpr::*;
428 match self.arg_expr.expr() {
429 ValueLiteral(v) => WriteableRawValue::new(*v).write_as_ion(writer),
431 EExp(e) => WriteableEExp::new(*e).write_as_ion(writer),
432 ArgGroup(group) => WriteableEExpArgGroup::<'_, D>::new(*group).write_as_ion(writer),
433 }
434 }
435}
436
437#[allow(dead_code)]
440pub struct WriteableEExpArgGroup<'a, D: Decoder> {
441 arg_group: <<D as Decoder>::EExp<'a> as RawEExpression<'a, D>>::ArgGroup,
442 spooky: PhantomData<&'a D>,
443}
444
445impl<'a, D: Decoder> WriteableEExpArgGroup<'a, D> {
446 pub fn new(arg_group: <<D as Decoder>::EExp<'a> as RawEExpression<'a, D>>::ArgGroup) -> Self {
447 Self {
448 arg_group,
449 spooky: PhantomData,
450 }
451 }
452}
453
454impl<D: Decoder> WriteAsIon for WriteableEExpArgGroup<'_, D> {
455 fn write_as_ion<V: ValueWriter>(&self, _writer: V) -> IonResult<()> {
456 todo!()
457 }
458}
459
460pub struct WriteableRawValueExpr<'a, D: Decoder> {
462 raw_value_expr: LazyRawValueExpr<'a, D>,
463 spooky: PhantomData<&'a D>,
464}
465
466impl<'a, D: Decoder> WriteableRawValueExpr<'a, D> {
467 pub fn new(raw_value_expr: LazyRawValueExpr<'a, D>) -> Self {
468 Self {
469 raw_value_expr,
470 spooky: PhantomData,
471 }
472 }
473}
474
475impl<D: Decoder> WriteAsIon for WriteableRawValueExpr<'_, D> {
476 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
477 use RawValueExpr::*;
478 match self.raw_value_expr {
479 ValueLiteral(v) => WriteableRawValue::new(v).write_as_ion(writer),
480 EExp(e) => WriteableEExp::new(e).write_as_ion(writer),
481 }
482 }
483}
484
485impl<D: Decoder> WriteAsIon for ValueRef<'_, D> {
486 fn write_as_ion<V: ValueWriter>(&self, value_writer: V) -> IonResult<()> {
487 use ValueRef::*;
488 match self {
489 Null(i) => value_writer.write_null(*i),
490 Bool(b) => value_writer.write_bool(*b),
491 Int(i) => value_writer.write_int(i),
492 Float(f) => value_writer.write_f64(*f),
493 Decimal(d) => value_writer.write_decimal(d),
494 Timestamp(t) => value_writer.write_timestamp(t),
495 Symbol(s) => value_writer.write_symbol(s),
496 String(s) => value_writer.write_string(s.text()),
497 Clob(c) => value_writer.write_clob(c.data()),
498 Blob(b) => value_writer.write_blob(b.data()),
499 List(l) => value_writer.write(l),
500 SExp(s) => value_writer.write(s),
501 Struct(s) => value_writer.write(s),
502 }
503 }
504}
505
506impl<D: Decoder> WriteAsIon for LazyList<'_, D> {
507 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
508 let mut list = writer.list_writer()?;
509 for value in self {
510 list.write(value?)?;
511 }
512 list.close()
513 }
514}
515
516impl<D: Decoder> WriteAsIon for LazySExp<'_, D> {
517 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
518 let mut sexp = writer.sexp_writer()?;
519 for value in self {
520 sexp.write(value?)?;
521 }
522 sexp.close()
523 }
524}
525
526impl<D: Decoder> WriteAsIon for LazyStruct<'_, D> {
527 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
528 let mut struct_writer = writer.struct_writer()?;
529 for field_result in self {
530 let field = field_result?;
531 struct_writer.write(field.name()?, field.value())?;
532 }
533 struct_writer.close()
534 }
535}
536
537impl<T: WriteAsIon> WriteAsIon for Option<T> {
538 fn write_as_ion<V: ValueWriter>(&self, writer: V) -> IonResult<()> {
539 if let Some(value) = self {
540 value.write_as_ion(writer)
541 } else {
542 writer.write_null(IonType::Null)
543 }
544 }
545}
546
547#[cfg(test)]
548mod tests {
549 use super::*;
550 use crate::v1_0;
551
552 #[test]
553 fn test_element_write_as_ion_without_annotations() -> IonResult<()> {
554 let element = Element::read_one("42")?;
555 let encoded: String = element.encode_as(v1_0::Text)?;
556 assert_eq!(encoded.trim(), "42");
557 Ok(())
558 }
559
560 #[test]
561 fn test_element_write_as_ion_with_annotations() -> IonResult<()> {
562 let element = Element::read_one("foo::42")?;
563 let encoded: String = element.encode_as(v1_0::Text)?;
564 assert_eq!(encoded.trim(), "foo::42");
565 Ok(())
566 }
567}