cbor_data/builder/mod.rs
1use crate::CborOwned;
2use std::marker::PhantomData;
3
4mod encoder;
5mod low_level;
6mod writer;
7mod writers;
8
9pub use encoder::Encoder;
10use low_level::*;
11pub use writer::Writer;
12pub use writers::{ArrayWriter, DictWriter, KeyBuilder, SingleBuilder, SingleResult};
13
14/// Marker trait to distinguish a builder that emits an owned value from one that appends to a vector
15pub trait CborOutput {
16 type Output;
17 fn output(bytes: &[u8]) -> Self::Output;
18}
19/// Marker type for builders that emit an owned value
20pub struct WithOutput;
21impl CborOutput for WithOutput {
22 type Output = CborOwned;
23 fn output(bytes: &[u8]) -> Self::Output {
24 CborOwned::unchecked(bytes)
25 }
26}
27/// Marker type for builders that only append to a provided vector
28pub struct NoOutput;
29impl CborOutput for NoOutput {
30 type Output = ();
31 fn output(_bytes: &[u8]) -> Self::Output {}
32}
33
34/// Builder for a single CBOR value.
35///
36/// [`CborOwned::canonical`](struct.CborOwned.html#method.canonical) uses the default configuration,
37/// which implies writing bytes into a fresh `Vec<u8>` and finally moving them into a SmallVec. You
38/// can minimise allocations by reusing the build buffer, and you can influence whether definite or
39/// indefinite length encoding is used for arrays and dictionaries.
40///
41/// # Example
42///
43/// ```rust
44/// use cbor_data::{Cbor, CborBuilder, Writer};
45///
46/// // this could come from a thread-local in real code:
47/// let mut build_buffer = Vec::new();
48/// // buffer will be cleared before use
49/// build_buffer.extend_from_slice(b"some garbage");
50///
51/// let bytes_from_elsewhere = [0x82, 1, 2];
52/// assert_eq!(Cbor::checked(&bytes_from_elsewhere).unwrap().to_string(), "[1, 2]");
53///
54/// let cbor = CborBuilder::with_scratch_space(&mut build_buffer)
55/// .with_max_definite_size(Some(1))
56/// .write_canonical(bytes_from_elsewhere.as_ref())
57/// .unwrap();
58///
59/// // now it is using indefinite-length encoding, since the array has more than 1 item
60/// assert_eq!(cbor.to_string(), "[_ 1, 2]");
61/// assert_eq!(cbor.as_slice(), [0x9f, 1, 2, 0xff]);
62/// ```
63pub struct CborBuilder<'a, O: CborOutput> {
64 bytes: Bytes<'a>,
65 max_definite: Option<u64>,
66 ph: PhantomData<O>,
67}
68
69impl Default for CborBuilder<'static, WithOutput> {
70 fn default() -> Self {
71 Self::new()
72 }
73}
74
75impl<'a> CborBuilder<'a, WithOutput> {
76 /// Create a builder that writes into its own fresh vector.
77 pub fn new() -> Self {
78 Self {
79 bytes: Bytes::Owned(Vec::new()),
80 max_definite: Some(255),
81 ph: PhantomData,
82 }
83 }
84
85 /// Create a builder that clears the given vector and writes into it.
86 ///
87 /// You can use this to reuse a scratch space across multiple values being built, e.g. by
88 /// keeping the same vector in a thread-local variable.
89 pub fn with_scratch_space(v: &'a mut Vec<u8>) -> Self {
90 v.clear();
91 Self {
92 bytes: Bytes::Borrowed(v),
93 max_definite: Some(255),
94 ph: PhantomData,
95 }
96 }
97}
98
99impl<'a> CborBuilder<'a, NoOutput> {
100 /// Append the CBOR bytes to the given vector and do not return a separate output value.
101 ///
102 /// ```
103 /// # use cbor_data::{CborBuilder, Writer};
104 /// let mut v = Vec::new();
105 /// let result: () = CborBuilder::append_to(&mut v).write_pos(12, None);
106 ///
107 /// assert_eq!(v, vec![12u8])
108 /// ```
109 pub fn append_to(v: &'a mut Vec<u8>) -> Self {
110 Self {
111 bytes: Bytes::Borrowed(v),
112 max_definite: Some(255),
113 ph: PhantomData,
114 }
115 }
116}
117
118impl<'a, O: CborOutput> CborBuilder<'a, O> {
119 /// Configure the limit above which indefinite size encoding will be used.
120 ///
121 /// The default is 255, which is the largest size up to which definite size is at least as
122 /// compact as indefinite size. Set to 23 to avoid moving bytes around when finishing the array.
123 /// Set to `None` to always use indefinite size encoding.
124 pub fn with_max_definite_size(self, max_definite: Option<u64>) -> Self {
125 Self {
126 bytes: self.bytes,
127 max_definite,
128 ph: PhantomData,
129 }
130 }
131}
132
133impl<'a, O: CborOutput> Writer for CborBuilder<'a, O> {
134 type Output = O::Output;
135
136 fn bytes<T>(&mut self, f: impl FnOnce(&mut Vec<u8>) -> T) -> T {
137 f(self.bytes.as_mut())
138 }
139
140 fn into_output(self) -> Self::Output {
141 O::output(self.bytes.as_slice())
142 }
143
144 fn max_definite(&self) -> Option<u64> {
145 self.max_definite
146 }
147
148 fn set_max_definite(&mut self, max: Option<u64>) {
149 self.max_definite = max;
150 }
151}