#![cfg_attr(not(feature = "std"), no_std)]
#![deny(missing_docs)]
extern crate alloc;
use alloc::{format, vec::Vec};
use anyhow::anyhow;
const HEX_ENCODING_PREFIX: &str = "0x";
pub fn try_bytes_from_hex_str(s: &str) -> Result<Vec<u8>, anyhow::Error> {
let target = s.replace(HEX_ENCODING_PREFIX, "");
let data = hex::decode(target).map_err(|e| anyhow!("{e:?}"))?;
Ok(data)
}
pub mod as_hex {
use super::*;
use alloc::string::String;
use serde::de::Deserialize;
pub fn serialize<S, T: AsRef<[u8]>>(data: T, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let encoding = hex::encode(data.as_ref());
let output = format!("{HEX_ENCODING_PREFIX}{encoding}");
serializer.collect_str(&output)
}
pub fn serialize_option<S, T: AsRef<[u8]>>(
data: &Option<T>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if let Some(data) = data {
let encoding = hex::encode(data.as_ref());
let output = format!("{HEX_ENCODING_PREFIX}{encoding}");
serializer.collect_str(&output)
} else {
serializer.collect_str(&"")
}
}
pub fn deserialize_option<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: serde::Deserializer<'de>,
T: TryFrom<Vec<u8>>,
{
let s = <String>::deserialize(deserializer)?;
let data = try_bytes_from_hex_str(&s).map_err(serde::de::Error::custom)?;
if data.is_empty() {
Ok(None)
} else {
let inner = T::try_from(data).map_err(|_| {
serde::de::Error::custom("type failed to parse bytes from hex data")
})?;
Ok(Some(inner))
}
}
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: serde::Deserializer<'de>,
T: TryFrom<Vec<u8>>,
{
let s = <String>::deserialize(deserializer)?;
let data = try_bytes_from_hex_str(&s).map_err(serde::de::Error::custom)?;
let inner = T::try_from(data)
.map_err(|_| serde::de::Error::custom("type failed to parse bytes from hex data"))?;
Ok(inner)
}
}
pub mod as_utf8_string {
use super::*;
use alloc::string::String;
use serde::de::Deserialize;
pub fn serialize<S, T: AsRef<[u8]>>(data: T, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let output =
String::from_utf8(data.as_ref().to_vec()).map_err(serde::ser::Error::custom)?;
serializer.collect_str(&output)
}
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: serde::Deserializer<'de>,
T: From<[u8; 4]>,
{
let s = <String>::deserialize(deserializer)?;
let mut bytes = [0u8; 4];
bytes.copy_from_slice(s.as_bytes());
Ok(bytes.into())
}
}
pub mod seq_of_hex {
use super::*;
use core::{fmt, marker::PhantomData};
use serde::{de::Deserializer, ser::SerializeSeq};
pub fn serialize<S, T>(data: T, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
T: AsRef<[Vec<u8>]>,
{
let mut seq = serializer.serialize_seq(None)?;
for elem in data.as_ref().iter() {
let encoding = hex::encode(elem);
let output = format!("{HEX_ENCODING_PREFIX}{encoding}");
seq.serialize_element(&output)?;
}
seq.end()
}
struct Visitor(PhantomData<Vec<Vec<u8>>>);
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = Vec<Vec<u8>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("sequence of string")
}
fn visit_seq<S>(self, mut access: S) -> Result<Self::Value, S::Error>
where
S: serde::de::SeqAccess<'de>,
{
let mut coll = Vec::with_capacity(access.size_hint().unwrap_or(0));
while let Some(elem) = access.next_element()? {
let recovered_elem =
try_bytes_from_hex_str(elem).map_err(serde::de::Error::custom)?;
coll.push(recovered_elem);
}
Ok(coll)
}
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<Vec<u8>>, D::Error>
where
D: Deserializer<'de>,
{
let data = deserializer.deserialize_seq(Visitor(PhantomData))?;
Ok(data)
}
}
pub mod as_string {
use alloc::{format, string::String};
use core::{fmt, str::FromStr};
use serde::de::Deserialize;
pub fn serialize<S, T: fmt::Display>(data: T, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let output = format!("{data}");
serializer.collect_str(&output)
}
pub fn deserialize<'de, D, T: FromStr>(deserializer: D) -> Result<T, D::Error>
where
D: serde::Deserializer<'de>,
{
let s: String = <String>::deserialize(deserializer)?;
let inner: T = s
.parse()
.map_err(|_| serde::de::Error::custom("failure to parse string data"))?;
Ok(inner)
}
}
pub mod seq_of_str {
use super::*;
use core::{fmt, marker::PhantomData, str::FromStr};
use serde::{
de::{Deserializer, Error},
ser::SerializeSeq,
};
pub fn serialize<S, T, U>(data: T, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
T: AsRef<[U]>,
U: fmt::Display,
{
let mut seq = serializer.serialize_seq(None)?;
for elem in data.as_ref().iter() {
let rendered_elem = format!("{elem}");
seq.serialize_element(&rendered_elem)?;
}
seq.end()
}
struct Visitor<T>(PhantomData<Vec<T>>);
impl<'de, T: FromStr> serde::de::Visitor<'de> for Visitor<T> {
type Value = Vec<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("sequence of string")
}
fn visit_seq<S>(self, mut access: S) -> Result<Self::Value, S::Error>
where
S: serde::de::SeqAccess<'de>,
{
let mut coll = Vec::with_capacity(access.size_hint().unwrap_or(0));
while let Some(elem) = access.next_element()? {
let recovered_elem = T::from_str(elem).map_err(|_| {
Error::custom("failure to parse element of sequence from string")
})?;
coll.push(recovered_elem);
}
Ok(coll)
}
}
pub fn deserialize<'de, D, T, U>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: TryFrom<Vec<U>>,
U: FromStr,
{
let data = deserializer.deserialize_seq(Visitor(PhantomData))?;
T::try_from(data).map_err(|_| serde::de::Error::custom("failure to parse collection"))
}
}
#[cfg(test)]
mod test {
use primitive_types::{H256, H512};
use ismp::router::{GetRequest, GetResponse, PostRequest, PostResponse, StorageValue};
#[test]
fn serialize_and_deserialize_post_request() {
let post = PostRequest {
source: ismp::host::StateMachine::Polkadot(100),
dest: ismp::host::StateMachine::Polkadot(2000),
nonce: 300,
from: H256::random().0.to_vec(),
to: H256::random().0.to_vec(),
timeout_timestamp: 0,
body: H512::random().0.to_vec(),
};
let serialized = serde_json::to_string(&post).unwrap();
println!("{serialized:?}\n");
let deserialized: PostRequest = serde_json::from_str(&serialized).unwrap();
assert_eq!(post, deserialized);
}
#[test]
fn serialize_and_deserialize_post_response() {
let post = PostRequest {
source: ismp::host::StateMachine::Polkadot(100),
dest: ismp::host::StateMachine::Polkadot(2000),
nonce: 300,
from: H256::random().0.to_vec(),
to: H256::random().0.to_vec(),
timeout_timestamp: 0,
body: H512::random().0.to_vec(),
};
let response =
PostResponse { post, response: H512::random().0.to_vec(), timeout_timestamp: 30000 };
let serialized = serde_json::to_string(&response).unwrap();
println!("{serialized:?}\n");
let deserialized: PostResponse = serde_json::from_str(&serialized).unwrap();
assert_eq!(response, deserialized);
}
#[test]
fn serialize_and_deserialize_get_request() {
let get = GetRequest {
source: ismp::host::StateMachine::Polkadot(100),
dest: ismp::host::StateMachine::Polkadot(2000),
nonce: 300,
context: Default::default(),
from: H256::random().0.to_vec(),
keys: vec![
H256::random().0.to_vec(),
H256::random().0.to_vec(),
H256::random().0.to_vec(),
],
timeout_timestamp: 40000,
height: 289900,
};
let serialized = serde_json::to_string(&get).unwrap();
println!("{serialized:?}\n");
let deserialized: GetRequest = serde_json::from_str(&serialized).unwrap();
assert_eq!(get, deserialized);
}
#[test]
fn serialize_and_deserialize_get_response() {
let get = GetRequest {
source: ismp::host::StateMachine::Polkadot(100),
dest: ismp::host::StateMachine::Polkadot(2000),
nonce: 300,
context: Default::default(),
from: H256::random().0.to_vec(),
keys: vec![
H256::random().0.to_vec(),
H256::random().0.to_vec(),
H256::random().0.to_vec(),
],
timeout_timestamp: 40000,
height: 289900,
};
let response = GetResponse {
get,
values: vec![
StorageValue {
key: H256::random().0.to_vec(),
value: Some(H256::random().0.to_vec()),
},
StorageValue { key: H256::random().0.to_vec(), value: None },
StorageValue {
key: H256::random().0.to_vec(),
value: Some(H256::random().0.to_vec()),
},
],
};
let serialized = serde_json::to_string(&response).unwrap();
println!("{serialized:?}\n");
let deserialized: GetResponse = serde_json::from_str(&serialized).unwrap();
assert_eq!(response, deserialized);
}
#[test]
fn serialize_state_machine_id() {
use ismp::{consensus::StateMachineId, host::StateMachine};
let state_machine_updated =
StateMachineId { state_id: StateMachine::Evm(11155111), consensus_state_id: *b"ETH0" };
let serialized = serde_json::to_string(&state_machine_updated).unwrap();
println!("{serialized:?}\n");
let deserialized: StateMachineId = serde_json::from_str(&serialized).unwrap();
assert_eq!(state_machine_updated, deserialized);
}
}