From 0b2c31e3038ed061e22d06e0dbb6105e508aecff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Thu, 25 Aug 2022 14:42:18 +0200 Subject: [PATCH] Add conversion and default functions for `NumberOrHex` (#636) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add conversion and default functions for `NumberOrHex` * Update subxt/src/rpc.rs Co-authored-by: Andrew Jones * Derive `Debug` with `thiserror::Error` * Remove unnecessary `#[cfg(test)]` * Add `#[error(…)]` * Remove `()` Co-authored-by: Andrew Jones --- subxt/src/rpc.rs | 103 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/subxt/src/rpc.rs b/subxt/src/rpc.rs index 1be869e122..49a4979413 100644 --- a/subxt/src/rpc.rs +++ b/subxt/src/rpc.rs @@ -135,6 +135,87 @@ impl From for BlockNumber { } } +impl Default for NumberOrHex { + fn default() -> Self { + Self::Number(Default::default()) + } +} + +impl NumberOrHex { + /// Converts this number into an U256. + pub fn into_u256(self) -> U256 { + match self { + NumberOrHex::Number(n) => n.into(), + NumberOrHex::Hex(h) => h, + } + } +} + +impl From for NumberOrHex { + fn from(n: u32) -> Self { + NumberOrHex::Number(n.into()) + } +} + +impl From for NumberOrHex { + fn from(n: u64) -> Self { + NumberOrHex::Number(n) + } +} + +impl From for NumberOrHex { + fn from(n: u128) -> Self { + NumberOrHex::Hex(n.into()) + } +} + +impl From for NumberOrHex { + fn from(n: U256) -> Self { + NumberOrHex::Hex(n) + } +} + +/// An error type that signals an out-of-range conversion attempt. +#[derive(Debug, thiserror::Error)] +#[error("Out-of-range conversion attempt")] +pub struct TryFromIntError; + +impl TryFrom for u32 { + type Error = TryFromIntError; + fn try_from(num_or_hex: NumberOrHex) -> Result { + num_or_hex + .into_u256() + .try_into() + .map_err(|_| TryFromIntError) + } +} + +impl TryFrom for u64 { + type Error = TryFromIntError; + fn try_from(num_or_hex: NumberOrHex) -> Result { + num_or_hex + .into_u256() + .try_into() + .map_err(|_| TryFromIntError) + } +} + +impl TryFrom for u128 { + type Error = TryFromIntError; + fn try_from(num_or_hex: NumberOrHex) -> Result { + num_or_hex + .into_u256() + .try_into() + .map_err(|_| TryFromIntError) + } +} + +impl From for U256 { + fn from(num_or_hex: NumberOrHex) -> U256 { + num_or_hex.into_u256() + } +} + // All unsigned ints can be converted into a BlockNumber: macro_rules! into_block_number { ($($t: ty)+) => { @@ -639,6 +720,18 @@ fn to_hex(bytes: impl AsRef<[u8]>) -> String { mod test { use super::*; + /// A util function to assert the result of serialization and deserialization is the same. + pub(crate) fn assert_deser(s: &str, expected: T) + where + T: std::fmt::Debug + + serde::ser::Serialize + + serde::de::DeserializeOwned + + PartialEq, + { + assert_eq!(serde_json::from_str::(s).unwrap(), expected); + assert_eq!(serde_json::to_string(&expected).unwrap(), s); + } + #[test] fn test_deser_runtime_version() { let val: RuntimeVersion = serde_json::from_str( @@ -664,4 +757,14 @@ mod test { } ); } + + #[test] + fn should_serialize_and_deserialize() { + assert_deser(r#""0x1234""#, NumberOrHex::Hex(0x1234.into())); + assert_deser(r#""0x0""#, NumberOrHex::Hex(0.into())); + assert_deser(r#"5"#, NumberOrHex::Number(5)); + assert_deser(r#"10000"#, NumberOrHex::Number(10000)); + assert_deser(r#"0"#, NumberOrHex::Number(0)); + assert_deser(r#"1000000000000"#, NumberOrHex::Number(1000000000000)); + } }