-
I am attempting to use #[serde_as]
#[derive(Clone, Debug, Serialize, Deserialize)]
struct TestType {
#[serde_as(as = "JsonString<Vec<Base62Encoded<u64>>>")]
field: Vec<u64>,
} The type use std::str::FromStr;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_with::{DeserializeAs, DeserializeFromStr, SerializeAs, SerializeDisplay};
#[derive(Clone, Debug, PartialEq, SerializeDisplay, DeserializeFromStr)]
pub struct Base62Encoded<T>(T);
impl<T> std::fmt::Display for Base62Encoded<T>
where
T: Clone + Into<u128>,
{
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str(&base62::encode(self.0.clone()))
}
}
impl<T> FromStr for Base62Encoded<T>
where
u128: TryInto<T>,
{
type Err = base62::DecodeError;
fn from_str(other: &str) -> Result<Self, Self::Err> {
match base62::decode(other)?.try_into() {
Ok(n) => Ok(Base62Encoded(n)),
Err(_) => Err(Self::Err::ArithmeticOverflow),
}
}
}
impl<T> SerializeAs<T> for Base62Encoded<T>
where
T: Clone + Into<u128>,
{
fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
Base62Encoded(source.clone()).serialize(serializer)
}
}
impl<'de, T> DeserializeAs<'de, T> for Base62Encoded<T>
where
u128: TryInto<T>,
{
fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
{
Base62Encoded::deserialize(deserializer).map(|this| this.0)
}
} This does appear to do the job as expected. Now, this works fine if I use use std::marker::PhantomData;
use serde::de::{DeserializeOwned, Error as DeserializeError, Visitor};
use serde::ser::Error as SerializeError;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_with::{DeserializeAs, SerializeAs};
#[derive(Clone, Debug, PartialEq)]
pub struct JsonString<T>(T);
impl<T> Serialize for JsonString<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_str(&serde_json::to_string(self).map_err(SerializeError::custom)?)
}
}
impl<'de, T> Deserialize<'de> for JsonString<T>
where
T: DeserializeOwned,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct JsonStringVisitor<T>(PhantomData<T>);
impl<'de, T> Visitor<'de> for JsonStringVisitor<T>
where
T: DeserializeOwned,
{
type Value = JsonString<T>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a value that can be serialized as a JSON string")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: DeserializeError,
{
Ok(JsonString(
serde_json::from_str(value).map_err(DeserializeError::custom)?,
))
}
}
deserializer.deserialize_str(JsonStringVisitor(PhantomData))
}
}
impl<T> SerializeAs<T> for JsonString<T>
where
T: Clone,
{
fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
JsonString(source.clone()).serialize(serializer)
}
}
impl<'de, T> DeserializeAs<'de, T> for JsonString<T>
where
T: DeserializeOwned,
{
fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
{
JsonString::deserialize(deserializer).map(|this| this.0)
}
} Using all of these in combination tells me that the compiler is expecting a totally different type:
I apologize for not asking a clearly defined question. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 10 replies
-
Hi, if you want to get into more complicated implementations, I encourage you to read the documentation of The problem is that you are asking I would be happy to accept a PR which changes the pub struct JsonString<T>(PhantomData<T>);
impl<T, TAs> SerializeAs<T> for JsonString<TAs>
where
TAs: SerializeAs<T>,
{
fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// `collect_str` will needlessly call `Display` again.
// Since you already have a `String` `serialize_str` is better
serializer.serialize_str(
&serde_json::to_string(&serde_with::ser::SerializeAsWrap::<T, TAs>::new(source))
.map_err(SerializeError::custom)?,
)
}
} A couple of notes on your code:
This looks like unbounded recursion to me. To use The |
Beta Was this translation helpful? Give feedback.
Hi, if you want to get into more complicated implementations, I encourage you to read the documentation of
SerializeAs
. It contains some examples which show how to implement the code.The problem is that you are asking
serde_json
to deserialize aVec<Base62Encoded<u64>>
, but you need to produce aVec<u64>
. You need to mark in your type signature, that theT
insideJsonString
is different than theT
you return. You turn theJsonString
into a container-like type.I would be happy to accept a PR which changes the
JsonString
in this crate to allow for this added flexibility.