use ::core::fmt::Write;
use core::fmt::Display;
use core::marker::PhantomData;
use core::str::FromStr;
use serde::Deserialize;
pub use serde_with::formats::{Lowercase, Uppercase};
use std::iter::FromIterator;
pub use serde_with::*;
mod sealed {
pub trait Sealed {}
}
pub trait HexFormat: sealed::Sealed {}
impl HexFormat for Uppercase {}
impl sealed::Sealed for Uppercase {}
impl HexFormat for Lowercase {}
impl sealed::Sealed for Lowercase {}
pub struct Padding<F: HexFormat>(PhantomData<fn() -> F>);
impl HexFormat for Padding<Uppercase> {}
impl sealed::Sealed for Padding<Uppercase> {}
impl HexFormat for Padding<Lowercase> {}
impl sealed::Sealed for Padding<Lowercase> {}
pub struct Leading0x<F: HexFormat>(PhantomData<fn() -> F>);
impl HexFormat for Leading0x<Uppercase> {}
impl sealed::Sealed for Leading0x<Uppercase> {}
impl HexFormat for Leading0x<Lowercase> {}
impl sealed::Sealed for Leading0x<Lowercase> {}
impl HexFormat for Leading0x<Padding<Uppercase>> {}
impl sealed::Sealed for Leading0x<Padding<Uppercase>> {}
impl HexFormat for Leading0x<Padding<Lowercase>> {}
impl sealed::Sealed for Leading0x<Padding<Lowercase>> {}
pub struct Hex<F: HexFormat>(std::marker::PhantomData<fn() -> F>);
impl<F: HexFormat> Hex<F> {
#[inline]
pub const fn display<T>(t: &T) -> HexDisplay<'_, F, T> {
HexDisplay::new(t)
}
}
#[derive(Copy, Clone)]
pub struct HexDisplay<'a, F: HexFormat, T> {
inner: &'a T,
_marker: std::marker::PhantomData<fn() -> F>,
}
impl<'a, F: HexFormat, T> HexDisplay<'a, F, T> {
#[inline]
pub const fn new(inner: &'a T) -> Self {
Self {
inner,
_marker: std::marker::PhantomData,
}
}
}
macro_rules! encode_hex {
($e:expr, $bound:path, $ident:path) => {
impl<T> serde_with::SerializeAs<T> for Hex<$ident>
where T: $bound {
fn serialize_as<S>(t: &T, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer
{
super::TRANSIENT_STRING_SERIALIZER.with(|s| {
let mut s = s.borrow_mut();
s.clear();
s.reserve(128);
write!(s, "{}", Self::display(t)).map_err(<S::Error as serde::ser::Error>::custom)?;
serializer.serialize_str(&s)
})
}
}
impl<'de, T> serde_with::DeserializeAs<'de, T> for Hex<$ident>
where T: FromStr,
<T as FromStr>::Err: Display,
{
fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
where D: serde::Deserializer<'de>,
{
let s = <&str>::deserialize(deserializer)?;
T::from_str(s).map_err(<D::Error as serde::de::Error>::custom)
}
}
impl<'a, T: $bound> ::core::fmt::Display for HexDisplay<'a, $ident, T> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
write!(f, $e, self.inner)
}
}
impl<'a, T: $bound> serde::Serialize for HexDisplay<'a, $ident, T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serde_with::As::<Hex<$ident>>::serialize(&self.inner, serializer)
}
}
impl<T: $bound + GraphqlString + Sync> async_graphql::OutputType for HexDisplay<'_, $ident, T> {
fn type_name() -> std::borrow::Cow<'static, str> {
T::name()
}
fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
String::create_type_info(registry)
}
async fn resolve(
&self,
_ctx: &async_graphql::ContextSelectionSet<'_>,
_field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
) -> async_graphql::ServerResult<async_graphql::Value> {
Ok(async_graphql::Value::String(self.to_string()))
}
}
};
}
encode_hex! {"{:x}", core::fmt::LowerHex, Lowercase}
encode_hex! {"{:X}", core::fmt::UpperHex, Uppercase}
encode_hex! {"{:#x}", core::fmt::LowerHex, Padding<Lowercase>}
encode_hex! {"{:#X}", core::fmt::UpperHex, Padding<Uppercase>}
encode_hex! {"0x{:x}", core::fmt::LowerHex, Leading0x<Lowercase>}
encode_hex! {"0x{:X}", core::fmt::UpperHex, Leading0x<Uppercase>}
encode_hex! {"0x{:#x}", core::fmt::LowerHex, Leading0x<Padding<Lowercase>>}
encode_hex! {"0x{:#X}", core::fmt::UpperHex, Leading0x<Padding<Uppercase>>}
pub trait IsZero {
fn is_zero(&self) -> bool;
}
impl<const N: usize> IsZero for super::H<N> {
fn is_zero(&self) -> bool {
self.is_zero()
}
}
impl<const N: usize> IsZero for super::U<N> {
fn is_zero(&self) -> bool {
self.is_zero()
}
}
impl IsZero for super::Bytes {
fn is_zero(&self) -> bool {
self.iter().all(|&x| x == 0)
}
}
macro_rules! impl_is_zero_for_num_array {
($($ty:ty),+ $(,)?) => {
$(
impl<const N: usize> IsZero for [$ty; N] {
fn is_zero(&self) -> bool {
self.iter().all(|&x| x == 0)
}
}
)*
};
}
impl_is_zero_for_num_array!(
u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
);
pub struct OnlyPadZero<F: HexFormat>(PhantomData<fn() -> F>);
impl HexFormat for OnlyPadZero<Uppercase> {}
impl sealed::Sealed for OnlyPadZero<Uppercase> {}
impl HexFormat for OnlyPadZero<Lowercase> {}
impl sealed::Sealed for OnlyPadZero<Lowercase> {}
macro_rules! encode_only_pad_zero_hex {
($no_padding:expr, $with_padding:expr, $bound:path, $ident:path) => {
impl<T: IsZero + $bound> serde_with::SerializeAs<T> for Hex<$ident> {
fn serialize_as<S>(t: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
super::TRANSIENT_STRING_SERIALIZER.with(|s| {
let mut s = s.borrow_mut();
s.clear();
s.reserve(128);
write!(s, "{}", Self::display(t)).map_err(<S::Error as serde::ser::Error>::custom)?;
serializer.serialize_str(&s)
})
}
}
impl<'de, T> serde_with::DeserializeAs<'de, T> for Hex<$ident>
where
T: FromStr,
<T as FromStr>::Err: Display,
{
fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = <&str>::deserialize(deserializer)?;
T::from_str(s).map_err(<D::Error as serde::de::Error>::custom)
}
}
impl<'a, T: IsZero + $bound> ::core::fmt::Display for HexDisplay<'a, $ident, T> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
if T::is_zero(self.inner) {
write!(f, $with_padding, self.inner)
} else {
write!(f, $no_padding, self.inner)
}
}
}
impl<'a, T: IsZero + $bound> serde::Serialize for HexDisplay<'a, $ident, T>
where
&'a T: IsZero,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serde_with::As::<Hex<$ident>>::serialize(&self.inner, serializer)
}
}
impl<T: $bound + IsZero + GraphqlString + Sync> async_graphql::OutputType
for HexDisplay<'_, $ident, T>
{
fn type_name() -> std::borrow::Cow<'static, str> {
T::name()
}
fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
String::create_type_info(registry)
}
async fn resolve(
&self,
_ctx: &async_graphql::ContextSelectionSet<'_>,
_field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
) -> async_graphql::ServerResult<async_graphql::Value> {
Ok(async_graphql::Value::String(self.to_string()))
}
}
};
}
encode_only_pad_zero_hex! {"{:x}", "{:#x}", core::fmt::LowerHex, OnlyPadZero<Lowercase>}
encode_only_pad_zero_hex! {"{:X}", "{:#X}", core::fmt::UpperHex, OnlyPadZero<Uppercase>}
pub trait GraphqlString {
fn name() -> std::borrow::Cow<'static, str>;
}
impl<const N: usize> GraphqlString for super::H<N> {
fn name() -> std::borrow::Cow<'static, str> {
Self::friendly_name().into()
}
}
impl<const N: usize> GraphqlString for super::U<N> {
fn name() -> std::borrow::Cow<'static, str> {
Self::friendly_name().into()
}
}
impl GraphqlString for super::Bytes {
fn name() -> std::borrow::Cow<'static, str> {
"Bytes".into()
}
}
pub struct SerdeFromStrErrDisplay;
impl<T> serde_with::SerializeAs<T> for SerdeFromStrErrDisplay
where
T: Display,
{
fn serialize_as<S>(t: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
super::TRANSIENT_STRING_SERIALIZER.with(|s| {
let mut s = s.borrow_mut();
s.clear();
s.reserve(128);
write!(s, "{t}").map_err(<S::Error as serde::ser::Error>::custom)?;
serializer.serialize_str(&s)
})
}
}
impl<'de, T> serde_with::DeserializeAs<'de, T> for SerdeFromStrErrDisplay
where
T: crate::cidomap::FromStrErrDisplay,
{
fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = <&str>::deserialize(deserializer)?;
T::_from_str(s).map_err(<D::Error as serde::de::Error>::custom)
}
}
pub struct FromIntoIter<T, U>(PhantomData<fn() -> (T, U)>);
impl<I, T, U> serde_with::SerializeAs<I> for FromIntoIter<T, U>
where
for<'a> &'a I: IntoIterator<Item = &'a U>,
T: serde_with::SerializeAs<U>,
{
fn serialize_as<S>(i: &I, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let s = i.into_iter().collect::<Vec<_>>();
<Vec<&T> as serde_with::SerializeAs<Vec<&U>>>::serialize_as(&s, serializer)
}
}
impl<'de, I: FromIterator<U>, T, U> serde_with::DeserializeAs<'de, I> for FromIntoIter<T, U>
where
T: serde_with::DeserializeAs<'de, U>,
{
fn deserialize_as<D>(deserializer: D) -> Result<I, D::Error>
where
D: serde::Deserializer<'de>,
{
let vec = <Vec<T> as serde_with::DeserializeAs<'de, Vec<U>>>::deserialize_as(deserializer)?;
Ok(vec.into_iter().collect())
}
}
pub mod serde_as_bytes {
use serde::Deserialize;
pub fn serialize<S, T: AsRef<[u8]>>(t: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_bytes(t.as_ref())
}
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: serde::Deserializer<'de>,
T: for<'a> TryFrom<&'a [u8]> + 'static,
for<'a> <T as TryFrom<&'a [u8]>>::Error: ::core::fmt::Display,
{
let bytes = <&[u8]>::deserialize(deserializer)?;
T::try_from(bytes).map_err(<D::Error as serde::de::Error>::custom)
}
}
#[test]
fn hex_serialization() {
use super::U;
let expected = "\"000000000000617E\"";
let expected_val: U<1> = U::from([0x617e]);
let mut bytes = Vec::new();
let mut serializer = serde_json::Serializer::new(&mut bytes);
<Hex<Padding<Uppercase>> as serde_with::SerializeAs<U<1>>>::serialize_as(
&expected_val,
&mut serializer,
)
.unwrap();
assert_eq!(expected, String::from_utf8(bytes).unwrap());
let mut deserializer = serde_json::Deserializer::from_slice(expected.as_bytes());
let val: U<1> =
<Hex<Padding<Uppercase>> as serde_with::DeserializeAs<U<1>>>::deserialize_as(&mut deserializer)
.unwrap();
assert_eq!(expected_val, val);
}
#[test]
fn test_serde_as() {
use super::{H, U};
#[serde_with::serde_as]
#[derive(serde::Serialize, serde::Deserialize)]
struct Test {
#[serde_as(as = "Vec<Hex<Lowercase>>")]
v: Vec<H<20>>,
#[serde_as(as = "Vec<Option<Hex<Leading0x<Lowercase>>>>")]
o: Vec<Option<U<2>>>,
}
let _test = Test {
v: vec![
H::from_hex_str("0xabcdef0123456789abcaabcdef0123456789abca"),
H::from_hex_str("abcdef0123456789abcbabcdef0123456789abcb"),
H::from_hex_str("0xABCDEF0123456789ABCCABCDEF0123456789ABCC"),
H::from_hex_str("ABCDEF0123456789ABCDABCDEF0123456789ABCD"),
],
o: vec![
None,
Some(U::from_hex_str("9a")),
Some(U::from_hex_str("0x8b")),
Some(U::from_hex_str("7c")),
Some(U::from_hex_str("0x6d")),
],
};
}