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}