acdc_parser/model/
metadata.rs1use serde::Serialize;
4
5use super::anchor::Anchor;
6use super::attributes::{AttributeValue, ElementAttributes};
7use super::attribution::{Attribution, CiteTitle};
8use super::location::Location;
9use super::substitution::SubstitutionSpec;
10
11pub type Role<'a> = &'a str;
12
13#[derive(Clone, Debug, Default, PartialEq, Serialize)]
15#[non_exhaustive]
16pub struct BlockMetadata<'a> {
17 #[serde(default, skip_serializing_if = "ElementAttributes::is_empty")]
18 pub attributes: ElementAttributes<'a>,
19 #[serde(default, skip_serializing)]
24 pub(crate) positional_attributes: Vec<&'a str>,
25 #[serde(default, skip_serializing_if = "Vec::is_empty")]
26 pub roles: Vec<Role<'a>>,
27 #[serde(default, skip_serializing_if = "Vec::is_empty")]
28 pub options: Vec<&'a str>,
29 #[serde(default, skip_serializing_if = "Option::is_none")]
30 pub style: Option<&'a str>,
31 #[serde(default, skip_serializing_if = "Option::is_none")]
32 pub id: Option<Anchor<'a>>,
33 #[serde(default, skip_serializing_if = "Vec::is_empty")]
34 pub anchors: Vec<Anchor<'a>>,
35 #[serde(default, skip_serializing_if = "Option::is_none")]
42 pub substitutions: Option<SubstitutionSpec>,
43 #[serde(default, skip_serializing_if = "Option::is_none")]
44 pub attribution: Option<Attribution<'a>>,
45 #[serde(default, skip_serializing_if = "Option::is_none")]
46 pub citetitle: Option<CiteTitle<'a>>,
47 #[serde(skip)]
48 pub location: Option<Location>,
49}
50
51impl<'a> BlockMetadata<'a> {
52 #[must_use]
54 pub fn new() -> Self {
55 Self::default()
56 }
57
58 #[must_use]
60 pub fn with_attributes(mut self, attributes: ElementAttributes<'a>) -> Self {
61 self.attributes = attributes;
62 self
63 }
64
65 #[must_use]
67 pub fn with_options(mut self, options: Vec<&'a str>) -> Self {
68 self.options = options;
69 self
70 }
71
72 #[must_use]
74 pub fn with_roles(mut self, roles: Vec<Role<'a>>) -> Self {
75 self.roles = roles;
76 self
77 }
78
79 #[must_use]
81 pub fn with_style(mut self, style: Option<&'a str>) -> Self {
82 self.style = style;
83 self
84 }
85
86 #[must_use]
88 pub fn with_id(mut self, id: Option<Anchor<'a>>) -> Self {
89 self.id = id;
90 self
91 }
92
93 pub(crate) fn move_positional_attributes_to_attributes(&mut self) {
94 for positional_attribute in self.positional_attributes.drain(..) {
95 self.attributes.insert(
96 std::borrow::Cow::Borrowed(positional_attribute),
97 AttributeValue::None,
98 );
99 }
100 }
101
102 #[must_use]
103 pub fn is_default(&self) -> bool {
104 self.roles.is_empty()
105 && self.options.is_empty()
106 && self.style.is_none()
107 && self.id.is_none()
108 && self.anchors.is_empty()
109 && self.attributes.is_empty()
110 && self.positional_attributes.is_empty()
111 && self.substitutions.is_none()
112 && self.attribution.is_none()
113 && self.citetitle.is_none()
114 }
115
116 #[tracing::instrument(level = "debug")]
117 pub(crate) fn merge(&mut self, other: &BlockMetadata<'a>) {
118 self.attributes.merge(other.attributes.clone());
119 self.positional_attributes
120 .extend(other.positional_attributes.clone());
121 self.roles.extend(other.roles.clone());
122 self.options.extend(other.options.clone());
123 if self.style.is_none() {
124 self.style.clone_from(&other.style);
125 }
126 if self.id.is_none() {
127 self.id.clone_from(&other.id);
128 }
129 self.anchors.extend(other.anchors.clone());
130 if self.substitutions.is_none() {
131 self.substitutions.clone_from(&other.substitutions);
132 }
133 if self.attribution.is_none() {
134 self.attribution.clone_from(&other.attribution);
135 }
136 if self.citetitle.is_none() {
137 self.citetitle.clone_from(&other.citetitle);
138 }
139 }
140}