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
use std::str::FromStr;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum DisplayHint {
NoHint {
zero_pad: usize,
},
Hexadecimal {
alternate: bool,
uppercase: bool,
zero_pad: usize,
},
Binary {
alternate: bool,
zero_pad: usize,
},
Ascii,
Debug,
Microseconds,
ISO8601(TimePrecision),
Bitflags {
name: String,
package: String,
disambiguator: String,
crate_name: String,
},
Unknown(String),
}
impl DisplayHint {
pub(crate) fn parse(mut s: &str) -> Option<Self> {
const BITFLAGS_HINT_START: &str = "__internal_bitflags_";
let alternate = if let Some(rest) = s.strip_prefix('#') {
s = rest;
true
} else {
false
};
let zero_pad = if let Some(rest) = s.strip_prefix('0') {
let (rest, columns) = parse_integer::<usize>(rest)?;
s = rest;
columns
} else {
0 };
if let Some(stripped) = s.strip_prefix(BITFLAGS_HINT_START) {
let parts = stripped.split('@').collect::<Vec<_>>();
match *parts {
[bitflags_name, package, disambiguator, crate_name] => {
return Some(DisplayHint::Bitflags {
name: bitflags_name.into(),
package: package.into(),
disambiguator: disambiguator.into(),
crate_name: crate_name.into(),
});
}
_ => return Some(DisplayHint::Unknown(s.into())),
}
}
Some(match s {
"" => DisplayHint::NoHint { zero_pad },
"us" => DisplayHint::Microseconds,
"a" => DisplayHint::Ascii,
"b" => DisplayHint::Binary {
alternate,
zero_pad,
},
"x" => DisplayHint::Hexadecimal {
alternate,
uppercase: false,
zero_pad,
},
"X" => DisplayHint::Hexadecimal {
alternate,
uppercase: true,
zero_pad,
},
"iso8601ms" => DisplayHint::ISO8601(TimePrecision::Millis),
"iso8601s" => DisplayHint::ISO8601(TimePrecision::Seconds),
"?" => DisplayHint::Debug,
_ => return None,
})
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum TimePrecision {
Millis,
Seconds,
}
fn parse_integer<T: FromStr>(s: &str) -> Option<(&str, usize)> {
let start_digits = s
.as_bytes()
.iter()
.copied()
.take_while(|b| b.is_ascii_digit())
.count();
let num = s[..start_digits].parse().ok()?;
Some((&s[start_digits..], num))
}