From 11c39d50411a747eedac4c6a16fedf598ae798f5 Mon Sep 17 00:00:00 2001 From: HampusM Date: Thu, 23 Feb 2023 22:35:06 +0100 Subject: feat: add project & getting function entries --- src/lib.rs | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 src/lib.rs (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..8e9e1e7 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,158 @@ +//! Rust API for the [OpenGL reference page sources]. +//! +//! [OpenGL reference page sources]: https://github.com/KhronosGroup/OpenGL-Refpages +#![cfg_attr(doc_cfg, feature(doc_cfg))] +#![deny(clippy::all, clippy::pedantic, missing_docs)] + +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::parser::{Error as ParserError, Parser}; + +pub mod description; + +mod util; +mod xml; + +static GL4_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/OpenGL-Refpages/gl4"); + +/// Reference entry. +#[derive(Debug)] +pub struct ReferenceEntry +{ + purpose: String, + description: Description, +} + +impl ReferenceEntry +{ + /// Returns a function reference entry. + /// + /// # Errors + /// Returns `Err` if + /// - No reference entry file was found. + /// - Parsing the reference entry file data fails. + /// - The reference entry file data is invalid. + pub fn get_function(function_name: &str) -> Result + { + let function_file = GL4_DIR + .files() + .find_map(|file| { + if file.path().extension()?.as_bytes() != b"xml" { + return None; + } + + if function_name.starts_with(file.path().file_stem()?.to_str()?) { + Some(file) + } else { + None + } + }) + .ok_or_else(|| ReferenceEntryError::NoFileFound(function_name.to_string()))?; + + let function_ref_content = function_file.contents(); + + let mut parser = Parser::new(function_ref_content); + + let root_elements = parser.parse()?; + + ReferenceEntry::from_elements(&root_elements) + } + + /// Returns the reference entry purpose. + #[must_use] + pub fn purpose(&self) -> &str + { + &self.purpose + } + + /// Returns the reference entry description. + #[must_use] + pub fn description(&self) -> &Description + { + &self.description + } +} + +impl FromElements for ReferenceEntry +{ + type Error = ReferenceEntryError; + + fn from_elements(elements: &Elements) -> Result + { + let refentry_element = elements + .get_first_tagged_with_name("refentry") + .ok_or(ReferenceEntryError::MissingRefEntry)?; + + let refnamediv_element = refentry_element + .child_elements() + .get_first_tagged_with_name("refnamediv") + .ok_or(ReferenceEntryError::MissingRefNameDiv)?; + + let refpurpose_element = refnamediv_element + .child_elements() + .get_first_tagged_with_name("refpurpose") + .ok_or(ReferenceEntryError::MissingRefPurpose)?; + + let purpose = refpurpose_element + .child_elements() + .get_first_text_element() + .cloned() + .unwrap_or_default(); + + let description_refsect = 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(ReferenceEntryError::MissingDescriptionRefSect)?; + + let description = + Description::from_elements(description_refsect.child_elements())?; + + Ok(ReferenceEntry { + purpose, + description, + }) + } +} + +/// [`ReferenceEntry`] error. +#[derive(Debug, thiserror::Error)] +pub enum ReferenceEntryError +{ + /// No reference entry file was found. + #[error("No reference entry file was found for '{0}'")] + NoFileFound(String), + + /// No 'refentry' element was found. + #[error("No 'refentry' element was found")] + MissingRefEntry, + + /// No 'refnamediv' element was found. + #[error("No 'refnamediv' element was found")] + MissingRefNameDiv, + + /// No 'refpurpose' element was found. + #[error("No 'refpurpose' element was found")] + MissingRefPurpose, + + /// No 'refsect1' element was found with id 'description''. + #[error("No 'refsect1' element was found with id 'description'")] + MissingDescriptionRefSect, + + /// Invalid description. + #[error("Invalid description")] + InvalidDescription(#[from] DescriptionError), + + /// Parsing failed. + #[error("Parsing failed")] + ParsingFailed(#[from] ParserError), +} -- cgit v1.2.3-18-g5258