libipld_raw_cbor/
encode.rs

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