use std::fmt;
use serde::Deserialize;
#[derive(Debug)]
pub(crate) struct Discard;
impl fmt::Display for Discard {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("unknown variant")
}
}
impl std::error::Error for Discard {}
impl serde::de::Error for Discard {
fn custom<T: fmt::Display>(_msg: T) -> Self {
Discard
}
}
pub(crate) fn parse_known<T: serde::de::DeserializeOwned>(s: &str) -> Option<T> {
use serde::de::IntoDeserializer;
let de: serde::de::value::StrDeserializer<'_, Discard> = s.into_deserializer();
T::deserialize(de).ok()
}
macro_rules! type_tag_union_deserialize {
($union:ident { $($wire:literal => $variant:ident),+ $(,)? }) => {
impl<'de> serde::Deserialize<'de> for $union {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let value = <serde_json::Value as serde::Deserialize>::deserialize(d)?;
match value.get("type").and_then(serde_json::Value::as_str) {
$(Some($wire) => {
if let Ok(block) = serde::Deserialize::deserialize(&value) {
return Ok(Self::$variant(block));
}
})+
_ => {}
}
serde::Deserialize::deserialize(value)
.map(Self::Raw)
.map_err(serde::de::Error::custom)
}
}
};
}
pub(crate) use type_tag_union_deserialize;
pub(crate) fn deserialize_extensible<'de, D, K, O>(
deserializer: D,
known: fn(K) -> O,
unknown: fn(String) -> O,
) -> Result<O, D::Error>
where
D: serde::Deserializer<'de>,
K: serde::de::DeserializeOwned,
{
let s = String::deserialize(deserializer)?;
Ok(match parse_known::<K>(&s) {
Some(k) => known(k),
None => unknown(s),
})
}