From 88262de9eef3cf218aa4cc6a2434c9146e815ab5 Mon Sep 17 00:00:00 2001 From: Meet Mangukiya Date: Sat, 5 Mar 2022 23:44:11 +0530 Subject: [PATCH] feat(ethers-core/Bytes): impl FromStr (#991) --- ethers-core/src/types/bytes.rs | 37 +++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/ethers-core/src/types/bytes.rs b/ethers-core/src/types/bytes.rs index 9ec30263..21f2c719 100644 --- a/ethers-core/src/types/bytes.rs +++ b/ethers-core/src/types/bytes.rs @@ -2,8 +2,13 @@ use serde::{ de::{Error, Unexpected}, Deserialize, Deserializer, Serialize, Serializer, }; +use thiserror::Error; -use std::fmt::{Display, Formatter, LowerHex, Result as FmtResult}; +use std::{ + clone::Clone, + fmt::{Debug, Display, Formatter, LowerHex, Result as FmtResult}, + str::FromStr, +}; /// Wrapper type around Bytes to deserialize/serialize "0x" prefixed ethereum hex strings #[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize, Ord, PartialOrd)] @@ -64,6 +69,24 @@ impl<'a, const N: usize> From<&'a [u8; N]> for Bytes { } } +#[derive(Debug, Clone, Error)] +#[error("Failed to parse bytes: {0}")] +pub struct ParseBytesError(String); + +impl FromStr for Bytes { + type Err = ParseBytesError; + + fn from_str(value: &str) -> Result { + if value.len() >= 2 && &value[0..2] == "0x" { + let bytes: Vec = hex::decode(&value[2..]) + .map_err(|e| ParseBytesError(format!("Invalid hex: {}", e)))?; + Ok(bytes.into()) + } else { + Err(ParseBytesError("Doesn't start with 0x".to_string())) + } + } +} + pub fn serialize_bytes(x: T, s: S) -> Result where S: Serializer, @@ -97,4 +120,16 @@ mod tests { assert_eq!(format!("{:x}", b), expected); assert_eq!(format!("{}", b), expected); } + + #[test] + fn test_from_str() { + let b = Bytes::from_str("0x1213"); + assert!(b.is_ok()); + let b = b.unwrap(); + assert_eq!(b.as_ref(), hex::decode("1213").unwrap()); + + let b = Bytes::from_str("1213"); + assert!(b.is_err()); + assert_eq!(b.err().unwrap().0, "Doesn't start with 0x"); + } }