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