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}