use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
use serde_yaml::{Mapping, Value};
use url::Url;
use crate::Date;
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Name {
Person(PersonName),
Entity(EntityName),
Anonymous,
}
impl Name {
pub fn is_person(&self) -> bool {
matches!(self, Self::Person(_))
}
pub fn is_entity(&self) -> bool {
matches!(self, Self::Entity(_))
}
pub fn is_anonymous(&self) -> bool {
matches!(self, Self::Anonymous)
}
pub fn as_person(&self) -> Option<&PersonName> {
if let Self::Person(p) = self {
Some(p)
} else {
None
}
}
pub fn as_entity(&self) -> Option<&EntityName> {
if let Self::Entity(e) = self {
Some(e)
} else {
None
}
}
}
impl Serialize for Name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Self::Person(p) => p.serialize(serializer),
Self::Entity(e) => e.serialize(serializer),
Self::Anonymous => Mapping::from_iter([(
Value::String("name".into()),
Value::String("anonymous".into()),
)])
.serialize(serializer),
}
}
}
impl<'de> Deserialize<'de> for Name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let yaml = Mapping::deserialize(deserializer)?;
if let Some(name) = yaml.get("name") {
if let Value::String(name) = name {
if name == "anonymous" {
Ok(Name::Anonymous)
} else {
let entity: EntityName = serde_yaml::from_value(Value::Mapping(yaml))
.map_err(|e| D::Error::custom(e.to_string()))?;
Ok(Name::Entity(entity))
}
} else {
Err(D::Error::custom(
"'name' value must be a string".to_string(),
))
}
} else {
let person: PersonName = serde_yaml::from_value(Value::Mapping(yaml))
.map_err(|e| D::Error::custom(e.to_string()))?;
Ok(Name::Person(person))
}
}
}
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct PersonName {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub family_names: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub given_names: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name_particle: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name_suffix: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub affiliation: Option<String>,
#[serde(flatten)]
pub meta: NameMeta,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct EntityName {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub date_start: Option<Date>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub date_end: Option<Date>,
#[serde(flatten)]
pub meta: NameMeta,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct NameMeta {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub orcid: Option<Url>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub address: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub alias: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub city: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub country: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub email: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub post_code: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub region: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub location: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tel: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub fax: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub website: Option<Url>,
}