iota_ledger_nano/api/
packable.rs1use thiserror::Error;
13
14pub use std::io::{Read, Write};
15
16use std::str;
17
18#[derive(Debug, Error)]
19#[allow(dead_code)] pub enum Error {
21 #[error("I/O error happened: {0}.")]
22 Io(#[from] std::io::Error),
23 #[error("Invalid variant read.")]
24 InvalidVariant,
25 #[error("Invalid Utf8 string read.")]
26 InvalidUtf8String,
27 #[error("Invalid version read.")]
28 InvalidVersion,
29 #[error("Invalid type read.")]
30 InvalidType,
31 #[error("Invalid announced len.")]
32 InvalidAnnouncedLen,
33 #[error("String too long.")]
34 StringTooLong,
35}
36
37pub trait Packable {
38 fn packed_len(&self) -> usize;
39
40 fn pack<W: Write>(&self, buf: &mut W) -> Result<(), Error>;
41
42 fn unpack<R: Read>(buf: &mut R) -> Result<Self, Error>
43 where
44 Self: Sized;
45}
46
47impl Packable for () {
48 fn packed_len(&self) -> usize {
49 0
50 }
51
52 fn pack<W: Write>(&self, _buf: &mut W) -> Result<(), Error> {
53 Ok(())
54 }
55
56 fn unpack<R: Read>(_buf: &mut R) -> Result<Self, Error>
57 where
58 Self: Sized,
59 {
60 Ok(())
61 }
62}
63
64macro_rules! impl_packable_for_num {
65 ($ty:ident) => {
66 impl Packable for $ty {
67 fn packed_len(&self) -> usize {
68 std::mem::size_of::<$ty>()
69 }
70
71 fn pack<W: Write>(&self, buf: &mut W) -> Result<(), Error> {
72 buf.write_all(self.to_le_bytes().as_ref())?;
73
74 Ok(())
75 }
76
77 fn unpack<R: Read>(buf: &mut R) -> Result<Self, Error> {
78 let mut bytes = [0; std::mem::size_of::<$ty>()];
79 buf.read_exact(&mut bytes)?;
80 Ok($ty::from_le_bytes(bytes))
81 }
82 }
83 };
84}
85
86impl Packable for String {
87 fn packed_len(&self) -> usize {
88 0u8.packed_len() + self.chars().count()
89 }
90
91 fn pack<W: Write>(&self, buf: &mut W) -> Result<(), Error> {
92 if self.chars().count() > 255 {
93 return Err(Error::StringTooLong);
94 }
95 let bytes = self.clone().into_bytes();
96 (bytes.len() as u8).pack(buf)?;
97 buf.write_all(&bytes)?;
98 Ok(())
99 }
100
101 fn unpack<R: Read>(buf: &mut R) -> Result<Self, Error>
102 where
103 Self: Sized,
104 {
105 let l = u8::unpack(buf)?;
106 let mut v: Vec<u8> = Vec::new();
107 for _ in 0..l {
108 v.push(u8::unpack(buf)?);
109 }
110 match str::from_utf8(v.as_ref()) {
111 Ok(v) => Ok(String::from(v)),
112 Err(_) => Err(Error::InvalidUtf8String),
113 }
114 }
115}
116
117impl_packable_for_num!(i8);
118impl_packable_for_num!(u8);
119impl_packable_for_num!(i16);
120impl_packable_for_num!(u16);
121impl_packable_for_num!(i32);
122impl_packable_for_num!(u32);
123impl_packable_for_num!(i64);
124impl_packable_for_num!(u64);
125impl_packable_for_num!(i128);
126impl_packable_for_num!(u128);