esp_config/generate/
validator.rs1use std::{io::Write, ops::Range};
2
3use serde::{Deserialize, Serialize};
4
5use super::{Error, snake_case, value::Value};
6
7#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
9pub enum Validator {
10 NegativeInteger,
12 NonNegativeInteger,
15 PositiveInteger,
17 IntegerInRange(Range<i128>),
19 Enumeration(Vec<String>),
21}
22
23impl Validator {
24 pub fn validate(&self, value: &Value) -> Result<(), Error> {
26 match self {
27 Validator::NegativeInteger => negative_integer(value)?,
28 Validator::NonNegativeInteger => non_negative_integer(value)?,
29 Validator::PositiveInteger => positive_integer(value)?,
30 Validator::IntegerInRange(range) => integer_in_range(range, value)?,
31 Validator::Enumeration(values) => enumeration(values, value)?,
32 }
33
34 Ok(())
35 }
36
37 pub(crate) fn description(&self) -> Option<String> {
38 match self {
39 Validator::NegativeInteger => Some(String::from("Negative integer")),
40 Validator::NonNegativeInteger => Some(String::from("Positive integer or 0")),
41 Validator::PositiveInteger => Some(String::from("Positive integer")),
42 Validator::IntegerInRange(range) => {
43 Some(format!("Integer in range {}..{}", range.start, range.end))
44 }
45 Validator::Enumeration(values) => Some(format!(
46 "One of: <ul style=\"display: inline-block; text-align: left\">{}</ul>",
47 values
48 .iter()
49 .map(|v| format!("<li>{v}</li>"))
50 .collect::<Vec<_>>()
51 .join("")
52 )),
53 }
54 }
55
56 pub(crate) fn emit_cargo_extras(
57 &self,
58 mut stdout: impl Write,
59 config_key: &str,
60 actual_value: &Value,
61 ) {
62 if let Validator::Enumeration(values) = self {
63 for possible_value in values {
64 writeln!(
65 stdout,
66 "cargo:rustc-check-cfg=cfg({config_key}_{})",
67 snake_case(possible_value)
68 )
69 .ok();
70 }
71
72 writeln!(
73 stdout,
74 "cargo:rustc-cfg={config_key}_{}",
75 snake_case(&actual_value.to_string())
76 )
77 .ok();
78 }
79 }
80}
81
82pub(crate) fn enumeration(values: &Vec<String>, value: &Value) -> Result<(), Error> {
83 if let Value::String(value) = value {
84 if !values.contains(value) {
85 return Err(Error::validation(format!(
86 "Expected one of {values:?}, found '{value}'"
87 )));
88 }
89
90 Ok(())
91 } else {
92 Err(Error::parse(
93 "Validator::Enumeration can only be used with string values",
94 ))
95 }
96}
97
98pub(crate) fn negative_integer(value: &Value) -> Result<(), Error> {
99 if !value.is_integer() {
100 return Err(Error::validation(
101 "Validator::NegativeInteger can only be used with integer values",
102 ));
103 } else if value.as_integer() >= 0 {
104 return Err(Error::validation(format!(
105 "Expected negative integer, found '{}'",
106 value.as_integer()
107 )));
108 }
109
110 Ok(())
111}
112
113pub(crate) fn non_negative_integer(value: &Value) -> Result<(), Error> {
114 if !value.is_integer() {
115 return Err(Error::validation(
116 "Validator::NonNegativeInteger can only be used with integer values",
117 ));
118 } else if value.as_integer() < 0 {
119 return Err(Error::validation(format!(
120 "Expected non-negative integer, found '{}'",
121 value.as_integer()
122 )));
123 }
124
125 Ok(())
126}
127
128pub(crate) fn positive_integer(value: &Value) -> Result<(), Error> {
129 if !value.is_integer() {
130 return Err(Error::validation(
131 "Validator::PositiveInteger can only be used with integer values",
132 ));
133 } else if value.as_integer() <= 0 {
134 return Err(Error::validation(format!(
135 "Expected positive integer, found '{}'",
136 value.as_integer()
137 )));
138 }
139
140 Ok(())
141}
142
143pub(crate) fn integer_in_range(range: &Range<i128>, value: &Value) -> Result<(), Error> {
144 if !value.is_integer() || !range.contains(&value.as_integer()) {
145 Err(Error::validation(format!(
146 "Value '{value}' does not fall within range '{range:?}'"
147 )))
148 } else {
149 Ok(())
150 }
151}