//! Rust API for the [OpenGL API and Extension Registry]. //! //! # Usage //! ``` //! use opengl_registry::Registry; //! //! let registry = Registry::retrieve().unwrap(); //! //! for command in registry.commands() { //! println!("Command {}", command.prototype().name()); //! println!(" Return type: {}", command.prototype().return_type()); //! println!(" Parameters:"); //! //! for param in command.parameters() { //! println!(" {} {}", param.get_type(), param.name()); //! } //! } //! ``` //! //! [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: &[u8] = include_bytes!("../OpenGL-Registry/xml/gl.xml"); const REGISTRY_TAG_NAME: &str = "registry"; /// Representation of the OpenGL registry. pub struct Registry { commands: Vec, } 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 { Self::retrieve_from_bytes(GL_REGISTRY_XML) } /// 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 { 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 { 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) -> 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 { 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::, _>>()?; 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);