compose_lens/model/
cpu_period.rs1#[derive(Debug, Clone, PartialEq, Eq)]
5#[non_exhaustive]
6pub enum CpuPeriod {
7 YamlNumber(String),
9 String(String),
11}
12
13impl CpuPeriod {
14 pub(crate) fn yaml_number_spelling(value: &str) -> bool {
16 let value = value
17 .strip_prefix('+')
18 .or_else(|| value.strip_prefix('-'))
19 .unwrap_or(value);
20 if let Some(digits) = value.strip_prefix("0b") {
21 return digit_sequence(digits, 2);
22 }
23 if let Some(digits) = value.strip_prefix("0o") {
24 return digit_sequence(digits, 8);
25 }
26 if let Some(digits) = value.strip_prefix("0x") {
27 return digit_sequence(digits, 16);
28 }
29
30 let (mantissa, exponent) = value
31 .split_once(['e', 'E'])
32 .map_or((value, None), |(mantissa, exponent)| (mantissa, Some(exponent)));
33 if exponent.is_some_and(|exponent| {
34 let exponent = exponent
35 .strip_prefix('+')
36 .or_else(|| exponent.strip_prefix('-'))
37 .unwrap_or(exponent);
38 !digit_sequence(exponent, 10)
39 }) {
40 return false;
41 }
42 let (integer, fraction) = mantissa
43 .split_once('.')
44 .map_or((mantissa, None), |(integer, fraction)| (integer, Some(fraction)));
45 digit_sequence(integer, 10)
46 && fraction.is_none_or(|fraction| fraction.is_empty() || digit_sequence(fraction, 10))
47 }
48}
49
50fn digit_sequence(value: &str, radix: u8) -> bool {
51 let mut saw_digit = false;
52 let mut previous_separator = false;
53 for byte in value.bytes() {
54 if byte == b'_' {
55 if !saw_digit || previous_separator {
56 return false;
57 }
58 previous_separator = true;
59 continue;
60 }
61 let digit = if byte.is_ascii_digit() {
62 byte - b'0'
63 } else if byte.is_ascii_alphabetic() {
64 byte.to_ascii_lowercase() - b'a' + 10
65 } else {
66 return false;
67 };
68 if digit >= radix {
69 return false;
70 }
71 saw_digit = true;
72 previous_separator = false;
73 }
74 saw_digit && !previous_separator
75}
76
77#[cfg(test)]
78mod tests {
79 use super::CpuPeriod;
80
81 #[test]
82 fn recognizes_plain_yaml_number_spellings() {
83 for value in ["-0xF_F", "+1.5", "1e+6", "1.", "0b1_0", "0o7_7"] {
84 assert!(CpuPeriod::yaml_number_spelling(value));
85 }
86 for value in ["", "1_", "0x_1", "1e", ".5", "opaque"] {
87 assert!(!CpuPeriod::yaml_number_spelling(value));
88 }
89 }
90}