use crate::part1::v3_1::key::Key;
use serde::de::{Error, Visitor};
use serde::{Deserialize, Deserializer, Serialize};
use std::fmt;
use std::ops::Deref;
use strum::{Display, EnumString};
#[cfg(feature = "openapi")]
use utoipa::ToSchema;
#[derive(Clone, PartialEq, Debug, Deserialize, Serialize, Default)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename = "Reference")]
pub struct ReferenceInner {
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "referredSemanticId")]
#[cfg_attr(feature = "openapi", schema(no_recursion))]
pub referred_semantic_id: Option<Box<Reference>>,
pub keys: Vec<Key>,
}
#[derive(EnumString, Clone, PartialEq, Debug, Deserialize, Serialize, Display)]
#[serde(tag = "type")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(
feature = "xml",
serde(from = "xml::ReferenceXML", into = "xml::ReferenceXML")
)]
pub enum Reference {
ExternalReference(ReferenceInner),
ModelReference(ReferenceInner),
}
impl ReferenceInner {
pub fn new(key: Key) -> Self {
Self {
referred_semantic_id: None,
keys: vec![key],
}
}
pub fn from_vec(keys: Vec<Key>) -> Self {
Self {
referred_semantic_id: None,
keys,
}
}
}
impl Deref for Reference {
type Target = ReferenceInner;
fn deref(&self) -> &Self::Target {
match self {
Reference::ExternalReference(i) | Reference::ModelReference(i) => i,
}
}
}
pub fn deserialize_model_reference<'de, D>(deserializer: D) -> Result<Reference, D::Error>
where
D: Deserializer<'de>,
{
struct SubmodelsVisitor;
impl<'de> Visitor<'de> for SubmodelsVisitor {
type Value = Reference;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an optional sequence of ModelReference")
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
let reference: Reference = Reference::deserialize(deserializer)?;
if let Reference::ModelReference(model_ref_inner) = reference {
Ok(Reference::ModelReference(model_ref_inner))
} else {
Err(D::Error::custom("unexpected reference type"))
}
}
}
deserializer.deserialize_option(SubmodelsVisitor)
}
pub fn deserialize_external_reference<'de, D>(deserializer: D) -> Result<Reference, D::Error>
where
D: Deserializer<'de>,
{
struct SubmodelsVisitor;
impl<'de> Visitor<'de> for SubmodelsVisitor {
type Value = Reference;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an optional sequence of ModelReference")
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
let reference: Reference = Reference::deserialize(deserializer)?;
if let Reference::ExternalReference(model_ref_inner) = reference {
Ok(Reference::ExternalReference(model_ref_inner))
} else {
Err(D::Error::custom("unexpected reference type"))
}
}
}
deserializer.deserialize_option(SubmodelsVisitor)
}
pub fn deserialize_optional_model_reference<'de, D>(
deserializer: D,
) -> Result<Option<Reference>, D::Error>
where
D: Deserializer<'de>,
{
struct SubmodelsVisitor;
impl<'de> Visitor<'de> for SubmodelsVisitor {
type Value = Option<Reference>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an optional sequence of ModelReference")
}
fn visit_none<E>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
let reference: Reference = Reference::deserialize(deserializer)?;
if let Reference::ModelReference(model_ref_inner) = reference {
Ok(Some(Reference::ModelReference(model_ref_inner)))
} else {
Err(D::Error::custom("unexpected reference type"))
}
}
}
deserializer.deserialize_option(SubmodelsVisitor)
}
pub fn deserialize_optional_external_reference<'de, D>(
deserializer: D,
) -> Result<Option<Reference>, D::Error>
where
D: Deserializer<'de>,
{
struct SubmodelsVisitor;
impl<'de> Visitor<'de> for SubmodelsVisitor {
type Value = Option<Reference>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an optional sequence of ModelReference")
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
let reference: Reference = Reference::deserialize(deserializer)?;
if let Reference::ExternalReference(model_ref_inner) = reference {
Ok(Some(Reference::ExternalReference(model_ref_inner)))
} else {
Err(D::Error::custom("unexpected reference type"))
}
}
}
deserializer.deserialize_option(SubmodelsVisitor)
}
#[cfg(feature = "xml")]
pub mod xml {
use crate::part1::v3_1::key::Key;
use crate::part1::v3_1::reference::{Reference, ReferenceInner};
use serde::{Deserialize, Serialize};
use strum::{Display, EnumString};
#[derive(EnumString, Clone, PartialEq, Debug, Deserialize, Serialize, Display)]
enum ReferenceType {
ExternalReference,
ModelReference,
}
#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
#[serde(rename = "Reference")]
pub struct ReferenceXML {
#[serde(rename = "type")]
ty: ReferenceType,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "referredSemanticId")]
pub referred_semantic_id: Option<Box<ReferenceXML>>,
pub keys: KeysXML,
}
impl From<ReferenceXML> for Reference {
fn from(value: ReferenceXML) -> Self {
match value.ty {
ReferenceType::ExternalReference => Reference::ExternalReference(ReferenceInner {
referred_semantic_id: value
.referred_semantic_id
.map(|v| *v)
.map(|v| Box::new(Reference::from(v))),
keys: value.keys.key,
}),
ReferenceType::ModelReference => Reference::ModelReference(ReferenceInner {
referred_semantic_id: value
.referred_semantic_id
.map(|v| *v)
.map(|v| Box::new(Reference::from(v))),
keys: value.keys.key,
}),
}
}
}
impl From<Reference> for ReferenceXML {
fn from(value: Reference) -> Self {
match value {
Reference::ExternalReference(inner) => ReferenceXML {
ty: ReferenceType::ExternalReference,
keys: KeysXML { key: inner.keys },
referred_semantic_id: inner
.referred_semantic_id
.map(|v| *v)
.map(|v| Box::new(ReferenceXML::from(v))),
},
Reference::ModelReference(inner) => ReferenceXML {
ty: ReferenceType::ModelReference,
keys: KeysXML { key: inner.keys },
referred_semantic_id: inner
.referred_semantic_id
.map(|v| *v)
.map(|v| Box::new(ReferenceXML::from(v))),
},
}
}
}
#[derive(Clone, PartialEq, Debug, Deserialize, Serialize, Default)]
#[serde(rename = "key")]
pub struct KeysXML {
pub key: Vec<Key>,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::part1::v3_1::key::Key;
#[test]
fn test_xml_serialize() {
let reference = ReferenceXML {
ty: ReferenceType::ExternalReference,
referred_semantic_id: None,
keys: KeysXML {
key: vec![Key::Blob("http://example/blob".into())],
},
};
let xml = quick_xml::se::to_string(&reference).unwrap();
println!("{}", xml);
}
#[test]
fn deserialize_blob_reference_xml() {
let xml = r#"
<Reference>
<type>ExternalReference</type>
<keys>
<key>
<type>Blob</type>
<value>http://example/blob</value>
</key>
<key>
<type>Blob</type>
<value>http://example/blob2</value>
</key>
</keys>
</Reference>"#;
let expected = Reference::ExternalReference(ReferenceInner {
referred_semantic_id: None,
keys: vec![
Key::Blob("http://example/blob".into()),
Key::Blob("http://example/blob2".into()),
],
});
let actual = quick_xml::de::from_str(xml).unwrap();
assert_eq!(expected, actual);
}
}
}