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 {}