1use crate::syntax::Atom::{self, *};
2use proc_macro2::{Ident, Span};
3use syn::parse::{Error, Parse, ParseStream, Result};
4use syn::{parenthesized, Expr, LitInt};
5
6pub(crate) enum Repr {
7 Align(LitInt),
8 Atom(Atom, Span),
9}
10
11impl Parse for Repr {
12 fn parse(input: ParseStream) -> Result<Self> {
13 let begin = input.cursor();
14 let ident: Ident = input.parse()?;
15 if let Some(atom) = Atom::from(&ident) {
16 match atom {
17 U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64 | Isize if input.is_empty() => {
18 return Ok(Repr::Atom(atom, ident.span()));
19 }
20 _ => {}
21 }
22 } else if ident == "align" {
23 let content;
24 match ::syn::__private::parse_parens(&input) {
::syn::__private::Ok(parens) => { content = parens.content; parens.token }
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};parenthesized!(content in input);
25 let align_expr: Expr = content.fork().parse()?;
26 if !#[allow(non_exhaustive_omitted_patterns)] match align_expr {
Expr::Lit(_) => true,
_ => false,
}matches!(align_expr, Expr::Lit(_)) {
27 return Err(Error::new_spanned(
28 align_expr,
29 "invalid repr(align) attribute: an arithmetic expression is not supported",
30 ));
31 }
32 let align_lit: LitInt = content.parse()?;
33 let align: u32 = align_lit.base10_parse()?;
34 if !align.is_power_of_two() {
35 return Err(Error::new_spanned(
36 align_lit,
37 "invalid repr(align) attribute: not a power of two",
38 ));
39 }
40 if align > 2u32.pow(13) {
41 return Err(Error::new_spanned(
42 align_lit,
43 "invalid repr(align) attribute: larger than 2^13",
44 ));
45 }
46 return Ok(Repr::Align(align_lit));
47 }
48 Err(Error::new_spanned(
49 begin.token_stream(),
50 "unrecognized repr",
51 ))
52 }
53}