libipld_cbor/
encode.rs

1//! CBOR encoder.
2
3use std::cmp::Ordering;
4use std::collections::BTreeMap;
5use std::io::Write;
6use std::iter::FromIterator;
7use std::ops::Deref;
8use std::sync::Arc;
9
10use byteorder::{BigEndian, ByteOrder};
11use libipld_core::cid::Cid;
12use libipld_core::codec::Encode;
13use libipld_core::error::Result;
14use libipld_core::ipld::Ipld;
15
16use crate::cbor::{MajorKind, FALSE, TRUE};
17use crate::error::NumberOutOfRange;
18use crate::DagCborCodec as DagCbor;
19
20/// Writes a null byte to a cbor encoded byte stream.
21pub fn write_null<W: Write>(w: &mut W) -> Result<()> {
22    w.write_all(&[0xf6])?;
23    Ok(())
24}
25
26/// Writes a u8 to a cbor encoded byte stream.
27pub fn write_u8<W: Write>(w: &mut W, major: MajorKind, value: u8) -> Result<()> {
28    let major = major as u8;
29    if value <= 0x17 {
30        let buf = [major << 5 | value];
31        w.write_all(&buf)?;
32    } else {
33        let buf = [major << 5 | 24, value];
34        w.write_all(&buf)?;
35    }
36    Ok(())
37}
38
39/// Writes a u16 to a cbor encoded byte stream.
40pub fn write_u16<W: Write>(w: &mut W, major: MajorKind, value: u16) -> Result<()> {
41    if value <= u16::from(u8::max_value()) {
42        write_u8(w, major, value as u8)?;
43    } else {
44        let mut buf = [(major as u8) << 5 | 25, 0, 0];
45        BigEndian::write_u16(&mut buf[1..], value);
46        w.write_all(&buf)?;
47    }
48    Ok(())
49}
50
51/// Writes a u32 to a cbor encoded byte stream.
52pub fn write_u32<W: Write>(w: &mut W, major: MajorKind, value: u32) -> Result<()> {
53    if value <= u32::from(u16::max_value()) {
54        write_u16(w, major, value as u16)?;
55    } else {
56        let mut buf = [(major as u8) << 5 | 26, 0, 0, 0, 0];
57        BigEndian::write_u32(&mut buf[1..], value);
58        w.write_all(&buf)?;
59    }
60    Ok(())
61}
62
63/// Writes a u64 to a cbor encoded byte stream.
64pub fn write_u64<W: Write>(w: &mut W, major: MajorKind, value: u64) -> Result<()> {
65    if value <= u64::from(u32::max_value()) {
66        write_u32(w, major, value as u32)?;
67    } else {
68        let mut buf = [(major as u8) << 5 | 27, 0, 0, 0, 0, 0, 0, 0, 0];
69        BigEndian::write_u64(&mut buf[1..], value);
70        w.write_all(&buf)?;
71    }
72    Ok(())
73}
74
75/// Writes a tag to a cbor encoded byte stream.
76pub fn write_tag<W: Write>(w: &mut W, tag: u64) -> Result<()> {
77    write_u64(w, MajorKind::Tag, tag)
78}
79
80impl Encode<DagCbor> for bool {
81    fn encode<W: Write>(&self, _: DagCbor, w: &mut W) -> Result<()> {
82        let buf = if *self { [TRUE.into()] } else { [FALSE.into()] };
83        w.write_all(&buf)?;
84        Ok(())
85    }
86}
87
88impl Encode<DagCbor> for u8 {
89    fn encode<W: Write>(&self, _: DagCbor, w: &mut W) -> Result<()> {
90        write_u8(w, MajorKind::UnsignedInt, *self)
91    }
92}
93
94impl Encode<DagCbor> for u16 {
95    fn encode<W: Write>(&self, _: DagCbor, w: &mut W) -> Result<()> {
96        write_u16(w, MajorKind::UnsignedInt, *self)
97    }
98}
99
100impl Encode<DagCbor> for u32 {
101    fn encode<W: Write>(&self, _: DagCbor, w: &mut W) -> Result<()> {
102        write_u32(w, MajorKind::UnsignedInt, *self)
103    }
104}
105
106impl Encode<DagCbor> for u64 {
107    fn encode<W: Write>(&self, _: DagCbor, w: &mut W) -> Result<()> {
108        write_u64(w, MajorKind::UnsignedInt, *self)
109    }
110}
111
112impl Encode<DagCbor> for i8 {
113    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
114        if self.is_negative() {
115            write_u8(w, MajorKind::NegativeInt, -(*self + 1) as u8)
116        } else {
117            (*self as u8).encode(c, w)
118        }
119    }
120}
121
122impl Encode<DagCbor> for i16 {
123    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
124        if self.is_negative() {
125            write_u16(w, MajorKind::NegativeInt, -(*self + 1) as u16)
126        } else {
127            (*self as u16).encode(c, w)
128        }
129    }
130}
131
132impl Encode<DagCbor> for i32 {
133    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
134        if self.is_negative() {
135            write_u32(w, MajorKind::NegativeInt, -(*self + 1) as u32)
136        } else {
137            (*self as u32).encode(c, w)
138        }
139    }
140}
141
142impl Encode<DagCbor> for i64 {
143    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
144        if self.is_negative() {
145            write_u64(w, MajorKind::NegativeInt, -(*self + 1) as u64)
146        } else {
147            (*self as u64).encode(c, w)
148        }
149    }
150}
151
152impl Encode<DagCbor> for f32 {
153    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
154        // IPLD maximally encodes floats.
155        f64::from(*self).encode(c, w)
156    }
157}
158
159impl Encode<DagCbor> for f64 {
160    fn encode<W: Write>(&self, _: DagCbor, w: &mut W) -> Result<()> {
161        // IPLD forbids nan, infinities, etc.
162        if !self.is_finite() {
163            return Err(NumberOutOfRange::new::<f64>().into());
164        }
165        let mut buf = [0xfb, 0, 0, 0, 0, 0, 0, 0, 0];
166        BigEndian::write_f64(&mut buf[1..], *self);
167        w.write_all(&buf)?;
168        Ok(())
169    }
170}
171
172impl Encode<DagCbor> for [u8] {
173    fn encode<W: Write>(&self, _: DagCbor, w: &mut W) -> Result<()> {
174        write_u64(w, MajorKind::ByteString, self.len() as u64)?;
175        w.write_all(self)?;
176        Ok(())
177    }
178}
179
180impl Encode<DagCbor> for Box<[u8]> {
181    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
182        self[..].encode(c, w)
183    }
184}
185
186impl Encode<DagCbor> for str {
187    fn encode<W: Write>(&self, _: DagCbor, w: &mut W) -> Result<()> {
188        write_u64(w, MajorKind::TextString, self.len() as u64)?;
189        w.write_all(self.as_bytes())?;
190        Ok(())
191    }
192}
193
194impl Encode<DagCbor> for String {
195    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
196        self.as_str().encode(c, w)
197    }
198}
199
200impl Encode<DagCbor> for i128 {
201    fn encode<W: Write>(&self, _: DagCbor, w: &mut W) -> Result<()> {
202        if *self < 0 {
203            if -(*self + 1) > u64::max_value() as i128 {
204                return Err(NumberOutOfRange::new::<i128>().into());
205            }
206            write_u64(w, MajorKind::NegativeInt, -(*self + 1) as u64)?;
207        } else {
208            if *self > u64::max_value() as i128 {
209                return Err(NumberOutOfRange::new::<i128>().into());
210            }
211            write_u64(w, MajorKind::UnsignedInt, *self as u64)?;
212        }
213        Ok(())
214    }
215}
216
217impl Encode<DagCbor> for Cid {
218    fn encode<W: Write>(&self, _: DagCbor, w: &mut W) -> Result<()> {
219        write_tag(w, 42)?;
220        // insert zero byte per https://github.com/ipld/specs/blob/master/block-layer/codecs/dag-cbor.md#links
221        // TODO: don't allocate
222        let buf = self.to_bytes();
223        let len = buf.len();
224        write_u64(w, MajorKind::ByteString, len as u64 + 1)?;
225        w.write_all(&[0])?;
226        w.write_all(&buf[..len])?;
227        Ok(())
228    }
229}
230
231impl<T: Encode<DagCbor>> Encode<DagCbor> for Option<T> {
232    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
233        if let Some(value) = self {
234            value.encode(c, w)?;
235        } else {
236            write_null(w)?;
237        }
238        Ok(())
239    }
240}
241
242impl<T: Encode<DagCbor>> Encode<DagCbor> for Vec<T> {
243    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
244        write_u64(w, MajorKind::Array, self.len() as u64)?;
245        for value in self {
246            value.encode(c, w)?;
247        }
248        Ok(())
249    }
250}
251
252impl<T: Encode<DagCbor> + 'static> Encode<DagCbor> for BTreeMap<String, T> {
253    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
254        write_u64(w, MajorKind::Map, self.len() as u64)?;
255        // CBOR RFC-7049 specifies a canonical sort order, where keys are sorted by length first.
256        // This was later revised with RFC-8949, but we need to stick to the original order to stay
257        // compatible with existing data.
258        let mut cbor_order = Vec::from_iter(self);
259        cbor_order.sort_unstable_by(|&(key_a, _), &(key_b, _)| {
260            match key_a.len().cmp(&key_b.len()) {
261                Ordering::Greater => Ordering::Greater,
262                Ordering::Less => Ordering::Less,
263                Ordering::Equal => key_a.cmp(key_b),
264            }
265        });
266        for (k, v) in cbor_order {
267            k.encode(c, w)?;
268            v.encode(c, w)?;
269        }
270        Ok(())
271    }
272}
273
274impl Encode<DagCbor> for Ipld {
275    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
276        match self {
277            Self::Null => write_null(w),
278            Self::Bool(b) => b.encode(c, w),
279            Self::Integer(i) => i.encode(c, w),
280            Self::Float(f) => f.encode(c, w),
281            Self::Bytes(b) => b.as_slice().encode(c, w),
282            Self::String(s) => s.encode(c, w),
283            Self::List(l) => l.encode(c, w),
284            Self::Map(m) => m.encode(c, w),
285            Self::Link(cid) => cid.encode(c, w),
286        }
287    }
288}
289
290impl<T: Encode<DagCbor>> Encode<DagCbor> for Arc<T> {
291    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
292        self.deref().encode(c, w)
293    }
294}
295
296impl Encode<DagCbor> for () {
297    fn encode<W: Write>(&self, _c: DagCbor, w: &mut W) -> Result<()> {
298        write_u8(w, MajorKind::Array, 0)?;
299        Ok(())
300    }
301}
302
303impl<A: Encode<DagCbor>> Encode<DagCbor> for (A,) {
304    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
305        write_u8(w, MajorKind::Array, 1)?;
306        self.0.encode(c, w)?;
307        Ok(())
308    }
309}
310
311impl<A: Encode<DagCbor>, B: Encode<DagCbor>> Encode<DagCbor> for (A, B) {
312    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
313        write_u8(w, MajorKind::Array, 2)?;
314        self.0.encode(c, w)?;
315        self.1.encode(c, w)?;
316        Ok(())
317    }
318}
319
320impl<A: Encode<DagCbor>, B: Encode<DagCbor>, C: Encode<DagCbor>> Encode<DagCbor> for (A, B, C) {
321    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
322        write_u8(w, MajorKind::Array, 3)?;
323        self.0.encode(c, w)?;
324        self.1.encode(c, w)?;
325        self.2.encode(c, w)?;
326        Ok(())
327    }
328}
329
330impl<A: Encode<DagCbor>, B: Encode<DagCbor>, C: Encode<DagCbor>, D: Encode<DagCbor>> Encode<DagCbor>
331    for (A, B, C, D)
332{
333    fn encode<W: Write>(&self, c: DagCbor, w: &mut W) -> Result<()> {
334        write_u8(w, MajorKind::Array, 4)?;
335        self.0.encode(c, w)?;
336        self.1.encode(c, w)?;
337        self.2.encode(c, w)?;
338        self.3.encode(c, w)?;
339        Ok(())
340    }
341}