enum_tools/parser/
values.rs

1use crate::feature::sorted::FeatureSorted;
2use crate::parser::error::Error;
3use proc_macro2::Span;
4use proc_macro_error::{abort, emit_error};
5use std::collections::HashMap;
6use syn::spanned::Spanned;
7use syn::{Data, Expr, ExprLit, ExprUnary, Fields, Ident, Lit, Meta, MetaNameValue, UnOp};
8
9pub(crate) fn parse_values(
10    span: Span,
11    data: Data,
12    sorted: FeatureSorted,
13) -> Vec<(i64, (Ident, String))> {
14    if let Data::Enum(data) = data {
15        let mut values = HashMap::new();
16        let mut last = -1i64;
17        let mut last_name = None;
18
19        for mut v in data.variants {
20            let span = v.span();
21            if !matches!(v.fields, Fields::Unit) {
22                emit_error!(span, Error::OnlyUnitField);
23            }
24            let mut name = v.ident.to_string();
25            for a in v.attrs {
26                if a.path().is_ident("enum_tools") {
27                    if let Meta::List(meta_list) = &a.meta {
28                        let nested = meta_list
29                            .parse_args()
30                            .unwrap_or_else(|e| abort!(meta_list, Error::MetaParseError(e)));
31                        if let Meta::NameValue(MetaNameValue {
32                            path,
33                            value:
34                                Expr::Lit(ExprLit {
35                                    lit: Lit::Str(lit_str),
36                                    ..
37                                }),
38                            ..
39                        }) = nested
40                        {
41                            if !path.is_ident("rename") {
42                                emit_error!(a, Error::UnsupportedAttributeType);
43                            } else {
44                                name = lit_str.value();
45                            }
46                        } else {
47                            emit_error!(a, Error::UnsupportedAttributeType);
48                        }
49                    } else {
50                        emit_error!(a, Error::UnsupportedAttributeType);
51                    }
52                }
53            }
54            if sorted.name {
55                if let Some(last_name) = last_name {
56                    if last_name >= name {
57                        emit_error!(span, Error::FieldsNotNameSorted);
58                    }
59                }
60                last_name = Some(name.clone());
61            }
62            if let Some((_, d)) = v.discriminant.take() {
63                // check if number is negated
64                let mut negate = false;
65                let mut num = &d;
66                if let Expr::Unary(ExprUnary { attrs, op, expr }) = &d {
67                    if attrs.is_empty() {
68                        if let UnOp::Neg(_) = op {
69                            num = expr;
70                            negate = true;
71                        }
72                    }
73                }
74
75                if let Expr::Lit(ExprLit {
76                    lit: Lit::Int(i), ..
77                }) = num
78                {
79                    if let Ok(mut i) = i.base10_parse::<i64>() {
80                        if negate {
81                            i = -i;
82                        }
83                        if sorted.value && !values.is_empty() && i < last {
84                            emit_error!(span, Error::FieldsNotValueSorted);
85                        }
86                        if values.insert(i, (v.ident, name)).is_some() {
87                            emit_error!(span, Error::DuplicateValue);
88                        }
89                        last = i;
90                    } else {
91                        emit_error!(span, Error::NoI64);
92                    }
93                } else {
94                    emit_error!(span, Error::NotInteger);
95                }
96            } else {
97                if last == i64::MAX {
98                    emit_error!(span, Error::I64Overflow);
99                }
100                last = last.wrapping_add(1);
101                if values.insert(last, (v.ident, name)).is_some() {
102                    emit_error!(span, Error::DuplicateValue);
103                }
104            }
105        }
106
107        let mut values = values
108            .iter()
109            .map(|(k, v)| (*k, v.clone()))
110            .collect::<Vec<_>>();
111        values.sort_by_key(|v| v.0);
112
113        if values.is_empty() {
114            abort!(span, Error::NoVariantsFound);
115        }
116
117        values
118    } else {
119        abort!(span, Error::NoEnum);
120    }
121}