aboutsummaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2023-02-19 13:49:41 +0100
committerHampusM <hampus@hampusmat.com>2023-02-19 18:27:23 +0100
commit7c5bec7db2a2fc8c796d5f31bdeb03da0946133d (patch)
tree7c80fa13c3aae658e63d9d6ae553593ebd7a93be /src/lib.rs
parent46c316bd9665cdc6026ccd2a4119e4c46778b65b (diff)
feat: add project & registry parsing /w commands
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..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);