1use syn::parse;
3use std::convert::TryInto;
4use syn::ext::IdentExt;
5
6pub trait ParseOpt: Sized {
11 fn parse(input: parse::ParseStream) -> parse::Result<Option<Self>>;
12}
13
14pub trait ParseOptExt {
15 fn parse_opt<T: ParseOpt>(&self) -> parse::Result<Option<T>>;
18}
19
20impl<'a> ParseOptExt for parse::ParseBuffer<'a> {
21 fn parse_opt<T: ParseOpt>(&self) -> parse::Result<Option<T>> {
22 T::parse(self)
23 }
24}
25
26pub fn eat_pseudo_keyword(input: parse::ParseStream, kw: &str) -> bool {
28 input.step(|cursor| {
29 if let Some((ident, rest)) = cursor.ident() {
30 if ident == kw {
31 return Ok(((), rest));
32 }
33 }
34 Err(cursor.error("expected identifier"))
35 }).is_ok()
36}
37
38pub fn parse_ident_or_rust_keyword(input: parse::ParseStream) -> parse::Result<syn::Ident> {
40 syn::Ident::parse_any(input)
41}
42
43pub fn as_ident(expr: &syn::Expr) -> Option<&syn::Ident> {
45 let path = match *expr {
46 syn::Expr::Path(syn::ExprPath {ref path, qself: None, ..}) => path,
47 _ => return None
48 };
49
50 path.get_ident()
51}
52
53pub fn as_lit(expr: &syn::Expr) -> Option<&syn::Lit> {
55 let mut inner = expr;
57 while let syn::Expr::Group(syn::ExprGroup { expr, .. }) = inner {
58 inner = expr;
59 }
60
61 match inner {
62 syn::Expr::Lit(syn::ExprLit { ref lit, .. } ) => Some(lit),
63 _ => None
64 }
65}
66
67pub fn as_lit_with_negation(expr: &syn::Expr) -> Option<(&syn::Lit, bool)> {
69 let mut inner = expr;
71 while let syn::Expr::Group(syn::ExprGroup { expr, .. }) = inner {
72 inner = expr;
73 }
74
75 match inner {
76 syn::Expr::Lit(syn::ExprLit { ref lit, .. } ) => Some((lit, false)),
77 syn::Expr::Unary(syn::ExprUnary { op: syn::UnOp::Neg(_), ref expr, .. } ) => {
78 match &**expr {
79 syn::Expr::Lit(syn::ExprLit { ref lit, .. } ) => Some((lit, true)),
80 _ => None
81 }
82 }
83 _ => None
84 }
85}
86
87pub fn as_unsigned_number(expr: &syn::Expr) -> Option<u64> {
89 match as_lit(expr)? {
90 syn::Lit::Int(i) => i.base10_parse().ok(),
91 _ => None
92 }
93}
94
95pub fn as_signed_number(expr: &syn::Expr) -> Option<i64> {
97 let (expr, negated) = as_lit_with_negation(expr)?;
99 match expr {
100 syn::Lit::Int(i) => if let Ok(value) = i.base10_parse::<u64>() {
101 let value: i64 = value.try_into().ok()?;
102 Some (if negated {-value} else {value})
103 } else {
104 None
105 },
106 _ => None
107 }
108}
109
110pub fn as_float(expr: &syn::Expr) -> Option<f64> {
112 let (expr, negated) = as_lit_with_negation(expr)?;
113 match expr {
114 syn::Lit::Float(i) => i.base10_parse::<f64>().ok().map(|i| if negated { -i } else { i } ),
115 _ => None
116 }
117}