1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
use std::{
fmt::{Debug, Display},
ops::{Deref, Not},
};
/// Parsed result of a boolean-style command-line flag.
///
/// `Flag` is a **value type** that can be declared in [`PickerArg`].
/// When the user passes `--verbose` on the command line, the parsed result is `Flag::Active`;
/// when the flag is absent, the result is `Flag::Inactive`.
///
/// # Why not just `bool`?
///
/// Unlike a raw `bool`, `Flag` carries **explicit semantics** about whether
/// the flag was actually provided by the user (`Active`) or simply omitted
/// (`Inactive`). This distinction matters when you want to distinguish
/// "the user intentionally omitted the flag" from "the flag was processed but
/// resolved to false" — the `Pickable` implementation for `Flag` always
/// returns `Parsed(Flag::Inactive)` when no matching argument is found,
/// rather than `NotFound`, making it always succeed with a meaningful default.
///
/// # Conversions
///
/// `Flag` interoperates seamlessly with `bool`: `Flag::Active` is `true`,
/// `Flag::Inactive` is `false`. The [`Deref`] impl allows using a `Flag`
/// directly in boolean contexts:
///
/// ```
/// # use mingling_picker::value::Flag;
/// let flag = Flag::Active;
/// if *flag { /* runs */ }
/// ```
///
/// [`PickerArg`]: crate::PickerArg
#[derive(Default, Clone, Copy, PartialEq, Eq)]
pub enum Flag {
/// The flag was **not** present on the command line.
///
/// This is the default state, equivalent to `false`.
#[default]
Inactive,
/// The flag **was** present on the command line.
///
/// Equivalent to `true`.
Active,
}
impl Debug for Flag {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Inactive => write!(f, "inactive"),
Self::Active => write!(f, "active"),
}
}
}
impl Display for Flag {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Inactive => write!(f, "inactive"),
Self::Active => write!(f, "active"),
}
}
}
impl Flag {
/// Converts this `Flag` into a `bool`.
///
/// Returns `true` if the flag is [`Active`], `false` if [`Inactive`].
///
/// # Examples
///
/// ```
/// # use mingling_picker::value::Flag;
/// assert!(Flag::Active.bool());
/// assert!(!Flag::Inactive.bool());
/// ```
///
/// [`Active`]: Flag::Active
/// [`Inactive`]: Flag::Inactive
#[must_use]
#[inline(always)]
pub fn bool(&self) -> bool {
*self == Flag::Active
}
}
impl PartialEq<bool> for Flag {
fn eq(&self, other: &bool) -> bool {
self.bool() == *other
}
}
/// Compares `bool` with `Flag` using `==`.
impl PartialEq<Flag> for bool {
fn eq(&self, other: &Flag) -> bool {
*self == other.bool()
}
}
impl From<bool> for Flag {
fn from(value: bool) -> Self {
if value { Flag::Active } else { Flag::Inactive }
}
}
impl From<Flag> for bool {
fn from(val: Flag) -> Self {
val == Flag::Active
}
}
/// Allows `Flag` to be used in boolean contexts via `*flag`.
///
/// # Examples
///
/// ```
/// # use mingling_picker::value::Flag;
/// let flag = Flag::Active;
/// if *flag {
/// println!("flag is set");
/// }
/// ```
impl Deref for Flag {
type Target = bool;
fn deref(&self) -> &bool {
match self {
Flag::Active => &true,
Flag::Inactive => &false,
}
}
}
impl Not for Flag {
type Output = Flag;
fn not(self) -> Flag {
match self {
Flag::Active => Flag::Inactive,
Flag::Inactive => Flag::Active,
}
}
}
|