1use std::io::{Read, Write};
6
7use thiserror::Error;
8
9#[derive(Error, Debug)]
10pub enum IoError {
11 #[error("IO error: {0}")]
12 Io(String),
13
14 #[error("{0}")]
15 Other(String),
16}
17
18pub type Result<T> = std::result::Result<T, IoError>;
19
20pub trait Import<const IS_HUMAN_READABLE: bool>: Sized {
21 fn import<R: Read>(reader: &mut R) -> Result<Self>;
23}
24
25pub trait Export<const IS_HUMAN_READABLE: bool> {
26 fn export<W: Write>(&self, writer: &mut W) -> Result<()>;
28}
29
30pub fn prefix_hex_string<T: Export<true>>(src: &T) -> Result<String> {
32 let mut buf = Vec::new();
33 src.export(&mut buf)?;
34 String::from_utf8(buf).map_err(|e| IoError::Other(e.to_string()))
35}
36
37pub fn decode_prefix_hex_string<T: Import<true>>(src: &str) -> Result<T> {
39 T::import(&mut src.as_bytes())
40}
41
42fn hex_encode_with_prefix<W: Write>(bytes: &[u8], writer: &mut W) -> Result<()> {
43 writer.write_all(b"0x").map_err(|e| IoError::Io(e.to_string()))?;
44 writer
45 .write_all(hex::encode(bytes).as_bytes())
46 .map_err(|e| IoError::Io(e.to_string()))?;
47 Ok(())
48}
49
50fn hex_decode_with_prefix<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
51 let mut buf = Vec::new();
52 reader.read_to_end(&mut buf).map_err(|e| IoError::Io(e.to_string()))?;
53 let hex_without_prefix = buf
54 .strip_prefix(b"0x")
55 .ok_or_else(|| IoError::Other("Must have '0x' prefix".to_string()))?;
56 hex::decode(hex_without_prefix).map_err(|e| IoError::Other(e.to_string()))
57}
58
59impl Export<true> for &[u8] {
60 fn export<W: Write>(&self, writer: &mut W) -> Result<()> {
61 hex_encode_with_prefix(self, writer)
62 }
63}
64
65impl Export<true> for Vec<u8> {
66 fn export<W: Write>(&self, writer: &mut W) -> Result<()> {
67 hex_encode_with_prefix(self, writer)
68 }
69}
70
71impl Import<true> for Vec<u8> {
72 fn import<R: Read>(reader: &mut R) -> Result<Self> {
73 hex_decode_with_prefix(reader)
74 }
75}