summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2023-02-26 12:12:07 +0100
committerHampusM <hampus@hampusmat.com>2023-02-26 12:12:07 +0100
commit2d633644a53dfe278b681a911b2eaea1230a07cc (patch)
treef493c209707df57a3f12398191f0a87dbabd8523
parente225d7344cef05f03676f6579415999478328ead (diff)
feat: add itemized list support
-rw-r--r--src/description.rs17
-rw-r--r--src/itemized_list.rs195
-rw-r--r--src/lib.rs1
3 files changed, 212 insertions, 1 deletions
diff --git a/src/description.rs b/src/description.rs
index dfa521b..f536b4f 100644
--- a/src/description.rs
+++ b/src/description.rs
@@ -1,4 +1,5 @@
//! Reference entry description.
+use crate::itemized_list::{Error as ItemizedListError, ItemizedList};
use crate::variable_list::{Error as VariableListError, VariableList};
use crate::xml::element::{Elements, FromElements, Tagged};
@@ -164,6 +165,9 @@ pub enum ParagraphPart
/// Variable list part.
VariableList(VariableList),
+
+ /// Itemized list part.
+ ItemizedList(ItemizedList),
}
impl FromElements for ParagraphPart
@@ -195,7 +199,7 @@ impl ParagraphPart
"function" => Self::Function,
"parameter" => Self::Parameter,
"citerefentry" => Self::Entry,
- "variablelist" => |_| {
+ "variablelist" | "itemizedlist" => |_| {
unreachable!();
},
_ => {
@@ -226,6 +230,13 @@ impl ParagraphPart
return Ok(Self::VariableList(variable_list));
}
+ if tagged_element.name() == "itemizedlist" {
+ let itemized_list =
+ ItemizedList::from_elements(tagged_element.child_elements())?;
+
+ return Ok(Self::ItemizedList(itemized_list));
+ }
+
let text_element = tagged_element
.child_elements()
.get_first_text_element()
@@ -258,4 +269,8 @@ pub enum ParagraphPartError
/// Invalid variable list.
#[error("Invalid variable list")]
InvalidVariableList(#[from] VariableListError),
+
+ /// Invalid itemized list.
+ #[error("Invalid itemized list")]
+ InvalidItemizedList(#[from] ItemizedListError),
}
diff --git a/src/itemized_list.rs b/src/itemized_list.rs
new file mode 100644
index 0000000..efe43b5
--- /dev/null
+++ b/src/itemized_list.rs
@@ -0,0 +1,195 @@
+//! Itemized list.
+use crate::description::{Paragraph, ParagraphError, ParagraphPartError};
+use crate::xml::element::{Element, FromElements};
+
+/// Itemized list.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ItemizedList
+{
+ items: Vec<Item>,
+}
+
+impl ItemizedList
+{
+ /// Returns a new `ItemizedList`.
+ pub fn new(entries: impl IntoIterator<Item = Item>) -> Self
+ {
+ Self {
+ items: entries.into_iter().collect(),
+ }
+ }
+
+ /// Returns the itemized list's items.
+ #[must_use]
+ pub fn items(&self) -> &[Item]
+ {
+ &self.items
+ }
+}
+
+impl FromElements for ItemizedList
+{
+ type Error = Error;
+
+ fn from_elements(
+ elements: &crate::xml::element::Elements,
+ ) -> Result<Self, Self::Error>
+ {
+ let items = elements
+ .get_all_tagged_elements_with_name("listitem")
+ .into_iter()
+ .map(|entry_elem| Item::from_elements(entry_elem.child_elements()))
+ .collect::<Result<Vec<_>, _>>()?;
+
+ Ok(Self { items })
+ }
+}
+
+/// [`ItemizedList`] error.
+#[derive(Debug, thiserror::Error)]
+pub enum Error
+{
+ /// Invalid item.
+ #[error("Invalid item")]
+ InvalidItem(#[from] ItemError),
+}
+
+/// Itemized list item.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Item
+{
+ paragraphs: Vec<Paragraph>,
+}
+
+impl Item
+{
+ /// Returns a new `Item`.
+ pub fn new(paragraphs: impl IntoIterator<Item = Paragraph>) -> Self
+ {
+ Self {
+ paragraphs: paragraphs.into_iter().collect(),
+ }
+ }
+
+ /// Returns the itemized list item paragraphs.
+ #[must_use]
+ pub fn paragraphs(&self) -> &[Paragraph]
+ {
+ &self.paragraphs
+ }
+}
+
+impl FromElements for Item
+{
+ type Error = ItemError;
+
+ fn from_elements(
+ elements: &crate::xml::element::Elements,
+ ) -> Result<Self, Self::Error>
+ {
+ let item = elements
+ .into_iter()
+ .filter_map(|elem| match elem {
+ Element::Tagged(tagged_elem) if tagged_elem.name() == "para" => {
+ Some(tagged_elem)
+ }
+ _ => None,
+ })
+ .map(|para_elem| Paragraph::from_elements(para_elem.child_elements()))
+ .collect::<Result<Vec<_>, _>>()
+ .map_err(|err| Self::Error::InvalidItemParagraph(Box::new(err)))?;
+
+ Ok(Self { paragraphs: item })
+ }
+}
+
+/// [`Item`] error.
+#[derive(Debug, thiserror::Error)]
+pub enum ItemError
+{
+ /// Missing tagged element with name 'term'.
+ #[error("Missing tagged element with name 'term'")]
+ MissingTerm,
+
+ /// Missing tagged element with name 'listitem'.
+ #[error("Missing tagged element with name 'listitem'")]
+ MissingListItem,
+
+ /// Invalid term.
+ #[error("Invalid term")]
+ InvalidTerm(#[source] Box<ParagraphPartError>),
+
+ /// Invalid item paragraph.
+ #[error("Invalid item paragraph")]
+ InvalidItemParagraph(#[source] Box<ParagraphError>),
+}
+
+#[cfg(test)]
+mod tests
+{
+ use super::*;
+ use crate::description::ParagraphPart;
+ use crate::xml::element::{Element, Elements, Tagged};
+
+ #[test]
+ fn itemized_list_from_elements_works()
+ {
+ let itemized_list = ItemizedList::from_elements(&Elements::from([
+ Element::Tagged(Tagged::new(
+ &"listitem",
+ [Element::Tagged(Tagged::new(
+ &"para",
+ [Element::Text("Hello hello.".to_string())],
+ [],
+ ))],
+ [],
+ )),
+ Element::Tagged(Tagged::new(
+ &"listitem",
+ [Element::Tagged(Tagged::new(
+ &"para",
+ [
+ Element::Text("Tosche station".to_string()),
+ Element::Text("Power converters".to_string()),
+ ],
+ [],
+ ))],
+ [],
+ )),
+ Element::Tagged(Tagged::new(
+ &"listitem",
+ [Element::Tagged(Tagged::new(
+ &"para",
+ [Element::Text("It's a trap".to_string())],
+ [],
+ ))],
+ [],
+ )),
+ ]))
+ .expect("Expected Ok");
+
+ assert_eq!(itemized_list.items.len(), 3);
+ }
+
+ #[test]
+ fn item_from_elements_works()
+ {
+ let item = Item::from_elements(&Elements::from([
+ Element::Tagged(Tagged::new(&"para", [Element::Text("bar".to_string())], [])),
+ Element::Tagged(Tagged::new(
+ &"para",
+ [Element::Text("Hello there.".to_string())],
+ [],
+ )),
+ ]))
+ .expect("Expected Ok");
+
+ assert_eq!(
+ item.paragraphs,
+ vec![
+ Paragraph::new([ParagraphPart::Text("bar".to_string())]),
+ Paragraph::new([ParagraphPart::Text("Hello there.".to_string())]),
+ ]
+ );
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index b6343de..c0a300b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -14,6 +14,7 @@ use crate::xml::element::{Attribute, Elements, FromElements};
use crate::xml::parser::{Error as ParserError, Parser};
pub mod description;
+pub mod itemized_list;
pub mod variable_list;
mod xml;