1#![cfg_attr(doc_cfg, feature(doc_cfg))]
22#![deny(clippy::all, clippy::pedantic, missing_docs)]
23
24use std::fs::File;
25use std::io::Read;
26
27use crate::command::{Command, Error as CommandError};
28use crate::xml::element::{Element, Elements, FromElements};
29use crate::xml::parser::{Error as ParserError, Parser};
30
31pub mod command;
32
33mod xml;
34
35#[cfg(feature = "include-xml")]
36const GL_REGISTRY_XML: &str = include_str!("../OpenGL-Registry/xml/gl.xml");
37
38const REGISTRY_TAG_NAME: &str = "registry";
39
40pub struct Registry
42{
43 commands: Vec<Command>,
44}
45
46impl Registry
47{
48 #[cfg(feature = "include-xml")]
53 #[cfg_attr(doc_cfg, doc(cfg(feature = "include-xml")))]
54 pub fn retrieve() -> Result<Registry, RegistryError>
55 {
56 Self::retrieve_from_bytes(GL_REGISTRY_XML.as_bytes())
57 }
58
59 pub fn retrieve_from_bytes(xml_bytes: &[u8]) -> Result<Registry, RegistryError>
64 {
65 let mut parser = Parser::new(xml_bytes);
66
67 let elements = parser.parse().map_err(ParsingError)?;
68
69 let registry_element = elements
70 .get_first_tagged_element(REGISTRY_TAG_NAME)
71 .ok_or(RegistryError::MissingRegistryElement)?;
72
73 let registry = Registry::from_elements(registry_element.child_elements())?;
74
75 Ok(registry)
76 }
77
78 pub fn retrieve_from_file(xml_file: &mut File) -> Result<Registry, RegistryError>
85 {
86 let mut buf = Vec::new();
87
88 xml_file.read_to_end(&mut buf)?;
89
90 Self::retrieve_from_bytes(&buf)
91 }
92
93 pub fn new(commands: impl IntoIterator<Item = Command>) -> Self
99 {
100 Self {
101 commands: commands.into_iter().collect(),
102 }
103 }
104
105 #[must_use]
107 pub fn commands(&self) -> &[Command]
108 {
109 &self.commands
110 }
111}
112
113impl FromElements for Registry
114{
115 type Error = RegistryError;
116
117 fn from_elements(elements: &Elements) -> Result<Self, Self::Error>
118 {
119 let commands_element = elements
120 .get_first_tagged_element("commands")
121 .ok_or(Self::Error::MissingCommandsElement)?;
122
123 let command_elements =
124 commands_element
125 .child_elements()
126 .into_iter()
127 .filter_map(|element| match element {
128 Element::Tagged(tagged_element)
129 if tagged_element.name() == "command" =>
130 {
131 Some(tagged_element)
132 }
133 _ => None,
134 });
135
136 let commands = command_elements
137 .into_iter()
138 .map(|command_element| {
139 Command::from_elements(command_element.child_elements())
140 })
141 .collect::<Result<Vec<_>, _>>()?;
142
143 Ok(Self { commands })
144 }
145}
146
147#[derive(Debug, thiserror::Error)]
149pub enum RegistryError
150{
151 #[error("No 'registry' element was found")]
153 MissingRegistryElement,
154
155 #[error("No 'commands' element was found")]
157 MissingCommandsElement,
158
159 #[error("Invalid command")]
161 InvalidCommand(#[from] CommandError),
162
163 #[error("Parsing failed")]
165 ParsingFailed(#[from] ParsingError),
166
167 #[error("I/O failed")]
169 IOFailed(#[from] std::io::Error),
170}
171
172#[derive(Debug, thiserror::Error)]
174#[error(transparent)]
175pub struct ParsingError(#[from] ParserError);