citum_schema_data/reference/
contributor.rs1use crate::reference::types::{MultilingualString, Place};
7#[cfg(feature = "schema")]
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10#[cfg(feature = "bindings")]
11use specta::Type;
12use std::fmt;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
16#[cfg_attr(feature = "schema", derive(JsonSchema))]
17#[cfg_attr(feature = "bindings", derive(Type))]
18#[serde(rename_all = "kebab-case")]
19pub enum ContributorGender {
20 Masculine,
22 Feminine,
24 Neuter,
26 Common,
28}
29
30#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
32#[cfg_attr(feature = "schema", derive(JsonSchema))]
33#[cfg_attr(feature = "bindings", derive(Type))]
34#[serde(untagged)]
35pub enum Contributor {
36 SimpleName(SimpleName),
37 StructuredName(StructuredName),
38 Multilingual(MultilingualName),
39 ContributorList(ContributorList),
40}
41
42#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
44#[cfg_attr(feature = "schema", derive(JsonSchema))]
45#[cfg_attr(feature = "bindings", derive(Type))]
46#[serde(rename_all = "kebab-case")]
47pub struct MultilingualName {
48 pub original: StructuredName,
50 #[serde(skip_serializing_if = "Option::is_none")]
52 pub lang: Option<crate::reference::types::LangID>,
53 #[serde(default, skip_serializing_if = "std::collections::HashMap::is_empty")]
55 pub transliterations: std::collections::HashMap<String, StructuredName>,
56 #[serde(default, skip_serializing_if = "std::collections::HashMap::is_empty")]
58 pub translations: std::collections::HashMap<crate::reference::types::LangID, StructuredName>,
59}
60
61#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
63#[cfg_attr(feature = "schema", derive(JsonSchema))]
64#[cfg_attr(feature = "bindings", derive(Type))]
65pub struct SimpleName {
66 pub name: MultilingualString,
68 #[serde(skip_serializing_if = "Option::is_none")]
70 pub location: Option<Place>,
71 #[serde(rename = "short-name", skip_serializing_if = "Option::is_none")]
73 pub short_name: Option<String>,
74}
75
76#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialEq)]
78#[cfg_attr(feature = "schema", derive(JsonSchema))]
79#[cfg_attr(feature = "bindings", derive(Type))]
80#[serde(rename_all = "kebab-case")]
81pub struct StructuredName {
82 pub given: MultilingualString,
83 pub family: MultilingualString,
84 #[serde(skip_serializing_if = "Option::is_none")]
85 pub suffix: Option<String>,
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub dropping_particle: Option<String>,
88 #[serde(skip_serializing_if = "Option::is_none")]
89 pub non_dropping_particle: Option<String>,
90}
91
92#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
94#[cfg_attr(feature = "schema", derive(JsonSchema))]
95#[cfg_attr(feature = "bindings", derive(Type))]
96pub struct ContributorList(pub Vec<Contributor>);
97
98impl Contributor {
99 pub fn to_names_vec(&self) -> Vec<FlatName> {
100 match self {
101 Contributor::SimpleName(n) => vec![FlatName {
102 literal: Some(n.name.to_string()),
103 short_name: n.short_name.clone(),
104 ..Default::default()
105 }],
106 Contributor::StructuredName(n) => vec![FlatName {
107 given: Some(n.given.to_string()),
108 family: Some(n.family.to_string()),
109 suffix: n.suffix.clone(),
110 dropping_particle: n.dropping_particle.clone(),
111 non_dropping_particle: n.non_dropping_particle.clone(),
112 ..Default::default()
113 }],
114 Contributor::Multilingual(m) => vec![FlatName {
115 given: Some(m.original.given.to_string()),
116 family: Some(m.original.family.to_string()),
117 suffix: m.original.suffix.clone(),
118 dropping_particle: m.original.dropping_particle.clone(),
119 non_dropping_particle: m.original.non_dropping_particle.clone(),
120 ..Default::default()
121 }],
122 Contributor::ContributorList(l) => l.0.iter().flat_map(|c| c.to_names_vec()).collect(),
123 }
124 }
125
126 pub fn name(&self) -> Option<String> {
127 match self {
128 Contributor::SimpleName(n) => Some(n.name.to_string()),
129 Contributor::Multilingual(m) => {
130 Some(format!("{} {}", m.original.given, m.original.family))
131 }
132 _ => None,
133 }
134 }
135
136 pub fn location(&self) -> Option<String> {
137 match self {
138 Contributor::SimpleName(n) => n.location.clone().map(Into::into),
139 _ => None,
140 }
141 }
142}
143
144#[derive(Debug, Clone, Default, PartialEq, Eq)]
146pub struct FlatName {
147 pub family: Option<String>,
148 pub given: Option<String>,
149 pub suffix: Option<String>,
150 pub dropping_particle: Option<String>,
151 pub non_dropping_particle: Option<String>,
152 pub literal: Option<String>,
153 pub short_name: Option<String>,
154}
155
156impl FlatName {
157 pub fn family_or_literal(&self) -> &str {
158 if let Some(ref f) = self.family {
159 f
160 } else if let Some(ref l) = self.literal {
161 l
162 } else {
163 ""
164 }
165 }
166}
167
168impl fmt::Display for Contributor {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 match self {
171 Contributor::SimpleName(n) => write!(f, "{}", n.name),
172 Contributor::StructuredName(n) => write!(f, "{} {}", n.given, n.family),
173 Contributor::Multilingual(m) => write!(f, "{} {}", m.original.given, m.original.family),
174 Contributor::ContributorList(l) => write!(f, "{}", l),
175 }
176 }
177}
178
179impl fmt::Display for ContributorList {
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 let names: Vec<String> = self.0.iter().map(|c| c.to_string()).collect();
182 write!(f, "{}", names.join(", "))
183 }
184}
185
186crate::tolerant_enum! {
187 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
189 pub enum ContributorRole {
190 Author = "author",
191 Editor = "editor",
192 Translator = "translator",
193 Director = "director",
194 Performer = "performer",
195 Composer = "composer",
196 Illustrator = "illustrator",
197 Narrator = "narrator",
198 Host = "host",
199 Guest = "guest",
200 Interviewer = "interviewer",
201 Recipient = "recipient",
202 Compiler = "compiler",
203 Producer = "producer",
204 Writer = "writer"
205 }
206}
207
208#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
210#[cfg_attr(feature = "schema", derive(JsonSchema))]
211#[cfg_attr(feature = "bindings", derive(Type))]
212#[serde(rename_all = "kebab-case")]
213pub struct ContributorEntry {
214 pub role: ContributorRole,
216 pub contributor: Contributor,
218 #[serde(skip_serializing_if = "Option::is_none")]
220 pub gender: Option<ContributorGender>,
221}