ssb_slp_encoding/
lib.rs

1//! ssb-slp-encoding
2//!
3//! A module that implements the Shallow Length Prefixed (SLP) encoding of collections of bytes
4//! used by the scuttlebutt envelope-spec.
5//!
6//! Spec defined [here](https://github.com/ssbc/envelope-spec/blob/master/encoding/slp.md)
7//!
8
9use bytes::{Buf, BufMut};
10use snafu::{ResultExt, Snafu};
11use std::convert::TryInto;
12use std::io::Read;
13use std::io::Write;
14
15#[derive(Debug, Snafu)]
16pub enum Error {
17    ItemTooLong { source: std::num::TryFromIntError },
18    WriteError { source: std::io::Error },
19    ReadError { source: std::io::Error },
20}
21
22#[derive(PartialEq, Debug)]
23pub struct SLP(pub Vec<Vec<u8>>);
24
25/// A type that owns a collection of bytes that can be encoded using the SLP encoding.
26impl SLP {
27    pub fn encode_write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
28        self.0.iter().try_for_each(|bytes| {
29            let byte_len: u16 = bytes.len().try_into().context(ItemTooLong)?;
30            let mut length_buf = [0u8; 2];
31            (&mut length_buf[..]).put_u16_le(byte_len);
32
33            writer.write(&length_buf).context(WriteError)?;
34            writer.write(&bytes).context(WriteError)?;
35
36            Ok::<(), Error>(())
37        })?;
38
39        Ok(())
40    }
41
42    pub fn decode_read<R: Read>(reader: &mut R) -> Result<Self, Error> {
43        let mut items = Vec::new();
44
45        let mut length_buf = [0u8; 2];
46
47        while let Ok(_) = reader.read_exact(&mut length_buf) {
48            let byte_len = (&length_buf[..]).get_u16_le();
49            let mut item = Vec::with_capacity(byte_len as usize);
50            item.resize(byte_len as usize, 0);
51            reader.read_exact(&mut item).context(ReadError)?;
52            items.push(item);
53        }
54        Ok(SLP(items))
55    }
56
57    pub fn into_inner(self) -> Vec<Vec<u8>> {
58        self.0
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use crate::*;
65    #[test]
66    fn encode_decode() {
67        let data = vec![vec![1u8, 2, 3], vec![4u8, 5, 6, 7]];
68        let slp = SLP(data);
69
70        let mut encode_writer = vec![];
71        slp.encode_write(&mut encode_writer).unwrap();
72
73        let decoded = SLP::decode_read(&mut encode_writer.as_slice()).unwrap();
74
75        assert_eq!(decoded, slp);
76    }
77}