citeworks_cff/cff.rs
1use semver::Version;
2use serde::{Deserialize, Serialize};
3use url::Url;
4
5use crate::{
6 date::Date, identifiers::Identifier, license::License, names::Name, references::Reference,
7};
8
9/// The top-level CFF document.
10///
11/// This contains the citation metadata for a project, and may also contain
12/// reference information (the project's bibligraphy).
13#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
14#[serde(rename_all = "kebab-case")]
15pub struct Cff {
16 /// Version of the CFF specification this document conforms to.
17 ///
18 /// This is required and must be non-empty.
19 pub cff_version: Version,
20
21 /// What to do with the citation metadata, in a human-readable message.
22 ///
23 /// This is required and must be non-empty.
24 ///
25 /// # Examples
26 ///
27 /// - "If you use this software, please cite it using the metadata from this file."
28 /// - "Please cite this software using these metadata."
29 /// - "Please cite this software using the metadata from 'preferred-citation'."
30 /// - "If you use this dataset, please cite it using the metadata from this file."
31 /// - "Please cite this dataset using these metadata."
32 /// - "Please cite this dataset using the metadata from 'preferred-citation'."
33 pub message: String,
34
35 /// The name of the work.
36 ///
37 /// This is required and must be non-empty.
38 pub title: String,
39
40 /// The type of the work.
41 #[serde(default, skip_serializing_if = "Option::is_none", rename = "type")]
42 pub work_type: Option<WorkType>,
43
44 /// Version of the work.
45 ///
46 /// There is no requirement that this be semver.
47 #[serde(default, skip_serializing_if = "Option::is_none")]
48 pub version: Option<String>,
49
50 /// The commit hash or revision number of the software version.
51 ///
52 /// By convention:
53 /// - if this is a Git hash, it should be bare lowercase hex, e.g.
54 /// `1ff847d81f29c45a3a1a5ce73d38e45c2f319bba`;
55 /// - if this is a decimal revision or build number, it should be preceded
56 /// by a label, e.g. `Revision: 8612`.
57 #[serde(default, skip_serializing_if = "Option::is_none")]
58 pub commit: Option<String>,
59
60 /// The date the work has been released.
61 #[serde(default, skip_serializing_if = "Option::is_none")]
62 pub date_released: Option<Date>,
63
64 /// A description of the work.
65 #[serde(default, skip_serializing_if = "Option::is_none", rename = "abstract")]
66 pub abstract_text: Option<String>,
67
68 /// Keywords that describe the work.
69 #[serde(default, skip_serializing_if = "Vec::is_empty")]
70 pub keywords: Vec<String>,
71
72 /// The URL of a landing page/website for the software or dataset.
73 #[serde(default, skip_serializing_if = "Option::is_none")]
74 pub url: Option<Url>,
75
76 /// The URL of the work in a repository/archive.
77 ///
78 /// This is to be used when the repository is neither a source code
79 /// repository nor a build artifact repository. For source code, use the
80 /// `repository_code` field; for binary releases or other built forms, use
81 /// the `repository_artifact` field.
82 #[serde(default, skip_serializing_if = "Option::is_none")]
83 pub repository: Option<Url>,
84
85 /// The URL of the work in a build artifact/binary repository.
86 #[serde(default, skip_serializing_if = "Option::is_none")]
87 pub repository_artifact: Option<Url>,
88
89 /// The URL of the work in a source code repository.
90 #[serde(default, skip_serializing_if = "Option::is_none")]
91 pub repository_code: Option<Url>,
92
93 /// [SPDX][spdx] license expression(s).
94 #[serde(default, skip_serializing_if = "Option::is_none")]
95 pub license: Option<License>,
96
97 /// The URL of the license text under which the work is licensed.
98 ///
99 /// This should only be used for non-standard licenses not included in the
100 /// SPDX License List.
101 #[serde(default, skip_serializing_if = "Option::is_none")]
102 pub license_url: Option<Url>,
103
104 /// The authors of the work.
105 ///
106 /// This is required and must contain at least one author.
107 pub authors: Vec<Name>,
108
109 /// The contact person, group, company, etc. for the work.
110 #[serde(default, skip_serializing_if = "Vec::is_empty")]
111 pub contact: Vec<Name>,
112
113 /// The DOI for the work.
114 ///
115 /// Use this if the work has a single DOI. Otherwise, use the `identifiers`
116 /// field.
117 ///
118 /// Note that the DOI is not parsed or validated in any way.
119 #[serde(default, skip_serializing_if = "Option::is_none")]
120 pub doi: Option<String>,
121
122 /// The identifiers for the work.
123 #[serde(default, skip_serializing_if = "Vec::is_empty")]
124 pub identifiers: Vec<Identifier>,
125
126 /// A reference to another work that should be cited instead of the work.
127 ///
128 /// Note that the principles of [software citation] and [data citation]
129 /// require that software should be cited on the same basis as any other
130 /// research product such as a paper or a book. Adding a different preferred
131 /// citation may result in a violation of the respective primary principle,
132 /// "Importance", when others cite this work.
133 ///
134 /// [software citation]: https://doi.org/10.7717/peerj-cs.86
135 /// [data citation]: https://doi.org/10.25490/a97f-egyk
136 #[serde(default, skip_serializing_if = "Option::is_none")]
137 pub preferred_citation: Option<Reference>,
138
139 /// Reference(s) to other creative works.
140 ///
141 /// Similar to a list of references in a paper, references of the software
142 /// or dataset may include other software (dependencies), or other research
143 /// products that the software or dataset builds on, but not work describing
144 /// the software or dataset.
145 #[serde(default, skip_serializing_if = "Vec::is_empty")]
146 pub references: Vec<Reference>,
147}
148
149impl Default for Cff {
150 fn default() -> Self {
151 Self {
152 cff_version: Version::new(1, 2, 0),
153 message: String::from("Please cite this software using these metadata."),
154 title: Default::default(),
155 work_type: Default::default(),
156 version: Default::default(),
157 commit: Default::default(),
158 date_released: Default::default(),
159 abstract_text: Default::default(),
160 keywords: Default::default(),
161 url: Default::default(),
162 repository: Default::default(),
163 repository_artifact: Default::default(),
164 repository_code: Default::default(),
165 license: Default::default(),
166 license_url: Default::default(),
167 authors: Default::default(),
168 contact: Default::default(),
169 doi: Default::default(),
170 identifiers: Default::default(),
171 preferred_citation: Default::default(),
172 references: Default::default(),
173 }
174 }
175}
176
177/// Types of works recognised by CFF.
178#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
179#[serde(rename_all = "kebab-case")]
180pub enum WorkType {
181 /// A software project.
182 Software,
183
184 /// A dataset.
185 Dataset,
186}