1use std::fmt::Debug;
2
3use crate::opt::ConfigValue;
4use crate::opt::Opt;
5use crate::set::Ctor;
6use crate::trace;
7use crate::Error;
8
9#[cfg(feature = "sync")]
10mod __creator {
11 use super::*;
12
13 pub struct Creator<O, C, E: Into<Error>> {
14 pub(crate) cid: Cid,
15
16 pub(crate) callback: Box<dyn FnMut(C) -> Result<O, E> + Send + Sync + 'static>,
17 }
18
19 impl<O: Opt, C, E: Into<Error>> Debug for Creator<O, C, E> {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 f.debug_struct("Creator")
22 .field("cid", &self.cid)
23 .field("callback", &"{...}")
24 .finish()
25 }
26 }
27
28 impl<O: Opt, C, E: Into<Error>> Creator<O, C, E> {
29 pub fn new(
30 cid: Cid,
31 callback: impl FnMut(C) -> Result<O, E> + Send + Sync + 'static,
32 ) -> Self {
33 Self {
34 cid,
35 callback: Box::new(callback),
36 }
37 }
38 }
39}
40
41#[cfg(not(feature = "sync"))]
42mod __creator {
43 use super::*;
44
45 pub struct Creator<O, C, E: Into<Error>> {
46 pub(crate) cid: Cid,
47
48 pub(crate) callback: Box<dyn FnMut(C) -> Result<O, E> + 'static>,
49 }
50
51 impl<O: Opt, C, E: Into<Error>> Debug for Creator<O, C, E> {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 f.debug_struct("Creator")
54 .field("cid", &self.cid)
55 .field("callback", &"{...}")
56 .finish()
57 }
58 }
59
60 impl<O: Opt, C, E: Into<Error>> Creator<O, C, E> {
61 pub fn new(cid: Cid, callback: impl FnMut(C) -> Result<O, E> + 'static) -> Self {
62 Self {
63 cid,
64 callback: Box::new(callback),
65 }
66 }
67 }
68}
69
70pub use __creator::Creator;
71
72impl<O: Opt, C, E: Into<Error>> Ctor for Creator<O, C, E> {
73 type Opt = O;
74
75 type Config = C;
76
77 type Error = E;
78
79 fn cid(&self) -> &Cid {
80 &self.cid
81 }
82
83 fn new_with(&mut self, config: Self::Config) -> Result<Self::Opt, Self::Error> {
84 (self.callback)(config)
85 }
86}
87
88pub(crate) const CID_INT_SHORT: &str = "i";
89pub(crate) const CID_INT_LONG: &str = "int";
90pub(crate) const CID_INT_TYPE: &str = "i64";
91pub(crate) const CID_BOOL_SHORT: &str = "b";
92pub(crate) const CID_BOOL_LONG: &str = "boolean";
93pub(crate) const CID_BOOL_TYPE: &str = "bool";
94pub(crate) const CID_UINT_SHORT: &str = "u";
95pub(crate) const CID_UINT_LONG: &str = "uint";
96pub(crate) const CID_UINT_TYPE: &str = "u64";
97pub(crate) const CID_STR_SHORT: &str = "s";
98pub(crate) const CID_STR_LONG: &str = "str";
99pub(crate) const CID_STR_TYPE: &str = "string";
100pub(crate) const CID_FLT_SHORT: &str = "f";
101pub(crate) const CID_FLT_LONG: &str = "flt";
102pub(crate) const CID_FLT_TYPE: &str = "f64";
103pub(crate) const CID_CMD_SHORT: &str = "c";
104pub(crate) const CID_CMD_LONG: &str = "cmd";
105pub(crate) const CID_POS_SHORT: &str = "p";
106pub(crate) const CID_POS_LONG: &str = "pos";
107pub(crate) const CID_MAIN_SHORT: &str = "m";
108pub(crate) const CID_MAIN_LONG: &str = "main";
109pub(crate) const CID_ANY_SHORT: &str = "a";
110pub(crate) const CID_ANY_LONG: &str = "any";
111pub(crate) const CID_RAW_SHORT: &str = "r";
112pub(crate) const CID_RAW_LONG: &str = "raw";
113pub(crate) const CID_FALLBACK: &str = "fallback";
114
115#[non_exhaustive]
116#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
117pub enum Cid {
118 Int,
120
121 Str,
123
124 Flt,
126
127 Uint,
129
130 Bool,
132
133 Cmd,
135
136 Pos,
138
139 Main,
141
142 Any,
144
145 Raw,
147
148 Fallback,
150
151 Name(String),
152}
153
154impl Cid {
155 pub fn is_suit<S: AsRef<str>>(&self, s: &S) -> bool {
156 let s = s.as_ref();
157
158 match self {
159 Cid::Int => matches!(s, CID_INT_SHORT | CID_INT_LONG | CID_INT_TYPE),
160 Cid::Str => matches!(s, CID_STR_SHORT | CID_STR_LONG | CID_STR_TYPE),
161 Cid::Flt => matches!(s, CID_FLT_SHORT | CID_FLT_LONG | CID_FLT_TYPE),
162 Cid::Uint => matches!(s, CID_UINT_SHORT | CID_UINT_LONG | CID_UINT_TYPE),
163 Cid::Bool => matches!(s, CID_BOOL_SHORT | CID_BOOL_LONG | CID_BOOL_TYPE),
164 Cid::Cmd => matches!(s, CID_CMD_SHORT | CID_CMD_LONG),
165 Cid::Pos => matches!(s, CID_POS_SHORT | CID_POS_LONG),
166 Cid::Main => matches!(s, CID_MAIN_SHORT | CID_MAIN_LONG),
167 Cid::Any => matches!(s, CID_ANY_SHORT | CID_ANY_LONG),
168 Cid::Raw => matches!(s, CID_RAW_SHORT | CID_RAW_LONG),
169 Cid::Fallback => matches!(s, CID_FALLBACK),
170 Cid::Name(name) => s == name.as_str(),
171 }
172 }
173}
174
175impl From<String> for Cid {
176 fn from(value: String) -> Self {
177 let s = value.as_str();
178
179 match s {
180 CID_INT_SHORT | CID_INT_LONG | CID_INT_TYPE => Cid::Int,
181 CID_STR_SHORT | CID_STR_LONG | CID_STR_TYPE => Cid::Str,
182 CID_FLT_SHORT | CID_FLT_LONG | CID_FLT_TYPE => Cid::Flt,
183 CID_UINT_SHORT | CID_UINT_LONG | CID_UINT_TYPE => Cid::Uint,
184 CID_BOOL_SHORT | CID_BOOL_LONG | CID_BOOL_TYPE => Cid::Bool,
185 CID_CMD_SHORT | CID_CMD_LONG => Cid::Cmd,
186 CID_POS_SHORT | CID_POS_LONG => Cid::Pos,
187 CID_MAIN_SHORT | CID_MAIN_LONG => Cid::Main,
188 CID_ANY_SHORT | CID_ANY_LONG => Cid::Any,
189 CID_RAW_SHORT | CID_RAW_LONG => Cid::Raw,
190 CID_FALLBACK => Cid::Fallback,
191 _ => Cid::Name(value),
192 }
193 }
194}
195
196impl From<&String> for Cid {
197 fn from(value: &String) -> Self {
198 Cid::from(value.clone())
199 }
200}
201
202impl From<&str> for Cid {
203 fn from(s: &str) -> Self {
204 match s {
205 CID_INT_SHORT | CID_INT_LONG | CID_INT_TYPE => Cid::Int,
206 CID_STR_SHORT | CID_STR_LONG | CID_STR_TYPE => Cid::Str,
207 CID_FLT_SHORT | CID_FLT_LONG | CID_FLT_TYPE => Cid::Flt,
208 CID_UINT_SHORT | CID_UINT_LONG | CID_UINT_TYPE => Cid::Uint,
209 CID_BOOL_SHORT | CID_BOOL_LONG | CID_BOOL_TYPE => Cid::Bool,
210 CID_CMD_SHORT | CID_CMD_LONG => Cid::Cmd,
211 CID_POS_SHORT | CID_POS_LONG => Cid::Pos,
212 CID_MAIN_SHORT | CID_MAIN_LONG => Cid::Main,
213 CID_ANY_SHORT | CID_ANY_LONG => Cid::Any,
214 CID_RAW_SHORT | CID_RAW_LONG => Cid::Raw,
215 CID_FALLBACK => Cid::Fallback,
216 s => Cid::Name(String::from(s)),
217 }
218 }
219}
220
221impl<T: Opt + TryFrom<C, Error: Into<Error>>, C: ConfigValue + Debug> Creator<T, C, Error> {
222 pub fn fallback() -> Self {
223 Self::new(Cid::Fallback, move |config: C| {
224 trace!("in fallback, construct option with config {:?}", &config);
225
226 T::try_from(config).map_err(Into::into)
227 })
228 }
229
230 pub fn new_type_ctor(ctor: Cid) -> Self {
231 if ctor == Cid::Fallback {
232 return Self::fallback();
233 }
234 Self::new(ctor, move |config: C| {
235 trace!("construct option with config {:?}", &config);
236
237 T::try_from(config).map_err(Into::into)
238 })
239 }
240}
241
242impl<T: Opt + TryFrom<C, Error: Into<Error>>, C: ConfigValue + Debug> From<Cid>
243 for Creator<T, C, Error>
244{
245 fn from(value: Cid) -> Self {
246 Self::new_type_ctor(value)
247 }
248}
249
250#[macro_export]
264macro_rules! ctors {
265 ($type:ident) => {
266 $crate::ctors!(
267 $type,
268 fallback,
269 int,
270 bool,
271 flt,
272 str,
273 uint,
274 cmd,
275 pos,
276 main,
277 any,
278 raw
279 )
280 };
281 ($type:ident, $($creator:ident),+) => {
282 {
283 let mut ret = $crate::HashMap::default();
284
285 $(
286 ret.insert(
287 $crate::opt::Cid::from( stringify!($creator) ),
288 <$type>::from(
289 $crate::opt::Cid::from( stringify!($creator) )
290 )
291 );
292 )+
293 ret
294 }
295 };
296}