use std::fmt;
use super::Icon;
use serde::de;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RelatedTopic {
TopicResult(TopicResult),
Topic(Topic),
}
impl<'de> de::Deserialize<'de> for RelatedTopic {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: de::Deserializer<'de>
{
deserializer.deserialize_map(Visitor)
}
}
struct Visitor;
macro_rules! serialise {
($builder:ident, $visitor:ident) => {
match &*$visitor.next_key::<String>().expect("valid key").expect("field") {
"Icon" => {
$builder.icon = $visitor.next_value()?;
}
"Result" => {
$builder.result = $visitor.next_value()?;
}
"FirstURL" => {
$builder.first_url = $visitor.next_value()?;
}
"Text" => {
$builder.text = $visitor.next_value()?;
}
other => panic!("no struct has key `{}`", other),
}
}
}
impl<'de> de::Visitor<'de> for Visitor {
type Value = RelatedTopic;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a object containing with Topics, FirstURL, Result properties")
}
fn visit_map<V>(self, mut visitor: V) -> Result<RelatedTopic, V::Error>
where V: de::MapAccess<'de>
{
let s: String = visitor.next_key()?.expect("got struct with no fields");
let val = match &*s {
"Topics" => {
Ok(RelatedTopic::Topic(Topic {
topics: visitor.next_value()?,
name: {
let s: String = visitor.next_key()?.expect("Name field");
assert_eq!(&s, "Name");
visitor.next_value()?
},
}))
},
"Name" => {
Ok(RelatedTopic::Topic(Topic {
name: visitor.next_value()?,
topics: {
let s: String = visitor.next_key()?.expect("Topics field");
assert_eq!(&s, "Topics");
visitor.next_value()?
},
}))
},
"FirstURL" => {
let mut builder = TopicResultBuilder::default();
let first_url = visitor.next_value()?;
serialise!(builder, visitor);
serialise!(builder, visitor);
serialise!(builder, visitor);
Ok(RelatedTopic::TopicResult(TopicResult {
first_url: first_url,
icon: builder.icon.expect("Icon field"),
result: builder.result.expect("Result field"),
text: builder.text.expect("Text field"),
}))
},
"Result" => {
let mut builder = TopicResultBuilder::default();
let result = visitor.next_value()?;
serialise!(builder, visitor);
serialise!(builder, visitor);
serialise!(builder, visitor);
Ok(RelatedTopic::TopicResult(TopicResult {
first_url: builder.first_url.expect("Result field"),
icon: builder.icon.expect("Icon field"),
result: result,
text: builder.text.expect("Text field"),
}))
},
"Icon" => {
let mut builder = TopicResultBuilder::default();
let icon = visitor.next_value()?;
serialise!(builder, visitor);
serialise!(builder, visitor);
serialise!(builder, visitor);
Ok(RelatedTopic::TopicResult(TopicResult {
first_url: builder.first_url.expect("Result field"),
icon: icon,
result: builder.result.expect("Icon field"),
text: builder.text.expect("Text field"),
}))
},
"Text" => {
let mut builder = TopicResultBuilder::default();
let text = visitor.next_value()?;
serialise!(builder, visitor);
serialise!(builder, visitor);
serialise!(builder, visitor);
Ok(RelatedTopic::TopicResult(TopicResult {
first_url: builder.first_url.expect("Result field"),
icon: builder.icon.expect("Icon field"),
result: builder.result.expect("Result field"),
text: text,
}))
},
other => panic!("no struct has field `{}`", other),
};
val
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
pub struct TopicResult {
#[serde(rename="FirstURL")]
pub first_url: String,
#[serde(rename="Icon")]
pub icon: Icon,
#[serde(rename="Result")]
pub result: String,
#[serde(rename="Text")]
pub text: String,
}
#[derive(Default)]
struct TopicResultBuilder {
pub first_url: Option<String>,
pub icon: Option<Icon>,
pub result: Option<String>,
pub text: Option<String>,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
pub struct Topic {
#[serde(rename="Topics")]
pub topics: Vec<RelatedTopic>,
#[serde(rename="Name")]
pub name: String,
}