use std::fmt;
use std::ops::{Deref, DerefMut};
use serde::de::{self, MapAccess, Visitor};
use serde::ser::SerializeStruct;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::Field;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Segment(pub er7::Segment);
impl From<er7::Segment> for Segment {
fn from(inner: er7::Segment) -> Segment {
Segment(inner)
}
}
impl From<Segment> for er7::Segment {
fn from(outer: Segment) -> er7::Segment {
outer.0
}
}
impl Deref for Segment {
type Target = er7::Segment;
fn deref(&self) -> &er7::Segment {
&self.0
}
}
impl DerefMut for Segment {
fn deref_mut(&mut self) -> &mut er7::Segment {
&mut self.0
}
}
impl Serialize for Segment {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let fields: Vec<Field> = self.0.fields.iter().map(|f| Field(f.clone())).collect();
let mut state = serializer.serialize_struct("Segment", 2)?;
state.serialize_field("name", &self.0.name)?;
state.serialize_field("fields", &fields)?;
state.end()
}
}
const FIELDS: &[&str] = &["name", "fields"];
struct SegmentVisitor;
impl<'de> Visitor<'de> for SegmentVisitor {
type Value = Segment;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a segment object with \"name\" and \"fields\"")
}
fn visit_map<V>(self, mut map: V) -> Result<Segment, V::Error>
where
V: MapAccess<'de>,
{
let mut name: Option<String> = None;
let mut fields: Option<Vec<Field>> = None;
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"name" => {
if name.is_some() {
return Err(de::Error::duplicate_field("name"));
}
name = Some(map.next_value()?);
}
"fields" => {
if fields.is_some() {
return Err(de::Error::duplicate_field("fields"));
}
fields = Some(map.next_value()?);
}
_ => {
let _ = map.next_value::<de::IgnoredAny>()?;
}
}
}
let name = name.ok_or_else(|| de::Error::missing_field("name"))?;
let fields = fields.ok_or_else(|| de::Error::missing_field("fields"))?;
Ok(Segment(er7::Segment {
name,
fields: fields.into_iter().map(|f| f.0).collect(),
}))
}
}
impl<'de> Deserialize<'de> for Segment {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_struct("Segment", FIELDS, SegmentVisitor)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trips_a_segment() {
let segment = Segment(er7::Segment {
name: "PID".into(),
fields: vec![er7::Field {
repetitions: vec![er7::Repetition {
components: vec![er7::Component {
subcomponents: vec![er7::Subcomponent::new("1")],
}],
}],
}],
});
let json = serde_json::to_string(&segment).unwrap();
let back: Segment = serde_json::from_str(&json).unwrap();
assert_eq!(back, segment);
}
#[test]
fn rejects_a_missing_name() {
let err = serde_json::from_str::<Segment>(r#"{"fields":[]}"#).unwrap_err();
assert!(err.to_string().contains("name"));
}
#[test]
fn ignores_unknown_fields() {
let json = r#"{"name":"ZZZ","fields":[],"extra":true}"#;
let back: Segment = serde_json::from_str(json).unwrap();
assert_eq!(back.name, "ZZZ");
}
}