ion_c_sys/
writer.rs

1// Copyright Amazon.com, Inc. or its affiliates.
2
3//! Provides higher-level APIs for Ion C's `hWRITER`.
4
5use std::convert::TryInto;
6use std::marker::PhantomData;
7use std::ops::{Deref, DerefMut};
8use std::ptr;
9
10use crate::int::*;
11use crate::result::*;
12use crate::*;
13
14/// Indicates at a high-level what type of writer to use.
15pub enum WriterMode {
16    Text = 0,
17    Binary = 1,
18}
19
20/// The API for Ion C value writing.
21pub trait IonCValueWriter {
22    /// Writes a `null` value.
23    ///
24    /// ## Usage
25    /// ```
26    /// # use std::convert::*;
27    /// # use ion_c_sys::*;
28    /// # use ion_c_sys::writer::*;
29    /// # use ion_c_sys::result::*;
30    /// # fn main() -> IonCResult<()> {
31    /// let mut buf = vec![0; 128];
32    /// let len = {
33    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
34    ///     writer.write_null(ION_TYPE_INT)?;
35    ///     writer.finish()?
36    /// };
37    /// assert_eq!(b"\xE0\x01\x00\xEA\x2F", &buf[0..len]);
38    /// # Ok(())
39    /// # }
40    /// ```
41    fn write_null(&mut self, tid: ION_TYPE) -> IonCResult<()>;
42
43    /// Writes a `bool` value.
44    ///
45    /// ## Usage
46    /// ```
47    /// # use std::convert::*;
48    /// # use ion_c_sys::*;
49    /// # use ion_c_sys::writer::*;
50    /// # use ion_c_sys::result::*;
51    /// # fn main() -> IonCResult<()> {
52    /// let mut buf = vec![0; 128];
53    /// let len = {
54    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Text)?;
55    ///     writer.write_bool(true)?;
56    ///     writer.write_bool(false)?;
57    ///     writer.finish()?
58    /// };
59    /// assert_eq!(b"true false", &buf[0..len]);
60    /// # Ok(())
61    /// # }
62    /// ```
63    fn write_bool(&mut self, value: bool) -> IonCResult<()>;
64
65    /// Writes an `int` value.
66    ///
67    /// ## Usage
68    /// ```
69    /// # use std::convert::*;
70    /// # use ion_c_sys::*;
71    /// # use ion_c_sys::writer::*;
72    /// # use ion_c_sys::result::*;
73    /// # fn main() -> IonCResult<()> {
74    /// let mut buf = vec![0; 128];
75    /// let len = {
76    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
77    ///     writer.write_i64(-16)?;
78    ///     writer.finish()?
79    /// };
80    /// assert_eq!(b"\xE0\x01\x00\xEA\x31\x10", &buf[0..len]);
81    /// # Ok(())
82    /// # }
83    /// ```
84    fn write_i64(&mut self, value: i64) -> IonCResult<()>;
85
86    /// Writes an `int` value.
87    ///
88    /// ## Usage
89    /// ```
90    /// # use std::convert::*;
91    /// # use ion_c_sys::*;
92    /// # use ion_c_sys::writer::*;
93    /// # use ion_c_sys::result::*;
94    /// # use num_bigint::BigInt;
95    /// # fn main() -> IonCResult<()> {
96    /// let mut buf = vec![0; 128];
97    /// let len = {
98    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
99    ///     let value = BigInt::parse_bytes(b"987654321987654321987654321", 10).unwrap();
100    ///     writer.write_bigint(&value)?;
101    ///     writer.finish()?
102    /// };
103    /// assert_eq!(
104    ///     b"\xE0\x01\x00\xEA\x2C\x03\x30\xF7\xF0\x14\x03\xF9\x4E\xDB\x18\x12\xB1",
105    ///     &buf[0..len]);
106    /// # Ok(())
107    /// # }
108    /// ```
109    fn write_bigint(&mut self, value: &BigInt) -> IonCResult<()>;
110
111    /// Writes a `float` value.
112    ///
113    /// ## Usage
114    /// ```
115    /// # use std::convert::*;
116    /// # use ion_c_sys::*;
117    /// # use ion_c_sys::writer::*;
118    /// # use ion_c_sys::result::*;
119    /// # fn main() -> IonCResult<()> {
120    /// let mut buf = vec![0; 128];
121    /// let len = {
122    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
123    ///     writer.write_f64(3.0)?;
124    ///     writer.finish()?
125    /// };
126    /// assert_eq!(b"\xE0\x01\x00\xEA\x48\x40\x08\x00\x00\x00\x00\x00\x00", &buf[0..len]);
127    /// # Ok(())
128    /// # }
129    /// ```
130    fn write_f64(&mut self, value: f64) -> IonCResult<()>;
131
132    /// Writes a `decimal` value.
133    ///
134    /// ## Usage
135    /// ```
136    /// # use std::convert::*;
137    /// # use ion_c_sys::*;
138    /// # use ion_c_sys::writer::*;
139    /// # use ion_c_sys::result::*;
140    /// # use bigdecimal::BigDecimal;
141    /// # fn main() -> IonCResult<()> {
142    /// let mut buf = vec![0; 128];
143    /// let len = {
144    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
145    ///     let value = BigDecimal::parse_bytes(b"1.1", 10).unwrap();
146    ///     writer.write_bigdecimal(&value)?;
147    ///     writer.finish()?
148    /// };
149    /// assert_eq!(
150    ///     b"\xE0\x01\x00\xEA\x52\xC1\x0B",
151    ///     &buf[0..len]);
152    /// # Ok(())
153    /// # }
154    /// ```
155    fn write_bigdecimal(&mut self, value: &BigDecimal) -> IonCResult<()>;
156
157    /// Writes a `timestamp` value.
158    ///
159    /// ## Usage
160    /// ```
161    /// # use std::convert::*;
162    /// # use ion_c_sys::*;
163    /// # use ion_c_sys::writer::*;
164    /// # use ion_c_sys::result::*;
165    /// # use ion_c_sys::timestamp::*;
166    /// # use ion_c_sys::timestamp::Mantissa::*;
167    /// # use ion_c_sys::timestamp::TSPrecision::*;
168    /// # use ion_c_sys::timestamp::TSOffsetKind::*;
169    /// # use chrono::DateTime;
170    /// # fn main() -> IonCResult<()> {
171    /// let mut buf = vec![0; 128];
172    /// let len = {
173    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Text)?;
174    ///     let dt = DateTime::parse_from_rfc3339("2020-01-02T12:34:00.123Z").unwrap();
175    ///
176    ///     // write the date time with microsecond precision and an unknown offset
177    ///     let ion_dt = IonDateTime::try_new(dt, Fractional(Digits(6)), UnknownOffset)?;
178    ///     writer.write_datetime(&ion_dt)?;
179    ///     writer.finish()?
180    /// };
181    /// assert_eq!(
182    ///     b"2020-01-02T12:34:00.123000-00:00",
183    ///     &buf[0..len]);
184    /// # Ok(())
185    /// # }
186    /// ```
187    fn write_datetime(&mut self, value: &IonDateTime) -> IonCResult<()>;
188
189    /// Writes a `symbol` value.
190    ///
191    /// ## Usage
192    /// ```
193    /// # use std::convert::*;
194    /// # use ion_c_sys::*;
195    /// # use ion_c_sys::writer::*;
196    /// # use ion_c_sys::result::*;
197    /// # fn main() -> IonCResult<()> {
198    /// let mut buf = vec![0; 128];
199    /// let len = {
200    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Text)?;
201    ///     writer.write_symbol("🍥")?;
202    ///     writer.finish()?
203    /// };
204    /// assert_eq!(b"'\xF0\x9F\x8D\xA5'", &buf[0..len]);
205    /// # Ok(())
206    /// # }
207    /// ```
208    fn write_symbol(&mut self, value: &str) -> IonCResult<()>;
209
210    /// Writes a `string` value.
211    ///
212    /// ## Usage
213    /// ```
214    /// # use std::convert::*;
215    /// # use ion_c_sys::*;
216    /// # use ion_c_sys::writer::*;
217    /// # use ion_c_sys::result::*;
218    /// # fn main() -> IonCResult<()> {
219    /// let mut buf = vec![0; 128];
220    /// let len = {
221    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
222    ///     writer.write_string("🐡")?;
223    ///     writer.finish()?
224    /// };
225    /// assert_eq!(b"\xE0\x01\x00\xEA\x84\xF0\x9F\x90\xA1", &buf[0..len]);
226    /// # Ok(())
227    /// # }
228    /// ```
229    fn write_string(&mut self, value: &str) -> IonCResult<()>;
230
231    /// Writes a `clob` value.
232    ///
233    /// ## Usage
234    /// ```
235    /// # use std::convert::*;
236    /// # use ion_c_sys::*;
237    /// # use ion_c_sys::writer::*;
238    /// # use ion_c_sys::result::*;
239    /// # fn main() -> IonCResult<()> {
240    /// let mut buf = vec![0; 128];
241    /// let len = {
242    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
243    ///     writer.write_clob("🐡".as_bytes())?;
244    ///     writer.finish()?
245    /// };
246    /// assert_eq!(b"\xE0\x01\x00\xEA\x94\xF0\x9F\x90\xA1", &buf[0..len]);
247    /// # Ok(())
248    /// # }
249    /// ```
250    fn write_clob(&mut self, value: &[u8]) -> IonCResult<()>;
251
252    /// Writes a `blob` value.
253    ///
254    /// ## Usage
255    /// ```
256    /// # use std::convert::*;
257    /// # use ion_c_sys::*;
258    /// # use ion_c_sys::writer::*;
259    /// # use ion_c_sys::result::*;
260    /// # fn main() -> IonCResult<()> {
261    /// let mut buf = vec![0; 128];
262    /// let len = {
263    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Text)?;
264    ///     writer.write_blob("🍥".as_bytes())?;
265    ///     writer.finish()?
266    /// };
267    /// assert_eq!(b"{{8J+NpQ==}}", &buf[0..len]);
268    /// # Ok(())
269    /// # }
270    /// ```
271    fn write_blob(&mut self, value: &[u8]) -> IonCResult<()>;
272
273    /// Starts a container.
274    ///
275    /// ## Usage
276    /// ```
277    /// # use std::convert::*;
278    /// # use ion_c_sys::*;
279    /// # use ion_c_sys::writer::*;
280    /// # use ion_c_sys::result::*;
281    /// # fn main() -> IonCResult<()> {
282    /// let mut buf = vec![0; 128];
283    /// let len = {
284    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
285    ///     writer.start_container(ION_TYPE_LIST)?;
286    ///     writer.finish_container()?;
287    ///     writer.finish()?
288    /// };
289    /// assert_eq!(b"\xE0\x01\x00\xEA\xB0", &buf[0..len]);
290    /// # Ok(())
291    /// # }
292    /// ```
293    fn start_container(&mut self, tid: ION_TYPE) -> IonCResult<()>;
294
295    /// Finishes a container.
296    fn finish_container(&mut self) -> IonCResult<()>;
297}
298
299/// The API for writing values with annotations and/or field names.
300pub trait IonCAnnotationsFieldWriter {
301    /// The associated type of value writer when writing within annotations/field context
302    type AFValueWriter: IonCValueWriter;
303
304    /// Writes a value within a context of annotations and/or a field name
305    ///
306    /// Note that it is undefined behavior if a value writing method is **not** called
307    /// or if a value writing method is called **more than once**.  For this reason,
308    /// most users should prefer the `field()` and/or `annotations()` method on the
309    /// [`IonCWriter`](./trait.IonCWriter.html) trait as it doesn't have this edge case.
310    fn write_annotations_and_field<'a, A, F, FN>(
311        &mut self,
312        annotations: A,
313        field: F,
314        applier: FN,
315    ) -> IonCResult<()>
316    where
317        A: Into<Option<&'a [&'a str]>>,
318        F: Into<Option<&'a str>>,
319        FN: Fn(&mut Self::AFValueWriter) -> IonCResult<()>;
320}
321
322/// The writing API for Ion C.
323///
324/// See also:
325/// * [`IonCValueWriter`](./trait.IonCValueWriter.html)
326/// * [`IonCWriterHandle`](./struct.IonCWriterHandle.html)
327///
328/// ## Usage
329/// ```
330/// # use ion_c_sys::*;
331/// # use ion_c_sys::writer::*;
332/// # use ion_c_sys::result::*;
333/// # use std::convert::*;
334/// # use std::ptr;
335/// # fn main() -> IonCResult<()> {
336/// // a buffer to write to
337/// let mut buf = vec![0; 12];
338///
339/// // borrow the buffer and do some writing!
340/// let len = {
341///     // write in binary
342///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut(), WriterMode::Binary)?;
343///
344///     // write something
345///     writer.write_i64(4)?;
346///
347///     // finish up the writing
348///     writer.finish()?
349///
350///     // handle implements Drop, so we're good to go!
351/// };
352///
353/// assert_eq!(b"\xE0\x01\x00\xEA\x21\x04", &buf[0..len]);
354/// # Ok(())
355/// # }
356/// ```
357pub trait IonCWriter<'a>: IonCValueWriter + IonCAnnotationsFieldWriter {
358    /// Returns a lifetime safe writing context for a field.
359    ///
360    /// ## Usage
361    /// ```
362    /// # use std::convert::*;
363    /// # use ion_c_sys::*;
364    /// # use ion_c_sys::writer::*;
365    /// # use ion_c_sys::result::*;
366    /// # fn main() -> IonCResult<()> {
367    /// let mut buf = vec![0; 128];
368    /// let len = {
369    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
370    ///     writer.start_container(ION_TYPE_STRUCT)?;
371    ///     {
372    ///         writer.field("name").write_string("kumo")?;
373    ///     }
374    ///     writer.finish_container()?;
375    ///     writer.finish()?
376    /// };
377    /// assert_eq!(b"\xE0\x01\x00\xEA\xD6\x84\x84kumo", &buf[0..len]);
378    /// # Ok(())
379    /// # }
380    /// ```
381    fn field<'b, 'c>(
382        &'b mut self,
383        field: &'c str,
384    ) -> IonCAnnotationsFieldWriterContext<'b, 'c, Self> {
385        IonCAnnotationsFieldWriterContext::new_field(self, field)
386    }
387
388    /// Returns a lifetime safe writing context for annotations.
389    ///
390    /// ## Usage
391    /// ```
392    /// # use std::convert::*;
393    /// # use std::str;
394    /// # use ion_c_sys::*;
395    /// # use ion_c_sys::writer::*;
396    /// # use ion_c_sys::result::*;
397    /// # fn main() -> IonCResult<()> {
398    /// let mut buf = vec![0; 128];
399    /// let len = {
400    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Text)?;
401    ///     writer.annotations(&["a", "b", "c"]).start_container(ION_TYPE_STRUCT)?;
402    ///     {
403    ///         writer.field("name").annotations(&["def"]).write_string("kumo")?;
404    ///         writer.annotations(&["ghi"]).field("type").write_symbol("dog")?;
405    ///     }
406    ///     writer.finish_container()?;
407    ///     writer.finish()?
408    /// };
409    /// assert_eq!("a::b::c::{name:def::\"kumo\",type:ghi::dog}", str::from_utf8(&buf[0..len])?);
410    /// # Ok(())
411    /// # }
412    /// ```
413    fn annotations<'b, 'c>(
414        &'b mut self,
415        annotations: &'c [&'c str],
416    ) -> IonCAnnotationsFieldWriterContext<'b, 'c, Self> {
417        IonCAnnotationsFieldWriterContext::new_annotations(self, annotations)
418    }
419
420    /// Finalizes writing for the writer and returns the amount of bytes written.
421    fn finish(&mut self) -> IonCResult<usize>;
422}
423
424/// Wrapper over `hWRITER` to make it easier to use writers in IonC correctly.
425///
426/// Specifically supports the `Drop` trait to make sure `ion_writer_close` is run.
427/// Access to the underlying `hWRITER` pointer is done by de-referencing the handle.
428///
429/// See also:
430/// * [IonCWriter](./trait.IonCWriter.html)
431/// * [IonCValueWriter](./trait.IonCValueWriter.html)
432pub struct IonCWriterHandle<'a> {
433    writer: hWRITER,
434    /// Placeholder to tie our lifecycle back to the destination--which might not
435    /// actually be a byte slice (if we constructed this from a file or Ion C stream callback)
436    referent: PhantomData<&'a mut u8>,
437}
438
439impl<'a> IonCWriterHandle<'a> {
440    /// Construct a writer to a given mutable slice with options.
441    #[inline]
442    pub fn new_buf(buf: &'a mut [u8], options: &mut ION_WRITER_OPTIONS) -> Result<Self, IonCError> {
443        let mut writer = ptr::null_mut();
444        ionc!(ion_writer_open_buffer(
445            &mut writer,
446            buf.as_mut_ptr(),
447            buf.len().try_into()?,
448            options
449        ))?;
450
451        Ok(IonCWriterHandle {
452            writer,
453            referent: PhantomData::default(),
454        })
455    }
456
457    /// Construct a text/binary mode writer with otherwise default options.
458    #[inline]
459    pub fn new_buf_mode(buf: &'a mut [u8], mode: WriterMode) -> Result<Self, IonCError> {
460        let mut options = ION_WRITER_OPTIONS {
461            output_as_binary: mode as i32,
462            ..Default::default()
463        };
464        Self::new_buf(buf, &mut options)
465    }
466}
467
468impl<'a> IonCWriter<'a> for IonCWriterHandle<'a> {
469    #[inline]
470    fn finish(&mut self) -> IonCResult<usize> {
471        let mut len = 0;
472        ionc!(ion_writer_finish(self.writer, &mut len))?;
473
474        Ok(len.try_into()?)
475    }
476}
477
478impl IonCValueWriter for IonCWriterHandle<'_> {
479    #[allow(clippy::not_unsafe_ptr_arg_deref)]
480    #[inline]
481    fn write_null(&mut self, tid: ION_TYPE) -> IonCResult<()> {
482        ionc!(ion_writer_write_typed_null(self.writer, tid))
483    }
484
485    #[inline]
486    fn write_bool(&mut self, value: bool) -> IonCResult<()> {
487        ionc!(ion_writer_write_bool(self.writer, value as BOOL))
488    }
489
490    #[inline]
491    fn write_i64(&mut self, value: i64) -> IonCResult<()> {
492        ionc!(ion_writer_write_int64(self.writer, value))
493    }
494
495    #[inline]
496    fn write_bigint(&mut self, value: &BigInt) -> IonCResult<()> {
497        let mut ion_int = IonIntPtr::try_from_bigint(value)?;
498        ionc!(ion_writer_write_ion_int(self.writer, &mut *ion_int))
499    }
500
501    #[inline]
502    fn write_f64(&mut self, value: f64) -> IonCResult<()> {
503        ionc!(ion_writer_write_double(self.writer, value))
504    }
505
506    #[inline]
507    fn write_bigdecimal(&mut self, value: &BigDecimal) -> IonCResult<()> {
508        let mut ion_decimal = IonDecimalPtr::try_from_bigdecimal(value)?;
509        ionc!(ion_writer_write_ion_decimal(self.writer, &mut *ion_decimal))
510    }
511
512    #[inline]
513    fn write_datetime(&mut self, value: &IonDateTime) -> IonCResult<()> {
514        let mut ion_timestamp = ION_TIMESTAMP::default();
515        ion_timestamp.try_assign_from_iondt(value)?;
516        ionc!(ion_writer_write_timestamp(self.writer, &mut ion_timestamp))
517    }
518
519    #[inline]
520    fn write_symbol(&mut self, value: &str) -> IonCResult<()> {
521        // Ion C promises that it won't do mutation for this call!
522        let mut ion_str = ION_STRING::try_from_str(value)?;
523        ionc!(ion_writer_write_symbol(self.writer, &mut ion_str))
524    }
525
526    #[inline]
527    fn write_string(&mut self, value: &str) -> IonCResult<()> {
528        // Ion C promises that it won't do mutation for this call!
529        let mut ion_str = ION_STRING::try_from_str(value)?;
530        ionc!(ion_writer_write_string(self.writer, &mut ion_str))
531    }
532
533    #[inline]
534    fn write_clob(&mut self, value: &[u8]) -> IonCResult<()> {
535        // Ion C promises that it won't mutate the buffer for this call!
536        ionc!(ion_writer_write_clob(
537            self.writer,
538            value.as_ptr() as *mut u8,
539            value.len().try_into()?
540        ))
541    }
542
543    #[inline]
544    fn write_blob(&mut self, value: &[u8]) -> IonCResult<()> {
545        // Ion C promises that it won't mutate the buffer for this call!
546        ionc!(ion_writer_write_blob(
547            self.writer,
548            value.as_ptr() as *mut u8,
549            value.len().try_into()?
550        ))
551    }
552
553    #[allow(clippy::not_unsafe_ptr_arg_deref)]
554    #[inline]
555    fn start_container(&mut self, tid: ION_TYPE) -> IonCResult<()> {
556        ionc!(ion_writer_start_container(self.writer, tid))
557    }
558
559    #[inline]
560    fn finish_container(&mut self) -> IonCResult<()> {
561        ionc!(ion_writer_finish_container(self.writer))
562    }
563}
564
565impl IonCAnnotationsFieldWriter for IonCWriterHandle<'_> {
566    type AFValueWriter = Self;
567
568    #[inline]
569    fn write_annotations_and_field<'a, A, F, FN>(
570        &mut self,
571        possible_annotations: A,
572        possible_field: F,
573        applier: FN,
574    ) -> IonCResult<()>
575    where
576        A: Into<Option<&'a [&'a str]>>,
577        F: Into<Option<&'a str>>,
578        FN: Fn(&mut Self::AFValueWriter) -> IonCResult<()>,
579    {
580        // Ion C promises that it won't do mutation for these!
581        if let Some(annotations) = possible_annotations.into() {
582            for annotation in annotations {
583                let mut annotation_str = ION_STRING::try_from_str(annotation)?;
584                ionc!(ion_writer_add_annotation(self.writer, &mut annotation_str))?;
585            }
586        }
587        if let Some(field) = possible_field.into() {
588            let mut ion_field = ION_STRING::try_from_str(field)?;
589            ionc!(ion_writer_write_field_name(self.writer, &mut ion_field))?;
590        }
591        applier(self)?;
592
593        Ok(())
594    }
595}
596
597impl Deref for IonCWriterHandle<'_> {
598    type Target = hWRITER;
599
600    fn deref(&self) -> &Self::Target {
601        &self.writer
602    }
603}
604
605impl DerefMut for IonCWriterHandle<'_> {
606    fn deref_mut(&mut self) -> &mut Self::Target {
607        &mut self.writer
608    }
609}
610
611impl Drop for IonCWriterHandle<'_> {
612    fn drop(&mut self) {
613        if !self.writer.is_null() {
614            ionc!(ion_writer_close(self.writer)).unwrap()
615        }
616    }
617}
618
619/// Context for writing annotations and fields in with proper reference lifetimes.
620///
621/// Specifically, writing annotations and fields with Ion C with
622/// `ion_writer_write_annotations`/`ion_writer_add_annotation` and `ion_writer_write_field`
623/// is particularly problematic because the lifetime of the `ION_STRING`
624/// passed into that function, must be valid until a corresponding
625/// `ion_writer_write_*` function is called for writing a value.
626///
627/// This context tracks the lifetime of the string slices that a user wants to
628/// write as annotations and the field name along with a mutable borrow of the writer handle
629/// and ensures that calls to `ion_writer_add_annotation`/`ion_writer_write_field`
630/// happen before invoking the `ion_writer_write_*` call for the value in a lifetime correct way.
631///
632/// Note that this context can be thought of as a partial function for writing
633/// annotations and/or `struct` fields, so doing nothing with it is simply a no-op, and performing
634/// multiple [`IonCValueWriter`](./trait.IonCValueWriter.html) trait method invocations
635/// is the same as writing the field before invoking the value writing methods
636/// (so duplicate fields would be generated in that case).
637pub struct IonCAnnotationsFieldWriterContext<'b, 'c, T: IonCAnnotationsFieldWriter + ?Sized> {
638    writer: &'b mut T,
639    annotations: Option<&'c [&'c str]>,
640    field: Option<&'c str>,
641}
642
643impl<'b, 'c, T: IonCAnnotationsFieldWriter + ?Sized> IonCAnnotationsFieldWriterContext<'b, 'c, T> {
644    #[inline]
645    fn new_field(writer: &'b mut T, field: &'c str) -> Self {
646        Self {
647            writer,
648            annotations: None,
649            field: Some(field),
650        }
651    }
652
653    #[inline]
654    fn new_annotations(writer: &'b mut T, annotations: &'c [&'c str]) -> Self {
655        Self {
656            writer,
657            annotations: Some(annotations),
658            field: None,
659        }
660    }
661
662    /// Sets the annotations for the context.
663    #[inline]
664    pub fn annotations(&mut self, annotations: &'c [&'c str]) -> &mut Self {
665        self.annotations = Some(annotations);
666        self
667    }
668
669    /// Sets the field name for the context.
670    #[inline]
671    pub fn field(&mut self, field: &'c str) -> &mut Self {
672        self.field = Some(field);
673        self
674    }
675
676    #[inline]
677    fn write_annotations_and_field<F>(&mut self, applier: F) -> IonCResult<()>
678    where
679        F: Fn(&mut T::AFValueWriter) -> IonCResult<()>,
680    {
681        self.writer
682            .write_annotations_and_field(self.annotations, self.field, applier)?;
683
684        Ok(())
685    }
686}
687
688impl<T: IonCAnnotationsFieldWriter + ?Sized> IonCValueWriter
689    for IonCAnnotationsFieldWriterContext<'_, '_, T>
690{
691    #[inline]
692    fn write_null(&mut self, tid: ION_TYPE) -> IonCResult<()> {
693        self.write_annotations_and_field(|v| v.write_null(tid))
694    }
695
696    #[inline]
697    fn write_bool(&mut self, value: bool) -> IonCResult<()> {
698        self.write_annotations_and_field(|v| v.write_bool(value))
699    }
700
701    #[inline]
702    fn write_i64(&mut self, value: i64) -> IonCResult<()> {
703        self.write_annotations_and_field(|v| v.write_i64(value))
704    }
705
706    #[inline]
707    fn write_bigint(&mut self, value: &BigInt) -> IonCResult<()> {
708        self.write_annotations_and_field(|v| v.write_bigint(value))
709    }
710
711    #[inline]
712    fn write_f64(&mut self, value: f64) -> IonCResult<()> {
713        self.write_annotations_and_field(|v| v.write_f64(value))
714    }
715
716    #[inline]
717    fn write_bigdecimal(&mut self, value: &BigDecimal) -> IonCResult<()> {
718        self.write_annotations_and_field(|v| v.write_bigdecimal(value))
719    }
720
721    fn write_datetime(&mut self, value: &IonDateTime) -> IonCResult<()> {
722        self.write_annotations_and_field(|v| v.write_datetime(value))
723    }
724
725    #[inline]
726    fn write_symbol(&mut self, value: &str) -> IonCResult<()> {
727        self.write_annotations_and_field(|v| v.write_symbol(value))
728    }
729
730    #[inline]
731    fn write_string(&mut self, value: &str) -> IonCResult<()> {
732        self.write_annotations_and_field(|v| v.write_string(value))
733    }
734
735    #[inline]
736    fn write_clob(&mut self, value: &[u8]) -> IonCResult<()> {
737        self.write_annotations_and_field(|v| v.write_clob(value))
738    }
739
740    #[inline]
741    fn write_blob(&mut self, value: &[u8]) -> IonCResult<()> {
742        self.write_annotations_and_field(|v| v.write_blob(value))
743    }
744
745    #[inline]
746    fn start_container(&mut self, tid: ION_TYPE) -> IonCResult<()> {
747        self.write_annotations_and_field(|v| v.start_container(tid))
748    }
749
750    /// This API is not relevant for this context and will always return an error.
751    #[inline]
752    fn finish_container(&mut self) -> IonCResult<()> {
753        Err(IonCError::from(ion_error_code_IERR_INVALID_STATE))
754    }
755}