walletconnect 0.1.0

WalletConnect client implementation in Rust.
Documentation
use crate::hex;
use ethers_core::types::Address;
use serde::de::{DeserializeOwned, Error as _};
use serde::ser::Error as _;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::borrow::Cow;

pub mod jsonstring {
    use super::*;

    pub fn serialize<T, S>(value: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
    where
        T: Serialize,
        S: Serializer,
    {
        let json = match value {
            None => Cow::from(""),
            Some(value) => serde_json::to_string(value)
                .map_err(S::Error::custom)?
                .into(),
        };
        serializer.serialize_str(&json)
    }

    pub fn deserialize<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
    where
        T: DeserializeOwned,
        D: Deserializer<'de>,
    {
        let json = Cow::<'de, str>::deserialize(deserializer)?;
        if !json.is_empty() {
            let value = serde_json::from_str(&json).map_err(D::Error::custom)?;
            Ok(Some(value))
        } else {
            Ok(None)
        }
    }
}

pub mod prefixedhexstring {
    use super::*;

    pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&format!("0x{}", hex::encode(bytes)))
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let string = Cow::<'de, str>::deserialize(deserializer)?;
        if !string.starts_with("0x") {
            return Err(D::Error::custom("hex string missing '0x' prefix"));
        }

        let bytes = hex::decode(&string[2..]).map_err(D::Error::custom)?;
        Ok(bytes)
    }
}

pub mod hexstring {
    use super::*;

    pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&hex::encode(bytes))
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let string = Cow::<'de, str>::deserialize(deserializer)?;
        let bytes = hex::decode(&*string).map_err(D::Error::custom)?;
        Ok(bytes)
    }
}

pub mod emptynoneaddress {
    use super::*;

    pub fn serialize<S>(value: &Option<Address>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match value {
            Some(value) => value.serialize(serializer),
            None => serializer.serialize_str(""),
        }
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Address>, D::Error>
    where
        D: Deserializer<'de>,
    {
        match Cow::<'de, str>::deserialize(deserializer)?.as_ref() {
            "" => Ok(None),
            value => value.parse().map(Some).map_err(D::Error::custom),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ethereum_types::H160;
    use serde_json::json;

    #[test]
    fn deserializes_empty_none_address() {
        assert_eq!(
            emptynoneaddress::deserialize(json!("0x000102030405060708090a0b0c0d0e0f10111213"))
                .unwrap(),
            Some(H160([
                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
            ])),
        );

        assert_eq!(emptynoneaddress::deserialize(json!("")).unwrap(), None,);
    }
}