use crate::ro_crate::constraints::DynamicEntity;
use crate::ro_crate::constraints::{DataType, Id};
use crate::ro_crate::modify::*;
use serde::ser::SerializeMap;
use serde::{
de::{self, MapAccess, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::collections::HashMap;
use std::fmt;
#[derive(Debug)]
pub struct MetadataDescriptor {
pub id: String,
pub type_: DataType,
pub conforms_to: Id,
pub about: Id,
pub dynamic_entity: Option<HashMap<String, DynamicEntity>>,
}
impl fmt::Display for MetadataDescriptor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Metadata Description: ID={}, Type={:?}, conforms_to={:?}, about={:?}",
self.id, self.type_, self.conforms_to, self.about
)
}
}
impl DynamicEntityManipulation for MetadataDescriptor {
fn dynamic_entity(&mut self) -> &mut Option<HashMap<String, DynamicEntity>> {
&mut self.dynamic_entity
}
fn dynamic_entity_immut(&self) -> &Option<HashMap<String, DynamicEntity>> {
&self.dynamic_entity
}
}
impl CustomSerialize for MetadataDescriptor {
fn dynamic_entity(&self) -> Option<&HashMap<String, DynamicEntity>> {
self.dynamic_entity.as_ref()
}
fn id(&self) -> &String {
&self.id
}
fn type_(&self) -> &DataType {
&self.type_
}
fn conforms_to(&self) -> &Id {
&self.conforms_to
}
fn about(&self) -> &Id {
&self.about
}
}
impl Serialize for MetadataDescriptor {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.custom_serialize(serializer)
}
}
pub trait CustomSerialize: Serialize {
fn dynamic_entity(&self) -> Option<&HashMap<String, DynamicEntity>>;
fn id(&self) -> &String;
fn type_(&self) -> &DataType;
fn conforms_to(&self) -> &Id;
fn about(&self) -> &Id;
fn custom_serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("@id", self.id())?;
map.serialize_entry("@type", self.type_())?;
map.serialize_entry("conformsTo", self.conforms_to())?;
map.serialize_entry("about", self.about())?;
if let Some(dynamic_entity) = self.dynamic_entity() {
for (k, v) in dynamic_entity {
map.serialize_entry(k, v)?;
}
}
map.end()
}
}
impl<'de> Deserialize<'de> for MetadataDescriptor {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct MetadataDescriptorVisitor;
impl<'de> Visitor<'de> for MetadataDescriptorVisitor {
type Value = MetadataDescriptor;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a map representing a MetadataDescriptorEntity")
}
fn visit_map<A>(self, mut map: A) -> Result<MetadataDescriptor, A::Error>
where
A: MapAccess<'de>,
{
let mut id = None;
let mut type_ = None;
let mut conforms_to = None;
let mut about = None;
let mut dynamic_entity: HashMap<String, DynamicEntity> = HashMap::new();
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"@id" => id = Some(map.next_value()?),
"@type" => type_ = Some(map.next_value()?),
"conformsTo" => conforms_to = Some(map.next_value()?),
"about" => about = Some(map.next_value()?),
_ => {
let value: DynamicEntity = map.next_value()?;
dynamic_entity.insert(key, value);
}
}
}
let id = id.ok_or_else(|| de::Error::missing_field("@id"))?;
let type_ = type_.ok_or_else(|| de::Error::missing_field("@type"))?;
let conforms_to =
conforms_to.ok_or_else(|| de::Error::missing_field("conformsTo"))?;
let about = about.ok_or_else(|| de::Error::missing_field("about"))?;
Ok(MetadataDescriptor {
id,
type_,
conforms_to,
about,
dynamic_entity: Some(dynamic_entity),
})
}
}
deserializer.deserialize_map(MetadataDescriptorVisitor)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ro_crate::constraints::IdValue;
#[test]
fn test_metadata_descriptor_creation() {
let metadata = MetadataDescriptor {
id: "metadata_id".to_string(),
type_: DataType::Term("MetadataType".to_string()),
conforms_to: Id::Id(IdValue {
id: "conformsTo_id".to_string(),
}),
about: Id::Id(IdValue {
id: "about_id".to_string(),
}),
dynamic_entity: Some(HashMap::new()),
};
assert_eq!(metadata.id, "metadata_id");
assert!(matches!(metadata.type_, DataType::Term(ref t) if t == "MetadataType"));
assert_eq!(
metadata.conforms_to,
Id::Id(IdValue {
id: "conformsTo_id".to_string()
})
);
assert_eq!(
metadata.about,
Id::Id(IdValue {
id: "about_id".to_string()
})
);
assert!(metadata.dynamic_entity.unwrap().is_empty());
}
#[test]
fn test_dynamic_entity_manipulation() {
let mut metadata = MetadataDescriptor {
id: "metadata_id".to_string(),
type_: DataType::Term("MetadataType".to_string()),
conforms_to: Id::Id(IdValue {
id: "conformsTo_id".to_string(),
}),
about: Id::Id(IdValue {
id: "about_id".to_string(),
}),
dynamic_entity: Some(HashMap::new()),
};
metadata.add_string_value("key1".to_string(), "value1".to_string());
assert_eq!(
metadata.dynamic_entity.as_ref().unwrap().get("key1"),
Some(&DynamicEntity::EntityString("value1".to_string()))
);
metadata.remove_field("key1");
assert!(metadata
.dynamic_entity
.as_ref()
.unwrap()
.get("key1")
.is_none());
}
#[test]
fn test_serialization() {
let metadata = MetadataDescriptor {
id: "metadata_id".to_string(),
type_: DataType::Term("MetadataType".to_string()),
conforms_to: Id::Id(IdValue {
id: "conformsTo_id".to_string(),
}),
about: Id::Id(IdValue {
id: "about_id".to_string(),
}),
dynamic_entity: Some(HashMap::new()),
};
let serialized = serde_json::to_string(&metadata).unwrap();
assert_eq!(
serialized,
r#"{"@id":"metadata_id","@type":"MetadataType","conformsTo":{"@id":"conformsTo_id"},"about":{"@id":"about_id"}}"#
);
}
#[test]
fn test_deserialization() {
let json_data = r#"
{
"@id": "metadata_id",
"@type": "MetadataType",
"conformsTo": {"@id": "conformsTo_id"},
"about": {"@id": "about_id"}
}
"#;
let deserialized: MetadataDescriptor = serde_json::from_str(json_data).unwrap();
assert_eq!(deserialized.id, "metadata_id");
assert!(matches!(deserialized.type_, DataType::Term(ref t) if t == "MetadataType"));
assert_eq!(
deserialized.conforms_to,
Id::Id(IdValue {
id: "conformsTo_id".to_string()
})
);
assert_eq!(
deserialized.about,
Id::Id(IdValue {
id: "about_id".to_string()
})
);
}
#[test]
fn test_deserialization_with_missing_fields() {
let json_data = r#"
{
"@id": "metadata_id",
"@type": "MetadataType"
}
"#;
let result: Result<MetadataDescriptor, _> = serde_json::from_str(json_data);
assert!(result.is_err());
}
}