1use super::*;
2
3impl 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
73fn 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
86fn 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
108fn 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