compose_lens/model/
pids.rs1use super::Located;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct PidsLimit {
8 raw: Located<String>,
9 kind: PidsLimitKind,
10}
11
12impl PidsLimit {
13 pub(crate) fn parse(raw: Located<String>) -> Self {
14 let kind = match raw.value().as_str() {
15 "-1" => PidsLimitKind::Unlimited,
16 value if value.contains('$') => PidsLimitKind::Expression,
17 value if decimal_digits(value) => {
18 if value.bytes().all(|byte| byte == b'0') {
19 PidsLimitKind::Zero
20 } else {
21 PidsLimitKind::Finite {
22 decimal: value.to_owned(),
23 }
24 }
25 }
26 _ => PidsLimitKind::Other,
27 };
28 Self { raw, kind }
29 }
30
31 #[must_use]
33 pub const fn raw(&self) -> &Located<String> {
34 &self.raw
35 }
36
37 #[must_use]
39 pub const fn kind(&self) -> &PidsLimitKind {
40 &self.kind
41 }
42}
43
44#[derive(Debug, Clone, PartialEq, Eq)]
46#[non_exhaustive]
47pub enum PidsLimitKind {
48 Unlimited,
50 Finite {
52 decimal: String,
54 },
55 Zero,
57 Expression,
59 Other,
61}
62
63pub(crate) fn valid_positive_pids_decimal(value: &str) -> bool {
64 decimal_digits(value) && value.bytes().any(|byte| byte != b'0')
65}
66
67fn decimal_digits(value: &str) -> bool {
68 !value.is_empty() && value.bytes().all(|byte| byte.is_ascii_digit())
69}
70
71#[cfg(test)]
72mod tests {
73 use super::{PidsLimit, PidsLimitKind, valid_positive_pids_decimal};
74 use crate::model::Located;
75 use crate::source::{SourceId, SourceSpan};
76
77 #[test]
78 fn classifies_without_fixed_width_integer_parsing_or_normalization() -> Result<(), &'static str> {
79 let cases = [
80 ("-1", PidsLimitKind::Unlimited),
81 (
82 "00042",
83 PidsLimitKind::Finite {
84 decimal: "00042".to_owned(),
85 },
86 ),
87 (
88 "18446744073709551616000000000000000000000000000000",
89 PidsLimitKind::Finite {
90 decimal: "18446744073709551616000000000000000000000000000000".to_owned(),
91 },
92 ),
93 ("000", PidsLimitKind::Zero),
94 ("${PIDS_LIMIT:-64}", PidsLimitKind::Expression),
95 ("1.5", PidsLimitKind::Other),
96 ("1e3", PidsLimitKind::Other),
97 ("+1", PidsLimitKind::Other),
98 ];
99 for (value, expected) in cases {
100 let span = SourceSpan::new(SourceId::new(1), 0, value.len()).ok_or("valid test span expected")?;
101 let limit = PidsLimit::parse(Located::new(value.to_owned(), span));
102 assert_eq!(limit.raw().value(), value);
103 assert_eq!(limit.kind(), &expected);
104 }
105 Ok(())
106 }
107
108 #[test]
109 fn validates_generated_positive_decimals_without_overflow() {
110 for value in ["1", "0001", "18446744073709551616000000000000000000000000000000"] {
111 assert!(valid_positive_pids_decimal(value));
112 }
113 for value in ["", "0", "000", "-1", "+1", "1.0", "1e3", "64MiB"] {
114 assert!(!valid_positive_pids_decimal(value));
115 }
116 }
117}