diff options
author | HampusM <hampus@hampusmat.com> | 2023-02-19 13:49:41 +0100 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2023-02-19 18:27:23 +0100 |
commit | 7c5bec7db2a2fc8c796d5f31bdeb03da0946133d (patch) | |
tree | 7c80fa13c3aae658e63d9d6ae553593ebd7a93be /src/lib.rs | |
parent | 46c316bd9665cdc6026ccd2a4119e4c46778b65b (diff) |
feat: add project & registry parsing /w commands
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..45f9fc9 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,158 @@ +//! Rust API for the [OpenGL API and Extension Registry]. +//! +//! [OpenGL API and Extension Registry]: https://github.com/KhronosGroup/OpenGL-Registry +#![cfg_attr(doc_cfg, feature(doc_cfg))] +#![deny(clippy::all, clippy::pedantic, missing_docs)] + +use std::fs::File; +use std::io::Read; + +use crate::command::{Command, Error as CommandError}; +use crate::xml::element::{Element, Elements, FromElements}; +use crate::xml::parser::{Error as ParserError, Parser}; + +pub mod command; + +mod xml; + +#[cfg(feature = "include-xml")] +const GL_REGISTRY_XML: &str = include_str!("../OpenGL-Registry/xml/gl.xml"); + +const REGISTRY_TAG_NAME: &str = "registry"; + +/// Representation of the OpenGL registry. +pub struct Registry +{ + commands: Vec<Command>, +} + +impl Registry +{ + /// Retrieves the OpenGL registry from a included XML file. + /// + /// # Errors + /// Returns `Err` if parsing fails in any way. + #[cfg(feature = "include-xml")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "include-xml")))] + pub fn retrieve() -> Result<Registry, RegistryError> + { + Self::retrieve_from_bytes(GL_REGISTRY_XML.as_bytes()) + } + + /// Retrieves the OpenGL registry from XML bytes. + /// + /// # Errors + /// Returns `Err` if parsing fails in any way. + pub fn retrieve_from_bytes(xml_bytes: &[u8]) -> Result<Registry, RegistryError> + { + let mut parser = Parser::new(xml_bytes); + + let elements = parser.parse().map_err(ParsingError)?; + + let registry_element = elements + .get_first_tagged_element(REGISTRY_TAG_NAME) + .ok_or(RegistryError::MissingRegistryElement)?; + + let registry = Registry::from_elements(registry_element.child_elements())?; + + Ok(registry) + } + + /// Retrieves the OpenGL registry from a XML file. + /// + /// # Errors + /// Returns `Err` if: + /// - Parsing fails in any way. + /// - An I/O error occurs. + pub fn retrieve_from_file(xml_file: &mut File) -> Result<Registry, RegistryError> + { + let mut buf = Vec::new(); + + xml_file.read_to_end(&mut buf)?; + + Self::retrieve_from_bytes(&buf) + } + + /// Creates a new `Registry`. + /// + /// # Note + /// This will **NOT** use anything from the actual OpenGL registry. Use the + /// [`Registry::retrieve`] method for that. + pub fn new(commands: impl IntoIterator<Item = Command>) -> Self + { + Self { + commands: commands.into_iter().collect(), + } + } + + /// Returns the available commands. + #[must_use] + pub fn commands(&self) -> &[Command] + { + &self.commands + } +} + +impl FromElements for Registry +{ + type Error = RegistryError; + + fn from_elements(elements: &Elements) -> Result<Self, Self::Error> + { + let commands_element = elements + .get_first_tagged_element("commands") + .ok_or(Self::Error::MissingCommandsElement)?; + + let command_elements = + commands_element + .child_elements() + .into_iter() + .filter_map(|element| match element { + Element::Tagged(tagged_element) + if tagged_element.name() == "command" => + { + Some(tagged_element) + } + _ => None, + }); + + let commands = command_elements + .into_iter() + .map(|command_element| { + Command::from_elements(command_element.child_elements()) + }) + .collect::<Result<Vec<_>, _>>()?; + + Ok(Self { commands }) + } +} + +/// [`Registry`] error. +#[derive(Debug, thiserror::Error)] +pub enum RegistryError +{ + /// No 'registry' element was found. + #[error("No 'registry' element was found")] + MissingRegistryElement, + + /// No 'commands' element was found. + #[error("No 'commands' element was found")] + MissingCommandsElement, + + /// A command is invalid. + #[error("Invalid command")] + InvalidCommand(#[from] CommandError), + + /// Parsing failed. + #[error("Parsing failed")] + ParsingFailed(#[from] ParsingError), + + /// I/O failed. + #[error("I/O failed")] + IOFailed(#[from] std::io::Error), +} + +/// Parsing error. +#[derive(Debug, thiserror::Error)] +#[error(transparent)] +pub struct ParsingError(#[from] ParserError); |