cbor_data/builder/
writer.rs

1use super::low_level::*;
2use crate::{
3    canonical::canonicalise, constants::*, ArrayWriter, Cbor, CborBuilder, DictWriter, Literal,
4    ParseError,
5};
6
7/// Low-level primitives for emitting CBOR items.
8///
9/// The methods of this trait give you full control over the encoding of values according to the
10/// CBOR specification (apart from the technically allowed non-optimal integer encodings). It
11/// allows you to emit any item tagged with any number you desire.
12///
13/// If you are looking for convenient methods of writing end-user data types please refer to
14/// the [`Encoder`](trait.Encoder.html) trait.
15pub trait Writer: Sized {
16    type Output;
17    #[doc(hidden)]
18    // internal helper method — do not use!
19    /// contract: each call to this method MUST corresopnd to a single CBOR item being written!
20    fn bytes<T>(&mut self, f: impl FnOnce(&mut Vec<u8>) -> T) -> T;
21    #[doc(hidden)]
22    // internal helper method — do not use!
23    fn into_output(self) -> Self::Output;
24
25    /// Configured maximum array or dict length up to which definite size encoding is used.
26    fn max_definite(&self) -> Option<u64>;
27
28    /// Set the maximum array or dict length up to which definite size encoding is used.
29    fn set_max_definite(&mut self, max: Option<u64>);
30
31    /// Write a unsigned value of up to 64 bits.
32    /// Tags are from outer to inner.
33    fn write_pos(mut self, value: u64, tags: impl IntoIterator<Item = u64>) -> Self::Output {
34        self.bytes(|b| write_positive(b, value, tags));
35        self.into_output()
36    }
37
38    /// Write a negative value of up to 64 bits — the represented number is `-1 - value`.
39    /// Tags are from outer to inner.
40    fn write_neg(mut self, value: u64, tags: impl IntoIterator<Item = u64>) -> Self::Output {
41        self.bytes(|b| write_neg(b, value, tags));
42        self.into_output()
43    }
44
45    /// Write the given slice as a definite size byte string.
46    /// Tags are from outer to inner.
47    fn write_bytes(mut self, value: &[u8], tags: impl IntoIterator<Item = u64>) -> Self::Output {
48        self.bytes(|b| write_bytes(b, value.len(), [value], tags));
49        self.into_output()
50    }
51
52    /// Write the given slices as a definite size byte string.
53    /// Tags are from outer to inner.
54    ///
55    /// Example:
56    /// ```rust
57    /// # use cbor_data::{CborBuilder, Writer};
58    /// let cbor = CborBuilder::default().write_bytes_chunked([&[0][..], &[1, 2][..]], [12]);
59    /// # assert_eq!(cbor.as_slice(), vec![0xccu8, 0x43, 0, 1, 2]);
60    /// ```
61    fn write_bytes_chunked(
62        mut self,
63        value: impl IntoIterator<Item = impl AsRef<[u8]>> + Copy,
64        tags: impl IntoIterator<Item = u64>,
65    ) -> Self::Output {
66        let len = value.into_iter().map(|x| x.as_ref().len()).sum();
67        self.bytes(|b| write_bytes(b, len, value, tags));
68        self.into_output()
69    }
70
71    /// Write the given slice as a definite size string.
72    /// Tags are from outer to inner.
73    fn write_str(mut self, value: &str, tags: impl IntoIterator<Item = u64>) -> Self::Output {
74        self.bytes(|b| write_str(b, value.len(), [value], tags));
75        self.into_output()
76    }
77
78    /// Write the given slice as a definite size string.
79    /// Tags are from outer to inner.
80    ///
81    /// Example:
82    /// ```rust
83    /// # use cbor_data::{CborBuilder, Writer};
84    /// let cbor = CborBuilder::default().write_str_chunked(["a", "b"], [12]);
85    /// # assert_eq!(cbor.as_slice(), vec![0xccu8, 0x62, 0x61, 0x62]);
86    /// ```
87    fn write_str_chunked(
88        mut self,
89        value: impl IntoIterator<Item = impl AsRef<str>> + Copy,
90        tags: impl IntoIterator<Item = u64>,
91    ) -> Self::Output {
92        let len = value.into_iter().map(|x| x.as_ref().len()).sum();
93        self.bytes(|b| write_str(b, len, value, tags));
94        self.into_output()
95    }
96
97    /// Tags are from outer to inner.
98    fn write_bool(mut self, value: bool, tags: impl IntoIterator<Item = u64>) -> Self::Output {
99        self.bytes(|b| write_bool(b, value, tags));
100        self.into_output()
101    }
102
103    /// Tags are from outer to inner.
104    fn write_null(mut self, tags: impl IntoIterator<Item = u64>) -> Self::Output {
105        self.bytes(|b| write_null(b, tags));
106        self.into_output()
107    }
108
109    /// Tags are from outer to inner.
110    fn write_undefined(mut self, tags: impl IntoIterator<Item = u64>) -> Self::Output {
111        self.bytes(|b| write_undefined(b, tags));
112        self.into_output()
113    }
114
115    /// Write custom literal value — [RFC 8949 §3.3](https://www.rfc-editor.org/rfc/rfc8949#section-3.3) is required reading.
116    /// Tags are from outer to inner.
117    fn write_lit(mut self, value: Literal, tags: impl IntoIterator<Item = u64>) -> Self::Output {
118        self.bytes(|b| {
119            write_tags(b, tags);
120            write_lit(b, value)
121        });
122        self.into_output()
123    }
124
125    /// Write a nested array using the given closure that receives an array builder.
126    /// Tags are from outer to inner.
127    ///
128    /// ```
129    /// # use cbor_data::{CborBuilder, Writer};
130    /// let cbor = CborBuilder::default().write_array(None, |builder| {
131    ///     builder.write_array_ret(None, |builder| {
132    ///         builder.write_pos(42, None);
133    ///     });
134    /// });
135    /// # assert_eq!(cbor.as_slice(), vec![0x81u8, 0x81, 0x18, 42]);
136    /// ```
137    fn write_array<F>(self, tags: impl IntoIterator<Item = u64>, f: F) -> Self::Output
138    where
139        F: FnOnce(&mut ArrayWriter<'_>),
140    {
141        self.write_array_ret(tags, f).0
142    }
143
144    /// Write a nested array using the given closure that receives an array builder.
145    /// Tags are from outer to inner.
146    ///
147    /// ```
148    /// # use cbor_data::{CborBuilder, Writer};
149    /// let (cbor, ret) = CborBuilder::default().write_array_ret(None, |builder| {
150    ///     builder.write_array_ret(None, |builder| {
151    ///         builder.write_pos(42, None);
152    ///     });
153    ///     42
154    /// });
155    /// assert_eq!(ret, 42);
156    /// # assert_eq!(cbor.as_slice(), vec![0x81u8, 0x81, 0x18, 42]);
157    /// ```
158    fn write_array_ret<T, F>(
159        mut self,
160        tags: impl IntoIterator<Item = u64>,
161        f: F,
162    ) -> (Self::Output, T)
163    where
164        F: FnOnce(&mut ArrayWriter<'_>) -> T,
165    {
166        let max_definite = self.max_definite();
167        let ret = self.bytes(|b| {
168            write_tags(b, tags);
169            let pos = b.len();
170            write_indefinite(b, MAJOR_ARRAY);
171            let mut writer = ArrayWriter::new(b, max_definite);
172            let ret = f(&mut writer);
173            let max_definite = writer.max_definite();
174            finish_array(writer.count(), b, pos, MAJOR_ARRAY, max_definite);
175            ret
176        });
177        (self.into_output(), ret)
178    }
179
180    /// Write a nested dict using the given closure that receives a dict builder.
181    /// Tags are from outer to inner.
182    ///
183    /// ```
184    /// # use cbor_data::{CborBuilder, Writer};
185    /// let cbor = CborBuilder::default().write_array(None, |builder | {
186    ///     builder.write_dict_ret(None, |builder| {
187    ///         builder.with_key("y", |b| b.write_pos(42, None));
188    ///     });
189    /// });
190    /// # assert_eq!(cbor.as_slice(), vec![0x81u8, 0xa1, 0x61, b'y', 0x18, 42]);
191    /// ```
192    fn write_dict<F>(self, tags: impl IntoIterator<Item = u64>, f: F) -> Self::Output
193    where
194        F: FnOnce(&mut DictWriter<'_>),
195    {
196        self.write_dict_ret(tags, f).0
197    }
198
199    /// Write a nested dict using the given closure that receives a dict builder.
200    /// Tags are from outer to inner.
201    ///
202    /// ```
203    /// # use cbor_data::{CborBuilder, Writer};
204    /// let (cbor, ret) = CborBuilder::default().write_array_ret(None, |builder | {
205    ///     builder.write_dict_ret(None, |builder| {
206    ///         builder.with_key("y", |b| b.write_pos(42, None));
207    ///     });
208    ///     42
209    /// });
210    /// assert_eq!(ret, 42);
211    /// # assert_eq!(cbor.as_slice(), vec![0x81u8, 0xa1, 0x61, b'y', 0x18, 42]);
212    /// ```
213    fn write_dict_ret<T, F>(
214        mut self,
215        tags: impl IntoIterator<Item = u64>,
216        f: F,
217    ) -> (Self::Output, T)
218    where
219        F: FnOnce(&mut DictWriter<'_>) -> T,
220    {
221        let max_definite = self.max_definite();
222        let ret = self.bytes(|b| {
223            write_tags(b, tags);
224            let pos = b.len();
225            write_indefinite(b, MAJOR_DICT);
226            let mut writer = DictWriter::new(b, max_definite);
227            let ret = f(&mut writer);
228            let max_definite = writer.max_definite();
229            finish_array(writer.count(), b, pos, MAJOR_DICT, max_definite);
230            ret
231        });
232        (self.into_output(), ret)
233    }
234
235    /// Interpret the given bytes as a single CBOR item and write it to this builder,
236    /// canonicalising its contents like [`CborOwned::canonical()`](struct.CborOwned.html#method.canonical)
237    fn write_canonical(mut self, bytes: &[u8]) -> Result<Self::Output, ParseError> {
238        let max_definite = self.max_definite();
239        self.bytes(|b| {
240            canonicalise(
241                bytes,
242                CborBuilder::append_to(b).with_max_definite_size(max_definite),
243            )
244        })
245        .map(|_| self.into_output())
246    }
247
248    /// Assume that the given bytes are a well-formed single CBOR item and write it to this builder.
249    ///
250    /// If those bytes are not valid CBOR you get to keep the pieces!
251    fn write_trusting(mut self, bytes: &[u8]) -> Self::Output {
252        self.bytes(|b| b.extend_from_slice(bytes));
253        self.into_output()
254    }
255
256    /// Write the given CBOR item
257    fn write_item(self, item: &Cbor) -> Self::Output {
258        self.write_trusting(item.as_slice())
259    }
260}
261
262impl<T> Writer for &mut T
263where
264    T: Writer<Output = T>,
265{
266    type Output = Self;
267
268    fn bytes<U>(&mut self, f: impl FnOnce(&mut Vec<u8>) -> U) -> U {
269        (*self).bytes(f)
270    }
271
272    fn into_output(self) -> Self::Output {
273        self
274    }
275
276    fn max_definite(&self) -> Option<u64> {
277        (**self).max_definite()
278    }
279
280    fn set_max_definite(&mut self, max: Option<u64>) {
281        (**self).set_max_definite(max);
282    }
283}