1 | use super::*; |
2 | |
3 | #[derive (Clone, Debug, PartialEq, Eq, Hash)] |
4 | pub struct CppConst { |
5 | pub namespace: &'static str, |
6 | pub field: Field, |
7 | } |
8 | |
9 | impl Ord for CppConst { |
10 | fn cmp(&self, other: &Self) -> Ordering { |
11 | (self.field.name(), self).cmp(&(other.field.name(), other)) |
12 | } |
13 | } |
14 | |
15 | impl PartialOrd for CppConst { |
16 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
17 | Some(self.cmp(other)) |
18 | } |
19 | } |
20 | |
21 | impl CppConst { |
22 | pub fn type_name(&self) -> TypeName { |
23 | TypeName(self.namespace, self.field.name()) |
24 | } |
25 | |
26 | pub fn write_name(&self, writer: &Writer) -> TokenStream { |
27 | self.type_name().write(writer, &[]) |
28 | } |
29 | |
30 | pub fn write(&self, writer: &Writer) -> TokenStream { |
31 | let name = to_ident(self.field.name()); |
32 | |
33 | if let Some(guid) = self.field.guid_attribute() { |
34 | return writer.write_cpp_const_guid(name, &guid); |
35 | } |
36 | |
37 | let field_ty = self.field.ty(None).to_const_type(); |
38 | |
39 | let mut dependencies = TypeMap::new(); |
40 | |
41 | if writer.config.package { |
42 | self.dependencies(&mut dependencies); |
43 | } |
44 | |
45 | let cfg = writer.write_cfg(self.field, self.namespace, &dependencies, false); |
46 | |
47 | if let Some(constant) = self.field.constant() { |
48 | let constant_ty = constant.ty(); |
49 | |
50 | if field_ty == constant_ty { |
51 | if field_ty == Type::String { |
52 | let crate_name = writer.write_core(); |
53 | let value = constant.value().write(); |
54 | |
55 | // TODO: if writer.config.no_core then write these literals out as byte strings? |
56 | if is_ansi_encoding(self.field) { |
57 | quote! { |
58 | #cfg |
59 | pub const #name: #crate_name PCSTR = #crate_name s!(#value); |
60 | } |
61 | } else { |
62 | quote! { |
63 | #cfg |
64 | pub const #name: #crate_name PCWSTR = #crate_name w!(#value); |
65 | } |
66 | } |
67 | } else { |
68 | let ty = field_ty.write_name(writer); |
69 | let value = constant.value().write(); |
70 | |
71 | quote! { |
72 | #cfg |
73 | pub const #name: #ty = #value; |
74 | } |
75 | } |
76 | } else { |
77 | let underlying_ty = field_ty.underlying_type(); |
78 | let ty = field_ty.write_name(writer); |
79 | let mut value = constant.value().write(); |
80 | |
81 | if underlying_ty == constant_ty { |
82 | if is_signed_error(&field_ty) { |
83 | if let Value::I32(signed) = constant.value() { |
84 | value = format!("0x {:X}_u32 as _" , signed).into(); |
85 | } |
86 | } |
87 | } else if field_ty == Type::Bool { |
88 | value = match constant.value() { |
89 | Value::U8(1) => quote! { true }, |
90 | Value::U8(0) => quote! { false }, |
91 | _ => panic!(), |
92 | }; |
93 | } else { |
94 | value = quote! { #value as _ }; |
95 | } |
96 | |
97 | if writer.config.sys || field_ty == Type::Bool { |
98 | quote! { |
99 | #cfg |
100 | pub const #name: #ty = #value; |
101 | } |
102 | } else { |
103 | quote! { |
104 | #cfg |
105 | pub const #name: #ty = #ty(#value); |
106 | } |
107 | } |
108 | } |
109 | } else if let Some(attribute) = self.field.find_attribute("ConstantAttribute" ) { |
110 | let args = attribute.args(); |
111 | let Some((_, Value::Str(mut input))) = args.first() else { |
112 | panic!() |
113 | }; |
114 | |
115 | let Type::CppStruct(ty) = &field_ty else { |
116 | panic!() |
117 | }; |
118 | |
119 | let mut tokens = quote! {}; |
120 | |
121 | for field in ty.def.fields() { |
122 | let (value, rest) = writer.field_initializer(field, input); |
123 | input = rest; |
124 | tokens.combine(value); |
125 | } |
126 | |
127 | let ty = field_ty.write_name(writer); |
128 | |
129 | quote! { |
130 | #cfg |
131 | pub const #name: #ty = #ty { #tokens }; |
132 | } |
133 | } else { |
134 | panic!() |
135 | } |
136 | } |
137 | |
138 | pub fn dependencies(&self, dependencies: &mut TypeMap) { |
139 | self.field |
140 | .ty(None) |
141 | .to_const_type() |
142 | .dependencies(dependencies); |
143 | } |
144 | } |
145 | |
146 | fn is_ansi_encoding(row: Field) -> bool { |
147 | row.find_attribute(name:"NativeEncodingAttribute" ).is_some_and(|attribute: Attribute| matches!(attribute.args().first(), Some((_, Value::Str(encoding))) if *encoding == "ansi" )) |
148 | } |
149 | |
150 | fn is_signed_error(ty: &Type) -> bool { |
151 | match ty { |
152 | Type::HRESULT => true, |
153 | Type::CppStruct(ty: &CppStruct) => ty.type_name() == TypeName::NTSTATUS, |
154 | _ => false, |
155 | } |
156 | } |
157 | |