Last active
November 11, 2024 15:20
-
-
Save ngerakines/3493cf363db01eb714fdd1938264f4e4 to your computer and use it in GitHub Desktop.
Rust plaground code that parses json value as string or complex enum
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::str::FromStr; | |
use std::fmt; | |
use std::marker::PhantomData; | |
use anyhow::anyhow; | |
use serde::{Deserialize, Serialize, Deserializer}; | |
use serde::de::{self, Visitor, MapAccess}; | |
#[derive(Clone, Debug, Deserialize, Serialize)] | |
#[serde(tag = "type")] | |
pub enum FeedQuery { | |
#[serde(rename="simple")] | |
Simple{}, | |
#[serde(rename="popular")] | |
Popular { | |
#[serde(default)] | |
age_floor: i64, | |
} | |
} | |
impl Default for FeedQuery { | |
fn default() -> Self { FeedQuery::Simple{} } | |
} | |
impl FromStr for FeedQuery { | |
type Err = anyhow::Error; | |
fn from_str(value: &str) -> Result<Self, Self::Err> { | |
match value { | |
"simple" => Ok(FeedQuery::Simple{}), | |
_ => Err(anyhow!("unsupported query")) | |
} | |
} | |
} | |
#[derive(Clone, Debug, Deserialize, Serialize)] | |
pub struct Feed { | |
pub name: String, | |
#[serde(default, deserialize_with = "string_or_struct")] | |
pub query: FeedQuery, | |
} | |
fn string_or_struct<'de, T, D>(deserializer: D) -> Result<T, D::Error> | |
where | |
T: Deserialize<'de> + FromStr<Err = anyhow::Error>, | |
D: Deserializer<'de>, | |
{ | |
struct StringOrStruct<T>(PhantomData<fn() -> T>); | |
impl<'de, T> Visitor<'de> for StringOrStruct<T> | |
where | |
T: Deserialize<'de> + FromStr<Err = anyhow::Error>, | |
{ | |
type Value = T; | |
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | |
formatter.write_str("string or FeedQuery") | |
} | |
fn visit_str<E>(self, value: &str) -> Result<T, E> | |
where | |
E: de::Error, | |
{ | |
FromStr::from_str(value).map_err(|_| de::Error::custom("cannot deserialize field")) | |
} | |
fn visit_map<M>(self, map: M) -> Result<T, M::Error> | |
where | |
M: MapAccess<'de>, | |
{ | |
Deserialize::deserialize(de::value::MapAccessDeserializer::new(map)) | |
} | |
} | |
deserializer.deserialize_any(StringOrStruct(PhantomData)) | |
} | |
fn main() { | |
let json = r#" | |
{ | |
"name": "popular", | |
"query": "simple" | |
} | |
"#; | |
let feed = serde_json::from_str::<Feed>(json); | |
println!("{:?}", feed); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment