midenc_session/flags/
mod.rs1mod arg_matches;
2mod flag;
3
4#[cfg(not(feature = "std"))]
5use alloc::borrow::Cow;
6use alloc::vec::Vec;
7use core::fmt;
8
9pub use self::{
10 arg_matches::ArgMatches,
11 flag::{CompileFlag, FlagAction},
12};
13use crate::diagnostics::Report;
14
15pub struct CompileFlags {
16 flags: Vec<CompileFlag>,
17 arg_matches: ArgMatches,
18}
19
20#[cfg(feature = "std")]
21impl Default for CompileFlags {
22 fn default() -> Self {
23 Self::new(None::<std::ffi::OsString>).unwrap()
24 }
25}
26
27#[cfg(not(feature = "std"))]
28impl Default for CompileFlags {
29 fn default() -> Self {
30 Self::new(None::<alloc::string::String>).unwrap()
31 }
32}
33
34impl From<ArgMatches> for CompileFlags {
35 fn from(arg_matches: ArgMatches) -> Self {
36 let flags = inventory::iter::<CompileFlag>.into_iter().cloned().collect();
37 Self { flags, arg_matches }
38 }
39}
40
41impl CompileFlags {
42 #[cfg(feature = "std")]
44 pub fn new<I, V>(argv: I) -> Result<Self, Report>
45 where
46 I: IntoIterator<Item = V>,
47 V: Into<std::ffi::OsString> + Clone,
48 {
49 use crate::diagnostics::IntoDiagnostic;
50
51 let flags = inventory::iter::<CompileFlag>.into_iter().cloned().collect();
52 fake_compile_command()
53 .try_get_matches_from(argv)
54 .into_diagnostic()
55 .map(|arg_matches| Self { flags, arg_matches })
56 }
57
58 #[cfg(not(feature = "std"))]
60 pub fn new<I, V>(argv: I) -> Result<Self, Report>
61 where
62 I: IntoIterator<Item = V>,
63 V: Into<Cow<'static, str>> + Clone,
64 {
65 use alloc::collections::{BTreeMap, VecDeque};
66
67 let argv = argv.into_iter().map(|arg| arg.into()).collect::<VecDeque<_>>();
68 let flags = inventory::iter::<CompileFlag>
69 .into_iter()
70 .map(|flag| (flag.name, flag))
71 .collect::<BTreeMap<_, _>>();
72
73 let arg_matches = ArgMatches::parse(argv, &flags)?;
74 let this = Self {
75 flags: flags.values().copied().cloned().collect(),
76 arg_matches,
77 };
78
79 Ok(this)
80 }
81
82 pub fn flags(&self) -> &[CompileFlag] {
83 self.flags.as_slice()
84 }
85
86 pub fn get_flag(&self, name: &str) -> bool {
88 self.arg_matches.get_flag(name)
89 }
90
91 pub fn get_flag_count(&self, name: &str) -> usize {
93 self.arg_matches.get_count(name) as usize
94 }
95
96 pub fn matches(&self) -> &ArgMatches {
98 &self.arg_matches
99 }
100}
101
102impl fmt::Debug for CompileFlags {
103 #[cfg(feature = "std")]
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 let mut map = f.debug_map();
106 for id in self.arg_matches.ids() {
107 use clap::parser::ValueSource;
108 if id.as_str() == "CompilerOptions" {
110 continue;
111 }
112 if matches!(self.arg_matches.value_source(id.as_str()), Some(ValueSource::DefaultValue))
114 {
115 continue;
116 }
117 map.key(&id.as_str()).value_with(|f| {
118 let mut list = f.debug_list();
119 if let Some(occurs) =
120 self.arg_matches.try_get_raw_occurrences(id.as_str()).expect("expected flag")
121 {
122 list.entries(occurs.flatten());
123 }
124 list.finish()
125 });
126 }
127 map.finish()
128 }
129
130 #[cfg(not(feature = "std"))]
131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 let mut map = f.debug_map();
133 for (name, raw_values) in self.arg_matches.iter() {
134 map.key(&name)
135 .value_with(|f| f.debug_list().entries(raw_values.iter()).finish());
136 }
137 map.finish()
138 }
139}
140
141#[cfg(feature = "std")]
143fn fake_compile_command() -> clap::Command {
144 let cmd = clap::Command::new("compile")
145 .no_binary_name(true)
146 .disable_help_flag(true)
147 .disable_version_flag(true)
148 .disable_help_subcommand(true);
149 register_flags(cmd)
150}
151
152#[cfg(feature = "std")]
154pub fn register_flags(cmd: clap::Command) -> clap::Command {
155 inventory::iter::<CompileFlag>.into_iter().fold(cmd, |cmd, flag| {
156 let arg = clap::Arg::new(flag.name)
157 .long(flag.long.unwrap_or(flag.name))
158 .action(clap::ArgAction::from(flag.action));
159 let arg = if let Some(help) = flag.help {
160 arg.help(help)
161 } else {
162 arg
163 };
164 let arg = if let Some(help_heading) = flag.help_heading {
165 arg.help_heading(help_heading)
166 } else {
167 arg
168 };
169 let arg = if let Some(short) = flag.short {
170 arg.short(short)
171 } else {
172 arg
173 };
174 let arg = if let Some(env) = flag.env {
175 arg.env(env)
176 } else {
177 arg
178 };
179 let arg = if let Some(value) = flag.default_missing_value {
180 arg.default_missing_value(value)
181 } else {
182 arg
183 };
184 let arg = if let Some(value) = flag.default_value {
185 arg.default_value(value)
186 } else {
187 arg
188 };
189 let arg = if let Some(value) = flag.hide {
190 arg.hide(value)
191 } else {
192 arg
193 };
194 cmd.arg(arg)
195 })
196}