| 1 | use super::*; |
| 2 | |
| 3 | impl Writer { |
| 4 | pub fn write_cpp_const_guid(&self, name: TokenStream, value: &GUID) -> TokenStream { |
| 5 | let crate_name = self.write_core(); |
| 6 | let value = self.write_guid_u128(value); |
| 7 | |
| 8 | quote! { |
| 9 | pub const #name: #crate_name GUID = #crate_name GUID::from_u128(#value); |
| 10 | } |
| 11 | } |
| 12 | |
| 13 | pub fn write_guid_u128(&self, value: &GUID) -> TokenStream { |
| 14 | format!( |
| 15 | "0x {:08x?}_ {:04x?}_ {:04x?}_ {:02x?}{:02x?}_ {:02x?}{:02x?}{:02x?}{:02x?}{:02x?}{:02x?}" , |
| 16 | value.0, |
| 17 | value.1, |
| 18 | value.2, |
| 19 | value.3, |
| 20 | value.4, |
| 21 | value.5, |
| 22 | value.6, |
| 23 | value.7, |
| 24 | value.8, |
| 25 | value.9, |
| 26 | value.10 |
| 27 | ) |
| 28 | .into() |
| 29 | } |
| 30 | |
| 31 | pub fn field_initializer<'a>(&self, field: Field, input: &'a str) -> (TokenStream, &'a str) { |
| 32 | let name = to_ident(field.name()); |
| 33 | |
| 34 | match field.ty(None) { |
| 35 | Type::GUID => { |
| 36 | let (literals, rest) = read_literal_array(input, 11); |
| 37 | let value = self.write_guid_u128(&GUID( |
| 38 | literals[0].parse().unwrap(), |
| 39 | literals[1].parse().unwrap(), |
| 40 | literals[2].parse().unwrap(), |
| 41 | literals[3].parse().unwrap(), |
| 42 | literals[4].parse().unwrap(), |
| 43 | literals[5].parse().unwrap(), |
| 44 | literals[6].parse().unwrap(), |
| 45 | literals[7].parse().unwrap(), |
| 46 | literals[8].parse().unwrap(), |
| 47 | literals[9].parse().unwrap(), |
| 48 | literals[10].parse().unwrap(), |
| 49 | )); |
| 50 | let crate_name = self.write_core(); |
| 51 | (quote! { #name: #crate_name GUID::from_u128(#value), }, rest) |
| 52 | } |
| 53 | Type::ArrayFixed(_, len) => { |
| 54 | let (literals, rest) = read_literal_array(input, len); |
| 55 | let literals = literals.iter().map(|literal| TokenStream::from(*literal)); |
| 56 | (quote! { #name: [#(#literals,)*], }, rest) |
| 57 | } |
| 58 | Type::PtrMut(_, _) => { |
| 59 | // The Win32 metadata uses integer values for initializing pointers. This is a workaround |
| 60 | // to allow most such cases to work. |
| 61 | let (_, rest) = read_literal(input); |
| 62 | (quote! { #name: core::ptr::null_mut(), }, rest) |
| 63 | } |
| 64 | _ => { |
| 65 | let (literal, rest) = read_literal(input); |
| 66 | let literal: TokenStream = literal.into(); |
| 67 | (quote! { #name: #literal, }, rest) |
| 68 | } |
| 69 | } |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | fn read_literal_array(input: &str, len: usize) -> (Vec<&str>, &str) { |
| 74 | let mut input: &str = read_token(input, token:b'{' ); |
| 75 | let mut result: Vec<&str> = vec![]; |
| 76 | |
| 77 | for _ in 0..len { |
| 78 | let (literal: &str, rest: &str) = read_literal(input); |
| 79 | result.push(literal); |
| 80 | input = rest; |
| 81 | } |
| 82 | |
| 83 | (result, read_token(input, token:b'}' )) |
| 84 | } |
| 85 | |
| 86 | fn read_literal(input: &str) -> (&str, &str) { |
| 87 | let mut start: Option = None; |
| 88 | let mut end: usize = 0; |
| 89 | |
| 90 | for (pos: usize, c: u8) in input.bytes().enumerate() { |
| 91 | if start.is_none() { |
| 92 | if c != b' ' && c != b',' { |
| 93 | start = Some(pos); |
| 94 | } |
| 95 | } else if c == b' ' || c == b',' || c == b'}' { |
| 96 | break; |
| 97 | } |
| 98 | end += 1; |
| 99 | } |
| 100 | |
| 101 | let Some(start: usize) = start else { |
| 102 | panic!(); |
| 103 | }; |
| 104 | |
| 105 | (&input[start..end], &input[end..]) |
| 106 | } |
| 107 | |
| 108 | fn read_token(input: &str, token: u8) -> &str { |
| 109 | for (pos: usize, c: u8) in input.bytes().enumerate() { |
| 110 | if c == token { |
| 111 | return &input[pos + 1..]; |
| 112 | } else if c != b' ' && c != b',' { |
| 113 | break; |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | panic!("` {}` expected" , token.escape_ascii()); |
| 118 | } |
| 119 | |