Skip to content
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
gl_generator: Make lookups more robust based on unstripped name
By stripping and later appending a *possible* prefix for enum constants
and command names we're not only spending a lot of CPU and human
cycles (because this logic is impossible to understand), we're also
loosing out on a few WGL commands that weren't prefixed with the
`wgl` name.  Conveniently these functions were referencing a typo'd
`PIXELFORMATDESCRIPTOR` without leading `P`, which might otherwise not
have been found.

Do this by keeping all commands and enums keyed by their full name
in `BTreeMap`s so that we can also track completely accurately when a
`<delete>` or `<require>` would erroneously specify a name that doesn't
exist.
  • Loading branch information
MarijnS95 committed Aug 8, 2025
commit bcef576f0b97b9404fa771c0c084e18e68447d14
89 changes: 49 additions & 40 deletions gl_generator/registry/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,8 @@ trait Parse: Sized + Iterator<Item = ParseEvent> {
fn parse(mut self, filter: &Filter, require_feature: bool) -> Registry {
self.consume_start_element("registry");

let mut enums = Vec::new();
let mut cmds = Vec::new();
let mut enums = BTreeMap::new();
let mut cmds = BTreeMap::new();
let mut features = Vec::new();
let mut extensions = BTreeMap::new();
let mut aliases = BTreeMap::new();
Expand All @@ -312,6 +312,7 @@ trait Parse: Sized + Iterator<Item = ParseEvent> {
enums.extend(self.consume_enums(filter.api));
let enums_group = get_attribute(attributes, "group");
let enums_type = get_attribute(attributes, "type");
// TODO UNWRAP
if let Some(group) = enums_group.and_then(|name| groups.get_mut(&name)) {
group.enums_type = enums_type;
}
Expand Down Expand Up @@ -365,11 +366,13 @@ trait Parse: Sized + Iterator<Item = ParseEvent> {
if remove.profile == filter.profile {
for enm in &remove.enums {
debug!("Removing {enm}");
desired_enums.remove(enm);
let s = desired_enums.remove(enm);
assert!(s, "{enm} not known");
}
for cmd in &remove.commands {
debug!("Removing {cmd}");
desired_cmds.remove(cmd);
let s = desired_cmds.remove(cmd);
assert!(s, "{cmd} not known");
}
}
}
Expand Down Expand Up @@ -408,24 +411,21 @@ trait Parse: Sized + Iterator<Item = ParseEvent> {
}
}

let is_desired_enum = |e: &Enum| {
desired_enums.contains(&("GL_".to_string() + &e.ident))
|| desired_enums.contains(&("WGL_".to_string() + &e.ident))
|| desired_enums.contains(&("GLX_".to_string() + &e.ident))
|| desired_enums.contains(&("EGL_".to_string() + &e.ident))
};

let is_desired_cmd = |c: &Cmd| {
desired_cmds.contains(&("gl".to_string() + &c.proto.ident))
|| desired_cmds.contains(&("wgl".to_string() + &c.proto.ident))
|| desired_cmds.contains(&("glX".to_string() + &c.proto.ident))
|| desired_cmds.contains(&("egl".to_string() + &c.proto.ident))
};
let enums = desired_enums
.iter()
.map(|n| enums.remove(n).expect(n))
.collect();
let cmds = desired_cmds
.iter()
.map(|n| cmds.remove(n).expect(n))
.collect();

Registry {
api: filter.api,
enums: enums.into_iter().filter(is_desired_enum).collect(),
cmds: cmds.into_iter().filter(is_desired_cmd).collect(),
enums,
// : enums.into_iter().filter(is_desired_enum).collect(),
cmds,
// : cmds.into_iter().filter(is_desired_cmd).collect(),
aliases: if filter.fallbacks == Fallbacks::None {
BTreeMap::new()
} else {
Expand Down Expand Up @@ -526,7 +526,7 @@ trait Parse: Sized + Iterator<Item = ParseEvent> {
}
}

fn consume_enums(&mut self, api: Api) -> Vec<Enum> {
fn consume_enums(&mut self, api: Api) -> Vec<(String, Enum)> {
let mut enums = Vec::new();
loop {
match self.next().unwrap() {
Expand All @@ -553,17 +553,21 @@ trait Parse: Sized + Iterator<Item = ParseEvent> {
enums
}

fn consume_enum(&mut self, api: Api, attributes: &[Attribute]) -> Enum {
let ident = trim_enum_prefix(&get_attribute(attributes, "name").unwrap(), api).to_string();
fn consume_enum(&mut self, api: Api, attributes: &[Attribute]) -> (String, Enum) {
let name = get_attribute(attributes, "name").unwrap();
let ident = trim_enum_prefix(&name, api).to_string();
let value = get_attribute(attributes, "value").unwrap();
let alias = get_attribute(attributes, "alias");
let ty = get_attribute(attributes, "type");
self.consume_end_element("enum");

match api {
Api::Egl => make_egl_enum(ident, ty, value, alias),
_ => make_enum(ident, ty, value, alias),
}
(
name,
match api {
Api::Egl => make_egl_enum(ident, ty, value, alias),
_ => make_enum(ident, ty, value, alias),
},
)
}

fn consume_groups(&mut self, api: Api) -> BTreeMap<String, Group> {
Expand Down Expand Up @@ -602,21 +606,21 @@ trait Parse: Sized + Iterator<Item = ParseEvent> {
enums
}

fn consume_cmds(&mut self, api: Api) -> (Vec<Cmd>, BTreeMap<String, Vec<String>>) {
fn consume_cmds(&mut self, api: Api) -> (Vec<(String, Cmd)>, BTreeMap<String, Vec<String>>) {
let mut cmds = Vec::new();
let mut aliases: BTreeMap<String, Vec<String>> = BTreeMap::new();
loop {
match self.next().unwrap() {
// add command definition
ParseEvent::Start(ref name, _) if name == "command" => {
let new = self.consume_cmd(api);
if let Some(ref v) = new.alias {
if let Some(ref v) = new.1.alias {
match aliases.entry(v.clone()) {
Entry::Occupied(mut ent) => {
ent.get_mut().push(new.proto.ident.clone());
ent.get_mut().push(new.1.proto.ident.clone());
},
Entry::Vacant(ent) => {
ent.insert(vec![new.proto.ident.clone()]);
ent.insert(vec![new.1.proto.ident.clone()]);
},
}
}
Expand All @@ -631,11 +635,12 @@ trait Parse: Sized + Iterator<Item = ParseEvent> {
(cmds, aliases)
}

fn consume_cmd(&mut self, api: Api) -> Cmd {
fn consume_cmd(&mut self, api: Api) -> (String, Cmd) {
// consume command prototype
self.consume_start_element("proto");
let mut proto = self.consume_binding("proto", &[]);
proto.ident = trim_cmd_prefix(&proto.ident, api).to_string();
let name = std::mem::take(&mut proto.ident);
proto.ident = trim_cmd_prefix(&name, api).to_string();

let mut params = Vec::new();
let mut alias = None;
Expand All @@ -648,6 +653,7 @@ trait Parse: Sized + Iterator<Item = ParseEvent> {
},
ParseEvent::Start(ref name, ref attributes) if name == "alias" => {
alias = get_attribute(attributes, "name");
// TODO: Use untrimmed names for aliases?
alias = alias.map(|t| trim_cmd_prefix(&t, api).to_string());
self.consume_end_element("alias");
},
Expand All @@ -667,13 +673,16 @@ trait Parse: Sized + Iterator<Item = ParseEvent> {
}
}

Cmd {
proto,
params,
alias,
vecequiv,
glx,
}
(
name,
Cmd {
proto,
params,
alias,
vecequiv,
glx,
},
)
}

fn consume_binding(&mut self, outside_tag: &str, attributes: &[Attribute]) -> Binding {
Expand Down Expand Up @@ -1022,7 +1031,7 @@ pub fn to_rust_ty<T: AsRef<str>>(ty: T) -> Cow<'static, str> {
"const HGPUNV *" => "*const types::HGPUNV",
"const LAYERPLANEDESCRIPTOR *" => "*const types::LAYERPLANEDESCRIPTOR",
"const LPVOID *" => "*const types::LPVOID",
"const PIXELFORMATDESCRIPTOR *" => "*const types::IXELFORMATDESCRIPTOR",
"const PIXELFORMATDESCRIPTOR *" => "*const types::PIXELFORMATDESCRIPTOR",
"const USHORT *" => "*const types::USHORT",
// "const char *" => "*const __gl_imports::raw::c_char",
// "const int *" => "*const __gl_imports::raw::c_int",
Expand Down