typeparam/
lib.rs

1//! TypeParam allows to write argument parsing in typesafe manner.
2//!
3//! TypeParam is a macro taking an annotated structure and generating a structure
4//! and implementation for parsing. Internally it uses
5//! [clap](https://crates.io/crates/clap).
6//!
7//! Please note that it is in very early stage of development and not all features
8//! are implemented. The interface and defaults are subject to change.
9//!
10//! # Example
11//!
12//! ```
13//! #[macro_use]
14//! extern crate typeparam;
15//! extern crate clap;
16//! typeparam!{
17//!     struct Params [@app test ::std::string::ParseError] {
18//!         quiet: bool [QUIET: -q],
19//!         verbose: bool [VERBOSE: -v (value: flag)],
20//!         cfg: String [CFG: -c (value: default String::from("---"))],
21//!         path: String [PATH: -p (value: required)],
22//!         foo: Option<String> [FOO: --foo (value: optional)],
23//!         n: Option<u32> [N: -n (value: option map (|_v: Option<&str>| Some(3)))],
24//!         x: u32 [X: -x (value: map (|_| 4))],
25//!         command: @SUBCOMMANDS<Commands> [list => List(List),
26//!                                          get => Get2(Get),
27//!                                          foo => Foo: (default = Default)]
28//!     }
29//!     struct List [@subcommand ::std::string::ParseError];
30//!     struct Get [@subcommand ::std::string::ParseError];
31//! }
32//!
33//! # // TODO: Autogenerate it
34//! # impl ::std::fmt::Debug for List {
35//! #    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
36//! #        fmt.debug_struct("List").finish()
37//! #    }
38//! # }
39//! # impl ::std::fmt::Debug for Get {
40//! #    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
41//! #        fmt.debug_struct("Get").finish()
42//! #    }
43//! # }
44//! #
45//! fn main() {
46//!     use typeparam::Command;
47//!     let params = Params::parse(["simple", "-v", "--foo", "bar", "-p", "path", "-x", "X"].iter()).unwrap();
48//!     assert!(!params.quiet);
49//!     assert!(params.verbose);
50//!     assert_eq!(params.cfg, "---");
51//!     assert_eq!(params.path, "path");
52//!     assert_eq!(params.foo, Some(String::from("bar")));
53//!     assert_eq!(params.n, Some(3));
54//!     assert_eq!(params.x, 4);
55//!     match params.command {
56//!         Commands::Default => {},
57//!         Commands::List(_) | Commands::Get2(_) | Commands::Foo => {
58//!             panic!("params.commands != Commands::Default")
59//!         }
60//!     }
61//! }
62//! ```
63//!
64//! In following example it created an parsing structure for application named
65//! `test`. Application takes two required arguments - `-p` and `-x` - and
66//! three optional ones - `--cfg`, `--foo` and `-n`. In addition it accepts two
67//! flags - `-q` anf `-v`.
68//!
69//! It accepts optionally one of three commands - `list`, `get` or `foo`.
70//!
71//! After successful parsing it returns a structure containing parsed commands.
72//!
73//! # Structures and Enums
74//!
75//! Currently two types of structures are accepted - apps and subcommands.
76//! Both have the same syntax with exception of the square brackets after type
77//! name.
78//!
79//! Apps need to have `@app` as first token appearing in square bracket followed
80//! by app name and type of error parsing may return.
81//!
82//! Subcommands need to have `@subcommand` as first token followed by type of
83//! error parsing may return.
84//!
85//! # Parameters and Options
86//!
87//! Parameters and options are specified as normal fields in struct followed by
88//! square brackets containing their name. Optionally after the name there can
89//! be colon followed by any number of arguments. Arguments can be specified in
90//! any order.
91//!
92//! To denote a short option a dash with a letter should be specified as argument
93//! (`-l`) while long double dash with an identifier (`--foo`). They are not
94//! mutually exclusive.
95//!
96//! ```
97//! #[macro_use]
98//! extern crate typeparam;
99//! extern crate clap;
100//! typeparam!{
101//!     struct Params [@app test ::std::string::ParseError] {
102//!         foo: bool [FOO: --foo],
103//!         bar: bool [BAR: -b],
104//!         foobar: bool [FOOBAR: -f --foobar]
105//!     }
106//! }
107//!
108//! fn main() {
109//!     use typeparam::Command;
110//!     let params = Params::parse(["simple", "-f", "--foo"].iter()).unwrap();
111//!     assert_eq!(params.foo, true);
112//!     assert_eq!(params.bar, false);
113//!     assert_eq!(params.foobar, true);
114//! }
115//! ```
116//!
117//! If either option is omitted the field denote a positional argument.
118//!
119//! ```
120//! #[macro_use]
121//! extern crate typeparam;
122//! extern crate clap;
123//! typeparam!{
124//!     struct Params [@app test ::std::string::ParseError] {
125//!         foo: String [FOO: (value: required)],
126//!         bar: String [BAR: (value: required)],
127//!         foobar: bool [FOOBAR: -f]
128//!     }
129//! }
130//!
131//! fn main() {
132//!     use typeparam::Command;
133//!     let params = Params::parse(["simple", "foo", "-f", "bar"].iter()).unwrap();
134//!     assert_eq!(params.foo.as_str(), "foo");
135//!     assert_eq!(params.bar.as_str(), "bar");
136//!     assert_eq!(params.foobar, true);
137//! }
138//! ```
139//!
140//! Each option can also take a `value` setting. Currently there are 5 valid
141//! settings:
142//!
143//!   - `value: flag` is default and denotes a single flag - in other words no
144//!     argument. Value returned is [`bool`](bool).
145//!   - `value: required` denotes an required argument. If user does not passes
146//!     it, an error is returned. Otherwise [`fromStr`](std::str::FromStr::from_str)
147//!     is called on value passed by user.
148//!   - `value: optional` denotes an optional argument. If user does not passes
149//!     it [`None`](std::option::Option::None) is returned. Otherwise [`fromStr`](std::str::FromStr::from_str)
150//!     is called on value and wrapped by [`Some`](std::option::Option::Some).
151//!   - `value: map callback` denotes an required argument, just as `value: required`,
152//!      however it allows to supply arbitrary function. Both functions returning value
153//!      directly as well as [`Result`](std::result::Result) are accepted.
154//!   - `value: option map callback` denotes an optional argument, just as
155//!     `value: optional`. However it allows to supply an arbitrary function.
156//!      Both functions returning value directly as well as
157//!      [`Result`](std::result::Result) are accepted.
158//!
159//! # Subcommands
160//! Subcommands functions as nested apps inside the command. This style has been
161//! popularized by (git)[https://git-scm.com/].
162//!
163//! For application (or recursivly subcommand) to have subcommands it is necessary
164//! to add field of type `@SUBCOMMANDS<NameOfEnum>`. There can be at most one such
165//! field in struct.
166//!
167//! ```compile_fail
168//! #[macro_use]
169//! extern crate typeparam;
170//! extern crate clap;
171//! typeparam!{
172//!     struct IllegalParams [@app illegal ::std::string::ParseError] {
173//!         illegal1: @SUBCOMMANDS<Illegal1> [foo => Foo],
174//!         illegal2: @SUBCOMMANDS<Illegal2> [foo => Bar]
175//!     }
176//! }
177//! # fn main() {}
178//! ```
179//!
180//! Afterwards the subcommands are specified in square brackets. There are
181//! two forms of subcommand specification - including type
182//! (`subcommand => Identifier(Type)`) and not (`subcommand => Identifier`).
183//! In the first form a type must be a subcommand and the description of fields
184//! is taken from there. The second form makes a subcommand not to get any
185//! additional fields.
186//! In both cases the `Identifier` is added to the enum specified after `@SUBCOMMAND`
187//! - with single argument or without any arguments respectivly.
188//!
189//! ```
190//! #[macro_use]
191//! extern crate typeparam;
192//! extern crate clap;
193//! typeparam!{
194//!     struct Params [@app test ::std::string::ParseError] {
195//!         command: @SUBCOMMANDS<Commands> [list => List, find => Find(Find)],
196//!         debug: bool [DEBUG: -d (value: flag)]
197//!     }
198//! }
199//! typeparam!{
200//!     struct Find [@subcommand ::std::string::ParseError] {
201//!         name: String [NAME: (value: required)],
202//!         case_insensitive: bool [CASE_INSENSITIVE: -i (value: flag)]
203//!     }
204//! }
205//!
206//! # // TODO: Autogenerate it
207//! # impl ::std::fmt::Debug for Find {
208//! #    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
209//! #        fmt.debug_struct("Find").field("name", &self.name).field("case_insensitive", &self.case_insensitive).finish()
210//! #    }
211//! # }
212//! #
213//! fn main() {
214//!    use typeparam::Command;
215//!    let list = Params::parse(["simple", "-d", "list"].iter()).unwrap();
216//!    assert_eq!(list.debug, true);
217//!    match list.command {
218//!        Commands::List => {},
219//!        _ => panic!("Expected Commands::List")
220//!    }
221//!    let find = Params::parse(["simple", "-d", "find", "-i", "something"].iter()).unwrap();
222//!    assert_eq!(find.debug, true);
223//!    match find.command {
224//!        Commands::Find(find_cmd) => {
225//!            assert_eq!(find_cmd.case_insensitive, true);
226//!            assert_eq!(find_cmd.name.as_str(), "something");
227//!        },
228//!        _ => panic!("Expected Commands::Find(_)")
229//!    }
230//! }
231//! ```
232//!
233//! Optionally they can be followed by colon and any number of arguments passed.
234//! Currently there is only one argument supported - `(default = Value)`. If it is
235//! specified `Value` becomes a value of enum when no command is given. Otherwise
236//! passing a command is required.
237//!
238//! ```
239//! #[macro_use]
240//! extern crate typeparam;
241//! extern crate clap;
242//! typeparam!{
243//!     struct Params [@app test ::std::string::ParseError] {
244//!         command: @SUBCOMMANDS<Commands> [list => List, find => Find(Find)],
245//!         debug: bool [DEBUG: -d (value: flag)]
246//!     }
247//!     struct Find [@subcommand ::std::string::ParseError] {
248//!         name: String [NAME: (value: required)],
249//!         case_insensitive: bool [CASE_INSENSITIVE: -i (value: flag)]
250//!     }
251//! }
252//!
253//! # // TODO: Autogenerate it
254//! # impl ::std::fmt::Debug for Find {
255//! #    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
256//! #        fmt.debug_struct("Find").field("name", &self.name).field("case_insensitive", &self.case_insensitive).finish()
257//! #    }
258//! # }
259//! #
260//! fn main() {
261//!    use typeparam::Command;
262//!    assert!(Params::parse(["simple"].iter()).is_err());
263//! }
264//! ```
265
266extern crate clap;
267
268#[doc(hidden)]
269pub mod clap_export {
270    pub use ::clap::{App,AppSettings,Arg,ArgMatches,SubCommand};
271}
272
273#[doc(hidden)]
274#[macro_export]
275macro_rules! typeparam_sanatize_struct_param {
276    ({$($data:tt)*} {{} {$($long:tt)*} {$($value:tt)*}} -$s:ident $($tail:tt)*) => {
277        typeparam_sanatize_struct_param!{
278            {$($data)*}
279            {{$s} {$($long)*} {$($value)*}}
280            $($tail)*
281        }
282    };
283    ({$($data:tt)*} {{$($short:tt)*} {} {$($value:tt)*}} --$l:ident $($tail:tt)*) => {
284        typeparam_sanatize_struct_param!{
285            {$($data)*}
286            {{$($short)*} {$l} {$($value)*}}
287            $($tail)*
288        }
289    };
290    ({$($data:tt)*} {{$($short:tt)*} {$($long:tt)*} {}} (value: flag) $($tail:tt)*) => {
291        typeparam_sanatize_struct_param!{
292            {$($data)*}
293            {{$($short)*} {$($long)*} {flag}}
294            $($tail)*
295        }
296    };
297    ({$($data:tt)*} {{$($short:tt)*} {$($long:tt)*} {}} (value: default $E:expr) $($tail:tt)*) => {
298        typeparam_sanatize_struct_param!{
299            {$($data)*}
300            {{$($short)*} {$($long)*} {default $E}}
301            $($tail)*
302        }
303    };
304    ({$($data:tt)*} {{$($short:tt)*} {$($long:tt)*} {}} (value: required) $($tail:tt)*) => {
305        typeparam_sanatize_struct_param!{
306            {$($data)*}
307            {{$($short)*} {$($long)*} {required}}
308            $($tail)*
309        }
310    };
311    ({$($data:tt)*} {{$($short:tt)*} {$($long:tt)*} {}} (value: optional) $($tail:tt)*) => {
312        typeparam_sanatize_struct_param!{
313            {$($data)*}
314            {{$($short)*} {$($long)*} {optional}}
315            $($tail)*
316        }
317    };
318    ({$($data:tt)*} {{$($short:tt)*} {$($long:tt)*} {}} (value: option map $E:expr) $($tail:tt)*) => {
319        typeparam_sanatize_struct_param!{
320            {$($data)*}
321            {{$($short)*} {$($long)*} {option map $E}}
322            $($tail)*
323        }
324    };
325    ({$($data:tt)*} {{$($short:tt)*} {$($long:tt)*} {}} (value: map $E:expr) $($tail:tt)*) => {
326        typeparam_sanatize_struct_param!{
327            {$($data)*}
328            {{$($short)*} {$($long)*} {map $E}}
329            $($tail)*
330        }
331    };
332    ({$($data:tt)*} {{$($short:tt)*} {$($long:tt)*} {}}) => {
333        typeparam_sanatize_struct_param_finish!{$($data)* [{$($short)*} {$($long)*} {flag}]}
334    };
335    ({$($data:tt)*} {{$($short:tt)*} {$($long:tt)*} {$($value:tt)*}}) => {
336        typeparam_sanatize_struct_param_finish!{$($data)* [{$($short)*} {$($long)*} {$($value)*}]}
337    };
338}
339
340#[doc(hidden)]
341#[macro_export]
342macro_rules! typeparam_sanatize_struct_param_finish {
343    (
344        [$acc:ident struct $N:ident [$($md:tt)*] {
345            $($tail:tt)*
346        }]
347        [$($prefix:tt)*]
348        [$($suffix:tt)*]
349        $facc:ident $F:ident $n:ident $T:ty
350        {$($params:tt)*}
351        [{$($short:tt)*} {$($long:tt)*} {$($value:tt)*}]
352    ) => {
353        typeparam_sanatize_struct!{
354            $acc struct $N [$($md)*] {
355                $($tail)*
356            } [
357                $($prefix)*
358                params => {$($params)* ($facc $F $n $T {$($short)*} {$($long)*} {$($value)*})}
359                $($suffix)*
360            ]
361        }
362    };
363}
364
365#[doc(hidden)]
366#[macro_export]
367macro_rules! typeparam_sanatize_struct_subcommand {
368    ({$($data:tt)*} {{} {$($params:tt)*}} $param:ident => $en:ident, $($tail:tt)*) => {
369        typeparam_sanatize_struct_subcommand!{{$($data)*} {{} {$($params)* (@subcmd $param ($en) ($crate::EmptySubcommand))}} $($tail)*}
370    };
371    ({$($data:tt)*} {{} {$($params:tt)*}} $param:ident => $en:ident($typ:ty), $($tail:tt)*) => {
372        typeparam_sanatize_struct_subcommand!{{$($data)*} {{} {$($params)* (@subcmd $param ($en($typ)) ($typ))}} $($tail)*}
373    };
374    ({$($data:tt)*} {{} {$($params:tt)*}} $param:ident => $en:ident: $($tail:tt)*) => {
375        typeparam_sanatize_struct_subcommand!{{$($data)*} {{} {$($params)* (@subcmd $param ($en) ($crate::EmptySubcommand))}} : $($tail)*}
376    };
377    ({$($data:tt)*} {{} {$($params:tt)*}} $param:ident => $en:ident($typ:ty): $($tail:tt)*) => {
378        typeparam_sanatize_struct_subcommand!{{$($data)*} {{} {$($params)* (@subcmd $param ($en($typ)) ($typ))}} : $($tail)*}
379    };
380    ({$($data:tt)*} {{} {$($params:tt)*}} $param:ident => $en:ident) => {
381        typeparam_sanatize_struct_subcommand!{{$($data)*} {{} {$($params)* (@subcmd $param ($en) ($crate::EmptySubcommand))}}}
382    };
383    ({$($data:tt)*} {{} {$($params:tt)*}} $param:ident => $en:ident($typ:ty)) => {
384        typeparam_sanatize_struct_subcommand!{{$($data)*} {{} {$($params)* (@subcmd $param ($en($typ)) ($typ))}}}
385    };
386    ({$($data:tt)*} {{} {$($params:tt)*}} : (default = $def:ident) $($tail:tt)*) => {
387        typeparam_sanatize_struct_subcommand!{{$($data)*} {{$def} {$($params)*}} : $($tail)*}
388    };
389    ({$($data:tt)*} {{$($def:tt)*} {$($params:tt)*}}) => {
390        typeparam_sanatize_struct_subcommand!{{$($data)*} {{$($def)*} {$($params)*}} :}
391    };
392    (
393        {
394            [$acc:ident struct $N:ident [$($md:tt)*] {
395                    $($tail:tt)*
396            }]
397            [$($prefix:tt)*]
398            [$($suffix:tt)*]
399            $facc:ident $F:ident $T:ident
400        }
401        {{$($def:tt)*} {$($params:tt)*}}
402        :
403    ) => {
404        typeparam_sanatize_struct!{
405            $acc struct $N [$($md)*] {
406                $($tail)*
407            } [
408                $($prefix)*
409                subcommands => {$facc $F $T {$($def)*} {$($params)*}}
410                $($suffix)*
411            ]
412        }
413    };
414}
415
416#[doc(hidden)]
417#[macro_export]
418macro_rules! typeparam_sanatize_struct {
419    ($acc:ident struct $N:ident [$($md:tt)*] { } [$($map:tt)*]) => {
420        typeparam_gen_struct!{$acc struct $N [$($md)*] [$($map)*]}
421    };
422    ($acc:ident struct $N:ident [$($md:tt)*] { , } [$($map:tt)*]) => {
423        typeparam_sanatize_struct!($acc struct $N [$($md)*] { } [$($map)*]);
424    };
425    (
426        $acc:ident struct $N:ident [$($md:tt)*] {
427            $F:ident : $T:ty [$n:ident: $($settings:tt)*],
428            $($tail:tt)*
429        } [
430            subcommands => { $($subcommands:tt)* }
431            params => { $($params:tt)* }
432            fields => { $($fields:tt)* }
433        ]
434    ) => {
435        typeparam_sanatize_struct_param!{
436            {
437                [$acc struct $N [$($md)*] {
438                    $($tail)*
439                }]
440                [subcommands => { $($subcommands)* }]
441                [fields => {$($fields)* $F: $T,}]
442                PRIV $F $n $T
443                {$($params)*}
444            }
445            { {} {} {} }
446            $($settings)*
447        }
448    };
449    (
450        $acc:ident struct $N:ident [$($md:tt)*] {
451            pub $F:ident : $T:ty [$n:ident: $($settings:tt)*],
452            $($tail:tt)*
453        } [
454            subcommands => { $($subcommands:tt)* }
455            params => { $($params:tt)* }
456            fields => { $($fields:tt)* }
457        ]
458    ) => {
459        typeparam_sanatize_struct_param!{
460            {
461                [$acc struct $N [$($md)*] {
462                    $($tail)*
463                }]
464                [subcommands => { $($subcommands)* }]
465                [fields => {$($fields)* pub $F: $T,}]
466                PUB $F $n $T
467                {$($params)*}
468            }
469            { {} {} {} }
470            $($settings)*
471        }
472    };
473    (
474        $acc:ident struct $N:ident [$($md:tt)*] {
475            $F:ident : @SUBCOMMANDS<$T:ident> [$($settings:tt)*],
476            $($tail:tt)*
477        } [
478            subcommands => { }
479            params => { $($params:tt)* }
480            fields => { $($fields:tt)* }
481        ]
482    ) => {
483        typeparam_sanatize_struct_subcommand!{
484            {
485                [$acc struct $N [$($md)*] {
486                    $($tail)*
487                }]
488                []
489                [params => { $($params)* } fields => {$($fields)* $F: $T,}]
490                PRIV $F $T
491            }
492            {{} {}}
493            $($settings)*
494        }
495    };
496    (
497        $acc:ident struct $N:ident [$($md:tt)*] {
498            $F:ident : @SUBCOMMANDS<$T:ident> [$($settings:tt)*],
499            $($tail:tt)*
500        } [
501            subcommands => { }
502            params => { $($params:tt)* }
503            fields => { $($fields:tt)* }
504        ]
505    ) => {
506        typeparam_sanatize_struct_subcommand!{
507            {
508                [$acc struct $N [$($md)*] {
509                    $($tail)*
510                }]
511                []
512                [params => { $($params)* } fields => {$($fields)* pub $F: $T,}]
513                PUB $F $T
514            }
515            {{} {}}
516            $($settings)*
517        }
518    };
519}
520
521#[doc(hidden)]
522#[macro_export]
523macro_rules! typeparam_gen_enum {
524    () => {};
525    (PRIV $F:ident $T:ident { $def:ident } {$((@subcmd $param:ident ($($el:tt)*) ($typ:ty)))*}) => {
526        #[derive(Debug)]
527        enum $T {
528            $def,
529            $($($el)*),*
530        }
531    };
532    (PRIV $F:ident $T:ident { } {$((@subcmd $param:ident ($($el:tt)*) ($typ:ty)))*}) => {
533        #[derive(Debug)]
534        enum $T {
535            $($($el)*),*
536        }
537    };
538    (PUB $F:ident $T:ident { $def:ident } {$((@subcmd $param:ident ($($el:tt)*) ($typ:ty)))*}) => {
539        #[derive(Debug)]
540        pub enum $T {
541            $def,
542            $($($el)*),*
543        }
544    };
545    (PUB $F:ident $T:ident { } {$((@subcmd $param:ident ($($el:tt)*) ($typ:ty)))*}) => {
546        #[derive(Debug)]
547        pub $facc enum $T {
548            $($($el)*),*
549        }
550    };
551}
552
553#[doc(hidden)]
554#[macro_export]
555macro_rules! typeparam_gen_struct_hlp {
556    (PRIV struct $N:ident {$($fields:tt)*}) => {
557        struct $N {
558            $($fields)*
559        }
560    };
561    (PUB struct $N:ident {$($fields:tt)*}) => {
562        pub struct $N {
563            $($fields)*
564        }
565    };
566}
567
568#[doc(hidden)]
569#[macro_export]
570macro_rules! typeparam_gen_commands {
571    (($app:expr)) => {$app};
572    (($app:expr) $facc:ident $F:ident $T:ident { $($def:tt)+ } { }) => {$app};
573    (($app:expr) $facc:ident $F:ident $T:ident { } { }) => {
574        $app.setting($crate::clap_export::AppSettings::SubcommandRequired)
575    };
576    (($app:expr) $facc:ident $F:ident $T:ident { $($def:tt)* } {(@subcmd $subcmd:ident ($($fld:tt)*) ($t:ty)) $($tail:tt)*}) => {{
577        fn subcommand<T : $crate::SubCommand>(name: &'static str) -> $crate::clap_export::App<'static, 'static> {
578            T::subcommand(name)
579        }
580        let app = $app.subcommand(subcommand::<$t>(stringify!($subcmd)));
581        typeparam_gen_commands!((app) $facc $F $T { $($def)* } {$($tail)*})
582    }}
583}
584
585#[doc(hidden)]
586#[macro_export]
587macro_rules! typeparam_gen_params_flg {
588    (($arg:expr) {$short:ident} {$($long:tt)*}) => {{
589        let arg = $arg.short(stringify!($short));
590        typeparam_gen_params_flg!((arg) {} {$($long)*})
591    }};
592    (($arg:expr) {} {$long:ident}) => {{
593        let arg = $arg.long(stringify!($long));
594        typeparam_gen_params_flg!((arg) {} {})
595    }};
596    (($arg:expr) {} {}) => {
597        $arg
598    };
599}
600
601#[doc(hidden)]
602#[macro_export]
603macro_rules! typeparam_gen_params {
604    (($app:expr) ($facc:ident $F:ident $n:ident $T:ty {$($short:tt)*} {$($long:tt)*} {flag}) $($tail:tt)*) => {{
605        let arg = typeparam_gen_params_flg!((::clap::Arg::with_name(stringify!($n))) {$($short)*} {$($long)*});
606        typeparam_gen_params!(($app.arg(arg.takes_value(false).required(false))) $($tail)*)
607    }};
608    (($app:expr) ($facc:ident $F:ident $n:ident $T:ty {$($short:tt)*} {$($long:tt)*} {default $E:expr}) $($tail:tt)*) => {{
609        let arg = typeparam_gen_params_flg!((::clap::Arg::with_name(stringify!($n))) {$($short)*} {$($long)*});
610        typeparam_gen_params!(($app.arg(arg.takes_value(true).required(false))) $($tail)*)
611    }};
612    (($app:expr) ($facc:ident $F:ident $n:ident $T:ty {$($short:tt)*} {$($long:tt)*} {optional}) $($tail:tt)*) => {{
613        let arg = typeparam_gen_params_flg!((::clap::Arg::with_name(stringify!($n))) {$($short)*} {$($long)*});
614        typeparam_gen_params!(($app.arg(arg.takes_value(true).required(false))) $($tail)*)
615    }};
616    (($app:expr) ($facc:ident $F:ident $n:ident $T:ty {$($short:tt)*} {$($long:tt)*} {required}) $($tail:tt)*) => {{
617        let arg = typeparam_gen_params_flg!((::clap::Arg::with_name(stringify!($n))) {$($short)*} {$($long)*});
618        typeparam_gen_params!(($app.arg(arg.takes_value(true).required(true))) $($tail)*)
619    }};
620    (($app:expr) ($facc:ident $F:ident $n:ident $T:ty {$($short:tt)*} {$($long:tt)*} {option map $E:expr}) $($tail:tt)*) => {{
621        let arg = typeparam_gen_params_flg!((::clap::Arg::with_name(stringify!($n))) {$($short)*} {$($long)*});
622        typeparam_gen_params!(($app.arg(arg.takes_value(true).required(false))) $($tail)*)
623    }};
624    (($app:expr) ($facc:ident $F:ident $n:ident $T:ty {$($short:tt)*} {$($long:tt)*} {map $E:expr}) $($tail:tt)*) => {{
625        let arg = typeparam_gen_params_flg!((::clap::Arg::with_name(stringify!($n))) {$($short)*} {$($long)*});
626        typeparam_gen_params!(($app.arg(arg.takes_value(true).required(true))) $($tail)*)
627    }};
628    (($app:expr)) => {$app};
629}
630
631#[derive(Copy, Clone, Debug)]
632#[doc(hidden)]
633pub struct Res<T, E>(pub Result<T, E>);
634
635impl<T, E> From<T> for Res<T, E> {
636    fn from(t: T) -> Res<T, E> {
637        Res(Ok(t))
638    }
639}
640
641impl<T, E2, E : Into<E2>> From<Result<T, E>> for Res<T, E2> {
642    fn from(r: Result<T, E>) -> Res<T, E2> {
643        match r {
644            Ok(t) => Res(Ok(t)),
645            Err(e) => Res(Err(E::into(e)))
646        }
647    }
648}
649
650#[doc(hidden)]
651#[macro_export]
652macro_rules! typeparam_gen_new_param_get {
653    (($match:expr) ($err:ty) $facc:ident $F:ident $n:ident $T:ty {$($short:tt)*} {$($long:tt)*} {flag}) => {
654        $match.is_present(stringify!($n))
655    };
656    (($match:expr) ($err:ty) $facc:ident $F:ident $n:ident $T:ty {$($short:tt)*} {$($long:tt)*} {default $E:expr}) => {
657        $match.value_of(stringify!($n)).map_or_else(|| Ok($E), |val| val.parse::<$T>(),)?
658    };
659    (($match:expr) ($err:ty) $facc:ident $F:ident $n:ident $T:ty {$($short:tt)*} {$($long:tt)*} {required}) => {
660        $match.value_of(stringify!($n)).map(|val| val.parse::<$T>()).unwrap()?
661    };
662    (($match:expr) ($err:ty) $facc:ident $F:ident $n:ident $T:ty {$($short:tt)*} {$($long:tt)*} {optional}) => {{
663        use std::str::FromStr;
664        trait OptionParse where Self : Sized {
665            type Error;
666            fn parse(string: Option<&str>) -> Result<Self, Self::Error>;
667        }
668        impl<T : FromStr> OptionParse for Option<T> {
669            type Error = T::Err;
670            fn parse(string: Option<&str>) -> Result<Self, Self::Error> {
671                match string {
672                    Some(ref val) => Ok(Some(val.parse::<T>()?)),
673                    None => Ok(None)
674                }
675            }
676        }
677        fn parse<T : OptionParse>(val: Option<&str>) -> Result<T, T::Error> {
678            T::parse(val)
679        }
680        parse::<$T>($match.value_of(stringify!($n)))?
681    }};
682    (($match:expr) ($err:ty) $facc:ident $F:ident $n:ident $T:ty {$($short:tt)*} {$($long:tt)*} {option map $E:expr}) => {{
683        fn coerce<R : Into<$crate::Res<$T, $err>>, F : FnOnce(Option<&str>) -> R>(f: F, val: Option<&str>) -> Result<$T, $err> {
684            R::into(f(val)).0
685        }
686        coerce($E, $match.value_of(stringify!($n)))?
687    }};
688    (($match:expr) ($err:ty) $facc:ident $F:ident $n:ident $T:ty {$($short:tt)*} {$($long:tt)*} {map $E:expr}) => {{
689        fn coerce<R : Into<$crate::Res<$T, $err>>, F : FnOnce(&str) -> R>(f: F, val: &str) -> Result<$T, $err> {
690            R::into(f(val)).0
691        }
692        coerce($E, $match.value_of(stringify!($n)).unwrap())?
693    }};
694}
695
696#[doc(hidden)]
697#[macro_export]
698macro_rules! typeparam_gen_new_command_get {
699    (($match:expr) $T:ident { $($def:tt)* } { (@subcmd $subcmd:ident ($fld:ident($typ:ty)) ( $typ2:ty)) $($tail:tt)* }) => {{
700        let mch = $match;
701        if let Some(submatch) = mch.subcommand_matches(stringify!($subcmd)) {
702            fn gen_subcmd<T : $crate::SubCommand>(am: &$crate::clap_export::ArgMatches) -> Result<T, T::Error> {
703                T::new(am)
704            }
705            $T::$fld(gen_subcmd::<$typ>(submatch)?) 
706        } else {
707            typeparam_gen_new_command_get!((mch) $T { $($def)* } { $($tail)* })
708        }
709    }};
710    (($match:expr) $T:ident { $($def:tt)* } { (@subcmd $subcmd:ident ($fld:ident) ( $typ2:ty)) $($tail:tt)* }) => {{
711        let mch = $match;
712        if mch.subcommand_name() == Some(stringify!($subcmd)) {
713            $T::$fld
714        } else {
715            typeparam_gen_new_command_get!((mch) $T { $($def)* } { $($tail)* })
716        }
717    }};
718    (($match:expr) $T:ident { $def:ident } { }) => {
719        $T::$def
720    };
721    (($match:expr) $T:ident { } { }) => {
722        panic!("No command given")
723    };
724}
725
726#[doc(hidden)]
727#[macro_export]
728macro_rules! typeparam_gen_new {
729    (($match:expr) $N:ident $err:ty {$($gen:tt)*} [subcommands => {$facc:ident $F:ident $T:ident { $($def:tt)* } { $($subcmd:tt)*} } params => {$($params:tt)*}]) => {{
730        let mch = $match;
731        let val: $T = typeparam_gen_new_command_get!((mch) $T { $($def)* } { $($subcmd)*});
732        typeparam_gen_new!((mch) $N $err {$($gen)* $F: val,} [params => { $($params)* }])
733    }};
734    (($match:expr) $N:ident $err:ty {$($gen:tt)*} [subcommands => {} params => {$($params:tt)*}]) => {
735        typeparam_gen_new!(($match) $N $err {$($gen)*} [params => { $($params)* }])
736    };
737    (($match:expr) $N:ident $err:ty {$($gen:tt)*} [params => { ($facc:ident $F:ident $n:ident $T:ty {$($short:tt)*} {$($long:tt)*} {$($value:tt)*}) $($params:tt)*}]) => {{
738        let mch = $match;
739        let val: $T = typeparam_gen_new_param_get!((mch) ($err) $facc $F $n $T {$($short)*} {$($long)*} {$($value)*});
740        typeparam_gen_new!((mch) $N $err {$($gen)* $F: val,} [params => { $($params)* }])
741    }};
742    (($match:expr) $N:ident $err:ty {$($gen:tt)*} [params => {}]) => {{
743        Ok($N {
744            $($gen)*
745        })
746    }}
747}
748
749#[doc(hidden)]
750#[macro_export]
751macro_rules! typeparam_gen_impl {
752    ($acc:ident struct $N:ident [@app $app:ident $err:ty] [subcommands => { $($subcmd:tt)* } params => { $($params:tt)* }]) => {
753        impl $crate::Command for $N {
754            type Error = $err;
755            fn command() -> $crate::clap_export::App<'static, 'static> {
756                let app = $crate::clap_export::App::new(stringify!($app));
757                let app = app.settings(&[
758                    $crate::clap_export::AppSettings::StrictUtf8
759                ]);
760                let app = typeparam_gen_commands!((app) $($subcmd)*);
761                let app = typeparam_gen_params!((app) $($params)*);
762                app
763            }
764            fn new(matches: &$crate::clap_export::ArgMatches) -> Result<Self, Self::Error> {
765                typeparam_gen_new!((&matches) $N $err {} [subcommands => { $($subcmd)* } params => { $($params) * }])
766            }
767        }
768    };
769    ($acc:ident struct $N:ident [@subcommand $err:ty] [subcommands => { $($subcmd:tt)* } params => { $($params:tt)* }]) => {
770        impl $crate::SubCommand for $N {
771            type Error = $err;
772            fn subcommand(name: &'static str) -> $crate::clap_export::App<'static, 'static> {
773                let app = $crate::clap_export::SubCommand::with_name(name);
774                let app = typeparam_gen_commands!((app) $($subcmd)*);
775                let app = typeparam_gen_params!((app) $($params)*);
776                app
777            }
778            fn new(_am: &$crate::clap_export::ArgMatches) -> Result<Self, Self::Error> {
779                typeparam_gen_new!((&_am) $N $err {} [subcommands => { $($subcmd)* } params => { $($params) * }])
780            }
781        } 
782    };
783}
784
785#[doc(hidden)]
786#[macro_export]
787macro_rules! typeparam_gen_struct {
788    ($acc:ident struct $N:ident [$($md:tt)*] [subcommands => { $($subcmd:tt)* } params => { $($params:tt)* } fields => { $($fields:tt)* }]) => {
789        typeparam_gen_enum!($($subcmd)*);
790        typeparam_gen_struct_hlp!($acc struct $N { $($fields)* });
791        typeparam_gen_impl!($acc struct $N [$($md)*] [subcommands => { $($subcmd)* } params => { $($params)* }]);
792    };
793}
794
795#[macro_export]
796macro_rules! typeparam {
797    (struct $N:ident [$($md:tt)*] { $($struct:tt)+ } $($tail:tt)*) => {
798        typeparam_sanatize_struct!{
799            PRIV struct $N [$($md)*] {
800                $($struct)*,
801            } [
802                subcommands => { }
803                params => { }
804                fields => { }
805            ]
806        }
807        typeparam!{$($tail)*}
808    };
809    (struct $N:ident [$($md:tt)*]; $($tail:tt)*) => {
810        typeparam_sanatize_struct!{
811            PRIV struct $N [$($md)*] { } [
812                subcommands => { }
813                params => { }
814                fields => { }
815            ]
816        }
817        typeparam!{$($tail)*}
818    };
819    () => {};
820}
821
822#[derive(Debug)]
823pub enum Error<T> {
824    Parse(clap::Error),
825    Command(T)
826}
827
828/// Commands are main result of [`typeparam!`](typeparam!) macro.
829pub trait Command where Self : Sized {
830    /// Error that may be returned by the user part of the process.
831    type Error;
832    /// Starts the automated parsing process with passed iterator.
833    ///
834    /// **NOTE** `--help` and `--version` are returned as errors.
835    ///
836    /// **NOTE** Note that first element of iteration is considered name of
837    /// binary.
838    fn parse<I : IntoIterator<Item = T>, T : Into<std::ffi::OsString> + Clone>(itr: I) -> Result<Self, Error<Self::Error>> {
839        Self::new(&Self::command().get_matches_from_safe(itr).map_err(|e| Error::Parse(e))?).map_err(|e| Error::Command(e))
840    }
841    /// Starts the automated parsing process with commandline arguments.
842    ///
843    /// **NOTE** `--help` and `--version` are returned as errors.
844    ///
845    /// **NOTE** Note that command name is considered just a binary name.
846    fn parse_args() -> Result<Self, Error<Self::Error>> {
847        Self::parse(std::env::args())
848    }
849    /// Starts the automated parsing process with passed iterator.
850    ///
851    /// **NOTE** `--help` and `--version` are returned as errors.
852    ///
853    /// **NOTE** Note that first element of iteration is considered name of
854    /// binary.
855    fn parse_any<I : IntoIterator<Item = T>, T : Into<std::ffi::OsString> + Clone, E : From<Self::Error> + From<clap::Error>>(itr: I) -> Result<Self, E> {
856        match Self::parse(itr) {
857            Ok(res) => Ok(res),
858            Err(Error::Parse(e)) => Err(E::from(e)),
859            Err(Error::Command(e)) => Err(E::from(e))
860        }
861    }
862    /// Starts the automated parsing process with commandline arguments.
863    ///
864    /// **NOTE** `--help` and `--version` are returned as errors.
865    ///
866    /// **NOTE** Note that command name is considered just a binary name.
867    fn parse_any_args<E : From<Self::Error> + From<clap::Error>>() -> Result<Self, E> {
868        Self::parse_any(std::env::args())
869    }
870    /// Starts the automated parsing process with passed iterator. If parsing
871    /// fails an error is printed and process exits.
872    ///
873    /// **NOTE** Note that command name is considered just a binary name.
874    fn parse_or_exit<I : IntoIterator<Item = T>, T : Into<std::ffi::OsString> + Clone>(itr: I) -> Self where Self::Error : std::fmt::Display {
875        let mut app = Self::command();
876        let res = app.get_matches_from_safe_borrow(itr).map_err(|e| Error::Parse(e)).and_then(|mch| {
877            Self::new(&mch).map_err(|e| Error::Command(e))
878        });
879        match res {
880            Ok(res) => res,
881            Err(Error::Parse(e)) => e.exit(),
882            Err(Error::Command(e)) => {
883                use std::io::Write;
884                let stderr = std::io::stderr();
885                writeln!(&mut stderr.lock(), "{:}", e).unwrap();
886                std::process::exit(1)
887            }
888        }
889    }
890    /// Starts the automated parsing process with passed iterator. If parsing
891    /// fails an error is printed and process exits.
892    ///
893    /// **NOTE** Note that command name is considered just a binary name.
894    fn parse_args_or_exit() -> Self where Self::Error : std::fmt::Display {
895        Self::parse_or_exit(std::env::args())
896    }
897    /// Creates an [`App`](clap::App) based on specified command
898    fn command() -> clap::App<'static, 'static>;
899    /// Creates structure based on matched arguments.
900    fn new(mch: &clap::ArgMatches) -> Result<Self, Self::Error>;
901}
902
903#[doc(hidden)]
904pub trait SubCommand where Self : Sized {
905    type Error;
906    fn subcommand(name: &'static str) -> clap::App<'static, 'static>;
907    fn new(mch: &clap::ArgMatches) -> Result<Self, Self::Error>;
908}
909
910#[derive(Copy, Clone, Debug)]
911#[doc(hidden)]
912pub enum EmptySubcommand {}
913
914impl SubCommand for EmptySubcommand {
915    type Error = std::string::ParseError;
916    fn subcommand(name: &'static str) -> clap::App<'static, 'static> {
917        clap::SubCommand::with_name(name)
918    }
919    fn new(_: &clap::ArgMatches) -> Result<Self, Self::Error> {
920        panic!("EmptySubcommand::new should never be called");
921    }
922}
923