From 5ab5fafd8f3cab7f82c11e7ad89f8fefd66e911c Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 26 Feb 2023 14:45:20 +0100 Subject: feat: add multiple description support --- src/description.rs | 41 ++++++++++++++++++++++++++++++++++++++--- src/lib.rs | 46 ++++++++++++++++++++++++++-------------------- src/xml/element.rs | 40 ++++++++++++++++++++-------------------- 3 files changed, 84 insertions(+), 43 deletions(-) diff --git a/src/description.rs b/src/description.rs index f536b4f..ccd95b2 100644 --- a/src/description.rs +++ b/src/description.rs @@ -7,16 +7,27 @@ use crate::xml::element::{Elements, FromElements, Tagged}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Description { + for_function: Option, parts: Vec, } impl Description { - /// Returns a new `ReferenceDescription`. + /// Returns a new empty `Description`. #[must_use] pub fn new() -> Self { - Self { parts: Vec::new() } + Self { + for_function: None, + parts: Vec::new(), + } + } + + /// Returns what function this description is specific for. + #[must_use] + pub fn for_function(&self) -> &Option + { + &self.for_function } /// Returns the description's parts. @@ -41,6 +52,27 @@ impl FromElements for Description fn from_elements(elements: &Elements) -> Result { + 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() @@ -61,7 +93,10 @@ impl FromElements for Description }) .collect::, Self::Error>>()?; - Ok(Description { parts }) + Ok(Description { + for_function, + parts, + }) } } diff --git a/src/lib.rs b/src/lib.rs index c0a300b..7a715f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ use std::os::unix::prelude::OsStrExt; use include_dir::{include_dir, Dir}; use crate::description::{Description, Error as DescriptionError}; -use crate::xml::element::{Attribute, Elements, FromElements}; +use crate::xml::element::{Elements, FromElements}; use crate::xml::parser::{Error as ParserError, Parser}; pub mod description; @@ -26,17 +26,20 @@ static GL4_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/OpenGL-Refpages/gl4"); pub struct ReferenceEntry { purpose: String, - description: Description, + descriptions: Vec, } impl ReferenceEntry { /// Returns a new `ReferenceEntry`. - pub fn new(purpose: &impl ToString, description: Description) -> Self + pub fn new( + purpose: &impl ToString, + descriptions: impl IntoIterator, + ) -> Self { Self { purpose: purpose.to_string(), - description, + descriptions: descriptions.into_iter().collect(), } } @@ -106,11 +109,11 @@ impl ReferenceEntry &self.purpose } - /// Returns the reference entry description. + /// Returns the reference entry descriptions. #[must_use] - pub fn description(&self) -> &Description + pub fn descriptions(&self) -> &[Description] { - &self.description + &self.descriptions } } @@ -140,23 +143,26 @@ impl FromElements for ReferenceEntry .cloned() .unwrap_or_default(); - let description_refsect = refentry_element + let description_elements = refentry_element .child_elements() - .get_first_tagged_with_name_and_attr( - "refsect1", - &Attribute { - key: "xml:id".to_string(), - value: b"description".to_vec(), - }, - ) - .ok_or(Self::Error::MissingDescriptionRefSect)?; - - let description = - Description::from_elements(description_refsect.child_elements())?; + .get_all_tagged_with_name_and_attr("refsect1", |attr| { + attr.key == "xml:id" && attr.value.starts_with(b"description") + }); + + if description_elements.is_empty() { + return Err(Self::Error::MissingDescriptionRefSect); + } + + let descriptions = description_elements + .iter() + .map(|description_element| { + Description::from_elements(description_element.child_elements()) + }) + .collect::, _>>()?; Ok(ReferenceEntry { purpose, - description, + descriptions, }) } } diff --git a/src/xml/element.rs b/src/xml/element.rs index b778dac..91e4130 100644 --- a/src/xml/element.rs +++ b/src/xml/element.rs @@ -24,26 +24,6 @@ impl Elements }) } - pub fn get_first_tagged_with_name_and_attr( - &self, - tag_name: &str, - attribute: &Attribute, - ) -> Option<&Tagged> - { - self.elements.iter().find_map(|element| match element { - Element::Tagged(tagged_element) - if tagged_element.name == tag_name - && tagged_element - .attributes - .iter() - .any(|attr| attr == attribute) => - { - Some(tagged_element) - } - _ => None, - }) - } - pub fn get_all_tagged_elements(&self) -> Vec<&Tagged> { self.elements @@ -68,6 +48,26 @@ impl Elements .collect() } + pub fn get_all_tagged_with_name_and_attr( + &self, + tag_name: &str, + attr_is_match: fn(&Attribute) -> bool, + ) -> Vec<&Tagged> + { + self.elements + .iter() + .filter_map(|element| match element { + Element::Tagged(tagged_element) + if tagged_element.name == tag_name + && tagged_element.attributes.iter().any(attr_is_match) => + { + Some(tagged_element) + } + _ => None, + }) + .collect() + } + pub fn get_first_text_element(&self) -> Option<&String> { self.elements.iter().find_map(|element| match element { -- cgit v1.2.3-18-g5258