wiki_api/
document.rs

1use serde_repr::Deserialize_repr;
2
3use crate::page::Link;
4
5#[derive(Clone, PartialEq, Eq)]
6pub struct Document {
7    pub nodes: Vec<Raw>,
8}
9
10impl std::fmt::Debug for Document {
11    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12        write!(f, "nodes: {}", self.nodes.len())
13    }
14}
15
16impl Document {
17    pub fn nth(&self, n: usize) -> Option<Node> {
18        Node::new(self, n)
19    }
20}
21
22#[derive(Clone, Debug, PartialEq, Eq, Deserialize_repr)]
23#[repr(usize)]
24pub enum HeaderKind {
25    Main = 1,
26    Sub = 2,
27    Section = 3,
28    Subsection = 4,
29    Minor = 5,
30    Detail = 6,
31}
32
33#[derive(Default, Clone, Debug, PartialEq, Eq)]
34pub enum Data {
35    Section {
36        id: usize,
37    },
38    Header {
39        id: String,
40        kind: HeaderKind,
41    },
42    Text {
43        contents: String,
44    },
45    Division,
46    Paragraph,
47    Span,
48    Reflink,
49    Hatnote,
50    RedirectMessage,
51    Disambiguation,
52    Blockquote,
53
54    OrderedList,
55    UnorderedList,
56    ListItem,
57
58    DescriptionList,
59    DescriptionListTerm,
60    DerscriptionListDescription,
61
62    Bold,
63    Italic,
64
65    Linebreak,
66
67    Link(Link),
68    #[default]
69    Unknown,
70
71    Unsupported(UnsupportedElement),
72    UnsupportedInline(UnsupportedElement),
73}
74
75#[derive(Clone, Debug, PartialEq, Eq)]
76pub enum UnsupportedElement {
77    Table,
78    Image,
79    Figure,
80    MathElement,
81    PreformattedText,
82}
83
84#[derive(Clone, Debug, PartialEq, Eq)]
85pub struct Raw {
86    pub index: usize,
87    pub parent: Option<usize>,
88    pub prev: Option<usize>,
89    pub next: Option<usize>,
90    pub first_child: Option<usize>,
91    pub last_child: Option<usize>,
92    pub data: Data,
93}
94
95#[derive(Copy, Clone, Debug, PartialEq, Eq)]
96pub struct Node<'a> {
97    document: &'a Document,
98    index: usize,
99}
100
101impl<'a> Node<'a> {
102    pub fn new(document: &'a Document, index: usize) -> Option<Node<'a>> {
103        if index < document.nodes.len() {
104            Some(Node { document, index })
105        } else {
106            None
107        }
108    }
109
110    pub fn index(&self) -> usize {
111        self.index
112    }
113
114    pub fn raw(&self) -> &'a Raw {
115        &self.document.nodes[self.index]
116    }
117
118    pub fn data(&self) -> &'a Data {
119        &self.raw().data
120    }
121
122    pub fn parent(&self) -> Option<Node<'a>> {
123        self.raw()
124            .parent
125            .map(|index| self.document.nth(index).unwrap())
126    }
127
128    pub fn prev(&self) -> Option<Node<'a>> {
129        self.raw()
130            .prev
131            .map(|index| self.document.nth(index).unwrap())
132    }
133
134    pub fn next(&self) -> Option<Node<'a>> {
135        self.raw()
136            .next
137            .map(|index| self.document.nth(index).unwrap())
138    }
139
140    pub fn first_child(&self) -> Option<Node<'a>> {
141        self.raw()
142            .first_child
143            .map(|index| self.document.nth(index).unwrap())
144    }
145
146    pub fn last_child(&self) -> Option<Node<'a>> {
147        self.raw()
148            .last_child
149            .map(|index| self.document.nth(index).unwrap())
150    }
151
152    pub fn descendants(&self) -> Descendants<'a> {
153        Descendants {
154            start: *self,
155            current: *self,
156            done: false,
157        }
158    }
159
160    pub fn children(&self) -> Children<'a> {
161        Children {
162            next: self.first_child(),
163        }
164    }
165}
166
167#[derive(Clone, Debug)]
168pub struct Descendants<'a> {
169    start: Node<'a>,
170    current: Node<'a>,
171    done: bool,
172}
173
174impl<'a> Iterator for Descendants<'a> {
175    type Item = Node<'a>;
176
177    fn next(&mut self) -> Option<Node<'a>> {
178        if self.done {
179            return None;
180        }
181
182        // If this is the start, we can only descdend into children.
183        if self.start.index() == self.current.index() {
184            if let Some(first_child) = self.current.first_child() {
185                self.current = first_child;
186            } else {
187                self.done = true;
188                return None;
189            }
190        } else {
191            // Otherwise we can also go to next sibling.
192            if let Some(first_child) = self.current.first_child() {
193                self.current = first_child;
194            } else if let Some(next) = self.current.next() {
195                self.current = next;
196            } else {
197                loop {
198                    // This unwrap should never fail.
199                    let parent = self.current.parent().unwrap();
200                    if parent.index() == self.start.index() {
201                        self.done = true;
202                        return None;
203                    }
204                    if let Some(next) = parent.next() {
205                        self.current = next;
206                        break;
207                    }
208                    self.current = parent;
209                }
210            }
211        }
212
213        Some(self.current)
214    }
215}
216
217pub struct Children<'a> {
218    next: Option<Node<'a>>,
219}
220
221impl<'a> Iterator for Children<'a> {
222    type Item = Node<'a>;
223    fn next(&mut self) -> Option<Node<'a>> {
224        if let Some(next) = self.next {
225            self.next = next.next();
226            Some(next)
227        } else {
228            None
229        }
230    }
231}