summaryrefslogtreecommitdiff
path: root/src/description.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/description.rs')
-rw-r--r--src/description.rs211
1 files changed, 211 insertions, 0 deletions
diff --git a/src/description.rs b/src/description.rs
new file mode 100644
index 0000000..ba37abc
--- /dev/null
+++ b/src/description.rs
@@ -0,0 +1,211 @@
+//! Reference entry description.
+use crate::util::enum_with_get_inner;
+use crate::xml::element::{Elements, FromElements, Tagged};
+
+/// Reference entry description.
+#[derive(Debug)]
+pub struct Description
+{
+ paragraphs: Vec<Paragraph>,
+}
+
+impl Description
+{
+ /// Returns a new `ReferenceDescription`.
+ #[must_use]
+ pub fn new() -> Self
+ {
+ Self {
+ paragraphs: Vec::new(),
+ }
+ }
+
+ /// Returns the reference description's paragraphs.
+ #[must_use]
+ pub fn paragraphs(&self) -> &[Paragraph]
+ {
+ &self.paragraphs
+ }
+}
+
+impl Default for Description
+{
+ fn default() -> Self
+ {
+ Self::new()
+ }
+}
+
+impl FromElements for Description
+{
+ type Error = Error;
+
+ fn from_elements(elements: &Elements) -> Result<Self, Self::Error>
+ {
+ let paragraphs = elements
+ .get_all_tagged_elements_with_name("para")
+ .into_iter()
+ .map(|paragraph_element| {
+ Paragraph::from_elements(paragraph_element.child_elements())
+ })
+ .collect::<Result<Vec<_>, _>>()?;
+
+ Ok(Description { paragraphs })
+ }
+}
+
+/// [`Description`] error.
+#[derive(Debug, thiserror::Error)]
+pub enum Error
+{
+ /// Invalid paragraph.
+ #[error("Invalid paragraph")]
+ InvalidParagraph(#[from] ParagraphError),
+}
+
+/// Reference entry description paragraph.
+#[derive(Debug)]
+pub struct Paragraph
+{
+ parts: Vec<ParagraphPart>,
+}
+
+impl Paragraph
+{
+ /// Returns the parts of the paragraph.
+ #[must_use]
+ pub fn parts(&self) -> &[ParagraphPart]
+ {
+ &self.parts
+ }
+}
+
+impl FromElements for Paragraph
+{
+ type Error = ParagraphError;
+
+ fn from_elements(elements: &Elements) -> Result<Self, Self::Error>
+ {
+ let parts = elements
+ .into_iter()
+ .map(|element| {
+ ParagraphPart::from_elements(&Elements::from([element.clone()]))
+ })
+ .collect::<Result<Vec<_>, _>>()?;
+
+ Ok(Self { parts })
+ }
+}
+
+/// [`Paragraph`] error.
+#[derive(Debug, thiserror::Error)]
+pub enum ParagraphError
+{
+ /// Invalid reference description part.
+ #[error("Invalid part")]
+ InvalidPart(#[from] ParagraphPartError),
+}
+
+enum_with_get_inner! {
+inner = String;
+
+/// Reference entry description paragraph part.
+#[derive(Debug)]
+pub enum ParagraphPart
+{
+ /// Text part.
+ Text(String),
+
+ /// <constant>..</constant> part.
+ Constant(String),
+
+ /// <function>..</function> part.
+ Function(String),
+
+ /// <parameter>..</parameter> part.
+ Parameter(String),
+
+ /// Reference entry citation part.
+ Entry(String),
+}
+}
+
+impl FromElements for ParagraphPart
+{
+ type Error = ParagraphPartError;
+
+ fn from_elements(elements: &Elements) -> Result<Self, Self::Error>
+ {
+ if let Some(tagged_element) = elements.get_first_tagged() {
+ return Self::from_tagged_element(tagged_element);
+ }
+
+ let text = elements
+ .get_first_text_element()
+ .ok_or(Self::Error::InputIsComment)?;
+
+ Ok(Self::Text(text.clone()))
+ }
+}
+
+impl ParagraphPart
+{
+ fn from_tagged_element(
+ tagged_element: &Tagged,
+ ) -> Result<Self, <Self as FromElements>::Error>
+ {
+ let create: fn(String) -> Self = match tagged_element.name() {
+ "constant" => Self::Constant,
+ "function" => Self::Function,
+ "parameter" => Self::Parameter,
+ "citerefentry" => Self::Entry,
+ _ => {
+ return Err(<Self as FromElements>::Error::UnknownPart(
+ tagged_element.name().to_string(),
+ ));
+ }
+ };
+
+ if tagged_element.name() == "citerefentry" {
+ let title_element = tagged_element
+ .child_elements()
+ .get_first_tagged_with_name("refentrytitle")
+ .ok_or(<Self as FromElements>::Error::NoEntryTitleFound)?;
+
+ let title = title_element
+ .child_elements()
+ .get_first_text_element()
+ .ok_or(<Self as FromElements>::Error::NoTextInTagged)?;
+
+ return Ok(Self::Entry(title.clone()));
+ }
+
+ let text_element = tagged_element
+ .child_elements()
+ .get_first_text_element()
+ .ok_or(<Self as FromElements>::Error::NoTextInTagged)?;
+
+ Ok(create(text_element.clone()))
+ }
+}
+
+/// [`ParagraphPart`] error.
+#[derive(Debug, thiserror::Error)]
+pub enum ParagraphPartError
+{
+ /// Input element is a comment.
+ #[error("Input element is a comment")]
+ InputIsComment,
+
+ /// A input element is a unknown reference description part.
+ #[error("Input element with name '{0}' is a unknown reference description part")]
+ UnknownPart(String),
+
+ /// No text was found in tagged input element.
+ #[error("No text was found in tagged input element")]
+ NoTextInTagged,
+
+ /// No entry title found.
+ #[error("No entry title found")]
+ NoEntryTitleFound,
+}