sp_ipld/dag_cbor/
encode.rs

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