clap_serde/de/app/
mod.rs

1use crate::CommandWrap;
2use appsettings::*;
3use clap::Command;
4use serde::{
5    de::{DeserializeSeed, Error, Visitor},
6    Deserialize,
7};
8
9mod appsettings;
10#[cfg(feature = "color")]
11mod color;
12
13const TMP_APP_NAME: &str = "__tmp__deserialize__name__";
14impl<'de> Deserialize<'de> for CommandWrap<'de> {
15    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
16    where
17        D: serde::Deserializer<'de>,
18    {
19        deserializer
20            .deserialize_map(CommandVisitor(Command::new(TMP_APP_NAME)))
21            //check the name so as not to expose the tmp name.
22            .and_then(|r| {
23                if r.app.get_name() != TMP_APP_NAME {
24                    Ok(r)
25                } else {
26                    Err(<D::Error>::missing_field("name"))
27                }
28            })
29    }
30}
31
32struct CommandVisitor<'a>(Command<'a>);
33
34impl<'a> Visitor<'a> for CommandVisitor<'a> {
35    type Value = CommandWrap<'a>;
36
37    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
38        formatter.write_str("Command Map")
39    }
40
41    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
42    where
43        A: serde::de::MapAccess<'a>,
44    {
45        let mut app = self.0;
46        //TODO: check the first key to get name from the input?
47        //currently the name change in `Clap::Command::name` doesn't change the `Clap::Command::id` so might cause problems?
48        while let Some(key) = map.next_key::<&str>()? {
49            app = parse_value!(key, app, map, Command, {
50                (about, &str),
51                (after_help, &str),
52                (after_long_help, &str),
53                (alias, &str),
54                ref (aliases, Vec<&str>),
55                (allow_external_subcommands, bool),
56                (allow_hyphen_values, bool),
57                (allow_invalid_utf8_for_external_subcommands, bool),
58                (allow_missing_positional, bool),
59                (allow_negative_numbers, bool),
60                //arg : not supported single arg(now)
61                //args : specialized
62                (arg_required_else_help, bool),
63                (args_conflicts_with_subcommands, bool),
64                (args_override_self, bool),
65                (author, &str),
66                (before_help, &str),
67                (before_long_help, &str),
68                (bin_name, &str),
69                // color : specialized
70                (disable_colored_help, bool),
71                (disable_help_flag, bool),
72                (disable_help_subcommand, bool),
73                (disable_version_flag, bool),
74                (display_name, &str),
75                (display_order, usize),
76                (dont_collapse_args_in_usage, bool),
77                (dont_delimit_trailing_values, bool),
78                // global_setting : specialized
79                // global_settings : specialized (though the original method is deprecated)
80                // group : not supported single group
81                // groups : specialized
82                (help_expected, bool),
83                (help_template, &str),
84                (hide, bool),
85                (hide_possible_values, bool),
86                (ignore_errors, bool),
87                (infer_long_args, bool),
88                (infer_subcommands, bool),
89                (long_about, &str),
90                (long_flag, &str),
91                (long_flag_alias, &str),
92                ref (long_flag_aliases, Vec<&str>),
93                (long_version, &str),
94                (max_term_width, usize),
95                (multicall, bool),
96                (name, &str),
97                (next_display_order, Option<usize>),
98                (next_help_heading, Option<&str>),
99                (next_line_help, bool),
100                (no_binary_name, bool),
101                (override_help, &str),
102                (override_usage, &str),
103                (propagate_version, bool),
104                // setting : specialized
105                // settings : specialized (though the original method is deprecated)
106                (short_flag, char),
107                (short_flag_alias, char),
108                ref (short_flag_aliases, Vec<char>),
109                // subcommand : not supported single subcommand(now)
110                // subcommands : specialized
111                (subcommand_help_heading, &str),
112                (subcommand_negates_reqs, bool),
113                (subcommand_required, bool),
114                (subcommand_value_name, &str),
115                (propagate_version, bool),
116                (term_width, usize),
117                (trailing_var_arg, bool),
118                (version, &str),
119                (visible_alias, &str),
120                ref (visible_aliases, Vec<&str>),
121                (visible_long_flag_alias, &str),
122                ref (visible_long_flag_aliases, Vec<&str>),
123                (visible_short_flag_alias, char),
124                ref (visible_short_flag_aliases, Vec<char>),
125            },
126            deprecated: [
127                "help_message",
128                "version_message",
129            ]{
130                "help_heading" => "next_help_heading",
131            },
132            not_supported: {
133                "arg" => "Use args instead",
134                "group" => "Use groups instead",
135            },
136            specialize:
137            [
138                "args" => map.next_value_seed(super::arg::Args::<true>(app))?
139                "args_map" => map.next_value_seed(super::arg::Args::<false>(app))?
140                "color" => {
141                    #[cfg(color)] {
142                        app.color(map.next_value_seed(ColorChoiceSeed)?)
143                    }
144                    #[cfg(not(color))] { return Err(Error::custom("color feature disabled"))}}
145                "subcommands" => map.next_value_seed(SubCommands::<true>(app))?
146                "subcommands_map" => map.next_value_seed(SubCommands::<false>(app))?
147                "groups" => map.next_value_seed(super::group::Groups(app))?
148                "setting" => app.setting(map.next_value_seed(AppSettingSeed)?)
149                "settings" => app.setting(map.next_value_seed(AppSettingsSeed)?)
150                "global_setting" => app.global_setting(map.next_value_seed(AppSettingSeed)?)
151                "global_settings" => {
152                    let sets = map.next_value::<Vec<AppSetting1>>()?.into_iter().map(|s|s.into());
153                    for s in sets{
154                        app = app.global_setting(s);
155                    }
156                    app
157                }
158            ]);
159        }
160
161        Ok(CommandWrap { app })
162    }
163}
164
165pub struct NameSeed<'a>(&'a str);
166
167impl<'de> DeserializeSeed<'de> for NameSeed<'de> {
168    type Value = CommandWrap<'de>;
169
170    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
171    where
172        D: serde::Deserializer<'de>,
173    {
174        deserializer.deserialize_map(CommandVisitor(Command::new(self.0)))
175    }
176}
177
178impl<'de> DeserializeSeed<'de> for CommandWrap<'de> {
179    type Value = CommandWrap<'de>;
180
181    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
182    where
183        D: serde::Deserializer<'de>,
184    {
185        deserializer.deserialize_map(CommandVisitor(self.app))
186    }
187}
188
189struct SubCommands<'a, const KV_ARRAY: bool>(Command<'a>);
190impl<'de, const KV_ARRAY: bool> DeserializeSeed<'de> for SubCommands<'de, KV_ARRAY> {
191    type Value = Command<'de>;
192
193    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
194    where
195        D: serde::Deserializer<'de>,
196    {
197        if KV_ARRAY {
198            deserializer.deserialize_seq(self)
199        } else {
200            deserializer.deserialize_map(self)
201        }
202    }
203}
204
205impl<'de, const KV_ARRAY: bool> Visitor<'de> for SubCommands<'de, KV_ARRAY> {
206    type Value = Command<'de>;
207
208    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
209        formatter.write_str("Subcommand")
210    }
211
212    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
213    where
214        A: serde::de::MapAccess<'de>,
215    {
216        let mut app = self.0;
217        while let Some(name) = map.next_key::<&str>()? {
218            let sub = map.next_value_seed(NameSeed(name))?;
219            app = app.subcommand(sub);
220        }
221        Ok(app)
222    }
223
224    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
225    where
226        A: serde::de::SeqAccess<'de>,
227    {
228        let mut app = self.0;
229        while let Some(sub) = seq.next_element_seed(InnerSubCommand)? {
230            app = app.subcommand(sub)
231        }
232        Ok(app)
233    }
234}
235
236pub struct InnerSubCommand;
237impl<'de> Visitor<'de> for InnerSubCommand {
238    type Value = Command<'de>;
239
240    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
241        formatter.write_str("Subcommand Inner")
242    }
243
244    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
245    where
246        A: serde::de::MapAccess<'de>,
247    {
248        let k = map
249            .next_key()?
250            .ok_or_else(|| A::Error::invalid_length(0, &"missing command in subcommand"))?;
251        let com = map.next_value_seed(NameSeed(k))?;
252        Ok(com.into())
253    }
254}
255
256impl<'de> DeserializeSeed<'de> for InnerSubCommand {
257    type Value = Command<'de>;
258
259    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
260    where
261        D: serde::Deserializer<'de>,
262    {
263        deserializer.deserialize_map(self)
264    }
265}