acdc_parser/model/
title.rs

1use std::ops::Deref;
2
3use serde::{
4    Deserialize, Serialize,
5    de::{Deserializer, SeqAccess, Visitor},
6    ser::Serializer,
7};
8
9use super::inlines::InlineNode;
10
11/// A title in a document (section titles, block titles, document title, etc.).
12///
13/// `Title` is a newtype wrapper around `Vec<InlineNode>` that provides convenient
14/// access to inline content. Titles can include formatting, links, and other inline
15/// elements.
16///
17/// # Accessing Content
18///
19/// `Title` implements `Deref<Target=[InlineNode]>`, so you can use slice methods directly:
20///
21/// ```
22/// # use acdc_parser::{Title, InlineNode};
23/// let title = Title::new(vec![/* inline nodes */]);
24///
25/// // Iterate over inline nodes
26/// for node in &title {
27///     // ...
28/// }
29///
30/// // Check if empty
31/// if title.is_empty() {
32///     // ...
33/// }
34///
35/// // Access by index (via deref)
36/// if let Some(first) = title.first() {
37///     // ...
38/// }
39/// ```
40///
41/// # Serialization
42///
43/// Serializes as a plain JSON array of inline nodes for ASG compatibility.
44#[derive(Clone, Debug, Default, PartialEq)]
45#[non_exhaustive]
46pub struct Title(Vec<InlineNode>);
47
48impl Serialize for Title {
49    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
50    where
51        S: Serializer,
52    {
53        self.0.serialize(serializer)
54    }
55}
56
57impl<'de> Deserialize<'de> for Title {
58    fn deserialize<D>(deserializer: D) -> Result<Title, D::Error>
59    where
60        D: Deserializer<'de>,
61    {
62        struct TitleVisitor;
63
64        impl<'de> Visitor<'de> for TitleVisitor {
65            type Value = Title;
66
67            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
68                formatter.write_str("a sequence of inline nodes")
69            }
70
71            fn visit_seq<A>(self, mut seq: A) -> Result<Title, A::Error>
72            where
73                A: SeqAccess<'de>,
74            {
75                let mut inlines = Vec::new();
76                while let Some(node) = seq.next_element()? {
77                    inlines.push(node);
78                }
79                Ok(Title(inlines))
80            }
81        }
82
83        deserializer.deserialize_seq(TitleVisitor)
84    }
85}
86
87pub type Subtitle = Title;
88
89impl Title {
90    /// Creates a new `Title` with the given inline content.
91    #[must_use]
92    pub fn new(inlines: Vec<InlineNode>) -> Self {
93        Self(inlines)
94    }
95
96    /// Returns `true` if the title has no content.
97    #[must_use]
98    pub fn is_empty(&self) -> bool {
99        self.0.is_empty()
100    }
101
102    /// Returns the number of inline nodes in the title.
103    #[must_use]
104    pub fn len(&self) -> usize {
105        self.0.len()
106    }
107}
108
109impl From<Vec<InlineNode>> for Title {
110    fn from(inlines: Vec<InlineNode>) -> Self {
111        Self(inlines)
112    }
113}
114
115impl AsRef<[InlineNode]> for Title {
116    fn as_ref(&self) -> &[InlineNode] {
117        &self.0
118    }
119}
120
121impl Deref for Title {
122    type Target = [InlineNode];
123
124    fn deref(&self) -> &Self::Target {
125        &self.0
126    }
127}
128
129impl<'a> IntoIterator for &'a Title {
130    type Item = &'a InlineNode;
131    type IntoIter = std::slice::Iter<'a, InlineNode>;
132
133    fn into_iter(self) -> Self::IntoIter {
134        self.0.iter()
135    }
136}