//! 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 quick_xml::events::BytesStart; use crate::api_interface_definition::APIInterfaceDefinition; use crate::command::{Command, Error as CommandError}; use crate::deserialization::buffer_deserializer::BufferDeserializer; use crate::deserialization::{Deserialize, Deserializer, DeserializerError, IgnoreEnd}; pub mod api_interface_definition; pub mod command; mod deserialization; /// 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. #[derive(Debug, PartialEq, Eq)] pub struct Registry { commands: Vec, api_interface_definitions: 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 deserializer = BufferDeserializer::new(xml_bytes); deserializer.skip_to_tag_start(REGISTRY_TAG_NAME)?; let registry = deserializer.de_tag::(REGISTRY_TAG_NAME, IgnoreEnd::Yes)?; 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, api_interface_definitions: impl IntoIterator, ) -> Self { Self { commands: commands.into_iter().collect(), api_interface_definitions: api_interface_definitions.into_iter().collect(), } } /// Returns the commands. #[must_use] pub fn commands(&self) -> &[Command] { &self.commands } /// Returns the API interface definitions. #[must_use] pub fn api_interface_definitions(&self) -> &[APIInterfaceDefinition] { &self.api_interface_definitions } } impl Deserialize for Registry { type Error = RegistryError; fn deserialize( _start: &BytesStart, deserializer: &mut TDeserializer, ) -> Result { deserializer.skip_to_tag_start("commands")?; let commands = deserializer.de_tag_with("commands", IgnoreEnd::No, |_, deserializer| { deserializer.de_tag_list::("command") })?; deserializer.skip_to_tag_start("feature")?; let api_interface_definitions = deserializer.de_tag_list::("feature")?; Ok(Self { commands, api_interface_definitions, }) } } /// [`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), /// I/O failed. #[error("I/O failed")] IOFailed(#[from] std::io::Error), /// Deserialization failed. #[error("Deserialization failed")] DeserializationFailed(#[from] DeserializationError), } impl From for RegistryError { fn from(err: DeserializerError) -> Self { DeserializationError(err).into() } } /// Deserialization error. #[derive(Debug, thiserror::Error)] #[error(transparent)] pub struct DeserializationError(#[from] DeserializerError); #[cfg(test)] mod tests { use super::*; #[test] fn registry_works() { let registry = Registry::retrieve().expect("Expected Ok"); for api_interface_def in registry.api_interface_definitions() { println!( "{} - {}", api_interface_def.api_name(), api_interface_def.version() ); println!("Removals:"); for removal in api_interface_def.removals() { for feature in removal.features() { println!(" {:?} - {}", feature.kind(), feature.name()); } } } } }