Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add interchain security protobuf #NTRN-408 #8

Merged
merged 9 commits into from
Nov 27, 2024
99 changes: 89 additions & 10 deletions packages/neutron-std/src/serde/mod.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,70 @@
use serde::{
de::{
self,
value::{I64Deserializer, U64Deserializer},
},
Deserialize,
};
use std::{
fmt::{Display, Formatter},
marker::PhantomData,
str::FromStr,
};

struct StringOrNumberVisitor<T> {
pr0n00gler marked this conversation as resolved.
Show resolved Hide resolved
p: PhantomData<T>,
}

impl<'de, T> de::Visitor<'de> for StringOrNumberVisitor<T>
where
T: Deserialize<'de>,
T::Err: Display,
T: FromStr,
{
type Value = T;

fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("a string or a number")
}

fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
T::deserialize(U64Deserializer::new(value))
}

fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
where
E: de::Error,
{
T::deserialize(I64Deserializer::new(value))
}

fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
value.parse::<T>().map_err(de::Error::custom)
}
}

// Helps (de)serialize any type that implements FromStr trait as str
// For example some structs in Cosmos SDK returns ints as strs and this mod helps deal with that
pub mod as_str {
use serde::{de, Deserialize, Deserializer, Serializer};
use std::{fmt::Display, str::FromStr};
use serde::{Deserialize, Deserializer, Serializer};
use std::{fmt::Display, marker::PhantomData, str::FromStr};

use super::StringOrNumberVisitor;

pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
T: FromStr,
T::Err: Display,
T: Deserialize<'de>,
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
T::from_str(&s).map_err(de::Error::custom)
deserializer.deserialize_any(StringOrNumberVisitor { p: PhantomData })
}

pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
Expand All @@ -29,15 +82,18 @@ pub mod option_as_str {
use serde::{de, Deserialize, Deserializer, Serializer};
use std::{fmt::Display, str::FromStr};

use super::NumberOrString;

pub fn deserialize<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
where
T: FromStr,
T: FromStr + Deserialize<'de>,
T::Err: Display,
D: Deserializer<'de>,
{
let encoded_string: Option<String> = Option::deserialize(deserializer)?;
let encoded_string: Option<NumberOrString<T>> = Option::deserialize(deserializer)?;
match encoded_string {
Some(s) => T::from_str(&s).map(Some).map_err(de::Error::custom),
Some(NumberOrString::String(s)) => T::from_str(&s).map(Some).map_err(de::Error::custom),
Some(NumberOrString::Number(n)) => Ok(Some(n)),
None => Ok(None),
}
}
Expand All @@ -58,16 +114,21 @@ pub mod as_str_vec {
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::{fmt::Display, str::FromStr};

use super::NumberOrString;

pub fn deserialize<'de, T, D>(deserializer: D) -> Result<Vec<T>, D::Error>
where
T: FromStr,
T: FromStr + Deserialize<'de>,
T::Err: Display,
D: Deserializer<'de>,
{
let vec_of_strings: Vec<String> = Vec::deserialize(deserializer)?;
let vec_of_strings: Vec<NumberOrString<T>> = Vec::deserialize(deserializer)?;
vec_of_strings
.into_iter()
.map(|s| T::from_str(&s).map_err(de::Error::custom))
.map(|v| match v {
NumberOrString::Number(n) => Ok(n),
NumberOrString::String(s) => T::from_str(&s).map_err(de::Error::custom),
})
.collect()
}

Expand Down Expand Up @@ -135,3 +196,21 @@ pub mod as_option_base64_encoded_string {
}
}
}

#[derive(Deserialize, Debug, PartialEq)]
#[serde(untagged)]
enum NumberOrString<T> {
Number(T),
String(String),
}

#[test]
fn parse_test() {
let int = "-11";
let res = serde_json_wasm::from_str::<NumberOrString<i64>>(int).unwrap();
assert_eq!(res, NumberOrString::Number(-11i64));

let str = "\"-11\"";
let res = serde_json_wasm::from_str::<NumberOrString<i64>>(str).unwrap();
assert_eq!(res, NumberOrString::String("-11".to_string()));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod v1;
Loading