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 | |