diff options
-rw-r--r-- | src/description.rs | 550 | ||||
-rw-r--r-- | src/description/mod.rs | 98 | ||||
-rw-r--r-- | src/description/part.rs | 104 | ||||
-rw-r--r-- | src/emphasis.rs | 66 | ||||
-rw-r--r-- | src/gloss_list.rs | 4 | ||||
-rw-r--r-- | src/itemized_list.rs | 8 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/paragraph/mod.rs | 61 | ||||
-rw-r--r-- | src/paragraph/part.rs | 247 | ||||
-rw-r--r-- | src/table.rs | 2 | ||||
-rw-r--r-- | src/variable_list.rs | 7 |
11 files changed, 593 insertions, 556 deletions
diff --git a/src/description.rs b/src/description.rs deleted file mode 100644 index d55737d..0000000 --- a/src/description.rs +++ /dev/null @@ -1,550 +0,0 @@ -//! Reference entry description. -use crate::gloss_list::{Error as GlossListError, GlossList}; -use crate::itemized_list::{Error as ItemizedListError, ItemizedList}; -use crate::table::{Error as TableError, Informal, Table}; -use crate::variable_list::{Error as VariableListError, VariableList}; -use crate::xml::element::{Element, Elements, FromElements, Tagged}; - -/// Reference entry description. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Description -{ - for_function: Option<String>, - parts: Vec<Part>, -} - -impl Description -{ - /// Returns a new empty `Description`. - #[must_use] - pub fn new() -> Self - { - Self { - for_function: None, - parts: Vec::new(), - } - } - - /// Returns what function this description is specific for. - #[must_use] - pub fn for_function(&self) -> &Option<String> - { - &self.for_function - } - - /// Returns the description's parts. - #[must_use] - pub fn parts(&self) -> &[Part] - { - &self.parts - } -} - -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 for_function = - elements - .get_first_tagged_with_name("title") - .and_then(|title_element| { - let title_text = - title_element.child_elements().get_first_text_element()?; - - if title_text != "Description for " { - return None; - } - - let function_element = title_element - .child_elements() - .get_first_tagged_with_name("function")?; - - function_element - .child_elements() - .get_first_text_element() - .cloned() - }); - - let parts = elements - .get_all_tagged_elements() - .into_iter() - .filter_map(|part_elem| match part_elem.name() { - "para" => Some( - Paragraph::from_elements(part_elem.child_elements()) - .map(Part::Paragraph) - .map_err(Self::Error::InvalidParagraph), - ), - - "variablelist" => Some( - VariableList::from_elements(part_elem.child_elements()) - .map(Part::VariableList) - .map_err(Self::Error::InvalidVariableList), - ), - "programlisting" => Some(Ok(Part::ProgramListing( - part_elem - .child_elements() - .get_first_text_element() - .cloned() - .unwrap_or_default(), - ))), - "informaltable" => Some( - Informal::from_elements(part_elem.child_elements()) - .map(Part::InformalTable) - .map_err(Self::Error::InvalidInformalTable), - ), - "itemizedlist" => Some( - ItemizedList::from_elements(part_elem.child_elements()) - .map(Part::ItemizedList) - .map_err(Self::Error::InvalidItemizedList), - ), - "table" => Some( - Table::from_elements(part_elem.child_elements()) - .map(Part::Table) - .map_err(Self::Error::InvalidTable), - ), - "glosslist" => Some( - GlossList::from_elements(part_elem.child_elements()) - .map(Part::GlossList) - .map_err(Self::Error::InvalidGlossList), - ), - "title" => None, - name => Some(Err(Self::Error::UnknownPartFound(name.to_string()))), - }) - .collect::<Result<Vec<_>, Self::Error>>()?; - - Ok(Description { - for_function, - parts, - }) - } -} - -/// [`Description`] error. -#[derive(Debug, thiserror::Error)] -pub enum Error -{ - /// Unknown part element found. - #[error("Unknown part element with name '{0}' found")] - UnknownPartFound(String), - - /// Invalid paragraph. - #[error("Invalid paragraph")] - InvalidParagraph(#[source] ParagraphError), - - /// Invalid variable list. - #[error("Invalid variable list")] - InvalidVariableList(#[source] VariableListError), - - /// Invalid informal table. - #[error("Invalid informal table")] - InvalidInformalTable(#[source] TableError), - - /// Invalid itemized list. - #[error("Invalid itemized list")] - InvalidItemizedList(#[source] ItemizedListError), - - /// Invalid table. - #[error("Invalid table")] - InvalidTable(#[source] TableError), - - /// Invalid gloss list. - #[error("Invalid gloss list")] - InvalidGlossList(#[source] GlossListError), -} - -/// Description part. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum Part -{ - /// Paragraph. - Paragraph(Paragraph), - - /// Variable list. - VariableList(VariableList), - - /// Program listing. - ProgramListing(String), - - /// Informal table. - InformalTable(Informal), - - /// Itemized list. - ItemizedList(ItemizedList), - - /// Table. - Table(Table), - - /// Gloss list. - GlossList(GlossList), -} - -/// Reference entry description paragraph. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Paragraph -{ - parts: Vec<ParagraphPart>, -} - -impl Paragraph -{ - /// Returns a new `Paragraph`. - pub fn new(parts: impl IntoIterator<Item = ParagraphPart>) -> Self - { - Self { - parts: parts.into_iter().collect(), - } - } - - /// 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() - .filter_map(|element| { - if matches!(element, Element::Comment(_)) { - return None; - } - - Some(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), -} - -/// Reference entry description paragraph part. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ParagraphPart -{ - /// Text part. - Text(String), - - /// <constant>..</constant> part. - Constant(String), - - /// <function>..</function> part. - Function(String), - - /// <parameter>..</parameter> part. - Parameter(String), - - /// Emphasis part. - Emphasis(Emphasis), - - /// Code part. - Code(String), - - /// Inline equation part. - InlineEquation(String), - - /// Program listing part. - ProgramListing(String), - - /// Reference entry citation part. - Entry(String), - - /// Variable list part. - VariableList(VariableList), - - /// Itemized list part. - ItemizedList(ItemizedList), - - /// Informal table part. - InformalTable(Informal), - - /// Paragraph part. - Paragraph(Paragraph), - - /// Footnote part. - Footnote(Paragraph), - - /// Table part. - Table(Table), - - /// Informal equation part. - InformalEquation(String), - - /// Superscript part. - Superscript(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::ExpectedTextElement)?; - - 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, - "code" => Self::Code, - "inlineequation" => Self::InlineEquation, - "programlisting" => Self::ProgramListing, - "citerefentry" => Self::Entry, - "superscript" => Self::Superscript, - "variablelist" | "itemizedlist" | "informaltable" | "para" | "footnote" - | "table" | "informalequation" | "emphasis" => |_| { - unreachable!(); - }, - _ => { - 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())); - } - - if tagged_element.name() == "variablelist" { - let variable_list = - VariableList::from_elements(tagged_element.child_elements())?; - - 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)); - } - - if tagged_element.name() == "informaltable" { - let informal_table = Informal::from_elements(tagged_element.child_elements()) - .map_err(|err| ParagraphPartError::InvalidInformalTable(Box::new(err)))?; - - return Ok(Self::InformalTable(informal_table)); - } - - if tagged_element.name() == "inlineequation" { - return Ok(Self::InlineEquation( - tagged_element - .child_elements() - .into_iter() - .map(ToString::to_string) - .collect::<String>(), - )); - } - - if tagged_element.name() == "para" { - return Ok(Self::Paragraph( - Paragraph::from_elements(tagged_element.child_elements()) - .map_err(|err| ParagraphPartError::InvalidParagraph(Box::new(err)))?, - )); - } - - if tagged_element.name() == "footnote" { - return Ok(Self::Footnote( - Paragraph::from_elements(tagged_element.child_elements()) - .map_err(|err| ParagraphPartError::InvalidFootnote(Box::new(err)))?, - )); - } - - if tagged_element.name() == "table" { - let table = Table::from_elements(tagged_element.child_elements()) - .map_err(|err| ParagraphPartError::InvalidInformalTable(Box::new(err)))?; - - return Ok(Self::Table(table)); - } - - if tagged_element.name() == "informalequation" { - return Ok(Self::InlineEquation( - tagged_element - .child_elements() - .into_iter() - .map(ToString::to_string) - .collect::<String>(), - )); - } - - if tagged_element.name() == "emphasis" { - return Ok(Self::Emphasis(Emphasis::from_tagged_element( - tagged_element, - )?)); - } - - 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 -{ - /// Expected a text element. - #[error("Expected a text element")] - ExpectedTextElement, - - /// A input element is a unknown paragraph part. - #[error("Input element with name '{0}' is a unknown paragraph 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, - - /// Invalid variable list. - #[error("Invalid variable list")] - InvalidVariableList(#[from] VariableListError), - - /// Invalid itemized list. - #[error("Invalid itemized list")] - InvalidItemizedList(#[from] ItemizedListError), - - /// Invalid informal table. - #[error("Invalid informal table")] - InvalidInformalTable(#[source] Box<TableError>), - - /// Invalid paragraph. - #[error("Invalid paragraph")] - InvalidParagraph(#[source] Box<ParagraphError>), - - /// Invalid footnote. - #[error("Invalid footnote")] - InvalidFootnote(#[source] Box<ParagraphError>), - - /// Invalid table. - #[error("Invalid table")] - InvalidTable(#[source] Box<TableError>), - - /// Invalid emphasis. - #[error("Invalid emphasis")] - InvalidEmphasis(#[from] EmphasisError), -} - -/// Emphasis. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Emphasis -{ - /// The emphasised text. - pub text: String, - - /// Emphasis role. - pub role: EmphasisRole, -} - -impl Emphasis -{ - fn from_tagged_element(tagged_element: &Tagged) -> Result<Self, EmphasisError> - { - return Ok(Emphasis { - text: tagged_element - .child_elements() - .get_first_text_element() - .cloned() - .unwrap_or_default(), - role: tagged_element - .attributes() - .iter() - .find(|attr| attr.key == "role") - .map(|attr| { - let value = String::from_utf8(attr.value.clone()) - .map_err(|_| EmphasisError::EmphasisRoleNotUTF8)?; - - if value == "bold" { - return Ok(EmphasisRole::Bold); - } - - Err(EmphasisError::UnknownEmphasisRole(value)) - }) - .unwrap_or(Ok(EmphasisRole::None))?, - }); - } -} - -/// [`Emphasis`] error. -#[derive(Debug, thiserror::Error)] -pub enum EmphasisError -{ - /// Emphasis role is not valid UTF-8. - #[error("Emphasis role is not valid UTF-8")] - EmphasisRoleNotUTF8, - - /// Unknown emphasis role. - #[error("Unknown emphasis role '{0}'")] - UnknownEmphasisRole(String), -} - -/// Emphasis role. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum EmphasisRole -{ - /// Bold. - Bold, - - /// None. - None, -} diff --git a/src/description/mod.rs b/src/description/mod.rs new file mode 100644 index 0000000..a87c1cf --- /dev/null +++ b/src/description/mod.rs @@ -0,0 +1,98 @@ +//! Reference entry description. +use crate::xml::element::{Elements, FromElements}; + +mod part; + +pub use part::{Error as PartError, Part}; + +/// Reference entry description. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Description +{ + for_function: Option<String>, + parts: Vec<Part>, +} + +impl Description +{ + /// Returns a new empty `Description`. + #[must_use] + pub fn new() -> Self + { + Self { + for_function: None, + parts: Vec::new(), + } + } + + /// Returns what function this description is specific for. + #[must_use] + pub fn for_function(&self) -> &Option<String> + { + &self.for_function + } + + /// Returns the description's parts. + #[must_use] + pub fn parts(&self) -> &[Part] + { + &self.parts + } +} + +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 for_function = + elements + .get_first_tagged_with_name("title") + .and_then(|title_element| { + let title_text = + title_element.child_elements().get_first_text_element()?; + + if title_text != "Description for " { + return None; + } + + let function_element = title_element + .child_elements() + .get_first_tagged_with_name("function")?; + + function_element + .child_elements() + .get_first_text_element() + .cloned() + }); + + let parts = elements + .get_all_tagged_elements() + .into_iter() + .map(Part::from_tagged_element) + .collect::<Result<Vec<_>, _>>()?; + + Ok(Description { + for_function, + parts, + }) + } +} + +/// [`Description`] error. +#[derive(Debug, thiserror::Error)] +pub enum Error +{ + /// Invalid description part. + #[error("Invalid description part")] + InvalidPart(#[from] PartError), +} diff --git a/src/description/part.rs b/src/description/part.rs new file mode 100644 index 0000000..2f1771f --- /dev/null +++ b/src/description/part.rs @@ -0,0 +1,104 @@ +use crate::gloss_list::{Error as GlossListError, GlossList}; +use crate::itemized_list::{Error as ItemizedListError, ItemizedList}; +use crate::paragraph::{Error as ParagraphError, Paragraph}; +use crate::table::{Error as TableError, Informal, Table}; +use crate::variable_list::{Error as VariableListError, VariableList}; +use crate::xml::element::{FromElements, Tagged}; + +/// Description part. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Part +{ + /// Paragraph. + Paragraph(Paragraph), + + /// Variable list. + VariableList(VariableList), + + /// Program listing. + ProgramListing(String), + + /// Informal table. + InformalTable(Informal), + + /// Itemized list. + ItemizedList(ItemizedList), + + /// Table. + Table(Table), + + /// Gloss list. + GlossList(GlossList), +} + +impl Part +{ + pub(crate) fn from_tagged_element(tagged_element: &Tagged) -> Result<Self, Error> + { + match tagged_element.name() { + "para" => Paragraph::from_elements(tagged_element.child_elements()) + .map(Part::Paragraph) + .map_err(Error::InvalidParagraph), + "variablelist" => { + VariableList::from_elements(tagged_element.child_elements()) + .map(Part::VariableList) + .map_err(Error::InvalidVariableList) + } + "programlisting" => Ok(Part::ProgramListing( + tagged_element + .child_elements() + .get_first_text_element() + .cloned() + .unwrap_or_default(), + )), + "informaltable" => Informal::from_elements(tagged_element.child_elements()) + .map(Part::InformalTable) + .map_err(Error::InvalidInformalTable), + "itemizedlist" => { + ItemizedList::from_elements(tagged_element.child_elements()) + .map(Part::ItemizedList) + .map_err(Error::InvalidItemizedList) + } + "table" => Table::from_elements(tagged_element.child_elements()) + .map(Part::Table) + .map_err(Error::InvalidTable), + "glosslist" => GlossList::from_elements(tagged_element.child_elements()) + .map(Part::GlossList) + .map_err(Error::InvalidGlossList), + name => Err(Error::Unknown(name.to_string())), + } + } +} + +/// [`Part`] error. +#[derive(Debug, thiserror::Error)] +pub enum Error +{ + /// Unknown description part. + #[error("Unknown description part '{0}'")] + Unknown(String), + + /// Invalid paragraph. + #[error("Invalid paragraph")] + InvalidParagraph(#[source] ParagraphError), + + /// Invalid variable list. + #[error("Invalid variable list")] + InvalidVariableList(#[source] VariableListError), + + /// Invalid informal table. + #[error("Invalid informal table")] + InvalidInformalTable(#[source] TableError), + + /// Invalid itemized list. + #[error("Invalid itemized list")] + InvalidItemizedList(#[source] ItemizedListError), + + /// Invalid table. + #[error("Invalid table")] + InvalidTable(#[source] TableError), + + /// Invalid gloss list. + #[error("Invalid gloss list")] + InvalidGlossList(#[source] GlossListError), +} diff --git a/src/emphasis.rs b/src/emphasis.rs new file mode 100644 index 0000000..12502ad --- /dev/null +++ b/src/emphasis.rs @@ -0,0 +1,66 @@ +//! Emphasis. +use crate::xml::element::Tagged; + +/// Emphasis. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Emphasis +{ + /// The emphasised text. + pub text: String, + + /// Emphasis role. + pub role: Role, +} + +impl Emphasis +{ + pub(crate) fn from_tagged_element(tagged_element: &Tagged) -> Result<Self, Error> + { + return Ok(Emphasis { + text: tagged_element + .child_elements() + .get_first_text_element() + .cloned() + .unwrap_or_default(), + role: tagged_element + .attributes() + .iter() + .find(|attr| attr.key == "role") + .map(|attr| { + let value = String::from_utf8(attr.value.clone()) + .map_err(|_| Error::EmphasisRoleNotUTF8)?; + + if value == "bold" { + return Ok(Role::Bold); + } + + Err(Error::UnknownEmphasisRole(value)) + }) + .unwrap_or(Ok(Role::None))?, + }); + } +} + +/// [`Emphasis`] error. +#[derive(Debug, thiserror::Error)] +pub enum Error +{ + /// Emphasis role is not valid UTF-8. + #[error("Emphasis role is not valid UTF-8")] + EmphasisRoleNotUTF8, + + /// Unknown emphasis role. + #[error("Unknown emphasis role '{0}'")] + UnknownEmphasisRole(String), +} + +/// Emphasis role. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Role +{ + /// Bold. + Bold, + + /// None. + None, +} diff --git a/src/gloss_list.rs b/src/gloss_list.rs index 74cf6f1..1b4febb 100644 --- a/src/gloss_list.rs +++ b/src/gloss_list.rs @@ -1,5 +1,5 @@ //! Gloss list. -use crate::description::{Paragraph, ParagraphError}; +use crate::paragraph::{Error as ParagraphError, Paragraph}; use crate::xml::element::{Element, FromElements}; /// Gloss list. @@ -150,7 +150,7 @@ mod tests use pretty_assertions::assert_str_eq; use super::*; - use crate::description::ParagraphPart; + use crate::paragraph::Part as ParagraphPart; use crate::xml::element::{Element, Elements, Tagged}; #[test] diff --git a/src/itemized_list.rs b/src/itemized_list.rs index efe43b5..36a2252 100644 --- a/src/itemized_list.rs +++ b/src/itemized_list.rs @@ -1,5 +1,9 @@ //! Itemized list. -use crate::description::{Paragraph, ParagraphError, ParagraphPartError}; +use crate::paragraph::{ + Error as ParagraphError, + Paragraph, + PartError as ParagraphPartError, +}; use crate::xml::element::{Element, FromElements}; /// Itemized list. @@ -128,7 +132,7 @@ pub enum ItemError mod tests { use super::*; - use crate::description::ParagraphPart; + use crate::paragraph::Part as ParagraphPart; use crate::xml::element::{Element, Elements, Tagged}; #[test] @@ -14,8 +14,10 @@ use crate::xml::element::{Elements, FromElements}; use crate::xml::parser::{Error as ParserError, Parser}; pub mod description; +pub mod emphasis; pub mod gloss_list; pub mod itemized_list; +pub mod paragraph; pub mod table; pub mod variable_list; diff --git a/src/paragraph/mod.rs b/src/paragraph/mod.rs new file mode 100644 index 0000000..32ab429 --- /dev/null +++ b/src/paragraph/mod.rs @@ -0,0 +1,61 @@ +//! Paragraph. +use crate::xml::element::{Element, Elements, FromElements}; + +mod part; + +pub use part::{Error as PartError, Part}; + +/// A paragraph. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Paragraph +{ + parts: Vec<Part>, +} + +impl Paragraph +{ + /// Returns a new `Paragraph`. + pub fn new(parts: impl IntoIterator<Item = Part>) -> Self + { + Self { + parts: parts.into_iter().collect(), + } + } + + /// Returns the parts of the paragraph. + #[must_use] + pub fn parts(&self) -> &[Part] + { + &self.parts + } +} + +impl FromElements for Paragraph +{ + type Error = Error; + + fn from_elements(elements: &Elements) -> Result<Self, Self::Error> + { + let parts = elements + .into_iter() + .filter_map(|element| { + if matches!(element, Element::Comment(_)) { + return None; + } + + Some(Part::from_elements(&Elements::from([element.clone()]))) + }) + .collect::<Result<Vec<_>, _>>()?; + + Ok(Self { parts }) + } +} + +/// [`Paragraph`] error. +#[derive(Debug, thiserror::Error)] +pub enum Error +{ + /// Invalid reference description part. + #[error("Invalid part")] + InvalidPart(#[from] PartError), +} diff --git a/src/paragraph/part.rs b/src/paragraph/part.rs new file mode 100644 index 0000000..5e5a846 --- /dev/null +++ b/src/paragraph/part.rs @@ -0,0 +1,247 @@ +use crate::emphasis::{Emphasis, Error as EmphasisError}; +use crate::itemized_list::{Error as ItemizedListError, ItemizedList}; +use crate::paragraph::{Error as ParagraphError, Paragraph}; +use crate::table::{Error as TableError, Informal as InformalTable, Table}; +use crate::variable_list::{Error as VariableListError, VariableList}; +use crate::xml::element::{Elements, FromElements, Tagged}; + +/// Paragraph part. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Part +{ + /// Text part. + Text(String), + + /// <constant>..</constant> part. + Constant(String), + + /// <function>..</function> part. + Function(String), + + /// <parameter>..</parameter> part. + Parameter(String), + + /// Emphasis part. + Emphasis(Emphasis), + + /// Code part. + Code(String), + + /// Inline equation part. + InlineEquation(String), + + /// Program listing part. + ProgramListing(String), + + /// Reference entry citation part. + Entry(String), + + /// Variable list part. + VariableList(VariableList), + + /// Itemized list part. + ItemizedList(ItemizedList), + + /// Informal table part. + InformalTable(InformalTable), + + /// Paragraph part. + Paragraph(Paragraph), + + /// Footnote part. + Footnote(Paragraph), + + /// Table part. + Table(Table), + + /// Informal equation part. + InformalEquation(String), + + /// Superscript part. + Superscript(String), +} + +impl FromElements for Part +{ + type Error = Error; + + 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::ExpectedTextElement)?; + + Ok(Self::Text(text.clone())) + } +} + +impl Part +{ + 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, + "code" => Self::Code, + "inlineequation" => Self::InlineEquation, + "programlisting" => Self::ProgramListing, + "citerefentry" => Self::Entry, + "superscript" => Self::Superscript, + "variablelist" | "itemizedlist" | "informaltable" | "para" | "footnote" + | "table" | "informalequation" | "emphasis" => |_| { + unreachable!(); + }, + _ => { + 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())); + } + + if tagged_element.name() == "variablelist" { + let variable_list = + VariableList::from_elements(tagged_element.child_elements())?; + + 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)); + } + + if tagged_element.name() == "informaltable" { + let informal_table = + InformalTable::from_elements(tagged_element.child_elements()) + .map_err(|err| Error::InvalidInformalTable(Box::new(err)))?; + + return Ok(Self::InformalTable(informal_table)); + } + + if tagged_element.name() == "inlineequation" { + return Ok(Self::InlineEquation( + tagged_element + .child_elements() + .into_iter() + .map(ToString::to_string) + .collect::<String>(), + )); + } + + if tagged_element.name() == "para" { + return Ok(Self::Paragraph( + Paragraph::from_elements(tagged_element.child_elements()) + .map_err(|err| Error::InvalidParagraph(Box::new(err)))?, + )); + } + + if tagged_element.name() == "footnote" { + return Ok(Self::Footnote( + Paragraph::from_elements(tagged_element.child_elements()) + .map_err(|err| Error::InvalidFootnote(Box::new(err)))?, + )); + } + + if tagged_element.name() == "table" { + let table = Table::from_elements(tagged_element.child_elements()) + .map_err(|err| Error::InvalidInformalTable(Box::new(err)))?; + + return Ok(Self::Table(table)); + } + + if tagged_element.name() == "informalequation" { + return Ok(Self::InlineEquation( + tagged_element + .child_elements() + .into_iter() + .map(ToString::to_string) + .collect::<String>(), + )); + } + + if tagged_element.name() == "emphasis" { + return Ok(Self::Emphasis(Emphasis::from_tagged_element( + tagged_element, + )?)); + } + + let text_element = tagged_element + .child_elements() + .get_first_text_element() + .ok_or(<Self as FromElements>::Error::NoTextInTagged)?; + + Ok(create(text_element.clone())) + } +} + +/// [`Part`] error. +#[derive(Debug, thiserror::Error)] +pub enum Error +{ + /// Expected a text element. + #[error("Expected a text element")] + ExpectedTextElement, + + /// A input element is a unknown paragraph part. + #[error("Input element with name '{0}' is a unknown paragraph 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, + + /// Invalid variable list. + #[error("Invalid variable list")] + InvalidVariableList(#[from] VariableListError), + + /// Invalid itemized list. + #[error("Invalid itemized list")] + InvalidItemizedList(#[from] ItemizedListError), + + /// Invalid informal table. + #[error("Invalid informal table")] + InvalidInformalTable(#[source] Box<TableError>), + + /// Invalid paragraph. + #[error("Invalid paragraph")] + InvalidParagraph(#[source] Box<ParagraphError>), + + /// Invalid footnote. + #[error("Invalid footnote")] + InvalidFootnote(#[source] Box<ParagraphError>), + + /// Invalid table. + #[error("Invalid table")] + InvalidTable(#[source] Box<TableError>), + + /// Invalid emphasis. + #[error("Invalid emphasis")] + InvalidEmphasis(#[from] EmphasisError), +} diff --git a/src/table.rs b/src/table.rs index b549b95..e3ddd3d 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,5 +1,5 @@ //! Tables. -use crate::description::{Paragraph, ParagraphError}; +use crate::paragraph::{Error as ParagraphError, Paragraph}; use crate::xml::element::{Elements, FromElements, Tagged}; /// Informal table. diff --git a/src/variable_list.rs b/src/variable_list.rs index 2c839f0..4b8cc65 100644 --- a/src/variable_list.rs +++ b/src/variable_list.rs @@ -1,6 +1,11 @@ //! Variable list. -use crate::description::{Paragraph, ParagraphError, ParagraphPart, ParagraphPartError}; +use crate::paragraph::{ + Error as ParagraphError, + Paragraph, + Part as ParagraphPart, + PartError as ParagraphPartError, +}; use crate::xml::element::{Element, FromElements}; /// Variable list. |