]>
git.proxmox.com Git - rustc.git/blob - extra/bitflags/src/parser.rs
2 Parsing flags from text.
4 Format and parse a flags value as text using the following grammar:
6 - _Flags:_ (_Whitespace_ _Flag_ _Whitespace_)`|`*
7 - _Flag:_ _Name_ | _Hex Number_
8 - _Name:_ The name of any defined flag
9 - _Hex Number_: `0x`([0-9a-fA-F])*
12 As an example, this is how `Flags::A | Flags::B | 0x0c` can be represented as text:
18 Alternatively, it could be represented without whitespace:
24 Note that identifiers are *case-sensitive*, so the following is *not equivalent*:
31 #![allow(clippy::let_unit_value)]
33 use core
::fmt
::{self, Write}
;
35 use crate::{Bits, Flags}
;
38 Write a flags value as text.
40 Any bits that aren't part of a contained flag will be formatted as a hex number.
42 pub fn to_writer
<B
: Flags
>(flags
: &B
, mut writer
: impl Write
) -> Result
<(), fmt
::Error
>
46 // A formatter for bitflags that produces text output like:
50 // The names of set flags are written in a bar-separated-format,
51 // followed by a hex number of any remaining bits that are set
52 // but don't correspond to any flags.
54 // Iterate over known flag values
56 let mut iter
= flags
.iter_names();
57 for (name
, _
) in &mut iter
{
59 writer
.write_str(" | ")?
;
63 writer
.write_str(name
)?
;
66 // Append any extra bits that correspond to flags to the end of the format
67 let remaining
= iter
.remaining().bits();
68 if remaining
!= B
::Bits
::EMPTY
{
70 writer
.write_str(" | ")?
;
73 writer
.write_str("0x")?
;
74 remaining
.write_hex(writer
)?
;
80 pub(crate) struct AsDisplay
<'a
, B
>(pub(crate) &'a B
);
82 impl<'a
, B
: Flags
> fmt
::Display
for AsDisplay
<'a
, B
>
86 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
92 Parse a flags value from text.
94 This function will fail on any names that don't correspond to defined flags.
95 Unknown bits will be retained.
97 pub fn from_str
<B
: Flags
>(input
: &str) -> Result
<B
, ParseError
>
101 let mut parsed_flags
= B
::empty();
103 // If the input is empty then return an empty set of flags
104 if input
.trim().is_empty() {
105 return Ok(parsed_flags
);
108 for flag
in input
.split('
|'
) {
109 let flag
= flag
.trim();
111 // If the flag is empty then we've got missing input
113 return Err(ParseError
::empty_flag());
116 // If the flag starts with `0x` then it's a hex number
117 // Parse it directly to the underlying bits type
118 let parsed_flag
= if let Some(flag
) = flag
.strip_prefix("0x") {
120 <B
::Bits
>::parse_hex(flag
).map_err(|_
| ParseError
::invalid_hex_flag(flag
))?
;
122 B
::from_bits_retain(bits
)
124 // Otherwise the flag is a name
125 // The generated flags type will determine whether
126 // or not it's a valid identifier
128 B
::from_name(flag
).ok_or_else(|| ParseError
::invalid_named_flag(flag
))?
131 parsed_flags
.insert(parsed_flag
);
138 Encode a value as a hex string.
140 Implementors of this trait should not write the `0x` prefix.
143 /// Write the value as hex.
144 fn write_hex
<W
: fmt
::Write
>(&self, writer
: W
) -> fmt
::Result
;
148 Parse a value from a hex string.
151 /// Parse the value from hex.
152 fn parse_hex(input
: &str) -> Result
<Self, ParseError
>
157 /// An error encountered while parsing flags from text.
159 pub struct ParseError(ParseErrorKind
);
162 #[allow(clippy::enum_variant_names)]
163 enum ParseErrorKind
{
166 #[cfg(not(feature = "std"))]
168 #[cfg(feature = "std")]
172 #[cfg(not(feature = "std"))]
174 #[cfg(feature = "std")]
180 /// An invalid hex flag was encountered.
181 pub fn invalid_hex_flag(flag
: impl fmt
::Display
) -> Self {
185 #[cfg(feature = "std")]
191 ParseError(ParseErrorKind
::InvalidHexFlag { got }
)
194 /// A named flag that doesn't correspond to any on the flags type was encountered.
195 pub fn invalid_named_flag(flag
: impl fmt
::Display
) -> Self {
199 #[cfg(feature = "std")]
205 ParseError(ParseErrorKind
::InvalidNamedFlag { got }
)
208 /// A hex or named flag wasn't found between separators.
209 pub const fn empty_flag() -> Self {
210 ParseError(ParseErrorKind
::EmptyFlag
)
214 impl fmt
::Display
for ParseError
{
215 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
217 ParseErrorKind
::InvalidNamedFlag { got }
=> {
220 write
!(f
, "unrecognized named flag")?
;
222 #[cfg(feature = "std")]
224 write
!(f
, " `{}`", _got
)?
;
227 ParseErrorKind
::InvalidHexFlag { got }
=> {
230 write
!(f
, "invalid hex flag")?
;
232 #[cfg(feature = "std")]
234 write
!(f
, " `{}`", _got
)?
;
237 ParseErrorKind
::EmptyFlag
=> {
238 write
!(f
, "encountered empty flag")?
;
246 #[cfg(feature = "std")]
247 impl std
::error
::Error
for ParseError {}