//! Provides utilities for parsing 0x-prefixed hex strings. use serde::de::{self, Visitor}; use std::fmt; /// Encode `data` as a 0x-prefixed hex string. pub fn encode>(data: T) -> String { let hex = hex::encode(data); let mut s = "0x".to_string(); s.push_str(hex.as_str()); s } /// Decode `data` from a 0x-prefixed hex string. pub fn decode(s: &str) -> Result, String> { if let Some(stripped) = s.strip_prefix("0x") { hex::decode(stripped).map_err(|e| format!("invalid hex: {:?}", e)) } else { Err("hex must have 0x prefix".to_string()) } } pub struct PrefixedHexVisitor; impl<'de> Visitor<'de> for PrefixedHexVisitor { type Value = Vec; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a hex string with 0x prefix") } fn visit_str(self, value: &str) -> Result where E: de::Error, { if let Some(stripped) = value.strip_prefix("0x") { Ok(hex::decode(stripped) .map_err(|e| de::Error::custom(format!("invalid hex ({:?})", e)))?) } else { Err(de::Error::custom("missing 0x prefix")) } } } pub struct HexVisitor; impl<'de> Visitor<'de> for HexVisitor { type Value = Vec; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a hex string (irrelevant of prefix)") } fn visit_str(self, value: &str) -> Result where E: de::Error, { Ok(hex::decode(value.trim_start_matches("0x")) .map_err(|e| de::Error::custom(format!("invalid hex ({:?})", e)))?) } } #[cfg(test)] mod test { use super::*; #[test] fn encoding() { let bytes = vec![0, 255]; let hex = encode(&bytes); assert_eq!(hex.as_str(), "0x00ff"); let bytes = vec![]; let hex = encode(&bytes); assert_eq!(hex.as_str(), "0x"); let bytes = vec![1, 2, 3]; let hex = encode(&bytes); assert_eq!(hex.as_str(), "0x010203"); } }