enum_tools/parser/
params.rs1use crate::parser::error::Error;
2use proc_macro2::{Ident, Span};
3use proc_macro_error::{abort, emit_error};
4use std::collections::HashMap;
5use syn::punctuated::Punctuated;
6use syn::spanned::Spanned;
7use syn::{Lit, Path, PathArguments, PathSegment, VisRestricted, Visibility};
8
9pub(crate) struct Params {
10 name: String,
11 span: Span,
12 params: HashMap<String, (Span, Option<Lit>)>,
13}
14
15impl Params {
16 pub(crate) fn new(path: Path) -> Params {
17 let (name, span) = Self::path_to_name_span(path);
18 Params {
19 name,
20 span,
21 params: HashMap::new(),
22 }
23 }
24
25 pub(crate) fn span(&self) -> Span {
26 self.span
27 }
28
29 pub(crate) fn name(&self) -> &str {
30 &self.name
31 }
32
33 pub(crate) fn insert(&mut self, path: Path, lit: Option<Lit>) -> bool {
34 let (name, span) = Self::path_to_name_span(path);
35 self.params.insert(name, (span, lit)).is_some()
36 }
37
38 fn path_to_name_span(path: Path) -> (String, Span) {
39 if path.leading_colon.is_none() && path.segments.len() == 1 {
40 let first = path.segments.first().unwrap();
41 if matches!(first.arguments, PathArguments::None) {
42 return (first.ident.to_string(), path.span());
43 }
44 }
45 abort!(path, Error::UnsupportedPath);
46 }
47
48 pub(crate) fn get_bool(&mut self, name: &str) -> bool {
49 if let Some((_, lit)) = self.params.remove(name) {
50 if let Some(lit) = lit {
51 emit_error!(lit.span(), Error::UnexpectedLiteral);
52 false
53 } else {
54 true
55 }
56 } else {
57 false
58 }
59 }
60
61 pub(crate) fn get_str_opt(&mut self, name: &str) -> Option<String> {
62 if let Some((path, lit)) = self.params.remove(name) {
63 if let Some(Lit::Str(l)) = lit {
64 Some(l.value())
65 } else {
66 emit_error!(
67 lit.map_or_else(|| path.span(), |l| l.span()),
68 Error::ExpectedLiteral("string")
69 );
70 None
71 }
72 } else {
73 None
74 }
75 }
76
77 pub(crate) fn get_vis_name(&mut self, default_name: &str) -> (Option<Visibility>, String) {
78 let vis = if let Some((path, lit)) = self.params.remove("vis") {
79 if let Some(Lit::Str(l)) = lit {
80 match l.value().as_str() {
81 "" => Some(vis_inherited()),
82 "pub(crate)" => Some(vis_pub_crate()),
83 "pub" => Some(vis_pub()),
84 _ => {
85 emit_error!(l, Error::UnsupportedVisibility);
86 None
87 }
88 }
89 } else {
90 emit_error!(path, Error::ExpectedLiteral("string"));
91 None
92 }
93 } else {
94 None
95 };
96 let name = self
97 .get_str_opt("name")
98 .unwrap_or_else(|| default_name.to_string());
99 (vis, name)
100 }
101
102 pub(crate) fn finish<T>(self, value: T) -> T {
103 for (_, (param_path, _)) in self.params.into_iter() {
104 emit_error!(param_path, Error::UnknownParameter)
105 }
106 value
107 }
108}
109
110const fn vis_inherited() -> Visibility {
113 Visibility::Inherited
114}
115
116fn vis_pub_crate() -> Visibility {
117 Visibility::Restricted(VisRestricted {
118 pub_token: Default::default(),
119 paren_token: Default::default(),
120 in_token: None,
121 path: Box::new(Path {
122 leading_colon: None,
123 segments: {
124 let mut path = Punctuated::new();
125 path.push_value(PathSegment {
126 ident: Ident::new("crate", Span::call_site()),
127 arguments: Default::default(),
128 });
129 path
130 },
131 }),
132 })
133}
134
135fn vis_pub() -> Visibility {
136 Visibility::Public(Default::default())
137}