aopt/opt/
creator.rs

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    /// Create names: `i`, `int`, `i64`
119    Int,
120
121    /// Create names: `s`, `str`, `string`
122    Str,
123
124    /// Create names: `f`, `flt`, `f64`
125    Flt,
126
127    /// Create names: `u`, `uint`, `u64`
128    Uint,
129
130    /// Create names: `b`, `boolean`, `bool`
131    Bool,
132
133    /// Create names: `c`, `cmd`
134    Cmd,
135
136    /// Create names: `p`, `pos`
137    Pos,
138
139    /// Create names: `m`, `main`
140    Main,
141
142    /// Create names: `a`, `any`
143    Any,
144
145    /// Create names: `r`, `raw`
146    Raw,
147
148    /// Create names: `fallback`
149    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/// Return an array of creators:
251///
252/// * [`Fallback`](Cid::Fallback)
253/// * [`Int`](Cid::Int)
254/// * [`Bool`](Cid::Bool)
255/// * [`Flt`](Cid::Flt)
256/// * [`Str`](Cid::Str)
257/// * [`Uint`](Cid::Uint)
258/// * [`Cmd`](Cid::Cmd)
259/// * [`Pos`](Cid::Pos)
260/// * [`Main`](Cid::Main)
261/// * [`Any`](Cid::Any)
262/// * [`Raw`](Cid::Raw)
263#[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}