cbor_core/encoder.rs
1//! Streaming encoder for CBOR sequences.
2//!
3//! [`SequenceWriter`] is the write-side counterpart of
4//! [`SequenceDecoder`](crate::SequenceDecoder) and
5//! [`SequenceReader`](crate::SequenceReader). It wraps any
6//! [`io::Write`](std::io::Write) and emits a CBOR sequence (RFC 8742)
7//! in the format selected by [`EncodeFormat`].
8
9use std::io::{self, Write};
10
11use crate::{EncodeFormat, Value};
12
13/// Streaming writer for CBOR sequences in binary, hex, or diagnostic notation.
14///
15/// Construct with [`SequenceWriter::new`], call
16/// [`write_item`](Self::write_item), [`write_items`](Self::write_items),
17/// or [`write_pairs`](Self::write_pairs) to emit content, and then
18/// [`into_inner`](Self::into_inner) to get the wrapped writer back.
19///
20/// Format semantics:
21///
22/// * [`EncodeFormat::Binary`] and [`EncodeFormat::Hex`]: items are
23/// concatenated with no separator. Each item's bytes form a
24/// self-delimiting CBOR value.
25/// * [`EncodeFormat::Diagnostic`]: items are separated by `, ` (comma
26/// and a space). The first item is written without a leading
27/// separator; no trailing comma is emitted.
28/// * [`EncodeFormat::DiagnosticPretty`]: items are pretty-printed with
29/// `{:#?}` (indented, multi-line for collections) and separated by
30/// `,\n`.
31///
32/// [`Format`](crate::Format) values accepted on the read side pass
33/// through the `impl Into<EncodeFormat>` bound unchanged.
34///
35/// # Examples
36///
37/// Binary sequence:
38///
39/// ```
40/// use cbor_core::{SequenceWriter, Value, EncodeFormat};
41///
42/// let mut buf = Vec::new();
43/// let mut sw = SequenceWriter::new(&mut buf, EncodeFormat::Binary);
44/// sw.write_item(&Value::from(1)).unwrap();
45/// sw.write_item(&Value::from(2)).unwrap();
46/// sw.write_item(&Value::from(3)).unwrap();
47/// assert_eq!(buf, [0x01, 0x02, 0x03]);
48/// ```
49///
50/// Diagnostic sequence, with separators inserted automatically:
51///
52/// ```
53/// use cbor_core::{SequenceWriter, Value, EncodeFormat};
54///
55/// let mut buf = Vec::new();
56/// let mut sw = SequenceWriter::new(&mut buf, EncodeFormat::Diagnostic);
57/// sw.write_items([Value::from(1), Value::from("hi"), Value::from(true)].iter()).unwrap();
58/// assert_eq!(String::from_utf8(buf).unwrap(), r#"1, "hi", true"#);
59/// ```
60///
61/// A [`Format`](crate::Format) value (from the read-side API) converts
62/// implicitly:
63///
64/// ```
65/// use cbor_core::{Format, SequenceWriter, Value};
66///
67/// let mut buf = Vec::new();
68/// let mut sw = SequenceWriter::new(&mut buf, Format::Hex);
69/// sw.write_item(&Value::from(1)).unwrap();
70/// assert_eq!(buf, b"01");
71/// ```
72///
73/// Round-trip through [`SequenceDecoder`](crate::SequenceDecoder):
74///
75/// ```
76/// use cbor_core::{Array, DecodeOptions, Format, SequenceWriter, Value, EncodeFormat};
77///
78/// let items = [Value::from(1), Value::from("hi"), Value::from(true)];
79///
80/// let mut buf = Vec::new();
81/// let mut sw = SequenceWriter::new(&mut buf, EncodeFormat::Diagnostic);
82/// sw.write_items(items.iter()).unwrap();
83///
84/// let decoded = Array::try_from_sequence(
85/// DecodeOptions::new().format(Format::Diagnostic).sequence_decoder(&buf),
86/// ).unwrap();
87/// assert_eq!(decoded.get_ref().as_slice(), &items);
88/// ```
89pub struct SequenceWriter<W: Write> {
90 writer: W,
91 format: EncodeFormat,
92 wrote_any: bool,
93}
94
95impl<W: Write> SequenceWriter<W> {
96 /// Create a new sequence writer wrapping `writer` and emitting
97 /// items in the selected `format`. Accepts any
98 /// `impl Into<EncodeFormat>`, so [`Format`](crate::Format) values
99 /// pass through unchanged.
100 ///
101 /// ```
102 /// use cbor_core::{SequenceWriter, EncodeFormat};
103 ///
104 /// let sw = SequenceWriter::new(Vec::new(), EncodeFormat::Hex);
105 /// // `sw` now accepts items via `write_item` / `write_items` / `write_pairs`.
106 /// # drop(sw);
107 /// ```
108 pub fn new(writer: W, format: impl Into<EncodeFormat>) -> Self {
109 Self {
110 writer,
111 format: format.into(),
112 wrote_any: false,
113 }
114 }
115
116 /// Write one item of the sequence.
117 ///
118 /// In [`EncodeFormat::Diagnostic`] a `, ` separator is inserted
119 /// before every item except the first. In
120 /// [`EncodeFormat::DiagnosticPretty`] the separator is `,\n` and
121 /// each item is formatted with `{:#?}`. In [`EncodeFormat::Binary`]
122 /// and [`EncodeFormat::Hex`] items are written back-to-back with no
123 /// separator.
124 ///
125 /// # Errors
126 ///
127 /// Returns any [`io::Error`] reported by the underlying writer.
128 ///
129 /// ```
130 /// use cbor_core::{SequenceWriter, Value, EncodeFormat};
131 ///
132 /// let mut buf = Vec::new();
133 /// let mut sw = SequenceWriter::new(&mut buf, EncodeFormat::Hex);
134 /// sw.write_item(&Value::from(1)).unwrap();
135 /// sw.write_item(&Value::from(2)).unwrap();
136 /// assert_eq!(buf, b"0102");
137 /// ```
138 pub fn write_item(&mut self, value: &Value<'_>) -> io::Result<()> {
139 match self.format {
140 EncodeFormat::Binary => value.write_to(&mut self.writer)?,
141 EncodeFormat::Hex => value.write_hex_to(&mut self.writer)?,
142 EncodeFormat::Diagnostic => {
143 if self.wrote_any {
144 self.writer.write_all(b", ")?;
145 }
146 write!(self.writer, "{value:?}")?;
147 }
148 EncodeFormat::DiagnosticPretty => {
149 if self.wrote_any {
150 self.writer.write_all(b",\n")?;
151 }
152 write!(self.writer, "{value:#?}")?;
153 }
154 }
155 self.wrote_any = true;
156 Ok(())
157 }
158
159 /// Write every item produced by `items`. Equivalent to calling
160 /// [`write_item`](Self::write_item) in a loop, but keeps the call
161 /// site concise.
162 ///
163 /// # Errors
164 ///
165 /// Stops at and returns the first [`io::Error`] reported by the
166 /// underlying writer.
167 ///
168 /// ```
169 /// use cbor_core::{SequenceWriter, Value, EncodeFormat};
170 ///
171 /// let items = [Value::from(1), Value::from(2), Value::from(3)];
172 /// let mut buf = Vec::new();
173 /// SequenceWriter::new(&mut buf, EncodeFormat::Binary)
174 /// .write_items(items.iter())
175 /// .unwrap();
176 /// assert_eq!(buf, [0x01, 0x02, 0x03]);
177 /// ```
178 pub fn write_items<'a, 'b, I>(&mut self, items: I) -> io::Result<()>
179 where
180 'a: 'b,
181 I: IntoIterator<Item = &'b Value<'a>>,
182 {
183 for item in items {
184 self.write_item(item)?;
185 }
186 Ok(())
187 }
188
189 /// Write each key/value pair as two consecutive items of the
190 /// sequence. Useful for emitting the contents of a map as a flat
191 /// CBOR sequence, mirroring [`Map::from_sequence`](crate::Map::from_sequence)
192 /// on the read side.
193 ///
194 /// The iterator yields borrowed references, which is the natural
195 /// shape of `&BTreeMap<Value, Value>::iter()`, so a map held in a
196 /// `Value` can be streamed directly.
197 ///
198 /// # Errors
199 ///
200 /// Stops at and returns the first [`io::Error`] reported by the
201 /// underlying writer.
202 ///
203 /// ```
204 /// use cbor_core::{SequenceWriter, Value, EncodeFormat, map};
205 ///
206 /// let value = map! { "a" => 1, "b" => 2 };
207 /// let mut sw = SequenceWriter::new(Vec::new(), EncodeFormat::Diagnostic);
208 /// sw.write_pairs(value.as_map().unwrap()).unwrap();
209 /// assert_eq!(sw.into_inner(), br#""a", 1, "b", 2"#);
210 /// ```
211 pub fn write_pairs<'a, 'b, I>(&mut self, pairs: I) -> io::Result<()>
212 where
213 'a: 'b,
214 I: IntoIterator<Item = (&'b Value<'a>, &'b Value<'a>)>,
215 {
216 for (k, v) in pairs {
217 self.write_item(k)?;
218 self.write_item(v)?;
219 }
220 Ok(())
221 }
222
223 /// Borrow the wrapped writer.
224 pub const fn get_ref(&self) -> &W {
225 &self.writer
226 }
227
228 /// Mutably borrow the wrapped writer. Direct writes bypass the
229 /// sequence writer's separator bookkeeping, so use this only for
230 /// format-specific ornamentation (for example, injecting a comment
231 /// into diagnostic output) between full items.
232 pub const fn get_mut(&mut self) -> &mut W {
233 &mut self.writer
234 }
235
236 /// Consume the sequence writer and return the wrapped writer.
237 ///
238 /// ```
239 /// use cbor_core::{SequenceWriter, Value, EncodeFormat};
240 ///
241 /// let mut sw = SequenceWriter::new(Vec::new(), EncodeFormat::Binary);
242 /// sw.write_item(&Value::from(1)).unwrap();
243 /// sw.write_item(&Value::from(2)).unwrap();
244 /// let buf = sw.into_inner();
245 /// assert_eq!(buf, [0x01, 0x02]);
246 /// ```
247 pub fn into_inner(self) -> W {
248 self.writer
249 }
250}