acdc_parser/model/
metadata.rs

1//! Block metadata types for `AsciiDoc` documents.
2
3use serde::{Deserialize, Serialize};
4
5use super::anchor::Anchor;
6use super::attributes::{AttributeValue, ElementAttributes};
7
8pub type Role = String;
9
10/// A `BlockMetadata` represents the metadata of a block in a document.
11#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
12#[non_exhaustive]
13pub struct BlockMetadata {
14    #[serde(default, skip_serializing_if = "ElementAttributes::is_empty")]
15    pub attributes: ElementAttributes,
16    #[serde(default, skip_serializing)]
17    pub positional_attributes: Vec<String>,
18    #[serde(default, skip_serializing_if = "Vec::is_empty")]
19    pub roles: Vec<Role>,
20    #[serde(default, skip_serializing_if = "Vec::is_empty")]
21    pub options: Vec<String>,
22    #[serde(default, skip_serializing_if = "Option::is_none")]
23    pub style: Option<String>,
24    #[serde(default, skip_serializing_if = "Option::is_none")]
25    pub id: Option<Anchor>,
26    #[serde(default, skip_serializing_if = "Vec::is_empty")]
27    pub anchors: Vec<Anchor>,
28}
29
30impl BlockMetadata {
31    /// Create a new block metadata with default values.
32    #[must_use]
33    pub fn new() -> Self {
34        Self::default()
35    }
36
37    /// Set the attributes.
38    #[must_use]
39    pub fn with_attributes(mut self, attributes: ElementAttributes) -> Self {
40        self.attributes = attributes;
41        self
42    }
43
44    /// Set the options.
45    #[must_use]
46    pub fn with_options(mut self, options: Vec<String>) -> Self {
47        self.options = options;
48        self
49    }
50
51    /// Set the roles.
52    #[must_use]
53    pub fn with_roles(mut self, roles: Vec<Role>) -> Self {
54        self.roles = roles;
55        self
56    }
57
58    /// Set the style.
59    #[must_use]
60    pub fn with_style(mut self, style: Option<String>) -> Self {
61        self.style = style;
62        self
63    }
64
65    /// Set the ID.
66    #[must_use]
67    pub fn with_id(mut self, id: Option<Anchor>) -> Self {
68        self.id = id;
69        self
70    }
71
72    pub fn move_positional_attributes_to_attributes(&mut self) {
73        for positional_attribute in self.positional_attributes.drain(..) {
74            self.attributes
75                .insert(positional_attribute, AttributeValue::None);
76        }
77    }
78
79    pub fn set_attributes(&mut self, attributes: ElementAttributes) {
80        self.attributes = attributes;
81    }
82
83    #[must_use]
84    pub fn is_default(&self) -> bool {
85        self.roles.is_empty()
86            && self.options.is_empty()
87            && self.style.is_none()
88            && self.id.is_none()
89            && self.anchors.is_empty()
90            && self.attributes.is_empty()
91            && self.positional_attributes.is_empty()
92    }
93
94    #[tracing::instrument(level = "debug")]
95    pub fn merge(&mut self, other: &BlockMetadata) {
96        self.attributes.merge(other.attributes.clone());
97        self.positional_attributes
98            .extend(other.positional_attributes.clone());
99        self.roles.extend(other.roles.clone());
100        self.options.extend(other.options.clone());
101        if self.style.is_none() {
102            self.style.clone_from(&other.style);
103        }
104        if self.id.is_none() {
105            self.id.clone_from(&other.id);
106        }
107        self.anchors.extend(other.anchors.clone());
108    }
109}