ion-c-sys 0.4.15

Bindings to Amazon Ion C
Documentation
// Copyright Amazon.com, Inc. or its affiliates.

//! Provides higher-level APIs for Ion C's `hWRITER`.

use std::convert::TryInto;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::ptr;

use crate::int::*;
use crate::result::*;
use crate::*;

/// Indicates at a high-level what type of writer to use.
pub enum WriterMode {
    Text = 0,
    Binary = 1,
}

/// The API for Ion C value writing.
pub trait IonCValueWriter {
    /// Writes a `null` value.
    ///
    /// ## Usage
    /// ```
    /// # use std::convert::*;
    /// # use ion_c_sys::*;
    /// # use ion_c_sys::writer::*;
    /// # use ion_c_sys::result::*;
    /// # fn main() -> IonCResult<()> {
    /// let mut buf = vec![0; 128];
    /// let len = {
    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
    ///     writer.write_null(ION_TYPE_INT)?;
    ///     writer.finish()?
    /// };
    /// assert_eq!(b"\xE0\x01\x00\xEA\x2F", &buf[0..len]);
    /// # Ok(())
    /// # }
    /// ```
    fn write_null(&mut self, tid: ION_TYPE) -> IonCResult<()>;

    /// Writes a `bool` value.
    ///
    /// ## Usage
    /// ```
    /// # use std::convert::*;
    /// # use ion_c_sys::*;
    /// # use ion_c_sys::writer::*;
    /// # use ion_c_sys::result::*;
    /// # fn main() -> IonCResult<()> {
    /// let mut buf = vec![0; 128];
    /// let len = {
    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Text)?;
    ///     writer.write_bool(true)?;
    ///     writer.write_bool(false)?;
    ///     writer.finish()?
    /// };
    /// assert_eq!(b"true false", &buf[0..len]);
    /// # Ok(())
    /// # }
    /// ```
    fn write_bool(&mut self, value: bool) -> IonCResult<()>;

    /// Writes an `int` value.
    ///
    /// ## Usage
    /// ```
    /// # use std::convert::*;
    /// # use ion_c_sys::*;
    /// # use ion_c_sys::writer::*;
    /// # use ion_c_sys::result::*;
    /// # fn main() -> IonCResult<()> {
    /// let mut buf = vec![0; 128];
    /// let len = {
    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
    ///     writer.write_i64(-16)?;
    ///     writer.finish()?
    /// };
    /// assert_eq!(b"\xE0\x01\x00\xEA\x31\x10", &buf[0..len]);
    /// # Ok(())
    /// # }
    /// ```
    fn write_i64(&mut self, value: i64) -> IonCResult<()>;

    /// Writes an `int` value.
    ///
    /// ## Usage
    /// ```
    /// # use std::convert::*;
    /// # use ion_c_sys::*;
    /// # use ion_c_sys::writer::*;
    /// # use ion_c_sys::result::*;
    /// # use num_bigint::BigInt;
    /// # fn main() -> IonCResult<()> {
    /// let mut buf = vec![0; 128];
    /// let len = {
    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
    ///     let value = BigInt::parse_bytes(b"987654321987654321987654321", 10).unwrap();
    ///     writer.write_bigint(&value)?;
    ///     writer.finish()?
    /// };
    /// assert_eq!(
    ///     b"\xE0\x01\x00\xEA\x2C\x03\x30\xF7\xF0\x14\x03\xF9\x4E\xDB\x18\x12\xB1",
    ///     &buf[0..len]);
    /// # Ok(())
    /// # }
    /// ```
    fn write_bigint(&mut self, value: &BigInt) -> IonCResult<()>;

    /// Writes a `float` value.
    ///
    /// ## Usage
    /// ```
    /// # use std::convert::*;
    /// # use ion_c_sys::*;
    /// # use ion_c_sys::writer::*;
    /// # use ion_c_sys::result::*;
    /// # fn main() -> IonCResult<()> {
    /// let mut buf = vec![0; 128];
    /// let len = {
    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
    ///     writer.write_f64(3.0)?;
    ///     writer.finish()?
    /// };
    /// assert_eq!(b"\xE0\x01\x00\xEA\x48\x40\x08\x00\x00\x00\x00\x00\x00", &buf[0..len]);
    /// # Ok(())
    /// # }
    /// ```
    fn write_f64(&mut self, value: f64) -> IonCResult<()>;

    /// Writes a `decimal` value.
    ///
    /// ## Usage
    /// ```
    /// # use std::convert::*;
    /// # use ion_c_sys::*;
    /// # use ion_c_sys::writer::*;
    /// # use ion_c_sys::result::*;
    /// # use bigdecimal::BigDecimal;
    /// # fn main() -> IonCResult<()> {
    /// let mut buf = vec![0; 128];
    /// let len = {
    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
    ///     let value = BigDecimal::parse_bytes(b"1.1", 10).unwrap();
    ///     writer.write_bigdecimal(&value)?;
    ///     writer.finish()?
    /// };
    /// assert_eq!(
    ///     b"\xE0\x01\x00\xEA\x52\xC1\x0B",
    ///     &buf[0..len]);
    /// # Ok(())
    /// # }
    /// ```
    fn write_bigdecimal(&mut self, value: &BigDecimal) -> IonCResult<()>;

    /// Writes a `timestamp` value.
    ///
    /// ## Usage
    /// ```
    /// # use std::convert::*;
    /// # use ion_c_sys::*;
    /// # use ion_c_sys::writer::*;
    /// # use ion_c_sys::result::*;
    /// # use ion_c_sys::timestamp::*;
    /// # use ion_c_sys::timestamp::Mantissa::*;
    /// # use ion_c_sys::timestamp::TSPrecision::*;
    /// # use ion_c_sys::timestamp::TSOffsetKind::*;
    /// # use chrono::DateTime;
    /// # fn main() -> IonCResult<()> {
    /// let mut buf = vec![0; 128];
    /// let len = {
    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Text)?;
    ///     let dt = DateTime::parse_from_rfc3339("2020-01-02T12:34:00.123Z").unwrap();
    ///
    ///     // write the date time with microsecond precision and an unknown offset
    ///     let ion_dt = IonDateTime::try_new(dt, Fractional(Digits(6)), UnknownOffset)?;
    ///     writer.write_datetime(&ion_dt)?;
    ///     writer.finish()?
    /// };
    /// assert_eq!(
    ///     b"2020-01-02T12:34:00.123000-00:00",
    ///     &buf[0..len]);
    /// # Ok(())
    /// # }
    /// ```
    fn write_datetime(&mut self, value: &IonDateTime) -> IonCResult<()>;

    /// Writes a `symbol` value.
    ///
    /// ## Usage
    /// ```
    /// # use std::convert::*;
    /// # use ion_c_sys::*;
    /// # use ion_c_sys::writer::*;
    /// # use ion_c_sys::result::*;
    /// # fn main() -> IonCResult<()> {
    /// let mut buf = vec![0; 128];
    /// let len = {
    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Text)?;
    ///     writer.write_symbol("🍥")?;
    ///     writer.finish()?
    /// };
    /// assert_eq!(b"'\xF0\x9F\x8D\xA5'", &buf[0..len]);
    /// # Ok(())
    /// # }
    /// ```
    fn write_symbol(&mut self, value: &str) -> IonCResult<()>;

    /// Writes a `string` value.
    ///
    /// ## Usage
    /// ```
    /// # use std::convert::*;
    /// # use ion_c_sys::*;
    /// # use ion_c_sys::writer::*;
    /// # use ion_c_sys::result::*;
    /// # fn main() -> IonCResult<()> {
    /// let mut buf = vec![0; 128];
    /// let len = {
    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
    ///     writer.write_string("🐡")?;
    ///     writer.finish()?
    /// };
    /// assert_eq!(b"\xE0\x01\x00\xEA\x84\xF0\x9F\x90\xA1", &buf[0..len]);
    /// # Ok(())
    /// # }
    /// ```
    fn write_string(&mut self, value: &str) -> IonCResult<()>;

    /// Writes a `clob` value.
    ///
    /// ## Usage
    /// ```
    /// # use std::convert::*;
    /// # use ion_c_sys::*;
    /// # use ion_c_sys::writer::*;
    /// # use ion_c_sys::result::*;
    /// # fn main() -> IonCResult<()> {
    /// let mut buf = vec![0; 128];
    /// let len = {
    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
    ///     writer.write_clob("🐡".as_bytes())?;
    ///     writer.finish()?
    /// };
    /// assert_eq!(b"\xE0\x01\x00\xEA\x94\xF0\x9F\x90\xA1", &buf[0..len]);
    /// # Ok(())
    /// # }
    /// ```
    fn write_clob(&mut self, value: &[u8]) -> IonCResult<()>;

    /// Writes a `blob` value.
    ///
    /// ## Usage
    /// ```
    /// # use std::convert::*;
    /// # use ion_c_sys::*;
    /// # use ion_c_sys::writer::*;
    /// # use ion_c_sys::result::*;
    /// # fn main() -> IonCResult<()> {
    /// let mut buf = vec![0; 128];
    /// let len = {
    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Text)?;
    ///     writer.write_blob("🍥".as_bytes())?;
    ///     writer.finish()?
    /// };
    /// assert_eq!(b"{{8J+NpQ==}}", &buf[0..len]);
    /// # Ok(())
    /// # }
    /// ```
    fn write_blob(&mut self, value: &[u8]) -> IonCResult<()>;

    /// Starts a container.
    ///
    /// ## Usage
    /// ```
    /// # use std::convert::*;
    /// # use ion_c_sys::*;
    /// # use ion_c_sys::writer::*;
    /// # use ion_c_sys::result::*;
    /// # fn main() -> IonCResult<()> {
    /// let mut buf = vec![0; 128];
    /// let len = {
    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
    ///     writer.start_container(ION_TYPE_LIST)?;
    ///     writer.finish_container()?;
    ///     writer.finish()?
    /// };
    /// assert_eq!(b"\xE0\x01\x00\xEA\xB0", &buf[0..len]);
    /// # Ok(())
    /// # }
    /// ```
    fn start_container(&mut self, tid: ION_TYPE) -> IonCResult<()>;

    /// Finishes a container.
    fn finish_container(&mut self) -> IonCResult<()>;
}

/// The API for writing values with annotations and/or field names.
pub trait IonCAnnotationsFieldWriter {
    /// The associated type of value writer when writing within annotations/field context
    type AFValueWriter: IonCValueWriter;

    /// Writes a value within a context of annotations and/or a field name
    ///
    /// Note that it is undefined behavior if a value writing method is **not** called
    /// or if a value writing method is called **more than once**.  For this reason,
    /// most users should prefer the `field()` and/or `annotations()` method on the
    /// [`IonCWriter`](./trait.IonCWriter.html) trait as it doesn't have this edge case.
    fn write_annotations_and_field<'a, A, F, FN>(
        &mut self,
        annotations: A,
        field: F,
        applier: FN,
    ) -> IonCResult<()>
    where
        A: Into<Option<&'a [&'a str]>>,
        F: Into<Option<&'a str>>,
        FN: Fn(&mut Self::AFValueWriter) -> IonCResult<()>;
}

/// The writing API for Ion C.
///
/// See also:
/// * [`IonCValueWriter`](./trait.IonCValueWriter.html)
/// * [`IonCWriterHandle`](./struct.IonCWriterHandle.html)
///
/// ## Usage
/// ```
/// # use ion_c_sys::*;
/// # use ion_c_sys::writer::*;
/// # use ion_c_sys::result::*;
/// # use std::convert::*;
/// # use std::ptr;
/// # fn main() -> IonCResult<()> {
/// // a buffer to write to
/// let mut buf = vec![0; 12];
///
/// // borrow the buffer and do some writing!
/// let len = {
///     // write in binary
///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut(), WriterMode::Binary)?;
///
///     // write something
///     writer.write_i64(4)?;
///
///     // finish up the writing
///     writer.finish()?
///
///     // handle implements Drop, so we're good to go!
/// };
///
/// assert_eq!(b"\xE0\x01\x00\xEA\x21\x04", &buf[0..len]);
/// # Ok(())
/// # }
/// ```
pub trait IonCWriter<'a>: IonCValueWriter + IonCAnnotationsFieldWriter {
    /// Returns a lifetime safe writing context for a field.
    ///
    /// ## Usage
    /// ```
    /// # use std::convert::*;
    /// # use ion_c_sys::*;
    /// # use ion_c_sys::writer::*;
    /// # use ion_c_sys::result::*;
    /// # fn main() -> IonCResult<()> {
    /// let mut buf = vec![0; 128];
    /// let len = {
    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Binary)?;
    ///     writer.start_container(ION_TYPE_STRUCT)?;
    ///     {
    ///         writer.field("name").write_string("kumo")?;
    ///     }
    ///     writer.finish_container()?;
    ///     writer.finish()?
    /// };
    /// assert_eq!(b"\xE0\x01\x00\xEA\xD6\x84\x84kumo", &buf[0..len]);
    /// # Ok(())
    /// # }
    /// ```
    fn field<'b, 'c>(
        &'b mut self,
        field: &'c str,
    ) -> IonCAnnotationsFieldWriterContext<'b, 'c, Self> {
        IonCAnnotationsFieldWriterContext::new_field(self, field)
    }

    /// Returns a lifetime safe writing context for annotations.
    ///
    /// ## Usage
    /// ```
    /// # use std::convert::*;
    /// # use std::str;
    /// # use ion_c_sys::*;
    /// # use ion_c_sys::writer::*;
    /// # use ion_c_sys::result::*;
    /// # fn main() -> IonCResult<()> {
    /// let mut buf = vec![0; 128];
    /// let len = {
    ///     let mut writer = IonCWriterHandle::new_buf_mode(buf.as_mut_slice(), WriterMode::Text)?;
    ///     writer.annotations(&["a", "b", "c"]).start_container(ION_TYPE_STRUCT)?;
    ///     {
    ///         writer.field("name").annotations(&["def"]).write_string("kumo")?;
    ///         writer.annotations(&["ghi"]).field("type").write_symbol("dog")?;
    ///     }
    ///     writer.finish_container()?;
    ///     writer.finish()?
    /// };
    /// assert_eq!("a::b::c::{name:def::\"kumo\",type:ghi::dog}", str::from_utf8(&buf[0..len])?);
    /// # Ok(())
    /// # }
    /// ```
    fn annotations<'b, 'c>(
        &'b mut self,
        annotations: &'c [&'c str],
    ) -> IonCAnnotationsFieldWriterContext<'b, 'c, Self> {
        IonCAnnotationsFieldWriterContext::new_annotations(self, annotations)
    }

    /// Finalizes writing for the writer and returns the amount of bytes written.
    fn finish(&mut self) -> IonCResult<usize>;
}

/// Wrapper over `hWRITER` to make it easier to use writers in IonC correctly.
///
/// Specifically supports the `Drop` trait to make sure `ion_writer_close` is run.
/// Access to the underlying `hWRITER` pointer is done by de-referencing the handle.
///
/// See also:
/// * [IonCWriter](./trait.IonCWriter.html)
/// * [IonCValueWriter](./trait.IonCValueWriter.html)
pub struct IonCWriterHandle<'a> {
    writer: hWRITER,
    /// Placeholder to tie our lifecycle back to the destination--which might not
    /// actually be a byte slice (if we constructed this from a file or Ion C stream callback)
    referent: PhantomData<&'a mut u8>,
}

impl<'a> IonCWriterHandle<'a> {
    /// Construct a writer to a given mutable slice with options.
    #[inline]
    pub fn new_buf(buf: &'a mut [u8], options: &mut ION_WRITER_OPTIONS) -> Result<Self, IonCError> {
        let mut writer = ptr::null_mut();
        ionc!(ion_writer_open_buffer(
            &mut writer,
            buf.as_mut_ptr(),
            buf.len().try_into()?,
            options
        ))?;

        Ok(IonCWriterHandle {
            writer,
            referent: PhantomData::default(),
        })
    }

    /// Construct a text/binary mode writer with otherwise default options.
    #[inline]
    pub fn new_buf_mode(buf: &'a mut [u8], mode: WriterMode) -> Result<Self, IonCError> {
        let mut options = ION_WRITER_OPTIONS {
            output_as_binary: mode as i32,
            ..Default::default()
        };
        Self::new_buf(buf, &mut options)
    }
}

impl<'a> IonCWriter<'a> for IonCWriterHandle<'a> {
    #[inline]
    fn finish(&mut self) -> IonCResult<usize> {
        let mut len = 0;
        ionc!(ion_writer_finish(self.writer, &mut len))?;

        Ok(len.try_into()?)
    }
}

impl IonCValueWriter for IonCWriterHandle<'_> {
    #[allow(clippy::not_unsafe_ptr_arg_deref)]
    #[inline]
    fn write_null(&mut self, tid: ION_TYPE) -> IonCResult<()> {
        ionc!(ion_writer_write_typed_null(self.writer, tid))
    }

    #[inline]
    fn write_bool(&mut self, value: bool) -> IonCResult<()> {
        ionc!(ion_writer_write_bool(self.writer, value as BOOL))
    }

    #[inline]
    fn write_i64(&mut self, value: i64) -> IonCResult<()> {
        ionc!(ion_writer_write_int64(self.writer, value))
    }

    #[inline]
    fn write_bigint(&mut self, value: &BigInt) -> IonCResult<()> {
        let mut ion_int = IonIntPtr::try_from_bigint(value)?;
        ionc!(ion_writer_write_ion_int(self.writer, &mut *ion_int))
    }

    #[inline]
    fn write_f64(&mut self, value: f64) -> IonCResult<()> {
        ionc!(ion_writer_write_double(self.writer, value))
    }

    #[inline]
    fn write_bigdecimal(&mut self, value: &BigDecimal) -> IonCResult<()> {
        let mut ion_decimal = IonDecimalPtr::try_from_bigdecimal(value)?;
        ionc!(ion_writer_write_ion_decimal(self.writer, &mut *ion_decimal))
    }

    #[inline]
    fn write_datetime(&mut self, value: &IonDateTime) -> IonCResult<()> {
        let mut ion_timestamp = ION_TIMESTAMP::default();
        ion_timestamp.try_assign_from_iondt(value)?;
        ionc!(ion_writer_write_timestamp(self.writer, &mut ion_timestamp))
    }

    #[inline]
    fn write_symbol(&mut self, value: &str) -> IonCResult<()> {
        // Ion C promises that it won't do mutation for this call!
        let mut ion_str = ION_STRING::try_from_str(value)?;
        ionc!(ion_writer_write_symbol(self.writer, &mut ion_str))
    }

    #[inline]
    fn write_string(&mut self, value: &str) -> IonCResult<()> {
        // Ion C promises that it won't do mutation for this call!
        let mut ion_str = ION_STRING::try_from_str(value)?;
        ionc!(ion_writer_write_string(self.writer, &mut ion_str))
    }

    #[inline]
    fn write_clob(&mut self, value: &[u8]) -> IonCResult<()> {
        // Ion C promises that it won't mutate the buffer for this call!
        ionc!(ion_writer_write_clob(
            self.writer,
            value.as_ptr() as *mut u8,
            value.len().try_into()?
        ))
    }

    #[inline]
    fn write_blob(&mut self, value: &[u8]) -> IonCResult<()> {
        // Ion C promises that it won't mutate the buffer for this call!
        ionc!(ion_writer_write_blob(
            self.writer,
            value.as_ptr() as *mut u8,
            value.len().try_into()?
        ))
    }

    #[allow(clippy::not_unsafe_ptr_arg_deref)]
    #[inline]
    fn start_container(&mut self, tid: ION_TYPE) -> IonCResult<()> {
        ionc!(ion_writer_start_container(self.writer, tid))
    }

    #[inline]
    fn finish_container(&mut self) -> IonCResult<()> {
        ionc!(ion_writer_finish_container(self.writer))
    }
}

impl IonCAnnotationsFieldWriter for IonCWriterHandle<'_> {
    type AFValueWriter = Self;

    #[inline]
    fn write_annotations_and_field<'a, A, F, FN>(
        &mut self,
        possible_annotations: A,
        possible_field: F,
        applier: FN,
    ) -> IonCResult<()>
    where
        A: Into<Option<&'a [&'a str]>>,
        F: Into<Option<&'a str>>,
        FN: Fn(&mut Self::AFValueWriter) -> IonCResult<()>,
    {
        // Ion C promises that it won't do mutation for these!
        if let Some(annotations) = possible_annotations.into() {
            for annotation in annotations {
                let mut annotation_str = ION_STRING::try_from_str(annotation)?;
                ionc!(ion_writer_add_annotation(self.writer, &mut annotation_str))?;
            }
        }
        if let Some(field) = possible_field.into() {
            let mut ion_field = ION_STRING::try_from_str(field)?;
            ionc!(ion_writer_write_field_name(self.writer, &mut ion_field))?;
        }
        applier(self)?;

        Ok(())
    }
}

impl Deref for IonCWriterHandle<'_> {
    type Target = hWRITER;

    fn deref(&self) -> &Self::Target {
        &self.writer
    }
}

impl DerefMut for IonCWriterHandle<'_> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.writer
    }
}

impl Drop for IonCWriterHandle<'_> {
    fn drop(&mut self) {
        if !self.writer.is_null() {
            ionc!(ion_writer_close(self.writer)).unwrap()
        }
    }
}

/// Context for writing annotations and fields in with proper reference lifetimes.
///
/// Specifically, writing annotations and fields with Ion C with
/// `ion_writer_write_annotations`/`ion_writer_add_annotation` and `ion_writer_write_field`
/// is particularly problematic because the lifetime of the `ION_STRING`
/// passed into that function, must be valid until a corresponding
/// `ion_writer_write_*` function is called for writing a value.
///
/// This context tracks the lifetime of the string slices that a user wants to
/// write as annotations and the field name along with a mutable borrow of the writer handle
/// and ensures that calls to `ion_writer_add_annotation`/`ion_writer_write_field`
/// happen before invoking the `ion_writer_write_*` call for the value in a lifetime correct way.
///
/// Note that this context can be thought of as a partial function for writing
/// annotations and/or `struct` fields, so doing nothing with it is simply a no-op, and performing
/// multiple [`IonCValueWriter`](./trait.IonCValueWriter.html) trait method invocations
/// is the same as writing the field before invoking the value writing methods
/// (so duplicate fields would be generated in that case).
pub struct IonCAnnotationsFieldWriterContext<'b, 'c, T: IonCAnnotationsFieldWriter + ?Sized> {
    writer: &'b mut T,
    annotations: Option<&'c [&'c str]>,
    field: Option<&'c str>,
}

impl<'b, 'c, T: IonCAnnotationsFieldWriter + ?Sized> IonCAnnotationsFieldWriterContext<'b, 'c, T> {
    #[inline]
    fn new_field(writer: &'b mut T, field: &'c str) -> Self {
        Self {
            writer,
            annotations: None,
            field: Some(field),
        }
    }

    #[inline]
    fn new_annotations(writer: &'b mut T, annotations: &'c [&'c str]) -> Self {
        Self {
            writer,
            annotations: Some(annotations),
            field: None,
        }
    }

    /// Sets the annotations for the context.
    #[inline]
    pub fn annotations(&mut self, annotations: &'c [&'c str]) -> &mut Self {
        self.annotations = Some(annotations);
        self
    }

    /// Sets the field name for the context.
    #[inline]
    pub fn field(&mut self, field: &'c str) -> &mut Self {
        self.field = Some(field);
        self
    }

    #[inline]
    fn write_annotations_and_field<F>(&mut self, applier: F) -> IonCResult<()>
    where
        F: Fn(&mut T::AFValueWriter) -> IonCResult<()>,
    {
        self.writer
            .write_annotations_and_field(self.annotations, self.field, applier)?;

        Ok(())
    }
}

impl<T: IonCAnnotationsFieldWriter + ?Sized> IonCValueWriter
    for IonCAnnotationsFieldWriterContext<'_, '_, T>
{
    #[inline]
    fn write_null(&mut self, tid: ION_TYPE) -> IonCResult<()> {
        self.write_annotations_and_field(|v| v.write_null(tid))
    }

    #[inline]
    fn write_bool(&mut self, value: bool) -> IonCResult<()> {
        self.write_annotations_and_field(|v| v.write_bool(value))
    }

    #[inline]
    fn write_i64(&mut self, value: i64) -> IonCResult<()> {
        self.write_annotations_and_field(|v| v.write_i64(value))
    }

    #[inline]
    fn write_bigint(&mut self, value: &BigInt) -> IonCResult<()> {
        self.write_annotations_and_field(|v| v.write_bigint(value))
    }

    #[inline]
    fn write_f64(&mut self, value: f64) -> IonCResult<()> {
        self.write_annotations_and_field(|v| v.write_f64(value))
    }

    #[inline]
    fn write_bigdecimal(&mut self, value: &BigDecimal) -> IonCResult<()> {
        self.write_annotations_and_field(|v| v.write_bigdecimal(value))
    }

    fn write_datetime(&mut self, value: &IonDateTime) -> IonCResult<()> {
        self.write_annotations_and_field(|v| v.write_datetime(value))
    }

    #[inline]
    fn write_symbol(&mut self, value: &str) -> IonCResult<()> {
        self.write_annotations_and_field(|v| v.write_symbol(value))
    }

    #[inline]
    fn write_string(&mut self, value: &str) -> IonCResult<()> {
        self.write_annotations_and_field(|v| v.write_string(value))
    }

    #[inline]
    fn write_clob(&mut self, value: &[u8]) -> IonCResult<()> {
        self.write_annotations_and_field(|v| v.write_clob(value))
    }

    #[inline]
    fn write_blob(&mut self, value: &[u8]) -> IonCResult<()> {
        self.write_annotations_and_field(|v| v.write_blob(value))
    }

    #[inline]
    fn start_container(&mut self, tid: ION_TYPE) -> IonCResult<()> {
        self.write_annotations_and_field(|v| v.start_container(tid))
    }

    /// This API is not relevant for this context and will always return an error.
    #[inline]
    fn finish_container(&mut self) -> IonCResult<()> {
        Err(IonCError::from(ion_error_code_IERR_INVALID_STATE))
    }
}