Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- [
- {
- "Name": "a single unit param",
- "Units": "m/s"
- },
- {
- "Name": "a multi unit param",
- "Units": {
- "Metric": {
- "Units": "m/s"
- },
- "Imperial": {
- "Units": "ft/s"
- }
- }
- }
- ]
- use serde::de::{self, MapAccess, Visitor};
- use serde::{Deserialize, Deserializer}; // 1.0.91
- use std::fmt;
- #[derive(Debug, Deserialize)]
- pub struct SingleUnitParam {
- name: String,
- units: String,
- }
- #[derive(Debug, Deserialize)]
- pub struct UnitInfo {
- units: String,
- }
- #[derive(Debug, Deserialize)]
- pub struct MultiUnits {
- metric: UnitInfo,
- imperial: UnitInfo,
- }
- #[derive(Debug, Deserialize)]
- #[serde(untagged)]
- enum StrOrUnitsObj<'a> {
- Str(&'a str),
- UnitsObj(MultiUnits),
- }
- #[derive(Debug, Deserialize)]
- pub struct MultiUnitParam {
- name: String,
- units: MultiUnits,
- }
- #[derive(Debug)]
- pub enum Param {
- Single(SingleUnitParam),
- Multiple(MultiUnitParam),
- }
- impl<'de> Deserialize<'de> for Param {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: Deserializer<'de>,
- {
- enum Field {
- Name,
- UnitsAsObj,
- UnitsAsStr,
- };
- impl<'de> Deserialize<'de> for Field {
- fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
- where
- D: Deserializer<'de>,
- {
- struct FieldVisitor;
- impl<'de> Visitor<'de> for FieldVisitor {
- type Value = Field;
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("`Name` or `Units`")
- }
- fn visit_str<E>(self, value: &str) -> Result<Field, E>
- where
- E: de::Error,
- {
- match value {
- "Name" => Ok(Field::Name),
- "Units" => Ok({
- let val = StrOrUnitsObj::deserialize(deserializer).unwrap();
- match val {
- StrOrUnitsObj::Str(s) => Field::UnitsAsObj,
- StrOrUnitsObj::UnitsObj(obj) => Field::UnitsAsStr,
- }
- }),
- _ => Err(de::Error::unknown_field(value, FIELDS)),
- }
- }
- }
- deserializer.deserialize_identifier(FieldVisitor)
- }
- }
- struct ParamVisitor;
- impl<'de> Visitor<'de> for ParamVisitor {
- type Value = Param;
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("enum Param")
- }
- fn visit_map<V>(self, mut map: V) -> Result<Param, V::Error>
- where
- V: MapAccess<'de>,
- {
- let mut name = None;
- let mut units_as_string = None;
- let mut units_as_object = None;
- while let Some(key) = map.next_key()? {
- match key {
- Field::Name => {
- if name.is_some() {
- return Err(de::Error::duplicate_field("Name"));
- }
- name = Some(map.next_value()?);
- }
- Field::UnitsAsObj => {
- if units_as_object.is_some() {
- return Err(de::Error::duplicate_field("Units"));
- }
- units_as_object = Some(map.next_value()?);
- }
- Field::UnitsAsStr => {
- if units_as_string.is_some() {
- return Err(de::Error::duplicate_field("Units"));
- }
- units_as_string = Some(map.next_value()?);
- }
- }
- }
- let name = name.ok_or_else(|| de::Error::missing_field("Name"))?;
- if let Some(units_as_object) = units_as_object {
- Ok(Param::Multiple(MultiUnitParam {
- name: name,
- units: units_as_object,
- }))
- } else {
- let units_as_string =
- units_as_string.ok_or_else(|| de::Error::missing_field("Units"))?;
- Ok(Param::Single(SingleUnitParam {
- name: name,
- units: units_as_string,
- }))
- }
- }
- }
- const FIELDS: &'static [&'static str] = &["Name", "Units"];
- deserializer.deserialize_struct("Param", FIELDS, ParamVisitor)
- }
- }
- fn main() {
- let json_raw = r#"[
- { "Name": "a single unit param", "Units": "m/s" },
- { "Name": "a multi unit param", "Units": { "Metric": { "Units": "m/s" }, "Imperial": { "Units": "ft/s" } } }
- ]"#;
- let j: Vec<Param> = serde_json::from_str(&json_raw).unwrap();
- match &j[0] {
- Param::Single(p) => {
- assert_eq!(p.name, "a single unit param");
- assert_eq!(p.units, "m/s");
- }
- Param::Multiple(_p) => panic!("Expected SingleUnitParam, actual MultiUnitParam"),
- }
- match &j[1] {
- Param::Single(_p) => panic!("Expected MultiUnitParam, actual SingleUnitParam"),
- Param::Multiple(p) => {
- assert_eq!(p.name, "a multi unit param");
- assert_eq!(p.units.metric.units, "m/s");
- assert_eq!(p.units.imperial.units, "ft/s");
- }
- }
- }
- fn visit_str<E>(self, value: &str) -> Result<Field, E>
- where
- E: de::Error,
- {
- match value {
- "Name" => Ok(Field::Name),
- "Units" => Ok({
- let val = StrOrUnitsObj::deserialize(deserializer).unwrap();
- match val {
- StrOrUnitsObj::Str(s) => {
- Field::UnitsAsObj
- },
- StrOrUnitsObj::UnitsObj(obj) => {
- Field::UnitsAsStr
- }
- }
- }),
- _ => Err(de::Error::unknown_field(value, FIELDS)),
- }
- }
- use std::fmt;
- use serde::{Deserialize, Deserializer}; // 1.0.91
- use serde::de::{self, Visitor, MapAccess};
- #[derive(Debug, Deserialize)]
- pub struct SingleUnitParam {
- name: String,
- units: String,
- }
- #[derive(Debug, Deserialize)]
- pub struct UnitInfo {
- #[serde(alias = "Units")]
- units: String,
- }
- #[derive(Debug, Deserialize)]
- pub struct MultiUnits {
- #[serde(alias = "Metric")]
- metric: UnitInfo,
- #[serde(alias = "Imperial")]
- imperial: UnitInfo,
- }
- #[derive(Debug, Deserialize)]
- #[serde(untagged)]
- enum StrOrUnitsObj<'a> {
- Str(&'a str),
- UnitsObj(MultiUnits)
- }
- #[derive(Debug, Deserialize)]
- pub struct MultiUnitParam {
- name: String,
- units: MultiUnits,
- }
- #[derive(Debug)]
- pub enum Param {
- Single(SingleUnitParam),
- Multiple(MultiUnitParam),
- }
- impl<'de> Deserialize<'de> for Param {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: Deserializer<'de>,
- {
- enum Field { Name, Units/*, UnitsAsObj, UnitsAsStr*/ };
- impl<'de> Deserialize<'de> for Field {
- fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
- where
- D: Deserializer<'de>,
- {
- struct FieldVisitor;
- impl<'de> Visitor<'de> for FieldVisitor {
- type Value = Field;
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("`Name` or `Units`")
- }
- fn visit_str<E>(self, value: &str) -> Result<Field, E>
- where
- E: de::Error,
- {
- match value {
- "Name" => Ok(Field::Name),
- "Units" => Ok(Field::Units),
- // Can't get access to the JSON value to inspect it here.
- // "Units" => Ok({
- // let val = StrOrUnitsObj::deserialize(deserializer).unwrap();
- // match val {
- // StrOrUnitsObj::Str(s) => {
- // Field::UnitsAsObj
- // },
- // StrOrUnitsObj::UnitsObj(obj) => {
- // Field::UnitsAsStr
- // }
- // }
- // }),
- _ => Err(de::Error::unknown_field(value, FIELDS)),
- }
- }
- }
- deserializer.deserialize_identifier(FieldVisitor)
- }
- }
- struct ParamVisitor;
- impl<'de> Visitor<'de> for ParamVisitor {
- type Value = Param;
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("enum Param")
- }
- fn visit_map<V>(self, mut map: V) -> Result<Param, V::Error>
- where
- V: MapAccess<'de>,
- {
- let mut name = None;
- let mut units_as_string = None;
- let mut units_as_object = None;
- while let Some(key) = map.next_key()? {
- match key {
- Field::Name => {
- if name.is_some() {
- return Err(de::Error::duplicate_field("Name"));
- }
- name = Some(map.next_value()?);
- }
- Field::Units => {
- if units_as_string.is_some() || units_as_object.is_some() {
- return Err(de::Error::duplicate_field("Units"));
- }
- // Here is where we can get the JSON value and check its type.
- let v: serde_json::Value = map.next_value()?;
- if v.is_object() {
- let v: MultiUnits = serde_json::from_value(v).unwrap();
- units_as_object = Some(v);
- } else if v.is_string() {
- units_as_string = Some(v.as_str().unwrap().to_owned());
- }
- }
- // Field::UnitsAsObj => {
- // if units_as_object.is_some() {
- // return Err(de::Error::duplicate_field("Units"));
- // }
- // units_as_object = Some(map.next_value()?);
- // }
- // Field::UnitsAsStr => {
- // if units_as_string.is_some() {
- // return Err(de::Error::duplicate_field("Units"));
- // }
- // units_as_string = Some(map.next_value()?);
- // }
- }
- }
- let name = name.ok_or_else(|| de::Error::missing_field("Name"))?;
- if let Some(units_as_object) = units_as_object {
- Ok(Param::Multiple(MultiUnitParam {
- name: name,
- units: units_as_object
- }))
- } else {
- let units_as_string = units_as_string.ok_or_else(|| de::Error::missing_field("Units"))?;
- Ok(Param::Single(SingleUnitParam {
- name: name,
- units: units_as_string
- }))
- }
- }
- }
- const FIELDS: &'static [&'static str] = &["Name", "Units"];
- deserializer.deserialize_struct("Param", FIELDS, ParamVisitor)
- }
- }
- fn main() {
- let json_raw = r#"[
- { "Name": "a single unit param", "Units": "m/s" },
- { "Name": "a multi unit param", "Units": { "Metric": { "Units": "m/s" }, "Imperial": { "Units": "ft/s" } } }
- ]"#;
- let j: Vec<Param> = serde_json::from_str(&json_raw).unwrap();
- match &j[0] {
- Param::Single(p) => {
- assert_eq!(p.name, "a single unit param");
- assert_eq!(p.units, "m/s");
- },
- Param::Multiple(_p) => panic!("Expected SingleUnitParam, actual MultiUnitParam")
- }
- match &j[1] {
- Param::Single(_p) => panic!("Expected MultiUnitParam, actual SingleUnitParam"),
- Param::Multiple(p) => {
- assert_eq!(p.name, "a multi unit param");
- assert_eq!(p.units.metric.units, "m/s");
- assert_eq!(p.units.imperial.units, "ft/s");
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement