pub use with::*;
#[doc(hidden)]
#[cfg(feature = "serde-as-wrapper")]
pub use wrapper::*;
mod with {
use std::fmt;
use std::marker::PhantomData;
use serde::de::{Error as DeserializeError, Unexpected, Visitor};
use serde::{Deserializer, Serializer};
pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: Clone + Into<u128>,
{
serializer.serialize_str(&base62::encode(value.clone()))
}
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
u128: TryInto<T>,
{
struct _Visitor<T>(PhantomData<T>);
impl<'de, T> Visitor<'de> for _Visitor<T>
where
u128: TryInto<T>,
{
type Value = T;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a value that can be converted from a base-62 encoded u128")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: DeserializeError,
{
base62::decode(value)
.map_err(DeserializeError::custom)?
.try_into()
.map_err(|_| DeserializeError::invalid_value(Unexpected::Str(value), &self))
}
}
deserializer.deserialize_str(_Visitor(PhantomData))
}
}
#[cfg(feature = "serde-as-wrapper")]
mod wrapper {
use serde::{Deserializer, Serializer};
use serde_with::{DeserializeAs, SerializeAs};
pub struct Base62;
impl<T> SerializeAs<T> for Base62
where
T: Clone + Into<u128>,
{
fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
super::with::serialize(source, serializer)
}
}
impl<'de, T> DeserializeAs<'de, T> for Base62
where
u128: TryInto<T>,
{
fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
{
super::with::deserialize(deserializer)
}
}
}
#[cfg(test)]
pub mod tests {
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use super::Base62;
#[serde_as]
#[derive(Serialize, Deserialize)]
struct TestType<T>
where
T: Clone + Into<u128>,
u128: TryInto<T>,
{
#[serde_as(as = "Vec<Base62>")]
pub values: Vec<T>,
}
#[test]
fn test_roundtrip() {
let range = ((u128::MAX - 1000)..u128::MAX).chain([0]);
let expect = range.clone().map(base62::encode);
let container = TestType {
values: range.collect(),
};
let serialized = serde_json::to_string(&container).unwrap();
let parsed = serde_json::from_str::<serde_json::Value>(&serialized).unwrap();
let parsed = parsed
.as_object()
.unwrap()
.get("values")
.unwrap()
.as_array()
.unwrap()
.iter()
.map(|v| v.as_str().unwrap());
for (expect, actual) in std::iter::zip(expect, parsed) {
assert_eq!(&expect, &actual);
}
}
}