summaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs158
1 files changed, 158 insertions, 0 deletions
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<Self, ReferenceEntryError>
+ {
+ 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<Self, Self::Error>
+ {
+ 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),
+}