Skip to main content

om_crypto_types/
io.rs

1//! Minimal IO utilities for import/export used by publishable types.
2//!
3//! This intentionally avoids depending on internal crates like `om-utils`.
4
5use 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    /// Import from a reader.
22    fn import<R: Read>(reader: &mut R) -> Result<Self>;
23}
24
25pub trait Export<const IS_HUMAN_READABLE: bool> {
26    /// Export to a writer.
27    fn export<W: Write>(&self, writer: &mut W) -> Result<()>;
28}
29
30/// Encode `T` to hex string with '0x' prefix.
31pub 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
37/// Decode from hex string with '0x' prefix to `T`.
38pub 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}