1 | // Copyright 2015 Brendan Zabarauskas and the gl-rs developers |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | extern crate khronos_api; |
16 | |
17 | use std::borrow::Cow; |
18 | use std::collections::btree_map::Entry; |
19 | use std::collections::{BTreeMap, BTreeSet}; |
20 | use std::io; |
21 | use xml::attribute::OwnedAttribute; |
22 | use xml::reader::XmlEvent; |
23 | use xml::EventReader as XmlEventReader; |
24 | |
25 | use registry::{Binding, Cmd, Enum, GlxOpcode, Group, Registry}; |
26 | use {Api, Fallbacks, Profile}; |
27 | |
28 | pub fn from_xml<R: io::Read>( |
29 | src: R, |
30 | filter: &Filter, |
31 | require_feature: bool, |
32 | ) -> Registry { |
33 | XmlEventReaderimpl Iterator ::new(source:src) |
34 | .into_iter() |
35 | .map(Result::unwrap) |
36 | .filter_map(ParseEvent::from_xml) |
37 | .parse(filter, require_feature) |
38 | } |
39 | |
40 | #[derive (Debug, PartialEq, Eq)] |
41 | struct Attribute { |
42 | key: String, |
43 | value: String, |
44 | } |
45 | |
46 | impl Attribute { |
47 | fn new<Key, Value>(key: Key, value: Value) -> Attribute |
48 | where |
49 | Key: ToString, |
50 | Value: ToString, |
51 | { |
52 | Attribute { |
53 | key: key.to_string(), |
54 | value: value.to_string(), |
55 | } |
56 | } |
57 | } |
58 | |
59 | impl From<OwnedAttribute> for Attribute { |
60 | fn from(attribute: OwnedAttribute) -> Attribute { |
61 | Attribute::new(key:attribute.name.local_name, attribute.value) |
62 | } |
63 | } |
64 | |
65 | #[derive (Debug, PartialEq, Eq)] |
66 | enum ParseEvent { |
67 | Start(String, Vec<Attribute>), |
68 | End(String), |
69 | Text(String), |
70 | } |
71 | |
72 | impl ParseEvent { |
73 | fn from_xml(event: XmlEvent) -> Option<ParseEvent> { |
74 | match event { |
75 | XmlEvent::StartDocument { .. } => None, |
76 | XmlEvent::EndDocument => None, |
77 | XmlEvent::StartElement { |
78 | name: OwnedName, attributes: Vec, .. |
79 | } => { |
80 | let attributes: Vec = attributes.into_iter().map(Attribute::from).collect(); |
81 | Some(ParseEvent::Start(name.local_name, attributes)) |
82 | }, |
83 | XmlEvent::EndElement { name: OwnedName } => Some(ParseEvent::End(name.local_name)), |
84 | XmlEvent::Characters(chars: String) => Some(ParseEvent::Text(chars)), |
85 | XmlEvent::ProcessingInstruction { .. } => None, |
86 | XmlEvent::CData(_) => None, |
87 | XmlEvent::Comment(_) => None, |
88 | XmlEvent::Whitespace(_) => None, |
89 | } |
90 | } |
91 | } |
92 | |
93 | fn api_from_str(src: &str) -> Result<Option<Api>, ()> { |
94 | match src { |
95 | "gl" => Ok(Some(Api::Gl)), |
96 | "glx" => Ok(Some(Api::Glx)), |
97 | "wgl" => Ok(Some(Api::Wgl)), |
98 | "egl" => Ok(Some(Api::Egl)), |
99 | "glcore" => Ok(Some(Api::GlCore)), |
100 | "gles1" => Ok(Some(Api::Gles1)), |
101 | "gles2" => Ok(Some(Api::Gles2)), |
102 | "glsc2" => Ok(Some(Api::Glsc2)), |
103 | "disabled" => Ok(None), |
104 | _ => Err(()), |
105 | } |
106 | } |
107 | |
108 | fn profile_from_str(src: &str) -> Result<Profile, ()> { |
109 | match src { |
110 | "core" => Ok(Profile::Core), |
111 | "compatibility" => Ok(Profile::Compatibility), |
112 | _ => Err(()), |
113 | } |
114 | } |
115 | |
116 | fn underscore_numeric_prefix(src: &str) -> String { |
117 | match src.chars().next() { |
118 | Some(c: char) if c.is_numeric() => format!("_ {}" , src), |
119 | Some(_) | None => src.to_string(), |
120 | } |
121 | } |
122 | |
123 | fn underscore_keyword(ident: String) -> String { |
124 | match ident.as_ref() { |
125 | "in" => "in_" .to_string(), |
126 | "ref" => "ref_" .to_string(), |
127 | "type" => "type_" .to_string(), |
128 | _ => ident, |
129 | } |
130 | } |
131 | |
132 | fn trim_str<'a>(s: &'a str, trim: &str) -> &'a str { |
133 | if s.starts_with(trim) { |
134 | &s[trim.len()..] |
135 | } else { |
136 | s |
137 | } |
138 | } |
139 | |
140 | fn trim_enum_prefix(ident: &str, api: Api) -> String { |
141 | let ident: &str = match api { |
142 | Api::Gl | Api::GlCore | Api::Gles1 | Api::Gles2 | Api::Glsc2 => trim_str(s:ident, trim:"GL_" ), |
143 | Api::Glx => trim_str(s:ident, trim:"GLX_" ), |
144 | Api::Wgl => trim_str(s:ident, trim:"WGL_" ), |
145 | Api::Egl => trim_str(s:ident, trim:"EGL_" ), |
146 | }; |
147 | underscore_numeric_prefix(src:ident) |
148 | } |
149 | |
150 | fn make_enum(ident: String, ty: Option<String>, value: String, alias: Option<String>) -> Enum { |
151 | let (ty, value, cast) = { |
152 | if value.starts_with("((" ) && value.ends_with(")" ) { |
153 | // Some enums have a value of the form `'((' type ')' expr ')'`. |
154 | |
155 | // nothing to see here.... |
156 | // just brute forcing some paren matching... (ノ ◕ ◡ ◕)ノ *:・゚✧ |
157 | let working = &value[2..value.len() - 1]; |
158 | if let Some((i, _)) = working.match_indices(")" ).next() { |
159 | let ty = working[..i].to_string(); |
160 | let value = working[i + 1..].to_string(); |
161 | |
162 | (Cow::Owned(ty), value, true) |
163 | } else { |
164 | panic!("Unexpected value format: {}" , value) |
165 | } |
166 | } else { |
167 | let ty = match ty { |
168 | Some(ref ty) if ty == "u" => "GLuint" , |
169 | Some(ref ty) if ty == "ull" => "GLuint64" , |
170 | Some(ty) => panic!("Unhandled enum type: {}" , ty), |
171 | None if value.starts_with(" \"" ) => "&'static str" , |
172 | None if ident == "TRUE" || ident == "FALSE" => "GLboolean" , |
173 | None => "GLenum" , |
174 | }; |
175 | (Cow::Borrowed(ty), value, false) |
176 | } |
177 | }; |
178 | |
179 | Enum { |
180 | ident: ident, |
181 | value: value, |
182 | cast: cast, |
183 | alias: alias, |
184 | ty: ty, |
185 | } |
186 | } |
187 | |
188 | fn make_egl_enum(ident: String, ty: Option<String>, value: String, alias: Option<String>) -> Enum { |
189 | let (ty, value, cast) = { |
190 | if value.starts_with("EGL_CAST(" ) && value.ends_with(")" ) { |
191 | // Handling "SpecialNumbers" in the egl.xml file |
192 | // The values for these enums has the form `'EGL_CAST(' type ',' expr ')'`. |
193 | let working = &value[9..value.len() - 1]; |
194 | if let Some((i, _)) = working.match_indices("," ).next() { |
195 | let ty = working[..i].to_string(); |
196 | let value = working[i + 1..].to_string(); |
197 | |
198 | (Cow::Owned(ty), value, true) |
199 | } else { |
200 | panic!("Unexpected value format: {}" , value) |
201 | } |
202 | } else { |
203 | match value.chars().next() { |
204 | Some('-' ) | Some('0' ..='9' ) => (), |
205 | _ => panic!("Unexpected value format: {}" , value), |
206 | } |
207 | |
208 | let ty = match ty { |
209 | Some(ref ty) if ty == "ull" => "EGLuint64KHR" , |
210 | Some(ty) => panic!("Unhandled enum type: {}" , ty), |
211 | None if value.starts_with('-' ) => "EGLint" , |
212 | None if ident == "TRUE" || ident == "FALSE" => "EGLBoolean" , |
213 | None => "EGLenum" , |
214 | }; |
215 | (Cow::Borrowed(ty), value, false) |
216 | } |
217 | }; |
218 | |
219 | Enum { |
220 | ident: ident, |
221 | value: value, |
222 | cast: cast, |
223 | alias: alias, |
224 | ty: ty, |
225 | } |
226 | } |
227 | |
228 | fn trim_cmd_prefix(ident: &str, api: Api) -> &str { |
229 | match api { |
230 | Api::Gl | Api::GlCore | Api::Gles1 | Api::Gles2 | Api::Glsc2 => trim_str(s:ident, trim:"gl" ), |
231 | Api::Glx => trim_str(s:ident, trim:"glX" ), |
232 | Api::Wgl => trim_str(s:ident, trim:"wgl" ), |
233 | Api::Egl => trim_str(s:ident, trim:"egl" ), |
234 | } |
235 | } |
236 | |
237 | fn merge_map(a: &mut BTreeMap<String, Vec<String>>, b: BTreeMap<String, Vec<String>>) { |
238 | for (k: String, v: Vec) in b { |
239 | match a.entry(key:k) { |
240 | Entry::Occupied(mut ent: OccupiedEntry<'_, String, …>) => { |
241 | ent.get_mut().extend(iter:v); |
242 | }, |
243 | Entry::Vacant(ent: VacantEntry<'_, String, Vec<…>>) => { |
244 | ent.insert(v); |
245 | }, |
246 | } |
247 | } |
248 | } |
249 | |
250 | #[derive (Clone)] |
251 | struct Feature { |
252 | pub api: Api, |
253 | pub name: String, |
254 | pub number: String, |
255 | pub requires: Vec<Require>, |
256 | pub removes: Vec<Remove>, |
257 | } |
258 | |
259 | #[derive (Clone)] |
260 | struct Require { |
261 | /// A reference to the earlier types, by name |
262 | pub enums: Vec<String>, |
263 | /// A reference to the earlier types, by name |
264 | pub commands: Vec<String>, |
265 | } |
266 | |
267 | #[derive (Clone)] |
268 | struct Remove { |
269 | // always Core, for now |
270 | pub profile: Profile, |
271 | /// A reference to the earlier types, by name |
272 | pub enums: Vec<String>, |
273 | /// A reference to the earlier types, by name |
274 | pub commands: Vec<String>, |
275 | } |
276 | |
277 | #[derive (Clone)] |
278 | struct Extension { |
279 | pub name: String, |
280 | /// which apis this extension is defined for (see Feature.api) |
281 | pub supported: Vec<Api>, |
282 | pub requires: Vec<Require>, |
283 | } |
284 | |
285 | pub struct Filter { |
286 | pub api: Api, |
287 | pub fallbacks: Fallbacks, |
288 | pub extensions: BTreeSet<String>, |
289 | pub profile: Profile, |
290 | pub version: String, |
291 | } |
292 | |
293 | trait Parse: Sized + Iterator<Item = ParseEvent> { |
294 | fn parse(mut self, filter: &Filter, require_feature: bool) -> Registry { |
295 | self.consume_start_element("registry" ); |
296 | |
297 | let mut enums = Vec::new(); |
298 | let mut cmds = Vec::new(); |
299 | let mut features = Vec::new(); |
300 | let mut extensions = Vec::new(); |
301 | let mut aliases = BTreeMap::new(); |
302 | let mut groups: BTreeMap<String, Group> = BTreeMap::new(); |
303 | |
304 | while let Some(event) = self.next() { |
305 | match event { |
306 | // ignores |
307 | ParseEvent::Text(_) => (), |
308 | ParseEvent::Start(ref name, _) if name == "comment" => self.skip_to_end("comment" ), |
309 | ParseEvent::Start(ref name, _) if name == "types" => self.skip_to_end("types" ), |
310 | |
311 | // add group namespace |
312 | ParseEvent::Start(ref name, _) if name == "groups" => { |
313 | groups.extend(self.consume_groups(filter.api)); |
314 | }, |
315 | |
316 | // add enum namespace |
317 | ParseEvent::Start(ref name, ref attributes) if name == "enums" => { |
318 | enums.extend(self.consume_enums(filter.api)); |
319 | let enums_group = get_attribute(&attributes, "group" ); |
320 | let enums_type = get_attribute(&attributes, "type" ); |
321 | if let Some(group) = enums_group.and_then(|name| groups.get_mut(&name)) { |
322 | group.enums_type = enums_type; |
323 | } |
324 | }, |
325 | |
326 | // add command namespace |
327 | ParseEvent::Start(ref name, _) if name == "commands" => { |
328 | let (new_cmds, new_aliases) = self.consume_cmds(filter.api); |
329 | cmds.extend(new_cmds); |
330 | merge_map(&mut aliases, new_aliases); |
331 | }, |
332 | |
333 | ParseEvent::Start(ref name, ref attributes) if name == "feature" => { |
334 | debug!("Parsing feature: {:?}" , attributes); |
335 | features.push(Feature::convert(&mut self, &attributes)); |
336 | }, |
337 | |
338 | ParseEvent::Start(ref name, _) if name == "extensions" => loop { |
339 | match self.next().unwrap() { |
340 | ParseEvent::Start(ref name, ref attributes) if name == "extension" => { |
341 | extensions.push(Extension::convert(&mut self, &attributes)); |
342 | }, |
343 | ParseEvent::End(ref name) if name == "extensions" => break, |
344 | event => panic!("Unexpected message {:?}" , event), |
345 | } |
346 | }, |
347 | |
348 | // finished building the registry |
349 | ParseEvent::End(ref name) if name == "registry" => break, |
350 | |
351 | // error handling |
352 | event => panic!("Expected </registry>, found: {:?}" , event), |
353 | } |
354 | } |
355 | |
356 | let mut desired_enums = BTreeSet::new(); |
357 | let mut desired_cmds = BTreeSet::new(); |
358 | |
359 | // find the features we want |
360 | let mut found_feature = false; |
361 | for feature in &features { |
362 | // XXX: verify that the string comparison with <= actually works as desired |
363 | if feature.api == filter.api && feature.number <= filter.version { |
364 | for require in &feature.requires { |
365 | desired_enums.extend(require.enums.iter().map(|x| x.clone())); |
366 | desired_cmds.extend(require.commands.iter().map(|x| x.clone())); |
367 | } |
368 | |
369 | for remove in &feature.removes { |
370 | if remove.profile == filter.profile { |
371 | for enm in &remove.enums { |
372 | debug!("Removing {}" , enm); |
373 | desired_enums.remove(enm); |
374 | } |
375 | for cmd in &remove.commands { |
376 | debug!("Removing {}" , cmd); |
377 | desired_cmds.remove(cmd); |
378 | } |
379 | } |
380 | } |
381 | } |
382 | if feature.number == filter.version { |
383 | found_feature = true; |
384 | } |
385 | } |
386 | |
387 | if !found_feature && require_feature { |
388 | panic!("Did not find version {} in the registry" , filter.version); |
389 | } |
390 | |
391 | for extension in &extensions { |
392 | if filter.extensions.contains(&extension.name) { |
393 | if !extension.supported.contains(&filter.api) { |
394 | panic!( |
395 | "Requested {}, which doesn't support the {} API" , |
396 | extension.name, filter.api |
397 | ); |
398 | } |
399 | for require in &extension.requires { |
400 | desired_enums.extend(require.enums.iter().map(|x| x.clone())); |
401 | desired_cmds.extend(require.commands.iter().map(|x| x.clone())); |
402 | } |
403 | } |
404 | } |
405 | |
406 | let is_desired_enum = |e: &Enum| { |
407 | desired_enums.contains(&("GL_" .to_string() + &e.ident)) |
408 | || desired_enums.contains(&("WGL_" .to_string() + &e.ident)) |
409 | || desired_enums.contains(&("GLX_" .to_string() + &e.ident)) |
410 | || desired_enums.contains(&("EGL_" .to_string() + &e.ident)) |
411 | }; |
412 | |
413 | let is_desired_cmd = |c: &Cmd| { |
414 | desired_cmds.contains(&("gl" .to_string() + &c.proto.ident)) |
415 | || desired_cmds.contains(&("wgl" .to_string() + &c.proto.ident)) |
416 | || desired_cmds.contains(&("glX" .to_string() + &c.proto.ident)) |
417 | || desired_cmds.contains(&("egl" .to_string() + &c.proto.ident)) |
418 | }; |
419 | |
420 | Registry { |
421 | api: filter.api, |
422 | enums: enums.into_iter().filter(is_desired_enum).collect(), |
423 | cmds: cmds.into_iter().filter(is_desired_cmd).collect(), |
424 | aliases: if filter.fallbacks == Fallbacks::None { |
425 | BTreeMap::new() |
426 | } else { |
427 | aliases |
428 | }, |
429 | groups, |
430 | } |
431 | } |
432 | |
433 | fn consume_characters(&mut self) -> String { |
434 | match self.next().unwrap() { |
435 | ParseEvent::Text(ch) => ch, |
436 | event => panic!("Expected characters, found: {:?}" , event), |
437 | } |
438 | } |
439 | |
440 | fn consume_start_element(&mut self, expected_name: &str) -> Vec<Attribute> { |
441 | match self.next().unwrap() { |
442 | ParseEvent::Start(name, attributes) => { |
443 | if expected_name == name { |
444 | attributes |
445 | } else { |
446 | panic!("Expected < {}>, found: < {}>" , expected_name, name) |
447 | } |
448 | }, |
449 | event => panic!("Expected < {}>, found: {:?}" , expected_name, event), |
450 | } |
451 | } |
452 | |
453 | fn consume_end_element(&mut self, expected_name: &str) { |
454 | match self.next().unwrap() { |
455 | ParseEvent::End(ref name) if expected_name == name => (), |
456 | event => panic!("Expected </ {}>, found: {:?}" , expected_name, event), |
457 | } |
458 | } |
459 | |
460 | fn skip_to_end(&mut self, expected_name: &str) { |
461 | loop { |
462 | match self.next().unwrap() { |
463 | ParseEvent::End(ref name) if expected_name == name => break, |
464 | _ => {}, |
465 | } |
466 | } |
467 | } |
468 | |
469 | fn consume_two<'a, T: FromXml, U: FromXml>( |
470 | &mut self, |
471 | one: &'a str, |
472 | two: &'a str, |
473 | end: &'a str, |
474 | ) -> (Vec<T>, Vec<U>) { |
475 | debug!("consume_two: looking for {} and {} until {}" , one, two, end); |
476 | |
477 | let mut ones = Vec::new(); |
478 | let mut twos = Vec::new(); |
479 | |
480 | loop { |
481 | match self.next().unwrap() { |
482 | ParseEvent::Start(ref name, ref attributes) => { |
483 | debug!("Found start element < {:?} {:?}>" , name, attributes); |
484 | debug!("one and two are {} and {}" , one, two); |
485 | |
486 | let n = name.clone(); |
487 | |
488 | if one == n { |
489 | ones.push(FromXml::convert(self, &attributes)); |
490 | } else if "type" == n { |
491 | // XXX: GL1.1 contains types, which we never care about anyway. |
492 | // Make sure consume_two doesn't get used for things which *do* |
493 | // care about type. |
494 | warn!("Ignoring type!" ); |
495 | continue; |
496 | } else if two == n { |
497 | twos.push(FromXml::convert(self, &attributes)); |
498 | } else { |
499 | panic!("Unexpected element: < {:?} {:?}>" , n, &attributes); |
500 | } |
501 | }, |
502 | ParseEvent::End(ref name) => { |
503 | debug!("Found end element </ {:?}>" , name); |
504 | |
505 | if one == name || two == name { |
506 | continue; |
507 | } else if "type" == name { |
508 | // XXX: GL1.1 contains types, which we never care about anyway. |
509 | // Make sure consume_two doesn't get used for things which *do* |
510 | // care about type. |
511 | warn!("Ignoring type!" ); |
512 | continue; |
513 | } else if end == name { |
514 | return (ones, twos); |
515 | } else { |
516 | panic!("Unexpected end element {:?}" , name); |
517 | } |
518 | }, |
519 | event => panic!("Unexpected message {:?}" , event), |
520 | } |
521 | } |
522 | } |
523 | |
524 | fn consume_enums(&mut self, api: Api) -> Vec<Enum> { |
525 | let mut enums = Vec::new(); |
526 | loop { |
527 | match self.next().unwrap() { |
528 | // ignores |
529 | ParseEvent::Text(_) => {}, |
530 | ParseEvent::Start(ref name, _) if name == "unused" => self.skip_to_end("unused" ), |
531 | |
532 | // add enum definition |
533 | ParseEvent::Start(ref name, ref attributes) if name == "enum" => { |
534 | enums.push(self.consume_enum(api, attributes)); |
535 | }, |
536 | |
537 | // finished building the namespace |
538 | ParseEvent::End(ref name) if name == "enums" => break, |
539 | // error handling |
540 | event => panic!("Expected </enums>, found: {:?}" , event), |
541 | } |
542 | } |
543 | enums |
544 | } |
545 | |
546 | fn consume_enum(&mut self, api: Api, attributes: &[Attribute]) -> Enum { |
547 | let ident = trim_enum_prefix(&get_attribute(&attributes, "name" ).unwrap(), api).to_string(); |
548 | let value = get_attribute(&attributes, "value" ).unwrap(); |
549 | let alias = get_attribute(&attributes, "alias" ); |
550 | let ty = get_attribute(&attributes, "type" ); |
551 | self.consume_end_element("enum" ); |
552 | |
553 | match api { |
554 | Api::Egl => make_egl_enum(ident, ty, value, alias), |
555 | _ => make_enum(ident, ty, value, alias), |
556 | } |
557 | } |
558 | |
559 | fn consume_groups(&mut self, api: Api) -> BTreeMap<String, Group> { |
560 | let mut groups = BTreeMap::new(); |
561 | loop { |
562 | match self.next().unwrap() { |
563 | ParseEvent::Start(ref name, ref attributes) if name == "group" => { |
564 | let ident = get_attribute(&attributes, "name" ).unwrap(); |
565 | let group = Group { |
566 | ident: ident.clone(), |
567 | enums_type: None, |
568 | enums: self.consume_group_enums(api) |
569 | }; |
570 | groups.insert(ident, group); |
571 | }, |
572 | ParseEvent::End(ref name) if name == "groups" => break, |
573 | event => panic!("Expected </groups>, found: {:?}" , event), |
574 | } |
575 | } |
576 | groups |
577 | } |
578 | |
579 | fn consume_group_enums(&mut self, api: Api) -> Vec<String> { |
580 | let mut enums = Vec::new(); |
581 | loop { |
582 | match self.next().unwrap() { |
583 | ParseEvent::Start(ref name, ref attributes) if name == "enum" => { |
584 | let enum_name = get_attribute(&attributes, "name" ); |
585 | enums.push(trim_enum_prefix(&enum_name.unwrap(), api)); |
586 | self.consume_end_element("enum" ); |
587 | }, |
588 | ParseEvent::End(ref name) if name == "group" => break, |
589 | event => panic!("Expected </group>, found: {:?}" , event), |
590 | } |
591 | } |
592 | enums |
593 | } |
594 | |
595 | fn consume_cmds(&mut self, api: Api) -> (Vec<Cmd>, BTreeMap<String, Vec<String>>) { |
596 | let mut cmds = Vec::new(); |
597 | let mut aliases: BTreeMap<String, Vec<String>> = BTreeMap::new(); |
598 | loop { |
599 | match self.next().unwrap() { |
600 | // add command definition |
601 | ParseEvent::Start(ref name, _) if name == "command" => { |
602 | let new = self.consume_cmd(api); |
603 | if let Some(ref v) = new.alias { |
604 | match aliases.entry(v.clone()) { |
605 | Entry::Occupied(mut ent) => { |
606 | ent.get_mut().push(new.proto.ident.clone()); |
607 | }, |
608 | Entry::Vacant(ent) => { |
609 | ent.insert(vec![new.proto.ident.clone()]); |
610 | }, |
611 | } |
612 | } |
613 | cmds.push(new); |
614 | }, |
615 | // finished building the namespace |
616 | ParseEvent::End(ref name) if name == "commands" => break, |
617 | // error handling |
618 | event => panic!("Expected </commands>, found: {:?}" , event), |
619 | } |
620 | } |
621 | (cmds, aliases) |
622 | } |
623 | |
624 | fn consume_cmd(&mut self, api: Api) -> Cmd { |
625 | // consume command prototype |
626 | self.consume_start_element("proto" ); |
627 | let mut proto = self.consume_binding("proto" , &[]); |
628 | proto.ident = trim_cmd_prefix(&proto.ident, api).to_string(); |
629 | |
630 | let mut params = Vec::new(); |
631 | let mut alias = None; |
632 | let mut vecequiv = None; |
633 | let mut glx = None; |
634 | loop { |
635 | match self.next().unwrap() { |
636 | ParseEvent::Start(ref name, ref attributes) if name == "param" => { |
637 | params.push(self.consume_binding("param" , attributes)); |
638 | }, |
639 | ParseEvent::Start(ref name, ref attributes) if name == "alias" => { |
640 | alias = get_attribute(&attributes, "name" ); |
641 | alias = alias.map(|t| trim_cmd_prefix(&t, api).to_string()); |
642 | self.consume_end_element("alias" ); |
643 | }, |
644 | ParseEvent::Start(ref name, ref attributes) if name == "vecequiv" => { |
645 | vecequiv = get_attribute(&attributes, "vecequiv" ); |
646 | self.consume_end_element("vecequiv" ); |
647 | }, |
648 | ParseEvent::Start(ref name, ref attributes) if name == "glx" => { |
649 | glx = Some(GlxOpcode { |
650 | opcode: get_attribute(&attributes, "opcode" ).unwrap(), |
651 | name: get_attribute(&attributes, "name" ), |
652 | }); |
653 | self.consume_end_element("glx" ); |
654 | }, |
655 | ParseEvent::End(ref name) if name == "command" => break, |
656 | event => panic!("Expected </command>, found: {:?}" , event), |
657 | } |
658 | } |
659 | |
660 | Cmd { |
661 | proto: proto, |
662 | params: params, |
663 | alias: alias, |
664 | vecequiv: vecequiv, |
665 | glx: glx, |
666 | } |
667 | } |
668 | |
669 | fn consume_binding(&mut self, outside_tag: &str, attributes: &[Attribute]) -> Binding { |
670 | // consume type |
671 | let mut ty = String::new(); |
672 | loop { |
673 | match self.next().unwrap() { |
674 | ParseEvent::Text(text) => ty.push_str(&text), |
675 | ParseEvent::Start(ref name, _) if name == "ptype" => (), |
676 | ParseEvent::End(ref name) if name == "ptype" => (), |
677 | ParseEvent::Start(ref name, _) if name == "name" => break, |
678 | event => panic!("Expected binding, found: {:?}" , event), |
679 | } |
680 | } |
681 | |
682 | // consume identifier |
683 | let ident = underscore_keyword(self.consume_characters()); |
684 | self.consume_end_element("name" ); |
685 | |
686 | // consume the type suffix |
687 | loop { |
688 | match self.next().unwrap() { |
689 | ParseEvent::Text(text) => ty.push_str(&text), |
690 | ParseEvent::End(ref name) if name == outside_tag => break, |
691 | event => panic!("Expected binding, found: {:?}" , event), |
692 | } |
693 | } |
694 | |
695 | Binding { |
696 | ident: ident, |
697 | ty: to_rust_ty(ty), |
698 | group: get_attribute(&attributes, "group" ), |
699 | } |
700 | } |
701 | } |
702 | |
703 | impl<T> Parse for T where T: Sized + Iterator<Item = ParseEvent> {} |
704 | |
705 | fn get_attribute(attribs: &[Attribute], key: &str) -> Option<String> { |
706 | attribsOption<&Attribute> |
707 | .iter() |
708 | .find(|attrib: &&Attribute| attrib.key == key) |
709 | .map(|attrib: &Attribute| attrib.value.clone()) |
710 | } |
711 | |
712 | trait FromXml { |
713 | fn convert<P: Parse>(parser: &mut P, a: &[Attribute]) -> Self; |
714 | } |
715 | |
716 | impl FromXml for Require { |
717 | fn convert<P: Parse>(parser: &mut P, _: &[Attribute]) -> Require { |
718 | debug!("Doing a FromXml on Require" ); |
719 | let (enums: Vec, commands: Vec) = parser.consume_two(one:"enum" , two:"command" , end:"require" ); |
720 | Require { |
721 | enums: enums, |
722 | commands: commands, |
723 | } |
724 | } |
725 | } |
726 | |
727 | impl FromXml for Remove { |
728 | fn convert<P: Parse>(parser: &mut P, a: &[Attribute]) -> Remove { |
729 | debug!("Doing a FromXml on Remove" ); |
730 | let profile: String = get_attribute(attribs:a, key:"profile" ).unwrap(); |
731 | let profile: Profile = profile_from_str(&profile).unwrap(); |
732 | let (enums: Vec, commands: Vec) = parser.consume_two(one:"enum" , two:"command" , end:"remove" ); |
733 | |
734 | Remove { |
735 | profile: profile, |
736 | enums: enums, |
737 | commands: commands, |
738 | } |
739 | } |
740 | } |
741 | |
742 | impl FromXml for Feature { |
743 | fn convert<P: Parse>(parser: &mut P, a: &[Attribute]) -> Feature { |
744 | debug!("Doing a FromXml on Feature" ); |
745 | let api: String = get_attribute(attribs:a, key:"api" ).unwrap(); |
746 | let api: Api = api_from_str(&api).unwrap().unwrap(); |
747 | let name: String = get_attribute(attribs:a, key:"name" ).unwrap(); |
748 | let number: String = get_attribute(attribs:a, key:"number" ).unwrap(); |
749 | |
750 | debug!("Found api = {}, name = {}, number = {}" , api, name, number); |
751 | |
752 | let (require: Vec, remove: Vec) = parser.consume_two(one:"require" , two:"remove" , end:"feature" ); |
753 | |
754 | Feature { |
755 | api: api, |
756 | name: name, |
757 | number: number, |
758 | requires: require, |
759 | removes: remove, |
760 | } |
761 | } |
762 | } |
763 | |
764 | impl FromXml for Extension { |
765 | fn convert<P: Parse>(parser: &mut P, a: &[Attribute]) -> Extension { |
766 | debug!("Doing a FromXml on Extension" ); |
767 | let name = get_attribute(a, "name" ).unwrap(); |
768 | let supported = get_attribute(a, "supported" ) |
769 | .unwrap() |
770 | .split('|' ) |
771 | .filter_map(|api| { |
772 | api_from_str(api).unwrap_or_else(|()| panic!("unsupported API ` {}`" , api)) |
773 | }) |
774 | .collect::<Vec<_>>(); |
775 | let mut require = Vec::new(); |
776 | loop { |
777 | match parser.next().unwrap() { |
778 | ParseEvent::Start(ref name, ref attributes) if name == "require" => { |
779 | require.push(FromXml::convert(parser, &attributes)); |
780 | }, |
781 | ParseEvent::End(ref name) if name == "extension" => break, |
782 | event => panic!("Unexpected message {:?}" , event), |
783 | } |
784 | } |
785 | |
786 | Extension { |
787 | name: name, |
788 | supported: supported, |
789 | requires: require, |
790 | } |
791 | } |
792 | } |
793 | |
794 | impl FromXml for String { |
795 | fn convert<P: Parse>(_: &mut P, a: &[Attribute]) -> String { |
796 | get_attribute(attribs:a, key:"name" ).unwrap() |
797 | } |
798 | } |
799 | |
800 | /// Converts a C style type definition to the Rust equivalent |
801 | pub fn to_rust_ty<T: AsRef<str>>(ty: T) -> Cow<'static, str> { |
802 | let ty = match ty.as_ref().trim() { |
803 | // gl.xml types |
804 | "GLDEBUGPROC" => "types::GLDEBUGPROC" , |
805 | "GLDEBUGPROCAMD" => "types::GLDEBUGPROCAMD" , |
806 | "GLDEBUGPROCARB" => "types::GLDEBUGPROCARB" , |
807 | "GLDEBUGPROCKHR" => "types::GLDEBUGPROCKHR" , |
808 | "GLbitfield" => "types::GLbitfield" , |
809 | "GLboolean" => "types::GLboolean" , |
810 | "GLbyte" => "types::GLbyte" , |
811 | "GLclampd" => "types::GLclampd" , |
812 | "GLclampf" => "types::GLclampf" , |
813 | "GLclampx" => "types::GLclampx" , |
814 | "GLdouble" => "types::GLdouble" , |
815 | "GLeglImageOES" => "types::GLeglImageOES" , |
816 | "GLenum" => "types::GLenum" , |
817 | "GLfixed" => "types::GLfixed" , |
818 | "GLfloat" => "types::GLfloat" , |
819 | "GLhalfNV" => "types::GLhalfNV" , |
820 | "GLhandleARB" => "types::GLhandleARB" , |
821 | "GLint" => "types::GLint" , |
822 | "GLint64" => "types::GLint64" , |
823 | "GLint64EXT" => "types::GLint64EXT" , |
824 | "GLintptr" => "types::GLintptr" , |
825 | "GLintptrARB" => "types::GLintptrARB" , |
826 | "GLshort" => "types::GLshort" , |
827 | "GLsizei" => "types::GLsizei" , |
828 | "GLsizeiptr" => "types::GLsizeiptr" , |
829 | "GLsizeiptrARB" => "types::GLsizeiptrARB" , |
830 | "GLsync" => "types::GLsync" , |
831 | "GLubyte" => "types::GLubyte" , |
832 | "GLuint" => "types::GLuint" , |
833 | "GLuint64" => "types::GLuint64" , |
834 | "GLuint64EXT" => "types::GLuint64EXT" , |
835 | "GLushort" => "types::GLushort" , |
836 | "GLvdpauSurfaceNV" => "types::GLvdpauSurfaceNV" , |
837 | "void" => "()" , |
838 | "GLboolean *" => "*mut types::GLboolean" , |
839 | "GLchar *" => "*mut types::GLchar" , |
840 | "const GLchar*" => "*const types::GLchar" , |
841 | "GLcharARB *" => "*mut types::GLcharARB" , |
842 | "GLdouble *" => "*mut types::GLdouble" , |
843 | "GLenum *" => "*mut types::GLenum" , |
844 | "GLfixed *" => "*mut types::GLfixed" , |
845 | "GLfloat *" => "*mut types::GLfloat" , |
846 | "GLhandleARB *" => "*mut types::GLhandleARB" , |
847 | "GLint *" => "*mut types::GLint" , |
848 | "GLint64 *" => "*mut types::GLint64" , |
849 | "GLint64EXT *" => "*mut types::GLint64EXT" , |
850 | "GLsizei *" => "*mut types::GLsizei" , |
851 | "GLubyte *" => "*mut types::GLubyte" , |
852 | "GLuint *" => "*mut types::GLuint" , |
853 | "GLuint [2]" => "*mut [types::GLuint; 2]" , |
854 | "GLuint64 *" => "*mut types::GLuint64" , |
855 | "GLuint64EXT *" => "*mut types::GLuint64EXT" , |
856 | "GLushort *" => "*mut types::GLushort" , |
857 | "GLvoid *" => "*mut types::GLvoid" , |
858 | "GLvoid **" => "*const *mut types::GLvoid" , |
859 | "void *" => "*mut __gl_imports::raw::c_void" , |
860 | "void **" => "*const *mut __gl_imports::raw::c_void" , |
861 | "const GLboolean *" => "*const types::GLboolean" , |
862 | "const GLbyte *" => "*const types::GLbyte" , |
863 | "const GLchar *" => "*const types::GLchar" , |
864 | "const GLcharARB *" => "*const types::GLcharARB" , |
865 | "const GLclampf *" => "*const types::GLclampf" , |
866 | "const GLdouble *" => "*const types::GLdouble" , |
867 | "const GLenum *" => "*const types::GLenum" , |
868 | "const GLfixed *" => "*const types::GLfixed" , |
869 | "const GLfloat" => "types::GLfloat" , |
870 | "const GLfloat *" => "*const types::GLfloat" , |
871 | "const GLhalfNV *" => "*const types::GLhalfNV" , |
872 | "const GLint *" => "*const types::GLint" , |
873 | "const GLint*" => "*const types::GLint" , |
874 | "const GLint64 *" => "*const types::GLint64" , |
875 | "const GLint64EXT *" => "*const types::GLint64EXT" , |
876 | "const GLintptr *" => "*const types::GLintptr" , |
877 | "const GLshort *" => "*const types::GLshort" , |
878 | "const GLsizei*" | |
879 | "const GLsizei *" => "*const types::GLsizei" , |
880 | "const GLsizeiptr *" => "*const types::GLsizeiptr" , |
881 | "const GLubyte *" => "*const types::GLubyte" , |
882 | "const GLuint *" => "*const types::GLuint" , |
883 | "const GLuint64 *" => "*const types::GLuint64" , |
884 | "const GLuint64EXT *" => "*const types::GLuint64EXT" , |
885 | "const GLushort *" => "*const types::GLushort" , |
886 | "const GLvdpauSurfaceNV *" => "*const types::GLvdpauSurfaceNV" , |
887 | "const GLvoid *" => "*const types::GLvoid" , |
888 | "const void*" | |
889 | "const void *" => "*const __gl_imports::raw::c_void" , |
890 | "const void **" => "*const *const __gl_imports::raw::c_void" , |
891 | "const void *const*" => "*const *const __gl_imports::raw::c_void" , |
892 | "const GLboolean **" => "*const *const types::GLboolean" , |
893 | "const GLchar **" => "*const *const types::GLchar" , |
894 | "const GLcharARB **" => "*const *const types::GLcharARB" , |
895 | "const GLvoid **" => "*const *const types::GLvoid" , |
896 | "const GLchar *const*" => "*const *const types::GLchar" , |
897 | "const GLvoid *const*" => "*const *const types::GLvoid" , |
898 | "struct _cl_context *" => "*const types::_cl_context" , |
899 | "struct _cl_event *" => "*const types::_cl_event" , |
900 | "GLuint[2]" => "[Gluint; 2]" , |
901 | |
902 | // glx.xml types |
903 | "Bool" => "types::Bool" , |
904 | "Colormap" => "types::Colormap" , |
905 | "DMbuffer" => "types::DMbuffer" , |
906 | "Font" => "types::Font" , |
907 | "GLXContext" => "types::GLXContext" , |
908 | "GLXContextID" => "types::GLXContextID" , |
909 | "GLXDrawable" => "types::GLXDrawable" , |
910 | "GLXFBConfig" => "types::GLXFBConfig" , |
911 | "GLXFBConfigSGIX" => "types::GLXFBConfigSGIX" , |
912 | "GLXPbuffer" => "types::GLXPbuffer" , |
913 | "GLXPbufferSGIX" => "types::GLXPbufferSGIX" , |
914 | "GLXPixmap" => "types::GLXPixmap" , |
915 | "GLXVideoCaptureDeviceNV" => "types::GLXVideoCaptureDeviceNV" , |
916 | "GLXVideoDeviceNV" => "types::GLXVideoDeviceNV" , |
917 | "GLXVideoSourceSGIX" => "types::GLXVideoSourceSGIX" , |
918 | "GLXWindow" => "types::GLXWindow" , |
919 | // "GLboolean" => "types::GLboolean", |
920 | // "GLenum" => "types::GLenum", |
921 | // "GLint" => "types::GLint", |
922 | // "GLsizei" => "types::GLsizei", |
923 | // "GLuint" => "types::GLuint", |
924 | "Pixmap" => "types::Pixmap" , |
925 | "Status" => "types::Status" , |
926 | "VLNode" => "types::VLNode" , |
927 | "VLPath" => "types::VLPath" , |
928 | "VLServer" => "types::VLServer" , |
929 | "Window" => "types::Window" , |
930 | "__GLXextFuncPtr" => "types::__GLXextFuncPtr" , |
931 | "const GLXContext" => "const types::GLXContext" , |
932 | "float" => "__gl_imports::raw::c_float" , |
933 | "int" => "__gl_imports::raw::c_int" , |
934 | "int64_t" => "i64" , |
935 | "unsigned int" => "__gl_imports::raw::c_uint" , |
936 | "unsigned long" => "__gl_imports::raw::c_ulong" , |
937 | // "void " => "()", |
938 | "DMparams *" => "*mut types::DMparams" , |
939 | "Display *" => "*mut types::Display" , |
940 | "GLXFBConfig *" => "*mut types::GLXFBConfig" , |
941 | "GLXFBConfigSGIX *" => "*mut types::GLXFBConfigSGIX" , |
942 | "GLXHyperpipeConfigSGIX *" => "*mut types::GLXHyperpipeConfigSGIX" , |
943 | "GLXHyperpipeNetworkSGIX *" => "*mut types::GLXHyperpipeNetworkSGIX" , |
944 | "GLXVideoCaptureDeviceNV *" => "*mut types::GLXVideoCaptureDeviceNV" , |
945 | "GLXVideoDeviceNV *" => "*mut types::GLXVideoDeviceNV" , |
946 | // "GLuint *" => "*mut types::GLuint", |
947 | "XVisualInfo *" => "*mut types::XVisualInfo" , |
948 | // "const GLubyte *" => "*GLubyte", |
949 | "const char *" => "*const __gl_imports::raw::c_char" , |
950 | "const int *" => "*const __gl_imports::raw::c_int" , |
951 | // "const void *" => "*const __gl_imports::raw::c_void", |
952 | "int *" => "*mut __gl_imports::raw::c_int" , |
953 | "int32_t *" => "*mut i32" , |
954 | "int64_t *" => "*mut i64" , |
955 | "long *" => "*mut __gl_imports::raw::c_long" , |
956 | "unsigned int *" => "*mut __gl_imports::raw::c_uint" , |
957 | "unsigned long *" => "*mut __gl_imports::raw::c_ulong" , |
958 | // "void *" => "*mut __gl_imports::raw::c_void", |
959 | |
960 | // wgl.xml types |
961 | "BOOL" => "types::BOOL" , |
962 | "DWORD" => "types::DWORD" , |
963 | "FLOAT" => "types::FLOAT" , |
964 | // "GLbitfield" => "types::GLbitfield", |
965 | // "GLboolean" => "types::GLboolean", |
966 | // "GLenum" => "types::GLenum", |
967 | // "GLfloat" => "types::GLfloat", |
968 | // "GLint" => "types::GLint", |
969 | // "GLsizei" => "types::GLsizei", |
970 | // "GLuint" => "types::GLuint", |
971 | // "GLushort" => "types::GLushort", |
972 | "HANDLE" => "types::HANDLE" , |
973 | "HDC" => "types::HDC" , |
974 | "HENHMETAFILE" => "types::HENHMETAFILE" , |
975 | "HGLRC" => "types::HGLRC" , |
976 | "HGPUNV" => "types::HGPUNV" , |
977 | "HPBUFFERARB" => "types::HPBUFFERARB" , |
978 | "HPBUFFEREXT" => "types::HPBUFFEREXT" , |
979 | "HPVIDEODEV" => "types::HPVIDEODEV" , |
980 | "HVIDEOINPUTDEVICENV" => "types::HVIDEOINPUTDEVICENV" , |
981 | "HVIDEOOUTPUTDEVICENV" => "types::HVIDEOOUTPUTDEVICENV" , |
982 | "INT" => "types::INT" , |
983 | "INT64" => "types::INT64" , |
984 | "LPCSTR" => "types::LPCSTR" , |
985 | "LPGLYPHMETRICSFLOAT" => "types::LPGLYPHMETRICSFLOAT" , |
986 | "LPVOID" => "types::LPVOID" , |
987 | "PGPU_DEVICE" => "types::PGPU_DEVICE" , |
988 | "PROC" => "types::PROC" , |
989 | "UINT" => "types::UINT" , |
990 | "VOID" => "types::VOID" , |
991 | // "int " => "__gl_imports::raw::c_int", |
992 | // "unsigned int " => "__gl_imports::raw::c_uint", |
993 | // "void " => "()", |
994 | "BOOL *" => "*mut types::BOOL" , |
995 | "DWORD *" => "*mut types::DWORD" , |
996 | "FLOAT *" => "*mut types::FLOAT" , |
997 | // "GLuint *" => "*mut types::GLuint", |
998 | "HANDLE *" => "*mut types::HANDLE" , |
999 | "HGPUNV *" => "*mut types::HGPUNV" , |
1000 | "HPVIDEODEV *" => "*mut types::HPVIDEODEV" , |
1001 | "HVIDEOINPUTDEVICENV *" => "*mut types::HVIDEOINPUTDEVICENV" , |
1002 | "HVIDEOOUTPUTDEVICENV *" => "*mut types::HVIDEOOUTPUTDEVICENV" , |
1003 | "INT32 *" => "*mut types::INT32" , |
1004 | "INT64 *" => "*mut types::INT64" , |
1005 | "UINT *" => "*mut types::UINT" , |
1006 | "USHORT *" => "*mut types::USHORT" , |
1007 | "const COLORREF *" => "*const types::COLORREF" , |
1008 | "const DWORD *" => "*const types::DWORD" , |
1009 | "const FLOAT *" => "*const types::FLOAT" , |
1010 | // "const GLushort *" => "*const types::GLushort", |
1011 | "const HANDLE *" => "*const types::HANDLE" , |
1012 | "const HGPUNV *" => "*const types::HGPUNV" , |
1013 | "const LAYERPLANEDESCRIPTOR *" => "*const types::LAYERPLANEDESCRIPTOR" , |
1014 | "const LPVOID *" => "*const types::LPVOID" , |
1015 | "const PIXELFORMATDESCRIPTOR *" => "*const types::IXELFORMATDESCRIPTOR" , |
1016 | "const USHORT *" => "*const types::USHORT" , |
1017 | // "const char *" => "*const __gl_imports::raw::c_char", |
1018 | // "const int *" => "*const __gl_imports::raw::c_int", |
1019 | "float *" => "*mut __gl_imports::raw::c_float" , |
1020 | // "int *" => "*mut __gl_imports::raw::c_int", |
1021 | // "unsigned long *" => "*mut __gl_imports::raw::c_ulong", |
1022 | // "void *" => "*mut __gl_imports::raw::c_void", |
1023 | |
1024 | // elx.xml types |
1025 | "khronos_utime_nanoseconds_t" => "types::khronos_utime_nanoseconds_t" , |
1026 | "khronos_uint64_t" => "types::khronos_uint64_t" , |
1027 | "khronos_ssize_t" => "types::khronos_ssize_t" , |
1028 | "EGLNativeDisplayType" => "types::EGLNativeDisplayType" , |
1029 | "EGLNativePixmapType" => "types::EGLNativePixmapType" , |
1030 | "EGLNativeWindowType" => "types::EGLNativeWindowType" , |
1031 | "EGLint" => "types::EGLint" , |
1032 | "EGLint *" => "*mut types::EGLint" , |
1033 | "const EGLint *" => "*const types::EGLint" , |
1034 | "NativeDisplayType" => "types::NativeDisplayType" , |
1035 | "NativePixmapType" => "types::NativePixmapType" , |
1036 | "NativeWindowType" => "types::NativeWindowType" , |
1037 | //"Bool" => "types::Bool", |
1038 | "EGLBoolean" => "types::EGLBoolean" , |
1039 | "EGLenum" => "types::EGLenum" , |
1040 | "EGLAttribKHR" => "types::EGLAttribKHR" , |
1041 | "EGLAttrib" => "types::EGLAttrib" , |
1042 | "EGLAttrib *" => "*mut types::EGLAttrib" , |
1043 | "const EGLAttrib *" => "*const types::EGLAttrib" , |
1044 | "const EGLattrib *" => "*const types::EGLAttrib" , // Due to a typo in khronos_api/api_angle/scripts/egl_angle_ext.xml - see brendanzab/gl-rs#491 |
1045 | "EGLConfig" => "types::EGLConfig" , |
1046 | "EGLConfig *" => "*mut types::EGLConfig" , |
1047 | "EGLContext" => "types::EGLContext" , |
1048 | "EGLDeviceEXT" => "types::EGLDeviceEXT" , |
1049 | "EGLDisplay" => "types::EGLDisplay" , |
1050 | "EGLSurface" => "types::EGLSurface" , |
1051 | "EGLClientBuffer" => "types::EGLClientBuffer" , |
1052 | "__eglMustCastToProperFunctionPointerType" => { |
1053 | "types::__eglMustCastToProperFunctionPointerType" |
1054 | }, |
1055 | "EGLImageKHR" => "types::EGLImageKHR" , |
1056 | "EGLImage" => "types::EGLImage" , |
1057 | "EGLOutputLayerEXT" => "types::EGLOutputLayerEXT" , |
1058 | "EGLOutputPortEXT" => "types::EGLOutputPortEXT" , |
1059 | "EGLSyncKHR" => "types::EGLSyncKHR" , |
1060 | "EGLSync" => "types::EGLSync" , |
1061 | "EGLTimeKHR" => "types::EGLTimeKHR" , |
1062 | "EGLTime" => "types::EGLTime" , |
1063 | "EGLSyncNV" => "types::EGLSyncNV" , |
1064 | "EGLTimeNV" => "types::EGLTimeNV" , |
1065 | "EGLuint64NV" => "types::EGLuint64NV" , |
1066 | "EGLStreamKHR" => "types::EGLStreamKHR" , |
1067 | "EGLuint64KHR" => "types::EGLuint64KHR" , |
1068 | "EGLNativeFileDescriptorKHR" => "types::EGLNativeFileDescriptorKHR" , |
1069 | "EGLsizeiANDROID" => "types::EGLsizeiANDROID" , |
1070 | "EGLSetBlobFuncANDROID" => "types::EGLSetBlobFuncANDROID" , |
1071 | "EGLGetBlobFuncANDROID" => "types::EGLGetBlobFuncANDROID" , |
1072 | "EGLClientPixmapHI" => "types::EGLClientPixmapHI" , |
1073 | "struct EGLClientPixmapHI *" => "*const types::EGLClientPixmapHI" , |
1074 | "const EGLAttribKHR *" => "*const types::EGLAttribKHR" , |
1075 | "const EGLuint64KHR *" => "*const types::EGLuint64KHR" , |
1076 | "EGLAttribKHR *" => "*mut types::EGLAttribKHR" , |
1077 | "EGLDeviceEXT *" => "*mut types::EGLDeviceEXT" , |
1078 | "EGLNativeDisplayType *" => "*mut types::EGLNativeDisplayType" , |
1079 | "EGLNativePixmapType *" => "*mut types::EGLNativePixmapType" , |
1080 | "EGLNativeWindowType *" => "*mut types::EGLNativeWindowType" , |
1081 | "EGLOutputLayerEXT *" => "*mut types::EGLOutputLayerEXT" , |
1082 | "EGLTimeKHR *" => "*mut types::EGLTimeKHR" , |
1083 | "EGLOutputPortEXT *" => "*mut types::EGLOutputPortEXT" , |
1084 | "EGLuint64KHR *" => "*mut types::EGLuint64KHR" , |
1085 | "const struct AHardwareBuffer *" => "*const __gl_imports::raw::c_void" , // humm |
1086 | |
1087 | "GLeglClientBufferEXT" => "types::GLeglClientBufferEXT" , |
1088 | "GLVULKANPROCNV" => "types::GLVULKANPROCNV" , |
1089 | "EGLDEBUGPROCKHR" => "types::EGLDEBUGPROCKHR" , |
1090 | "EGLObjectKHR" => "types::EGLObjectKHR" , |
1091 | "EGLLabelKHR" => "types::EGLLabelKHR" , |
1092 | "EGLnsecsANDROID" => "types::EGLnsecsANDROID" , |
1093 | "EGLnsecsANDROID *" => "*mut types::EGLnsecsANDROID" , |
1094 | "EGLBoolean *" => "*mut types::EGLBoolean" , |
1095 | |
1096 | // failure |
1097 | _ => panic!("Type conversion not implemented for ` {}`" , ty.as_ref()), |
1098 | }; |
1099 | |
1100 | Cow::Borrowed(ty) |
1101 | } |
1102 | |
1103 | #[cfg (test)] |
1104 | mod tests { |
1105 | mod underscore_numeric_prefix { |
1106 | use registry::parse; |
1107 | |
1108 | #[test ] |
1109 | fn test_numeric_prefix() { |
1110 | assert_eq!(parse::underscore_numeric_prefix("3" ), "_3" ); |
1111 | assert_eq!(parse::underscore_numeric_prefix("123_FOO" ), "_123_FOO" ); |
1112 | } |
1113 | |
1114 | #[test ] |
1115 | fn test_non_numeric_prefix() { |
1116 | assert_eq!(parse::underscore_numeric_prefix("" ), "" ); |
1117 | assert_eq!(parse::underscore_numeric_prefix("A" ), "A" ); |
1118 | assert_eq!(parse::underscore_numeric_prefix("FOO" ), "FOO" ); |
1119 | } |
1120 | } |
1121 | |
1122 | mod underscore_keyword { |
1123 | use registry::parse; |
1124 | |
1125 | #[test ] |
1126 | fn test_keyword() { |
1127 | assert_eq!(parse::underscore_keyword("in" .to_string()), "in_" ); |
1128 | assert_eq!(parse::underscore_keyword("ref" .to_string()), "ref_" ); |
1129 | assert_eq!(parse::underscore_keyword("type" .to_string()), "type_" ); |
1130 | } |
1131 | |
1132 | #[test ] |
1133 | fn test_non_keyword() { |
1134 | assert_eq!(parse::underscore_keyword("foo" .to_string()), "foo" ); |
1135 | assert_eq!(parse::underscore_keyword("bar" .to_string()), "bar" ); |
1136 | } |
1137 | } |
1138 | mod make_enum { |
1139 | use registry::parse; |
1140 | |
1141 | #[test ] |
1142 | fn test_cast_0() { |
1143 | let e = parse::make_enum( |
1144 | "FOO" .to_string(), |
1145 | None, |
1146 | "((EGLint)-1)" .to_string(), |
1147 | Some("BAR" .to_string()), |
1148 | ); |
1149 | assert_eq!(e.ident, "FOO" ); |
1150 | assert_eq!((&*e.ty, &*e.value), ("EGLint" , "-1" )); |
1151 | assert_eq!(e.alias, Some("BAR" .to_string())); |
1152 | } |
1153 | |
1154 | #[test ] |
1155 | fn test_cast_1() { |
1156 | let e = parse::make_enum( |
1157 | "FOO" .to_string(), |
1158 | None, |
1159 | "((EGLint)(-1))" .to_string(), |
1160 | Some("BAR" .to_string()), |
1161 | ); |
1162 | assert_eq!(e.ident, "FOO" ); |
1163 | assert_eq!((&*e.ty, &*e.value), ("EGLint" , "(-1)" )); |
1164 | assert_eq!(e.alias, Some("BAR" .to_string())); |
1165 | } |
1166 | |
1167 | #[test ] |
1168 | fn test_no_type() { |
1169 | let e = parse::make_enum( |
1170 | "FOO" .to_string(), |
1171 | None, |
1172 | "value" .to_string(), |
1173 | Some("BAR" .to_string()), |
1174 | ); |
1175 | assert_eq!(e.ident, "FOO" ); |
1176 | assert_eq!(e.value, "value" ); |
1177 | assert_eq!(e.alias, Some("BAR" .to_string())); |
1178 | assert_eq!(e.ty, "GLenum" ); |
1179 | assert_eq!(e.cast, false); |
1180 | } |
1181 | |
1182 | #[test ] |
1183 | fn test_u() { |
1184 | let e = parse::make_enum( |
1185 | "FOO" .to_string(), |
1186 | Some("u" .to_string()), |
1187 | String::new(), |
1188 | None, |
1189 | ); |
1190 | assert_eq!(e.ty, "GLuint" ); |
1191 | } |
1192 | |
1193 | #[test ] |
1194 | fn test_ull() { |
1195 | let e = parse::make_enum( |
1196 | "FOO" .to_string(), |
1197 | Some("ull" .to_string()), |
1198 | String::new(), |
1199 | None, |
1200 | ); |
1201 | assert_eq!(e.ty, "GLuint64" ); |
1202 | } |
1203 | |
1204 | #[test ] |
1205 | #[should_panic ] |
1206 | fn test_unknown_type() { |
1207 | parse::make_enum( |
1208 | "FOO" .to_string(), |
1209 | Some("blargh" .to_string()), |
1210 | String::new(), |
1211 | None, |
1212 | ); |
1213 | } |
1214 | |
1215 | #[test ] |
1216 | fn test_value_str() { |
1217 | let e = parse::make_enum("FOO" .to_string(), None, " \"hi \"" .to_string(), None); |
1218 | assert_eq!(e.ty, "&'static str" ); |
1219 | } |
1220 | |
1221 | #[test ] |
1222 | fn test_ident_true() { |
1223 | let e = parse::make_enum("TRUE" .to_string(), None, String::new(), None); |
1224 | assert_eq!(e.ty, "GLboolean" ); |
1225 | } |
1226 | |
1227 | #[test ] |
1228 | fn test_ident_false() { |
1229 | let e = parse::make_enum("FALSE" .to_string(), None, String::new(), None); |
1230 | assert_eq!(e.ty, "GLboolean" ); |
1231 | } |
1232 | } |
1233 | |
1234 | mod make_egl_enum { |
1235 | use registry::parse; |
1236 | |
1237 | #[test ] |
1238 | fn test_cast_egl() { |
1239 | let e = parse::make_egl_enum( |
1240 | "FOO" .to_string(), |
1241 | None, |
1242 | "EGL_CAST(EGLint,-1)" .to_string(), |
1243 | Some("BAR" .to_string()), |
1244 | ); |
1245 | assert_eq!(e.ident, "FOO" ); |
1246 | assert_eq!((&*e.ty, &*e.value), ("EGLint" , "-1" )); |
1247 | assert_eq!(e.alias, Some("BAR" .to_string())); |
1248 | } |
1249 | |
1250 | #[test ] |
1251 | fn test_ident_true() { |
1252 | let e = parse::make_egl_enum("TRUE" .to_string(), None, "1234" .to_string(), None); |
1253 | assert_eq!(e.ty, "EGLBoolean" ); |
1254 | } |
1255 | |
1256 | #[test ] |
1257 | fn test_ident_false() { |
1258 | let e = parse::make_egl_enum("FALSE" .to_string(), None, "1234" .to_string(), None); |
1259 | assert_eq!(e.ty, "EGLBoolean" ); |
1260 | } |
1261 | |
1262 | #[test ] |
1263 | fn test_ull() { |
1264 | let e = parse::make_egl_enum( |
1265 | "FOO" .to_string(), |
1266 | Some("ull" .to_string()), |
1267 | "1234" .to_string(), |
1268 | None, |
1269 | ); |
1270 | assert_eq!(e.ty, "EGLuint64KHR" ); |
1271 | } |
1272 | |
1273 | #[test ] |
1274 | fn test_negative_value() { |
1275 | let e = parse::make_egl_enum("FOO" .to_string(), None, "-1" .to_string(), None); |
1276 | assert_eq!(e.ty, "EGLint" ); |
1277 | } |
1278 | |
1279 | #[test ] |
1280 | #[should_panic ] |
1281 | fn test_unknown_type() { |
1282 | parse::make_egl_enum( |
1283 | "FOO" .to_string(), |
1284 | Some("blargh" .to_string()), |
1285 | String::new(), |
1286 | None, |
1287 | ); |
1288 | } |
1289 | |
1290 | #[test ] |
1291 | #[should_panic ] |
1292 | fn test_unknown_value() { |
1293 | parse::make_egl_enum("FOO" .to_string(), None, "a" .to_string(), None); |
1294 | } |
1295 | |
1296 | #[test ] |
1297 | #[should_panic ] |
1298 | fn test_empty_value() { |
1299 | parse::make_egl_enum("FOO" .to_string(), None, String::new(), None); |
1300 | } |
1301 | } |
1302 | |
1303 | mod parse_event { |
1304 | mod from_xml { |
1305 | use xml::attribute::OwnedAttribute; |
1306 | use xml::common::XmlVersion; |
1307 | use xml::name::OwnedName; |
1308 | use xml::namespace::Namespace; |
1309 | use xml::reader::XmlEvent; |
1310 | |
1311 | use registry::parse::{Attribute, ParseEvent}; |
1312 | |
1313 | #[test ] |
1314 | fn test_start_event() { |
1315 | let given = XmlEvent::StartElement { |
1316 | name: OwnedName::local("element" ), |
1317 | attributes: vec![ |
1318 | OwnedAttribute::new(OwnedName::local("attr1" ), "val1" ), |
1319 | OwnedAttribute::new(OwnedName::local("attr2" ), "val2" ), |
1320 | ], |
1321 | namespace: Namespace::empty(), |
1322 | }; |
1323 | let expected = ParseEvent::Start( |
1324 | "element" .to_string(), |
1325 | vec![ |
1326 | Attribute::new("attr1" , "val1" ), |
1327 | Attribute::new("attr2" , "val2" ), |
1328 | ], |
1329 | ); |
1330 | assert_eq!(ParseEvent::from_xml(given), Some(expected)); |
1331 | } |
1332 | |
1333 | #[test ] |
1334 | fn test_end_element() { |
1335 | let given = XmlEvent::EndElement { |
1336 | name: OwnedName::local("element" ), |
1337 | }; |
1338 | let expected = ParseEvent::End("element" .to_string()); |
1339 | assert_eq!(ParseEvent::from_xml(given), Some(expected)); |
1340 | } |
1341 | |
1342 | #[test ] |
1343 | fn test_characters() { |
1344 | let given = XmlEvent::Characters("text" .to_string()); |
1345 | let expected = ParseEvent::Text("text" .to_string()); |
1346 | assert_eq!(ParseEvent::from_xml(given), Some(expected)); |
1347 | } |
1348 | |
1349 | #[test ] |
1350 | fn test_start_document() { |
1351 | let given = XmlEvent::StartDocument { |
1352 | version: XmlVersion::Version10, |
1353 | encoding: "" .to_string(), |
1354 | standalone: None, |
1355 | }; |
1356 | assert_eq!(ParseEvent::from_xml(given), None); |
1357 | } |
1358 | |
1359 | #[test ] |
1360 | fn test_end_document() { |
1361 | let given = XmlEvent::EndDocument; |
1362 | assert_eq!(ParseEvent::from_xml(given), None); |
1363 | } |
1364 | |
1365 | #[test ] |
1366 | fn test_processing_instruction() { |
1367 | let given = XmlEvent::ProcessingInstruction { |
1368 | name: "" .to_string(), |
1369 | data: None, |
1370 | }; |
1371 | assert_eq!(ParseEvent::from_xml(given), None); |
1372 | } |
1373 | |
1374 | #[test ] |
1375 | fn test_cdata() { |
1376 | let given = XmlEvent::CData("CData" .to_string()); |
1377 | assert_eq!(ParseEvent::from_xml(given), None); |
1378 | } |
1379 | |
1380 | #[test ] |
1381 | fn test_comment() { |
1382 | let given = XmlEvent::Comment("Comment" .to_string()); |
1383 | assert_eq!(ParseEvent::from_xml(given), None); |
1384 | } |
1385 | |
1386 | #[test ] |
1387 | fn test_whitespace() { |
1388 | let given = XmlEvent::Whitespace("Whitespace" .to_string()); |
1389 | assert_eq!(ParseEvent::from_xml(given), None); |
1390 | } |
1391 | } |
1392 | } |
1393 | } |
1394 | |