1use super::*;
2
3#[derive(Clone, Debug, PartialEq, Eq, Hash)]
4pub struct CppConst {
5 pub namespace: &'static str,
6 pub field: Field,
7}
8
9impl Ord for CppConst {
10 fn cmp(&self, other: &Self) -> Ordering {
11 (self.field.name(), self).cmp(&(other.field.name(), other))
12 }
13}
14
15impl PartialOrd for CppConst {
16 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
17 Some(self.cmp(other))
18 }
19}
20
21impl 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
146fn 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
150fn 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