use super::common::{
FieldLanguageMap, HasNumbering, LangID, NormalizeNumbering, Numbering, NumberingType,
Publisher, RefID, RichText, Title,
};
use crate::reference::WorkRelation;
use crate::reference::contributor::{Contributor, ContributorEntry};
use crate::reference::date::EdtfString;
#[cfg(feature = "schema")]
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[cfg(feature = "bindings")]
use specta::Type;
use std::collections::HashMap;
use url::Url;
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[cfg_attr(feature = "bindings", derive(Type))]
#[serde(rename_all = "kebab-case")]
pub struct Event {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<RefID>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<Title>,
#[serde(skip_serializing_if = "Option::is_none")]
pub container: Option<WorkRelation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub series: Option<WorkRelation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub original: Option<WorkRelation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub location: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub date: Option<EdtfString>,
#[cfg_attr(feature = "bindings", specta(type = Option<String>))]
#[serde(skip_serializing_if = "Option::is_none")]
pub available_date: Option<EdtfString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub genre: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub network: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub contributors: Vec<ContributorEntry>,
#[serde(alias = "URL", skip_serializing_if = "Option::is_none")]
pub url: Option<Url>,
#[cfg_attr(feature = "bindings", specta(type = Option<String>))]
#[serde(skip_serializing_if = "Option::is_none")]
pub accessed: Option<EdtfString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<LangID>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub field_languages: FieldLanguageMap,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<RichText>,
#[serde(
flatten,
default,
skip_serializing_if = "std::collections::BTreeMap::is_empty"
)]
#[cfg_attr(feature = "schema", schemars(skip))]
pub unknown_fields: std::collections::BTreeMap<String, serde_json::Value>,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[cfg_attr(feature = "bindings", derive(Type))]
#[serde(from = "ClassicDeser", rename_all = "kebab-case")]
pub struct Classic {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<RefID>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<Title>,
#[serde(skip_serializing_if = "Option::is_none")]
pub container: Option<WorkRelation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub original: Option<WorkRelation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub author: Option<Contributor>,
#[serde(skip_serializing_if = "Option::is_none")]
pub editor: Option<Contributor>,
#[serde(skip_serializing_if = "Option::is_none")]
pub translator: Option<Contributor>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub volume: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub issue: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub edition: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub number: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub part_number: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub supplement_number: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub printing_number: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub numbering: Vec<Numbering>,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default, skip_serializing_if = "EdtfString::is_empty")]
pub created: EdtfString,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default, skip_serializing_if = "EdtfString::is_empty")]
pub issued: EdtfString,
#[serde(skip_serializing_if = "Option::is_none")]
pub publisher: Option<Publisher>,
#[serde(alias = "URL", skip_serializing_if = "Option::is_none")]
pub url: Option<Url>,
#[cfg_attr(feature = "bindings", specta(type = Option<String>))]
#[serde(skip_serializing_if = "Option::is_none")]
pub accessed: Option<EdtfString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<LangID>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub field_languages: FieldLanguageMap,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<RichText>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keywords: Option<Vec<String>>,
#[serde(
flatten,
default,
skip_serializing_if = "std::collections::BTreeMap::is_empty"
)]
#[cfg_attr(feature = "schema", schemars(skip))]
pub unknown_fields: std::collections::BTreeMap<String, serde_json::Value>,
}
#[derive(Deserialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[cfg_attr(feature = "bindings", derive(Type))]
#[serde(rename_all = "kebab-case")]
struct ClassicDeser {
id: Option<RefID>,
title: Option<Title>,
container: Option<WorkRelation>,
original: Option<WorkRelation>,
author: Option<Contributor>,
editor: Option<Contributor>,
translator: Option<Contributor>,
#[serde(default, skip_serializing_if = "Option::is_none")]
volume: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
issue: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
edition: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
number: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
part_number: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
supplement_number: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
printing_number: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
numbering: Vec<Numbering>,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default)]
created: EdtfString,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default)]
issued: EdtfString,
publisher: Option<Publisher>,
#[serde(alias = "URL")]
url: Option<Url>,
#[cfg_attr(feature = "bindings", specta(type = Option<String>))]
accessed: Option<EdtfString>,
language: Option<LangID>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
field_languages: FieldLanguageMap,
note: Option<RichText>,
keywords: Option<Vec<String>>,
#[serde(flatten, default)]
unknown_fields: std::collections::BTreeMap<String, serde_json::Value>,
}
impl From<ClassicDeser> for Classic {
fn from(raw: ClassicDeser) -> Self {
let mut classic = Self {
id: raw.id,
title: raw.title,
container: raw.container,
original: raw.original,
author: raw.author,
editor: raw.editor,
translator: raw.translator,
volume: raw.volume,
issue: raw.issue,
edition: raw.edition,
number: raw.number,
part_number: raw.part_number,
supplement_number: raw.supplement_number,
printing_number: raw.printing_number,
numbering: raw.numbering,
created: raw.created,
issued: raw.issued,
publisher: raw.publisher,
url: raw.url,
accessed: raw.accessed,
language: raw.language,
field_languages: raw.field_languages,
note: raw.note,
keywords: raw.keywords,
unknown_fields: raw.unknown_fields,
};
classic.normalize_numbering();
classic
}
}
impl HasNumbering for Classic {
fn numbering(&self) -> &[Numbering] {
&self.numbering
}
}
impl NormalizeNumbering for Classic {
fn numbering_mut(&mut self) -> &mut Vec<Numbering> {
&mut self.numbering
}
fn volume_mut(&mut self) -> &mut Option<String> {
&mut self.volume
}
fn issue_mut(&mut self) -> &mut Option<String> {
&mut self.issue
}
fn edition_mut(&mut self) -> &mut Option<String> {
&mut self.edition
}
fn number_mut(&mut self) -> &mut Option<String> {
&mut self.number
}
fn part_number_mut(&mut self) -> &mut Option<String> {
&mut self.part_number
}
fn supplement_number_mut(&mut self) -> &mut Option<String> {
&mut self.supplement_number
}
fn printing_number_mut(&mut self) -> &mut Option<String> {
&mut self.printing_number
}
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[cfg_attr(feature = "bindings", derive(Type))]
#[serde(rename_all = "kebab-case")]
pub struct Patent {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<RefID>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<Title>,
#[serde(skip_serializing_if = "Option::is_none")]
pub author: Option<Contributor>,
#[serde(skip_serializing_if = "Option::is_none")]
pub assignee: Option<Contributor>,
#[serde(skip_serializing_if = "Option::is_none")]
pub original: Option<WorkRelation>,
pub patent_number: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub application_number: Option<String>,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default, skip_serializing_if = "EdtfString::is_empty")]
pub created: EdtfString,
#[cfg_attr(feature = "bindings", specta(type = Option<String>))]
#[serde(skip_serializing_if = "Option::is_none")]
pub filing_date: Option<EdtfString>,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default, skip_serializing_if = "EdtfString::is_empty")]
pub issued: EdtfString,
#[serde(skip_serializing_if = "Option::is_none")]
pub jurisdiction: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub authority: Option<String>,
#[serde(alias = "URL", skip_serializing_if = "Option::is_none")]
pub url: Option<Url>,
#[cfg_attr(feature = "bindings", specta(type = Option<String>))]
#[serde(skip_serializing_if = "Option::is_none")]
pub accessed: Option<EdtfString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<LangID>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub field_languages: FieldLanguageMap,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<RichText>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keywords: Option<Vec<String>>,
#[serde(
flatten,
default,
skip_serializing_if = "std::collections::BTreeMap::is_empty"
)]
#[cfg_attr(feature = "schema", schemars(skip))]
pub unknown_fields: std::collections::BTreeMap<String, serde_json::Value>,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[cfg_attr(feature = "bindings", derive(Type))]
#[serde(rename_all = "kebab-case")]
pub struct Dataset {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<RefID>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<Title>,
#[serde(skip_serializing_if = "Option::is_none")]
pub author: Option<Contributor>,
#[serde(skip_serializing_if = "Option::is_none")]
pub original: Option<WorkRelation>,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default, skip_serializing_if = "EdtfString::is_empty")]
pub created: EdtfString,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default, skip_serializing_if = "EdtfString::is_empty")]
pub issued: EdtfString,
#[serde(skip_serializing_if = "Option::is_none")]
pub publisher: Option<Publisher>,
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub repository: Option<String>,
#[serde(alias = "DOI", skip_serializing_if = "Option::is_none")]
pub doi: Option<String>,
#[serde(alias = "URL", skip_serializing_if = "Option::is_none")]
pub url: Option<Url>,
#[cfg_attr(feature = "bindings", specta(type = Option<String>))]
#[serde(skip_serializing_if = "Option::is_none")]
pub accessed: Option<EdtfString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<LangID>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub field_languages: FieldLanguageMap,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<RichText>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keywords: Option<Vec<String>>,
#[serde(
flatten,
default,
skip_serializing_if = "std::collections::BTreeMap::is_empty"
)]
#[cfg_attr(feature = "schema", schemars(skip))]
pub unknown_fields: std::collections::BTreeMap<String, serde_json::Value>,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[cfg_attr(feature = "bindings", derive(Type))]
#[serde(rename_all = "kebab-case")]
pub struct Standard {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<RefID>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<Title>,
#[serde(skip_serializing_if = "Option::is_none")]
pub original: Option<WorkRelation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub authority: Option<String>,
pub standard_number: String,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default, skip_serializing_if = "EdtfString::is_empty")]
pub created: EdtfString,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default, skip_serializing_if = "EdtfString::is_empty")]
pub issued: EdtfString,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub publisher: Option<Publisher>,
#[serde(alias = "URL", skip_serializing_if = "Option::is_none")]
pub url: Option<Url>,
#[cfg_attr(feature = "bindings", specta(type = Option<String>))]
#[serde(skip_serializing_if = "Option::is_none")]
pub accessed: Option<EdtfString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<LangID>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub field_languages: FieldLanguageMap,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<RichText>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keywords: Option<Vec<String>>,
#[serde(
flatten,
default,
skip_serializing_if = "std::collections::BTreeMap::is_empty"
)]
#[cfg_attr(feature = "schema", schemars(skip))]
pub unknown_fields: std::collections::BTreeMap<String, serde_json::Value>,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[cfg_attr(feature = "bindings", derive(Type))]
#[serde(rename_all = "kebab-case")]
pub struct Software {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<RefID>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<Title>,
#[serde(skip_serializing_if = "Option::is_none")]
pub original: Option<WorkRelation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub author: Option<Contributor>,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default, skip_serializing_if = "EdtfString::is_empty")]
pub created: EdtfString,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default, skip_serializing_if = "EdtfString::is_empty")]
pub issued: EdtfString,
#[serde(skip_serializing_if = "Option::is_none")]
pub publisher: Option<Publisher>,
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub repository: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub license: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub platform: Option<String>,
#[serde(alias = "DOI", skip_serializing_if = "Option::is_none")]
pub doi: Option<String>,
#[serde(alias = "URL", skip_serializing_if = "Option::is_none")]
pub url: Option<Url>,
#[cfg_attr(feature = "bindings", specta(type = Option<String>))]
#[serde(skip_serializing_if = "Option::is_none")]
pub accessed: Option<EdtfString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<LangID>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub field_languages: FieldLanguageMap,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<RichText>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keywords: Option<Vec<String>>,
#[serde(
flatten,
default,
skip_serializing_if = "std::collections::BTreeMap::is_empty"
)]
#[cfg_attr(feature = "schema", schemars(skip))]
pub unknown_fields: std::collections::BTreeMap<String, serde_json::Value>,
}
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[cfg_attr(feature = "bindings", derive(Type))]
#[serde(rename_all = "kebab-case")]
pub struct WorkCore {
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<Title>,
#[serde(skip_serializing_if = "Option::is_none")]
pub short_title: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub contributors: Vec<ContributorEntry>,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default, skip_serializing_if = "EdtfString::is_empty")]
pub created: EdtfString,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default, skip_serializing_if = "EdtfString::is_empty")]
pub issued: EdtfString,
#[serde(skip_serializing_if = "Option::is_none")]
pub original: Option<WorkRelation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<LangID>,
#[serde(skip_serializing_if = "Option::is_none")]
pub genre: Option<String>,
}
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[cfg_attr(feature = "bindings", derive(Type))]
#[serde(rename_all = "kebab-case")]
#[non_exhaustive]
pub enum AudioVisualType {
#[default]
Film,
Episode,
Recording,
Broadcast,
}
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[cfg_attr(feature = "bindings", derive(Type))]
#[serde(from = "AudioVisualDeser", rename_all = "kebab-case")]
pub struct AudioVisualWork {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<RefID>,
pub r#type: AudioVisualType,
#[serde(flatten)]
pub core: WorkCore,
#[serde(skip_serializing_if = "Option::is_none")]
pub container: Option<WorkRelation>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub numbering: Vec<Numbering>,
#[serde(skip_serializing_if = "Option::is_none")]
pub publisher: Option<Publisher>,
#[serde(skip_serializing_if = "Option::is_none")]
pub medium: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub platform: Option<String>,
#[serde(alias = "URL", skip_serializing_if = "Option::is_none")]
pub url: Option<Url>,
#[cfg_attr(feature = "bindings", specta(type = Option<String>))]
#[serde(skip_serializing_if = "Option::is_none")]
pub accessed: Option<EdtfString>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub field_languages: FieldLanguageMap,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<RichText>,
#[serde(
flatten,
default,
skip_serializing_if = "std::collections::BTreeMap::is_empty"
)]
#[cfg_attr(feature = "schema", schemars(skip))]
pub unknown_fields: std::collections::BTreeMap<String, serde_json::Value>,
}
#[derive(Deserialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[cfg_attr(feature = "bindings", derive(Type))]
#[serde(rename_all = "kebab-case")]
struct AudioVisualDeser {
id: Option<RefID>,
#[serde(default)]
r#type: AudioVisualType,
title: Option<Title>,
short_title: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
contributors: Vec<ContributorEntry>,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default)]
created: EdtfString,
#[cfg_attr(feature = "bindings", specta(type = String))]
#[serde(default)]
issued: EdtfString,
original: Option<WorkRelation>,
language: Option<LangID>,
genre: Option<String>,
container: Option<WorkRelation>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
numbering: Vec<Numbering>,
#[serde(skip_serializing_if = "Option::is_none")]
number: Option<String>,
publisher: Option<Publisher>,
medium: Option<String>,
platform: Option<String>,
#[serde(alias = "URL")]
url: Option<Url>,
#[cfg_attr(feature = "bindings", specta(type = Option<String>))]
accessed: Option<EdtfString>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
field_languages: FieldLanguageMap,
note: Option<RichText>,
#[serde(flatten, default)]
unknown_fields: std::collections::BTreeMap<String, serde_json::Value>,
}
impl HasNumbering for AudioVisualWork {
fn numbering(&self) -> &[Numbering] {
&self.numbering
}
}
impl From<AudioVisualDeser> for AudioVisualWork {
fn from(raw: AudioVisualDeser) -> Self {
let mut numbering = raw.numbering;
if let Some(n) = raw.number
&& !numbering.iter().any(|e| e.r#type == NumberingType::Number)
{
numbering.push(Numbering {
r#type: NumberingType::Number,
value: n,
});
}
Self {
id: raw.id,
r#type: raw.r#type,
core: WorkCore {
title: raw.title,
short_title: raw.short_title,
contributors: raw.contributors,
created: raw.created,
issued: raw.issued,
original: raw.original,
language: raw.language,
genre: raw.genre,
},
container: raw.container,
numbering,
publisher: raw.publisher,
medium: raw.medium,
platform: raw.platform,
url: raw.url,
accessed: raw.accessed,
field_languages: raw.field_languages,
note: raw.note,
unknown_fields: raw.unknown_fields,
}
}
}