1mod builder;
31mod extensions;
32mod io;
33mod provenance;
34mod security;
35mod state;
36mod verification;
37
38#[cfg(test)]
39mod tests;
40
41pub use builder::DocumentBuilder;
42pub use verification::{ExtensionValidationReport, VerificationReport};
43
44use chrono::Utc;
45
46use crate::content::Content;
47use crate::metadata::DublinCore;
48use crate::{DocumentId, DocumentState, HashAlgorithm, Manifest, Result};
49
50#[cfg(feature = "signatures")]
51use crate::security::SignatureFile;
52
53#[cfg(feature = "encryption")]
54use crate::security::EncryptionMetadata;
55
56use crate::extensions::academic::NumberingConfig;
57use crate::extensions::{Bibliography, CommentThread, FormData, JsonLdMetadata, PhantomClusters};
58
59trait MutableResource {
64 fn state(&self) -> DocumentState;
66
67 fn require_mutable(&self, action: &str) -> Result<()> {
73 if self.state().is_immutable() {
74 return Err(crate::Error::ImmutableDocument {
75 action: action.to_string(),
76 state: self.state(),
77 });
78 }
79 Ok(())
80 }
81}
82
83macro_rules! define_extension_accessors {
90 ($field:ident, $field_mut:ident, $has:ident, $set:ident, $clear:ident, $type:ty, $label:expr) => {
91 #[doc = concat!("Get the ", $label, ", if present.")]
92 #[must_use]
93 pub fn $field(&self) -> Option<&$type> {
94 self.$field.as_ref()
95 }
96
97 #[doc = concat!("Get a mutable reference to the ", $label, ".\n\n# Errors\n\nReturns an error if the document is in an immutable state.")]
98 pub fn $field_mut(&mut self) -> Result<Option<&mut $type>> {
99 self.require_mutable(concat!("modify ", $label))?;
100 Ok(self.$field.as_mut())
101 }
102
103 #[doc = concat!("Check if the document has ", $label, ".")]
104 #[must_use]
105 pub fn $has(&self) -> bool {
106 self.$field.is_some()
107 }
108
109 #[doc = concat!("Set the ", $label, ".\n\n# Errors\n\nReturns an error if the document is in an immutable state.")]
110 pub fn $set(&mut self, value: $type) -> Result<()> {
111 self.require_mutable(concat!("set ", $label))?;
112 self.$field = Some(value);
113 Ok(())
114 }
115
116 #[doc = concat!("Remove the ", $label, ".\n\n# Errors\n\nReturns an error if the document is in an immutable state.")]
117 pub fn $clear(&mut self) -> Result<()> {
118 self.require_mutable(concat!("remove ", $label))?;
119 self.$field = None;
120 Ok(())
121 }
122 };
123}
124
125pub(crate) use define_extension_accessors;
127
128impl MutableResource for Document {
129 fn state(&self) -> DocumentState {
130 self.manifest.state
131 }
132}
133
134#[derive(Debug, Clone)]
139pub struct Document {
140 manifest: Manifest,
141 content: Content,
142 dublin_core: DublinCore,
143 #[cfg(feature = "signatures")]
144 signature_file: Option<SignatureFile>,
145 #[cfg(feature = "encryption")]
146 encryption_metadata: Option<EncryptionMetadata>,
147 academic_numbering: Option<NumberingConfig>,
149 comments: Option<CommentThread>,
151 phantom_clusters: Option<PhantomClusters>,
153 form_data: Option<FormData>,
155 bibliography: Option<Bibliography>,
157 jsonld_metadata: Option<JsonLdMetadata>,
159}
160
161impl Document {
162 #[must_use]
164 pub fn builder() -> DocumentBuilder {
165 DocumentBuilder::new()
166 }
167
168 #[must_use]
170 pub fn manifest(&self) -> &Manifest {
171 &self.manifest
172 }
173
174 #[must_use]
176 pub fn content(&self) -> &Content {
177 &self.content
178 }
179
180 pub fn content_mut(&mut self) -> Result<&mut Content> {
186 self.require_mutable("modify content")?;
187 self.manifest.modified = Utc::now();
188 Ok(&mut self.content)
189 }
190
191 #[must_use]
193 pub fn dublin_core(&self) -> &DublinCore {
194 &self.dublin_core
195 }
196
197 pub fn dublin_core_mut(&mut self) -> Result<&mut DublinCore> {
203 self.require_mutable("modify Dublin Core metadata")?;
204 self.manifest.modified = Utc::now();
205 Ok(&mut self.dublin_core)
206 }
207
208 #[must_use]
210 pub fn title(&self) -> &str {
211 self.dublin_core.title()
212 }
213
214 #[must_use]
216 pub fn creators(&self) -> Vec<&str> {
217 self.dublin_core.creators()
218 }
219
220 #[must_use]
222 pub fn state(&self) -> DocumentState {
223 self.manifest.state
224 }
225
226 #[must_use]
228 pub fn id(&self) -> &DocumentId {
229 &self.manifest.id
230 }
231
232 #[must_use]
234 pub fn hash_algorithm(&self) -> HashAlgorithm {
235 self.manifest.hash_algorithm
236 }
237
238 #[must_use]
242 pub fn manifest_mut(&mut self) -> &mut Manifest {
243 &mut self.manifest
244 }
245}