use serde::{Deserialize, Deserializer, Serialize};
fn is_zero_i64(n: &i64) -> bool {
*n == 0
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Data {
pub id: String,
#[serde(rename = "type")]
pub type_: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub acronym: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub additional_descriptions: Vec<Description>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub additional_names: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub additional_titles: Vec<Title>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub additional_type: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub affiliations: Vec<Affiliation>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub archive_locations: Vec<String>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub asserted_by: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub citations: Vec<Citation>,
#[serde(default, skip_serializing_if = "Container::is_empty")]
pub container: Container,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub content: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub contributors: Vec<Contributor>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub country: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub date_published: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub date_updated: String,
#[serde(default, skip_serializing_if = "Dates::is_empty")]
pub dates: Dates,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub description: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub established: Option<i32>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub files: Vec<File>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub funding_references: Vec<FundingReference>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub geo_locations: Vec<GeoLocation>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub identifiers: Vec<Identifier>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub family_name: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub given_name: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub image: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub language: String,
#[serde(default, skip_serializing_if = "License::is_empty")]
pub license: License,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub name: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub provider: String,
#[serde(default, skip_serializing_if = "Publisher::is_empty")]
pub publisher: Publisher,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub references: Vec<Reference>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub relations: Vec<Relation>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub schema_version: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub status: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub subjects: Vec<Subject>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub title: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub types: Vec<String>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub url: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub urls: Vec<PersonUrl>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub version: String,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Affiliation {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub name: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub role: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub start_date: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub end_date: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub asserted_by: String,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Citation {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub key: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(rename = "type", default, skip_serializing_if = "String::is_empty")]
pub type_: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub reference: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub asserted_by: String,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Container {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub identifier: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub identifier_type: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub scheme: String,
#[serde(rename = "type", default, skip_serializing_if = "String::is_empty")]
pub type_: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub title: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub description: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub language: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub license: Option<License>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub platform: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub image: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub first_page: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub last_page: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub volume: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub issue: String,
}
impl Container {
pub fn is_empty(&self) -> bool {
self.identifier.is_empty()
&& self.identifier_type.is_empty()
&& self.type_.is_empty()
&& self.title.is_empty()
&& self.description.is_empty()
&& self.language.is_empty()
&& self.license.is_none()
&& self.platform.is_empty()
&& self.image.is_empty()
&& self.first_page.is_empty()
&& self.last_page.is_empty()
&& self.volume.is_empty()
&& self.issue.is_empty()
}
}
#[derive(Debug, Clone, Default, PartialEq, Serialize)]
pub struct Contributor {
#[serde(rename = "type", default, skip_serializing_if = "String::is_empty")]
pub type_: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub person: Option<Person>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub organization: Option<Organization>,
#[serde(default, skip_serializing_if = "Vec::is_empty", alias = "contributor_roles")]
pub roles: Vec<String>,
}
impl Contributor {
pub fn person(person: Person, roles: Vec<String>) -> Self {
Contributor {
type_: "Person".to_string(),
person: Some(person),
organization: None,
roles,
}
}
pub fn organization(organization: Organization, roles: Vec<String>) -> Self {
Contributor {
type_: "Organization".to_string(),
person: None,
organization: Some(organization),
roles,
}
}
pub fn given_name(&self) -> &str {
self.person.as_ref().map_or("", |p| p.given_name.as_str())
}
pub fn family_name(&self) -> &str {
self.person.as_ref().map_or("", |p| p.family_name.as_str())
}
pub fn name(&self) -> String {
if let Some(p) = &self.person {
format!("{} {}", p.given_name, p.family_name)
.trim()
.to_string()
} else {
self.organization
.as_ref()
.map(|o| o.name.clone())
.unwrap_or_default()
}
}
pub fn id(&self) -> &str {
self.person
.as_ref()
.map(|p| p.id.as_str())
.or_else(|| self.organization.as_ref().map(|o| o.id.as_str()))
.unwrap_or("")
}
pub fn affiliations(&self) -> &[Affiliation] {
self.person.as_ref().map_or(&[], |p| p.affiliations.as_slice())
}
}
#[derive(Debug, Clone, Default, Deserialize)]
struct ContributorInput {
#[serde(default)]
id: String,
#[serde(rename = "type", default)]
type_: String,
#[serde(default)]
name: String,
#[serde(default, alias = "givenName", alias = "given_name")]
given_name: String,
#[serde(default, alias = "familyName", alias = "family_name")]
family_name: String,
#[serde(default)]
affiliations: Vec<Affiliation>,
#[serde(default, alias = "roles", alias = "contributor_roles")]
roles: Vec<String>,
#[serde(default)]
person: Option<Person>,
#[serde(default)]
organization: Option<Organization>,
}
impl<'de> Deserialize<'de> for Contributor {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let input = ContributorInput::deserialize(deserializer)?;
let person = input.person.or_else(|| {
if input.given_name.is_empty() && input.family_name.is_empty() && input.id.is_empty()
{
None
} else {
Some(Person {
id: input.id.clone(),
given_name: input.given_name,
family_name: input.family_name,
affiliations: input.affiliations.clone(),
asserted_by: String::new(),
..Default::default()
})
}
});
let organization = input.organization.or_else(|| {
if person.is_some() || input.name.is_empty() {
None
} else {
Some(Organization {
id: input.id.clone(),
name: input.name,
asserted_by: String::new(),
})
}
});
let type_ = if !input.type_.is_empty() {
input.type_
} else if person.is_some() {
"Person".to_string()
} else if organization.is_some() {
"Organization".to_string()
} else {
String::new()
};
Ok(Contributor {
type_,
person,
organization,
roles: input.roles,
})
}
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct PersonUrl {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub name: String,
pub url: String,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Person {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub given_name: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub family_name: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub name: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub additional_names: Vec<String>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub description: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub affiliations: Vec<Affiliation>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub identifiers: Vec<Identifier>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub urls: Vec<PersonUrl>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub country: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub asserted_by: String,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Organization {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub name: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub asserted_by: String,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Dates {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub created: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub submitted: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub accepted: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub accessed: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub available: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub withdrawn: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub collected: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub valid: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub copyrighted: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub other: String,
}
impl Dates {
pub fn is_empty(&self) -> bool {
self.created.is_empty()
&& self.submitted.is_empty()
&& self.accepted.is_empty()
&& self.accessed.is_empty()
&& self.available.is_empty()
&& self.withdrawn.is_empty()
&& self.collected.is_empty()
&& self.valid.is_empty()
&& self.copyrighted.is_empty()
&& self.other.is_empty()
}
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Description {
pub description: String,
#[serde(rename = "type", default, skip_serializing_if = "String::is_empty")]
pub type_: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub language: String,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct File {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub bucket: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub key: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub checksum: String,
pub url: String,
#[serde(default, skip_serializing_if = "is_zero_i64")]
pub size: i64,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub mime_type: String,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct FundingReference {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub funder_id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub funder_name: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub award_id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub award_title: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub award_number: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub asserted_by: String,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct GeoLocation {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub place: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub point_longitude: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub point_latitude: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub box_west_longitude: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub box_east_longitude: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub box_south_latitude: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub box_north_latitude: Option<f64>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub polygon: String,
}
impl GeoLocation {
pub fn is_empty(&self) -> bool {
self.id.is_empty()
&& self.place.is_empty()
&& self.point_longitude.is_none()
&& self.point_latitude.is_none()
&& self.box_west_longitude.is_none()
&& self.box_east_longitude.is_none()
&& self.box_south_latitude.is_none()
&& self.box_north_latitude.is_none()
&& self.polygon.is_empty()
}
pub fn city(&self) -> &str {
self.place
.split(',')
.next()
.map(|s| s.trim())
.unwrap_or("")
}
pub fn country_name(&self) -> &str {
self.place
.rsplit(',')
.next()
.map(|s| s.trim())
.unwrap_or("")
}
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Identifier {
pub identifier: String,
pub identifier_type: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub scheme: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub asserted_by: String,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct License {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub title: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub url: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub asserted_by: String,
}
impl License {
pub fn is_empty(&self) -> bool {
self.id.is_empty()
&& self.title.is_empty()
&& self.url.is_empty()
&& self.asserted_by.is_empty()
}
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Publisher {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub name: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub asserted_by: String,
}
impl Publisher {
pub fn is_empty(&self) -> bool {
self.id.is_empty() && self.name.is_empty() && self.asserted_by.is_empty()
}
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Reference {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub key: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(rename = "type", default, skip_serializing_if = "String::is_empty")]
pub type_: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub reference: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub title: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub publisher: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub publication_year: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub volume: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub issue: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub first_page: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub last_page: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub unstructured: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub asserted_by: String,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Relation {
pub id: String,
#[serde(rename = "type")]
pub type_: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub asserted_by: String,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Subject {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
pub subject: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub language: String,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Title {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub title: String,
#[serde(rename = "type", default, skip_serializing_if = "String::is_empty")]
pub type_: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub language: String,
}