1#[allow(unused_imports)]
2use core_extensions::{matches, SelfOps};
3use proc_macro2::{Span, TokenStream};
4use quote::{quote, ToTokens};
5use syn::parse::ParseBuffer;
6
7use as_derive_utils::{
8 parse_utils::ParseBufferExt, return_syn_err, syn_err, to_token_fn::ToTokenFnMut,
9};
10
11use crate::{ignored_wrapper::Ignored, literals_constructors::rslice_tokenizer};
12
13use super::common_tokens::CommonTokens;
14
15#[derive(Debug, Copy, Clone, PartialEq, Eq)]
17pub struct UncheckedReprAttr {
18 is_aligned: Option<u32>,
19 is_packed: Option<u32>,
20 repr_kind: Option<UncheckedReprKind>,
21 repr_span: Ignored<Span>,
22 discriminant_repr: Option<DiscriminantRepr>,
23}
24
25impl Default for UncheckedReprAttr {
26 fn default() -> Self {
27 Self {
28 is_aligned: None,
29 is_packed: None,
30 repr_kind: None,
31 repr_span: Ignored::new(Span::call_site()),
32 discriminant_repr: None,
33 }
34 }
35}
36
37#[derive(Debug, Copy, Clone, PartialEq, Eq)]
38pub enum UncheckedReprKind {
39 C,
40 Transparent,
41 Int,
43}
44
45#[repr(u8)]
47#[derive(Debug, Copy, Clone, PartialEq, Eq)]
48pub enum DiscriminantRepr {
49 U8,
50 I8,
51 U16,
52 I16,
53 U32,
54 I32,
55 U64,
56 I64,
57 Usize,
58 Isize,
60}
61
62#[derive(Debug, Copy, Clone, PartialEq, Eq)]
67pub enum Repr {
68 C(Option<DiscriminantRepr>),
69 Transparent,
70 Int(DiscriminantRepr),
72}
73
74#[derive(Debug, Copy, Clone, PartialEq, Eq)]
75pub struct ReprAttr {
76 pub span: Ignored<Span>,
77 pub is_aligned: Option<u32>,
78 pub is_packed: Option<u32>,
79 pub variant: Repr,
80}
81
82pub(crate) static REPR_ERROR_MSG: &str = "\n\
83 the #[repr(..)] attribute must be one of the supported attributes:\n\
84 \t- #[repr(C)]\n\
85 \t- #[repr(transparent)]\n\
86 \t- #[repr(integer_type_up_to_64_bits)]:enums only\n\
87 \t- #[repr(usize)]:enums only\n\
88 \t- #[repr(isize)]:enums only\n\
89 \t- #[repr(align(<some_integer>))]\n\
90";
91
92impl UncheckedReprAttr {
93 pub fn set_aligned(&mut self, alignment: u32) -> Result<(), syn::Error> {
94 self.is_aligned = Some(alignment);
95 Ok(())
96 }
97 pub fn set_packed(&mut self, packing: Option<u32>) -> Result<(), syn::Error> {
98 self.is_packed = packing.or(Some(1));
99 Ok(())
100 }
101 pub fn set_repr_kind(
102 &mut self,
103 repr_kind: UncheckedReprKind,
104 repr_span: proc_macro2::Span,
105 ) -> Result<(), syn::Error> {
106 if let Some(from) = self.discriminant_repr {
107 return_syn_err!(
108 repr_span,
109 "Attempting to override {:?} representation with {:?}.",
110 from,
111 repr_kind
112 );
113 }
114 self.repr_kind = Some(repr_kind);
115 self.repr_span.value = repr_span;
116 Ok(())
117 }
118 pub fn set_discriminant_repr(
119 &mut self,
120 discriminant_repr: DiscriminantRepr,
121 repr_span: proc_macro2::Span,
122 ) -> Result<(), syn::Error> {
123 if let Some(x) = self.discriminant_repr {
124 return_syn_err!(
125 repr_span,
126 "Attempting to override {:?} representation with {:?}.",
127 x,
128 discriminant_repr
129 );
130 }
131 self.repr_kind = self.repr_kind.or(Some(UncheckedReprKind::Int));
132 self.repr_span.value = repr_span;
133
134 self.discriminant_repr = Some(discriminant_repr);
135 Ok(())
136 }
137}
138
139mod kw {
140 syn::custom_keyword! {u8}
141 syn::custom_keyword! {i8}
142 syn::custom_keyword! {u16}
143 syn::custom_keyword! {i16}
144 syn::custom_keyword! {u32}
145 syn::custom_keyword! {i32}
146 syn::custom_keyword! {u64}
147 syn::custom_keyword! {i64}
148 syn::custom_keyword! {usize}
149 syn::custom_keyword! {isize}
150}
151
152impl DiscriminantRepr {
153 pub fn from_parser(input: &'_ ParseBuffer<'_>) -> Option<Self> {
154 if input.peek_parse(kw::u8).ok()?.is_some() {
155 Some(DiscriminantRepr::U8)
156 } else if input.peek_parse(kw::i8).ok()?.is_some() {
157 Some(DiscriminantRepr::I8)
158 } else if input.peek_parse(kw::u16).ok()?.is_some() {
159 Some(DiscriminantRepr::U16)
160 } else if input.peek_parse(kw::i16).ok()?.is_some() {
161 Some(DiscriminantRepr::I16)
162 } else if input.peek_parse(kw::u32).ok()?.is_some() {
163 Some(DiscriminantRepr::U32)
164 } else if input.peek_parse(kw::i32).ok()?.is_some() {
165 Some(DiscriminantRepr::I32)
166 } else if input.peek_parse(kw::u64).ok()?.is_some() {
167 Some(DiscriminantRepr::U64)
168 } else if input.peek_parse(kw::i64).ok()?.is_some() {
169 Some(DiscriminantRepr::I64)
170 } else if input.peek_parse(kw::usize).ok()?.is_some() {
171 Some(DiscriminantRepr::Usize)
172 } else if input.peek_parse(kw::isize).ok()?.is_some() {
173 Some(DiscriminantRepr::Isize)
174 } else {
175 None
176 }
177 }
178}
179
180impl ReprAttr {
181 pub fn new(unchecked: UncheckedReprAttr) -> Result<Self, syn::Error> {
182 let span = unchecked.repr_span;
183 let is_aligned = unchecked.is_aligned;
184 let is_packed = unchecked.is_packed;
185 let ura: UncheckedReprKind = unchecked
186 .repr_kind
187 .ok_or_else(|| syn_err!(*span, "{}", REPR_ERROR_MSG))?;
188 let dr: Option<DiscriminantRepr> = unchecked.discriminant_repr;
189 let variant = match (ura, dr) {
190 (UncheckedReprKind::C, x) => Repr::C(x),
191 (UncheckedReprKind::Transparent, None) => Repr::Transparent,
192 (UncheckedReprKind::Transparent, Some(_)) => {
193 return_syn_err!(
194 *span,
195 "repr(transparent) cannot be combined with repr(IntegerType)",
196 )
197 }
198 (UncheckedReprKind::Int, None) => panic!("Bug:(UncheckedReprKind::Int,None)"),
199 (UncheckedReprKind::Int, Some(x)) => Repr::Int(x),
200 };
201 Ok(Self {
202 span,
203 variant,
204 is_aligned,
205 is_packed,
206 })
207 }
208
209 pub fn type_ident(&self) -> Option<syn::Ident> {
212 let int_repr = match self.variant {
213 Repr::C(None) => DiscriminantRepr::Isize,
214 Repr::C(Some(int_repr)) | Repr::Int(int_repr) => int_repr,
215 Repr::Transparent => return None,
216 };
217
218 let ty_lit = match int_repr {
219 DiscriminantRepr::U8 => "u8",
220 DiscriminantRepr::U16 => "u16",
221 DiscriminantRepr::U32 => "u32",
222 DiscriminantRepr::U64 => "u64",
223 DiscriminantRepr::I8 => "i8",
224 DiscriminantRepr::I16 => "i16",
225 DiscriminantRepr::I32 => "i32",
226 DiscriminantRepr::I64 => "i64",
227 DiscriminantRepr::Usize => "usize",
228 DiscriminantRepr::Isize => "isize",
229 };
230
231 Some(syn::Ident::new(ty_lit, Span::call_site()))
232 }
233
234 pub(crate) fn tokenize_discriminant_exprs<'a, I>(
239 self,
240 exprs: I,
241 ctokens: &'a CommonTokens,
242 ) -> impl ToTokens + 'a
243 where
244 I: IntoIterator<Item = Option<&'a syn::Expr>> + 'a,
245 {
246 let mut exprs = exprs.into_iter();
247
248 ToTokenFnMut::new(move |ts| {
249 let int_repr = match self.variant {
250 Repr::C(x) => x,
251 Repr::Int(x) => Some(x),
252 Repr::Transparent => unreachable!(),
253 };
254
255 match int_repr.unwrap_or(DiscriminantRepr::Isize) {
256 DiscriminantRepr::U8 => quote!(__TLDiscriminants::from_u8_slice),
257 DiscriminantRepr::U16 => quote!(__TLDiscriminants::from_u16_slice),
258 DiscriminantRepr::U32 => quote!(__TLDiscriminants::from_u32_slice),
259 DiscriminantRepr::U64 => quote!(__TLDiscriminants::from_u64_slice),
260 DiscriminantRepr::I8 => quote!(__TLDiscriminants::from_i8_slice),
261 DiscriminantRepr::I16 => quote!(__TLDiscriminants::from_i16_slice),
262 DiscriminantRepr::I32 => quote!(__TLDiscriminants::from_i32_slice),
263 DiscriminantRepr::I64 => quote!(__TLDiscriminants::from_i64_slice),
264 DiscriminantRepr::Usize => quote!(__TLDiscriminants::from_usize_slice),
265 DiscriminantRepr::Isize => quote!(__TLDiscriminants::from_isize_slice),
266 }
267 .to_tokens(ts);
268
269 ctokens.paren.surround(ts, |ts| {
270 tokenize_discriminant_exprs_inner(&mut exprs, SliceType::RSlice, ctokens, ts);
271 });
272 })
273 }
274
275 pub(crate) fn tokenize_discriminant_slice<'a, I>(
279 self,
280 exprs: I,
281 ctokens: &'a CommonTokens,
282 ) -> impl ToTokens + 'a
283 where
284 I: IntoIterator<Item = Option<&'a syn::Expr>> + 'a,
285 {
286 let mut exprs = exprs.into_iter();
287
288 ToTokenFnMut::new(move |ts| {
289 tokenize_discriminant_exprs_inner(&mut exprs, SliceType::StdSlice, ctokens, ts);
290 })
291 }
292}
293
294#[allow(dead_code)]
295impl ReprAttr {
296 pub fn span(self) -> Span {
297 *self.span
298 }
299
300 pub fn is_repr_transparent(self) -> bool {
301 matches!(self.variant, Repr::Transparent { .. })
302 }
303
304 pub fn is_repr_c(self) -> bool {
305 matches!(self.variant, Repr::C { .. })
306 }
307
308 pub fn is_repr_int(self) -> bool {
309 matches!(self.variant, Repr::Int { .. })
310 }
311}
312
313#[derive(Copy, Clone)]
314enum SliceType {
315 StdSlice,
316 RSlice,
317}
318
319fn tokenize_discriminant_exprs_inner<'a, I>(
323 exprs: I,
324 type_: SliceType,
325 ctokens: &'a CommonTokens,
326 ts: &mut TokenStream,
327) where
328 I: Iterator<Item = Option<&'a syn::Expr>>,
329{
330 let zero_expr = crate::utils::expr_from_int(0);
331 let mut last_explicit_discr = &zero_expr;
332 let mut since_last_expr = 0;
333
334 let iter = exprs.map(|expr| match expr {
335 Some(discr) => {
336 let ts = quote!(#discr);
337 last_explicit_discr = discr;
338 since_last_expr = 1;
339 ts
340 }
341 None => {
342 let offset = crate::utils::uint_lit(since_last_expr);
343 let ts = quote!( (#last_explicit_discr)+#offset );
344 since_last_expr += 1;
345 ts
346 }
347 });
348 match type_ {
349 SliceType::StdSlice => {
350 ctokens.and_.to_tokens(ts);
351 ctokens.bracket.surround(ts, |ts| {
352 for elem in iter {
353 elem.to_tokens(ts);
354 ctokens.comma.to_tokens(ts)
355 }
356 });
357 }
358 SliceType::RSlice => {
359 rslice_tokenizer(iter).to_tokens(ts);
360 }
361 }
362}
363
364impl ToTokens for ReprAttr {
365 fn to_tokens(&self, ts: &mut TokenStream) {
366 match self.variant {
367 Repr::C(None) => {
368 quote!(__ReprAttr::C)
369 }
370 Repr::C(Some(int_repr)) => {
371 let int_repr = discr_repr_tokenizer(int_repr);
372 quote!(__ReprAttr::CAndInt(#int_repr))
373 }
374 Repr::Transparent => {
375 quote!(__ReprAttr::Transparent)
376 }
377 Repr::Int(int_repr) => {
378 let int_repr = discr_repr_tokenizer(int_repr);
379 quote!(__ReprAttr::Int(#int_repr))
380 }
381 }
382 .to_tokens(ts);
383 }
384}
385
386fn discr_repr_tokenizer(repr: DiscriminantRepr) -> impl ToTokens {
387 ToTokenFnMut::new(move |ts| {
388 match repr {
389 DiscriminantRepr::U8 => quote!(__DiscriminantRepr::U8),
390 DiscriminantRepr::I8 => quote!(__DiscriminantRepr::I8),
391 DiscriminantRepr::U16 => quote!(__DiscriminantRepr::U16),
392 DiscriminantRepr::I16 => quote!(__DiscriminantRepr::I16),
393 DiscriminantRepr::U32 => quote!(__DiscriminantRepr::U32),
394 DiscriminantRepr::I32 => quote!(__DiscriminantRepr::I32),
395 DiscriminantRepr::U64 => quote!(__DiscriminantRepr::U64),
396 DiscriminantRepr::I64 => quote!(__DiscriminantRepr::I64),
397 DiscriminantRepr::Usize => quote!(__DiscriminantRepr::Usize),
398 DiscriminantRepr::Isize => quote!(__DiscriminantRepr::Isize),
399 }
400 .to_tokens(ts);
401 })
402}