summaryrefslogtreecommitdiffstats
path: root/vendor/windows-bindgen/src/constants.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/windows-bindgen/src/constants.rs')
-rw-r--r--vendor/windows-bindgen/src/constants.rs188
1 files changed, 188 insertions, 0 deletions
diff --git a/vendor/windows-bindgen/src/constants.rs b/vendor/windows-bindgen/src/constants.rs
new file mode 100644
index 000000000..1a08db0ae
--- /dev/null
+++ b/vendor/windows-bindgen/src/constants.rs
@@ -0,0 +1,188 @@
+use super::*;
+
+pub fn gen(gen: &Gen, def: Field) -> TokenStream {
+ let name = to_ident(gen.reader.field_name(def));
+ let ty = gen.reader.field_type(def, None).to_const_type();
+ let cfg = gen.reader.field_cfg(def);
+ let doc = gen.cfg_doc(&cfg);
+ let features = gen.cfg_features(&cfg);
+
+ if let Some(constant) = gen.reader.field_constant(def) {
+ let constant_type = gen.reader.constant_type(constant);
+
+ if ty == constant_type {
+ if ty == Type::String {
+ let crate_name = gen.crate_name();
+ if gen.reader.field_is_ansi(def) {
+ let value = gen.value(&gen.reader.constant_value(constant));
+ quote! {
+ #doc
+ #features
+ pub const #name: #crate_name PCSTR = #crate_name s!(#value);
+ }
+ } else {
+ let value = gen.value(&gen.reader.constant_value(constant));
+ quote! {
+ #doc
+ #features
+ pub const #name: #crate_name PCWSTR = #crate_name w!(#value);
+ }
+ }
+ } else {
+ let value = gen.typed_value(&gen.reader.constant_value(constant));
+ quote! {
+ #doc
+ #features
+ pub const #name: #value;
+ }
+ }
+ } else {
+ let kind = gen.type_default_name(&ty);
+ let value = gen.value(&gen.reader.constant_value(constant));
+ let underlying_type = gen.reader.type_underlying_type(&ty);
+
+ let value = if underlying_type == constant_type {
+ value
+ } else if gen.std && underlying_type == Type::ISize {
+ quote! { ::core::ptr::invalid_mut(#value as _) }
+ } else {
+ quote! { #value as _ }
+ };
+
+ if !gen.sys && gen.reader.type_has_replacement(&ty) {
+ quote! {
+ #doc
+ #features
+ pub const #name: #kind = #kind(#value);
+ }
+ } else {
+ quote! {
+ #doc
+ #features
+ pub const #name: #kind = #value;
+ }
+ }
+ }
+ } else if let Some(guid) = gen.reader.field_guid(def) {
+ let value = gen.guid(&guid);
+ let guid = gen.type_name(&Type::GUID);
+ quote! {
+ #doc
+ pub const #name: #guid = #value;
+ }
+ } else if let Some(value) = initializer(gen, def) {
+ let kind = gen.type_default_name(&ty);
+
+ quote! {
+ #doc
+ #features
+ pub const #name: #kind = #kind { #value };
+ }
+ } else {
+ quote! {}
+ }
+}
+
+fn initializer(gen: &Gen, def: Field) -> Option<TokenStream> {
+ let Some(value) = constant(gen, def) else {
+ return None;
+ };
+
+ let mut input = value.as_str();
+
+ let Type::TypeDef((def, _)) = gen.reader.field_type(def, None) else {
+ unimplemented!();
+ };
+
+ let mut result = quote! {};
+
+ for field in gen.reader.type_def_fields(def) {
+ let (value, rest) = field_initializer(gen, field, input);
+ input = rest;
+ result.combine(&value);
+ }
+
+ Some(result)
+}
+
+fn field_initializer<'a>(gen: &Gen, field: Field, input: &'a str) -> (TokenStream, &'a str) {
+ let name = to_ident(gen.reader.field_name(field));
+
+ match gen.reader.field_type(field, None) {
+ Type::GUID => {
+ let (literals, rest) = read_literal_array(input, 11);
+ let value = gen.guid(&GUID::from_string_args(&literals));
+ (quote! { #name: #value, }, rest)
+ }
+ Type::Win32Array((_, len)) => {
+ let (literals, rest) = read_literal_array(input, len);
+ let literals = literals.iter().map(|literal| TokenStream::from(*literal));
+ (quote! { #name: [#(#literals,)*], }, rest)
+ }
+ _ => {
+ let (literal, rest) = read_literal(input);
+ let literal: TokenStream = literal.into();
+ (quote! { #name: #literal, }, rest)
+ }
+ }
+}
+
+fn constant(gen: &Gen, def: Field) -> Option<String> {
+ gen.reader
+ .field_attributes(def)
+ .find(|attribute| gen.reader.attribute_name(*attribute) == "ConstantAttribute")
+ .map(|attribute| {
+ let args = gen.reader.attribute_args(attribute);
+ match &args[0].1 {
+ Value::String(value) => value.clone(),
+ _ => unimplemented!(),
+ }
+ })
+}
+
+fn read_literal(input: &str) -> (&str, &str) {
+ let mut start = None;
+ let mut end = 0;
+
+ for (pos, c) in input.bytes().enumerate() {
+ if start.is_none() {
+ if c != b' ' && c != b',' {
+ start = Some(pos);
+ }
+ } else if c == b' ' || c == b',' || c == b'}' {
+ break;
+ }
+ end += 1;
+ }
+
+ let Some(start) = start else {
+ unimplemented!();
+ };
+
+ (&input[start..end], &input[end..])
+}
+
+fn read_token(input: &str, token: u8) -> &str {
+ for (pos, c) in input.bytes().enumerate() {
+ if c == token {
+ return &input[pos + 1..];
+ } else if c != b' ' && c != b',' {
+ break;
+ }
+ }
+
+ panic!("`{}` expected", token.escape_ascii());
+}
+
+fn read_literal_array(input: &str, len: usize) -> (Vec<&str>, &str) {
+ let mut input = read_token(input, b'{');
+ let mut result = vec![];
+
+ for _ in 0..len {
+ let (literal, rest) = read_literal(input);
+ result.push(literal);
+ input = rest;
+ }
+
+ (result, read_token(input, b'}'))
+}