entrenar/research/artifact/
author.rs1use serde::{Deserialize, Serialize};
4
5use super::{validate_orcid, Affiliation, ContributorRole, ValidationError};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9pub struct Author {
10 pub name: String,
12 pub orcid: Option<String>,
14 pub affiliations: Vec<Affiliation>,
16 pub roles: Vec<ContributorRole>,
18}
19
20impl Author {
21 pub fn new(name: impl Into<String>) -> Self {
23 Self { name: name.into(), orcid: None, affiliations: Vec::new(), roles: Vec::new() }
24 }
25
26 pub fn with_orcid(mut self, orcid: impl Into<String>) -> Result<Self, ValidationError> {
28 let id = orcid.into();
29 if !validate_orcid(&id) {
30 return Err(ValidationError::InvalidOrcid(id));
31 }
32 self.orcid = Some(id);
33 Ok(self)
34 }
35
36 pub fn with_affiliation(mut self, affiliation: Affiliation) -> Self {
38 self.affiliations.push(affiliation);
39 self
40 }
41
42 pub fn with_role(mut self, role: ContributorRole) -> Self {
44 if !self.roles.contains(&role) {
45 self.roles.push(role);
46 }
47 self
48 }
49
50 pub fn with_roles(mut self, roles: impl IntoIterator<Item = ContributorRole>) -> Self {
52 for role in roles {
53 if !self.roles.contains(&role) {
54 self.roles.push(role);
55 }
56 }
57 self
58 }
59
60 pub fn last_name(&self) -> &str {
62 self.name.split_whitespace().next_back().unwrap_or(&self.name)
63 }
64}