1use serde::{
4 Serialize,
5 ser::{SerializeMap, Serializer},
6};
7
8use super::Block;
9use super::anchor::Anchor;
10use super::inlines::{CalloutRef, InlineNode};
11use super::location::Location;
12use super::metadata::BlockMetadata;
13use super::title::Title;
14
15pub type ListLevel = u8;
16
17#[derive(Clone, Debug, PartialEq)]
19#[non_exhaustive]
20pub enum ListItemCheckedStatus {
21 Checked,
22 Unchecked,
23}
24
25#[derive(Clone, Debug, PartialEq)]
32#[non_exhaustive]
33pub struct ListItem {
34 pub level: ListLevel,
35 pub marker: String,
36 pub checked: Option<ListItemCheckedStatus>,
37 pub principal: Vec<InlineNode>,
39 pub blocks: Vec<Block>,
41 pub location: Location,
42}
43
44#[derive(Clone, Debug, PartialEq)]
46#[non_exhaustive]
47pub struct DescriptionList {
48 pub title: Title,
49 pub metadata: BlockMetadata,
50 pub items: Vec<DescriptionListItem>,
51 pub location: Location,
52}
53
54#[derive(Clone, Debug, PartialEq, Serialize)]
76#[non_exhaustive]
77pub struct DescriptionListItem {
78 #[serde(default, skip_serializing_if = "Vec::is_empty")]
80 pub anchors: Vec<Anchor>,
81 #[serde(default, skip_serializing_if = "Vec::is_empty")]
83 pub term: Vec<InlineNode>,
84 pub delimiter: String,
86 #[serde(skip)]
88 pub delimiter_location: Option<Location>,
89 #[serde(default, skip_serializing_if = "Vec::is_empty")]
91 pub principal_text: Vec<InlineNode>,
92 pub description: Vec<Block>,
94 pub location: Location,
95}
96
97#[derive(Clone, Debug, PartialEq)]
99#[non_exhaustive]
100pub struct UnorderedList {
101 pub title: Title,
102 pub metadata: BlockMetadata,
103 pub items: Vec<ListItem>,
104 pub marker: String,
105 pub location: Location,
106}
107
108#[derive(Clone, Debug, PartialEq)]
110#[non_exhaustive]
111pub struct OrderedList {
112 pub title: Title,
113 pub metadata: BlockMetadata,
114 pub items: Vec<ListItem>,
115 pub marker: String,
116 pub location: Location,
117}
118
119#[derive(Clone, Debug, PartialEq)]
123#[non_exhaustive]
124pub struct CalloutList {
125 pub title: Title,
126 pub metadata: BlockMetadata,
127 pub items: Vec<CalloutListItem>,
128 pub location: Location,
129}
130
131#[derive(Clone, Debug, PartialEq)]
143#[non_exhaustive]
144pub struct CalloutListItem {
145 pub callout: CalloutRef,
147 pub principal: Vec<InlineNode>,
149 pub blocks: Vec<Block>,
151 pub location: Location,
153}
154
155macro_rules! impl_list_serialize {
160 ($type:ty, $variant:literal, with_marker) => {
161 impl Serialize for $type {
162 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
163 where
164 S: Serializer,
165 {
166 let mut state = serializer.serialize_map(None)?;
167 state.serialize_entry("name", "list")?;
168 state.serialize_entry("type", "block")?;
169 state.serialize_entry("variant", $variant)?;
170 state.serialize_entry("marker", &self.marker)?;
171 if !self.title.is_empty() {
172 state.serialize_entry("title", &self.title)?;
173 }
174 if !self.metadata.is_default() {
175 state.serialize_entry("metadata", &self.metadata)?;
176 }
177 state.serialize_entry("items", &self.items)?;
178 state.serialize_entry("location", &self.location)?;
179 state.end()
180 }
181 }
182 };
183 ($type:ty, $variant:literal) => {
184 impl Serialize for $type {
185 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
186 where
187 S: Serializer,
188 {
189 let mut state = serializer.serialize_map(None)?;
190 state.serialize_entry("name", "list")?;
191 state.serialize_entry("type", "block")?;
192 state.serialize_entry("variant", $variant)?;
193 if !self.title.is_empty() {
194 state.serialize_entry("title", &self.title)?;
195 }
196 if !self.metadata.is_default() {
197 state.serialize_entry("metadata", &self.metadata)?;
198 }
199 state.serialize_entry("items", &self.items)?;
200 state.serialize_entry("location", &self.location)?;
201 state.end()
202 }
203 }
204 };
205}
206
207impl_list_serialize!(UnorderedList, "unordered", with_marker);
208impl_list_serialize!(OrderedList, "ordered", with_marker);
209impl_list_serialize!(CalloutList, "callout");
210
211impl Serialize for DescriptionList {
212 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
213 where
214 S: Serializer,
215 {
216 let mut state = serializer.serialize_map(None)?;
217 state.serialize_entry("name", "dlist")?;
218 state.serialize_entry("type", "block")?;
219 if !self.title.is_empty() {
220 state.serialize_entry("title", &self.title)?;
221 }
222 if !self.metadata.is_default() {
223 state.serialize_entry("metadata", &self.metadata)?;
224 }
225 state.serialize_entry("items", &self.items)?;
226 state.serialize_entry("location", &self.location)?;
227 state.end()
228 }
229}
230
231impl Serialize for ListItem {
232 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
233 where
234 S: Serializer,
235 {
236 let mut state = serializer.serialize_map(None)?;
237 state.serialize_entry("name", "listItem")?;
238 state.serialize_entry("type", "block")?;
239 state.serialize_entry("marker", &self.marker)?;
240 if let Some(checked) = &self.checked {
241 state.serialize_entry("checked", checked)?;
242 }
243 state.serialize_entry("principal", &self.principal)?;
250 if !self.blocks.is_empty() {
251 state.serialize_entry("blocks", &self.blocks)?;
252 }
253 state.serialize_entry("location", &self.location)?;
254 state.end()
255 }
256}
257
258impl Serialize for ListItemCheckedStatus {
259 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
260 where
261 S: Serializer,
262 {
263 match &self {
264 ListItemCheckedStatus::Checked => serializer.serialize_bool(true),
265 ListItemCheckedStatus::Unchecked => serializer.serialize_bool(false),
266 }
267 }
268}
269
270impl Serialize for CalloutListItem {
271 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
272 where
273 S: Serializer,
274 {
275 let mut state = serializer.serialize_map(None)?;
276 state.serialize_entry("name", "listItem")?;
277 state.serialize_entry("type", "block")?;
278 state.serialize_entry("callout", &self.callout)?;
279 state.serialize_entry("principal", &self.principal)?;
280 if !self.blocks.is_empty() {
281 state.serialize_entry("blocks", &self.blocks)?;
282 }
283 state.serialize_entry("location", &self.location)?;
284 state.end()
285 }
286}