1use super::*;
2
3pub fn writer(writer: &Writer, def: TypeDef) -> TokenStream {
4 let type_name = def.type_name();
5 let ident = to_ident(type_name.name);
6 let underlying_type = def.underlying_type();
7 let underlying_type = writer.type_name(&underlying_type);
8
9 // TODO: unscoped enums should be removed from metadata
10 let is_scoped = def.flags().contains(TypeAttributes::WindowsRuntime) || def.has_attribute("ScopedEnumAttribute");
11
12 let cfg = type_def_cfg(def, &[]);
13 let doc = writer.cfg_doc(&cfg);
14 let features = writer.cfg_features(&cfg);
15
16 let fields: Vec<(TokenStream, TokenStream)> = def
17 .fields()
18 .filter_map(|field| {
19 if field.flags().contains(FieldAttributes::Literal) {
20 let field_name = to_ident(field.name());
21 let constant = field.constant().unwrap();
22 let value = writer.value(&constant.value());
23
24 Some((field_name, value))
25 } else {
26 None
27 }
28 })
29 .collect();
30
31 let eq = if writer.sys {
32 quote! {}
33 } else {
34 quote! {
35 // Unfortunately, Rust requires these to be derived to allow constant patterns.
36 #[derive(::core::cmp::PartialEq, ::core::cmp::Eq)]
37 }
38 };
39
40 let mut tokens = if is_scoped || !writer.sys {
41 quote! {
42 #doc
43 #features
44 #[repr(transparent)]
45 #eq
46 pub struct #ident(pub #underlying_type);
47 }
48 } else {
49 quote! {
50 #doc
51 #features
52 pub type #ident = #underlying_type;
53 }
54 };
55
56 if is_scoped {
57 let fields = fields.iter().map(|(field_name, value)| {
58 quote! {
59 pub const #field_name: Self = Self(#value);
60 }
61 });
62
63 tokens.combine(&quote! {
64 #features
65 impl #ident {
66 #(#fields)*
67 }
68 });
69 }
70
71 if is_scoped || !writer.sys {
72 tokens.combine(&quote! {
73 #features
74 impl ::core::marker::Copy for #ident {}
75 #features
76 impl ::core::clone::Clone for #ident {
77 fn clone(&self) -> Self {
78 *self
79 }
80 }
81 });
82 }
83
84 if !writer.sys {
85 tokens.combine(&quote! {
86 #features
87 impl ::core::default::Default for #ident {
88 fn default() -> Self {
89 Self(0)
90 }
91 }
92 });
93 }
94
95 if !writer.sys {
96 let name = type_name.name;
97 tokens.combine(&quote! {
98 #features
99 impl ::windows_core::TypeKind for #ident {
100 type TypeKind = ::windows_core::CopyType;
101 }
102 #features
103 impl ::core::fmt::Debug for #ident {
104 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
105 f.debug_tuple(#name).field(&self.0).finish()
106 }
107 }
108 });
109
110 // Win32 enums use the Flags attribute. WinRT enums don't have the Flags attribute but are paritioned merely based
111 // on whether they are signed.
112 // TODO: Win32 metadata should just follow WinRT's example here.
113 let type_def_is_flags = def.has_attribute("FlagsAttribute") || (def.flags().contains(TypeAttributes::WindowsRuntime) && def.underlying_type() == Type::U32);
114
115 if type_def_is_flags {
116 tokens.combine(&quote! {
117 #features
118 impl #ident {
119 pub const fn contains(&self, other: Self) -> bool {
120 self.0 & other.0 == other.0
121 }
122 }
123 #features
124 impl ::core::ops::BitOr for #ident {
125 type Output = Self;
126
127 fn bitor(self, other: Self) -> Self {
128 Self(self.0 | other.0)
129 }
130 }
131 #features
132 impl ::core::ops::BitAnd for #ident {
133 type Output = Self;
134
135 fn bitand(self, other: Self) -> Self {
136 Self(self.0 & other.0)
137 }
138 }
139 #features
140 impl ::core::ops::BitOrAssign for #ident {
141 fn bitor_assign(&mut self, other: Self) {
142 self.0.bitor_assign(other.0)
143 }
144 }
145 #features
146 impl ::core::ops::BitAndAssign for #ident {
147 fn bitand_assign(&mut self, other: Self) {
148 self.0.bitand_assign(other.0)
149 }
150 }
151 #features
152 impl ::core::ops::Not for #ident {
153 type Output = Self;
154
155 fn not(self) -> Self {
156 Self(self.0.not())
157 }
158 }
159 });
160 }
161
162 if def.flags().contains(TypeAttributes::WindowsRuntime) {
163 let signature = Literal::byte_string(type_def_signature(def, &[]).as_bytes());
164
165 tokens.combine(&quote! {
166 #features
167 impl ::windows_core::RuntimeType for #ident {
168 const SIGNATURE: ::windows_core::imp::ConstBuffer = ::windows_core::imp::ConstBuffer::from_slice(#signature);
169 }
170 });
171 }
172 }
173
174 tokens
175}
176