vimwiki_core/lang/elements/
mod.rs

1#![allow(clippy::large_enum_variant)]
2
3use crate::StrictEq;
4use derive_more::{Constructor, From, Index, IndexMut, IntoIterator};
5use serde::{Deserialize, Serialize};
6use std::iter::FromIterator;
7
8mod blocks;
9pub use blocks::*;
10mod utils;
11pub use utils::{
12    AsChildrenMutSlice, AsChildrenSlice, IntoChildren, Located, Region,
13};
14
15/// Represents a full page containing different elements
16#[derive(
17    Constructor,
18    Clone,
19    Debug,
20    Default,
21    Eq,
22    PartialEq,
23    Index,
24    IndexMut,
25    IntoIterator,
26    Serialize,
27    Deserialize,
28)]
29pub struct Page<'a> {
30    /// Comprised of the elements within a page
31    #[index]
32    #[index_mut]
33    #[into_iterator(owned, ref, ref_mut)]
34    pub elements: Vec<Located<BlockElement<'a>>>,
35}
36
37impl<'a> Page<'a> {
38    /// Returns elements within the page
39    pub fn elements(&self) -> &[Located<BlockElement<'a>>] {
40        &self.elements
41    }
42
43    /// Consumes the page and returns the elements within
44    pub fn into_elements(self) -> Vec<Located<BlockElement<'a>>> {
45        self.elements
46    }
47}
48
49impl Page<'_> {
50    pub fn to_borrowed(&self) -> Page {
51        let elements = self
52            .elements
53            .iter()
54            .map(|x| x.as_ref().map(BlockElement::to_borrowed))
55            .collect();
56
57        Page { elements }
58    }
59
60    pub fn into_owned(self) -> Page<'static> {
61        let elements = self
62            .elements
63            .into_iter()
64            .map(|x| x.map(BlockElement::into_owned))
65            .collect();
66
67        Page { elements }
68    }
69}
70
71impl<'a> IntoChildren for Page<'a> {
72    type Child = Located<BlockElement<'a>>;
73
74    fn into_children(self) -> Vec<Self::Child> {
75        self.elements
76    }
77}
78
79impl<'a> FromIterator<Located<BlockElement<'a>>> for Page<'a> {
80    fn from_iter<I: IntoIterator<Item = Located<BlockElement<'a>>>>(
81        iter: I,
82    ) -> Self {
83        Self {
84            elements: iter.into_iter().collect(),
85        }
86    }
87}
88
89impl<'a> StrictEq for Page<'a> {
90    /// Performs strict_eq on page elements
91    fn strict_eq(&self, other: &Self) -> bool {
92        self.elements.len() == other.elements.len()
93            && self
94                .elements
95                .iter()
96                .zip(other.elements.iter())
97                .all(|(x, y)| x.strict_eq(y))
98    }
99}
100
101/// Represents a `BlockElement`, an `InlineElement`, or one of a handful of
102/// special inbetween types like `ListItem`
103#[derive(Clone, Debug, From, PartialEq, Eq, Serialize, Deserialize)]
104pub enum Element<'a> {
105    Block(BlockElement<'a>),
106    Inline(InlineElement<'a>),
107    InlineBlock(InlineBlockElement<'a>),
108}
109
110impl Element<'_> {
111    pub fn to_borrowed(&self) -> Element {
112        match self {
113            Self::Block(x) => Element::Block(x.to_borrowed()),
114            Self::Inline(x) => Element::Inline(x.to_borrowed()),
115            Self::InlineBlock(x) => Element::InlineBlock(x.to_borrowed()),
116        }
117    }
118
119    pub fn into_owned(self) -> Element<'static> {
120        match self {
121            Self::Block(x) => Element::Block(x.into_owned()),
122            Self::Inline(x) => Element::Inline(x.into_owned()),
123            Self::InlineBlock(x) => Element::InlineBlock(x.into_owned()),
124        }
125    }
126}
127
128impl<'a> IntoChildren for Element<'a> {
129    type Child = Located<Element<'a>>;
130
131    fn into_children(self) -> Vec<Self::Child> {
132        match self {
133            Self::Block(x) => x.into_children(),
134            Self::Inline(x) => x
135                .into_children()
136                .into_iter()
137                .map(|x| x.map(Element::from))
138                .collect(),
139            Self::InlineBlock(x) => x.into_children(),
140        }
141    }
142}
143
144impl<'a> StrictEq for Element<'a> {
145    fn strict_eq(&self, other: &Self) -> bool {
146        match (self, other) {
147            (Self::Block(x), Self::Block(y)) => x.strict_eq(y),
148            (Self::Inline(x), Self::Inline(y)) => x.strict_eq(y),
149            (Self::InlineBlock(x), Self::InlineBlock(y)) => x.strict_eq(y),
150            _ => false,
151        }
152    }
153}
154
155impl<'a> Element<'a> {
156    pub fn as_block_element(&self) -> Option<&BlockElement<'a>> {
157        match self {
158            Self::Block(ref x) => Some(x),
159            _ => None,
160        }
161    }
162
163    pub fn into_block_element(self) -> Option<BlockElement<'a>> {
164        match self {
165            Self::Block(x) => Some(x),
166            _ => None,
167        }
168    }
169
170    pub fn as_inline_element(&self) -> Option<&InlineElement<'a>> {
171        match self {
172            Self::Inline(ref x) => Some(x),
173            _ => None,
174        }
175    }
176
177    pub fn into_inline_element(self) -> Option<InlineElement<'a>> {
178        match self {
179            Self::Inline(x) => Some(x),
180            _ => None,
181        }
182    }
183
184    pub fn as_inline_block_element(&self) -> Option<&InlineBlockElement<'a>> {
185        match self {
186            Self::InlineBlock(ref x) => Some(x),
187            _ => None,
188        }
189    }
190
191    pub fn into_inline_block_element(self) -> Option<InlineBlockElement<'a>> {
192        match self {
193            Self::InlineBlock(x) => Some(x),
194            _ => None,
195        }
196    }
197}
198
199/// Represents a some element that is a descendant of a `BlockElement`, but
200/// is not an `InlineElement` such as `ListItem`
201#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
202pub enum InlineBlockElement<'a> {
203    ListItem(ListItem<'a>),
204    Term(Term<'a>),
205    Definition(Definition<'a>),
206}
207
208impl<'a> From<ListItem<'a>> for InlineBlockElement<'a> {
209    fn from(list_item: ListItem<'a>) -> Self {
210        Self::ListItem(list_item)
211    }
212}
213
214impl InlineBlockElement<'_> {
215    pub fn to_borrowed(&self) -> InlineBlockElement {
216        match self {
217            Self::ListItem(x) => InlineBlockElement::ListItem(x.to_borrowed()),
218            Self::Term(x) => InlineBlockElement::Term(x.to_borrowed()),
219            Self::Definition(x) => {
220                InlineBlockElement::Definition(x.to_borrowed())
221            }
222        }
223    }
224
225    pub fn into_owned(self) -> InlineBlockElement<'static> {
226        match self {
227            Self::ListItem(x) => InlineBlockElement::ListItem(x.into_owned()),
228            Self::Term(x) => InlineBlockElement::Term(x.into_owned()),
229            Self::Definition(x) => {
230                InlineBlockElement::Definition(x.into_owned())
231            }
232        }
233    }
234}
235
236impl<'a> IntoChildren for InlineBlockElement<'a> {
237    type Child = Located<Element<'a>>;
238
239    fn into_children(self) -> Vec<Self::Child> {
240        match self {
241            Self::ListItem(x) => x.into_children(),
242            Self::Term(x) => x
243                .into_children()
244                .into_iter()
245                .map(|x| x.map(Element::from))
246                .collect(),
247            Self::Definition(x) => x
248                .into_children()
249                .into_iter()
250                .map(|x| x.map(Element::from))
251                .collect(),
252        }
253    }
254}
255
256impl<'a> StrictEq for InlineBlockElement<'a> {
257    fn strict_eq(&self, other: &Self) -> bool {
258        match (self, other) {
259            (Self::ListItem(x), Self::ListItem(y)) => x.strict_eq(y),
260            (Self::Term(x), Self::Term(y)) => x.strict_eq(y),
261            (Self::Definition(x), Self::Definition(y)) => x.strict_eq(y),
262            _ => false,
263        }
264    }
265}
266
267macro_rules! element_impl_from {
268    ($type:ty, $class:ident) => {
269        impl<'a> From<$type> for Element<'a> {
270            fn from(value: $type) -> Self {
271                Self::from($class::from(value))
272            }
273        }
274    };
275}
276
277element_impl_from!(Blockquote<'a>, BlockElement);
278element_impl_from!(DefinitionList<'a>, BlockElement);
279element_impl_from!(Divider, BlockElement);
280element_impl_from!(Header<'a>, BlockElement);
281element_impl_from!(List<'a>, BlockElement);
282element_impl_from!(MathBlock<'a>, BlockElement);
283element_impl_from!(Paragraph<'a>, BlockElement);
284element_impl_from!(Placeholder<'a>, BlockElement);
285element_impl_from!(CodeBlock<'a>, BlockElement);
286element_impl_from!(Table<'a>, BlockElement);
287
288element_impl_from!(Text<'a>, InlineElement);
289element_impl_from!(DecoratedText<'a>, InlineElement);
290element_impl_from!(Keyword, InlineElement);
291element_impl_from!(Link<'a>, InlineElement);
292element_impl_from!(Tags<'a>, InlineElement);
293element_impl_from!(CodeInline<'a>, InlineElement);
294element_impl_from!(MathInline<'a>, InlineElement);
295
296element_impl_from!(ListItem<'a>, InlineBlockElement);