cbor_data/builder/encoder.rs
1use crate::{
2 value::{Number, Precision, Timestamp},
3 ArrayWriter, DictWriter, Literal, Writer,
4};
5
6/// High-level encoding functions to write values in their canonical format.
7///
8/// ```
9/// use cbor_data::{CborBuilder, Encoder, Writer};
10///
11/// let cbor = CborBuilder::default().encode_u64(12);
12///
13/// let array = CborBuilder::default().encode_array(|builder| {
14/// builder
15/// .encode_u64(18)
16/// .encode_i64(-12);
17/// });
18///
19/// let array2 = CborBuilder::default().with_max_definite_size(Some(1)).write_array(None, |builder| {
20/// builder
21/// .encode_u64(18)
22/// .encode_i64(-12);
23/// });
24///
25/// let dict = CborBuilder::default().encode_dict(|builder| {
26/// builder
27/// .with_key("a", |b| b.encode_u64(14))
28/// .with_key("b", |b| b.encode_i64(-1));
29/// });
30///
31/// let (dict2, ret) = CborBuilder::default().write_dict_ret(None, |builder| {
32/// builder
33/// .with_key("a", |b| b.encode_u64(14))
34/// .with_key("b", |b| b.encode_i64(-1));
35/// "hello"
36/// });
37/// assert_eq!(ret, "hello");
38///
39/// # assert_eq!(cbor.as_slice(), vec![0x0cu8]);
40/// # assert_eq!(array.as_slice(), vec![0x82u8, 0x12, 0x2b]);
41/// # assert_eq!(array2.as_slice(), vec![0x9fu8, 0x12, 0x2b, 0xff]);
42/// # assert_eq!(dict.as_slice(), vec![0xa2u8, 0x61, b'a', 0x0e, 0x61, b'b', 0x20]);
43/// # assert_eq!(dict2.as_slice(), vec![0xa2u8, 0x61, b'a', 0x0e, 0x61, b'b', 0x20]);
44/// ```
45pub trait Encoder: Writer {
46 fn encode_undefined(self) -> Self::Output {
47 self.write_undefined(None)
48 }
49
50 fn encode_null(self) -> Self::Output {
51 self.write_null(None)
52 }
53
54 fn encode_bool(self, value: bool) -> Self::Output {
55 self.write_bool(value, None)
56 }
57
58 /// Encode an unsigned integer of at most 64 bit.
59 ///
60 /// Also to be used for smaller unsigned integers:
61 ///
62 /// ```
63 /// use cbor_data::{CborBuilder, Encoder};
64 ///
65 /// let short = 12345u16;
66 /// let cbor = CborBuilder::default().encode_u64(short.into());
67 ///
68 /// # assert_eq!(cbor.as_slice(), vec![0x19u8, 48, 57]);
69 /// ```
70 fn encode_u64(self, value: u64) -> Self::Output {
71 self.write_pos(value, None)
72 }
73
74 /// Encode a signed integer of at most 64 bit.
75 ///
76 /// Also to be used for smaller signed integers:
77 ///
78 /// ```
79 /// use cbor_data::{CborBuilder, Encoder};
80 ///
81 /// let short = -12345i16;
82 /// let cbor = CborBuilder::default().encode_i64(short.into());
83 ///
84 /// # assert_eq!(cbor.as_slice(), vec![0x39u8, 48, 56]);
85 /// ```
86 fn encode_i64(self, value: i64) -> Self::Output {
87 if value < 0 {
88 self.write_neg((-1 - value) as u64, None)
89 } else {
90 self.write_pos(value as u64, None)
91 }
92 }
93
94 /// Encode a floating-point number of at most 64 bit.
95 ///
96 /// Also to be used for smaller formats:
97 ///
98 /// ```
99 /// use cbor_data::{CborBuilder, Encoder};
100 ///
101 /// let single = -3.14f32;
102 /// let cbor = CborBuilder::default().encode_f64(single.into());
103 ///
104 /// # assert_eq!(cbor.as_slice(), vec![0xfbu8, 192, 9, 30, 184, 96, 0, 0, 0]);
105 /// ```
106 fn encode_f64(self, value: f64) -> Self::Output {
107 self.write_lit(Literal::L8(value.to_bits()), None)
108 }
109
110 /// Encode a timestamp with given target precision
111 ///
112 /// Since the CBOR-encoding itself does not carry precision information, the result
113 /// is not guaranteed to round-trip as the exact same timestamp. Encoding with `Precision::Seconds`
114 /// will discard the `nanos()` part.
115 ///
116 /// If the `rfc3339` feature flag is enabled, textual representation is chosen for
117 /// subsecond precision when encoding as a double-precision floating-point number would
118 /// not be enough (float is sufficient for 285 years around 1970 at microsecond precision).
119 /// Textual representation retains timezone information in the output.
120 fn encode_timestamp(self, timestamp: Timestamp, precision: Precision) -> Self::Output {
121 timestamp.encode(self, precision)
122 }
123
124 /// Encode a possibly big number
125 ///
126 /// The number will be encoded as simple integer or float if its mantissa is small enough.
127 fn encode_number(self, number: &Number) -> Self::Output {
128 number.encode(self)
129 }
130
131 /// Encode a string.
132 ///
133 /// ```
134 /// use cbor_data::{CborBuilder, Encoder};
135 ///
136 /// let cbor = CborBuilder::default().encode_array(|builder| {
137 /// builder.encode_str("hello");
138 /// builder.encode_str(String::new());
139 /// });
140 ///
141 /// # assert_eq!(cbor.as_slice(), vec![0x82, 0x65, b'h', b'e', b'l', b'l', b'o', 0x60]);
142 /// ```
143 fn encode_str(self, value: impl AsRef<str>) -> Self::Output {
144 self.write_str(value.as_ref(), None)
145 }
146
147 /// Encode a byte string.
148 ///
149 /// ```
150 /// use cbor_data::{CborBuilder, Encoder};
151 ///
152 /// let cbor = CborBuilder::default().encode_array(|builder| {
153 /// builder.encode_bytes(b"hello");
154 /// });
155 ///
156 /// # assert_eq!(cbor.as_slice(), vec![0x81, 0x45, b'h', b'e', b'l', b'l', b'o']);
157 /// ```
158 fn encode_bytes(self, value: impl AsRef<[u8]>) -> Self::Output {
159 self.write_bytes(value.as_ref(), None)
160 }
161
162 /// Write an array that is then filled by the provided closure using the passed builder.
163 ///
164 /// see [`trait Encoder`](trait.Encoder.html) for usage examples
165 fn encode_array<F>(self, f: F) -> Self::Output
166 where
167 F: FnOnce(&mut ArrayWriter<'_>),
168 {
169 self.write_array(None, |builder| f(builder))
170 }
171
172 /// Write a dict that is then filled by the provided closure using the passed builder.
173 ///
174 /// see [`trait Encoder`](trait.Encoder.html) for usage examples
175 fn encode_dict<F>(self, f: F) -> Self::Output
176 where
177 F: FnOnce(&mut DictWriter<'_>),
178 {
179 self.write_dict(None, |builder| f(builder))
180 }
181}
182
183impl<T: Writer> Encoder for T {}