1 | use super::*; |
2 | |
3 | pub 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("e! { |
64 | #features |
65 | impl #ident { |
66 | #(#fields)* |
67 | } |
68 | }); |
69 | } |
70 | |
71 | if is_scoped || !writer.sys { |
72 | tokens.combine("e! { |
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("e! { |
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("e! { |
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("e! { |
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("e! { |
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 | |