lmn_core/request_template/validators/
float.rs1use serde::Deserialize;
2
3use crate::request_template::definition::TemplateDef;
4use crate::request_template::error::TemplateError;
5use crate::request_template::validators::Validator;
6
7#[derive(Deserialize, Default)]
10pub struct RawFloatDetails {
11 pub decimals: Option<u8>,
12}
13
14pub struct FloatDef {
17 pub strategy: FloatStrategy,
18 pub decimals: u8,
19}
20
21pub enum FloatStrategy {
22 Exact(f64),
23 Range { min: f64, max: f64 },
24}
25
26pub struct FloatValidator {
29 pub exact: Option<f64>,
30 pub min: Option<f64>,
31 pub max: Option<f64>,
32 pub details: Option<RawFloatDetails>,
33}
34
35impl Validator for FloatValidator {
36 fn validate(self, name: &str) -> Result<TemplateDef, TemplateError> {
37 let decimals = self.details.unwrap_or_default().decimals.unwrap_or(2);
38
39 let strategy = if let Some(v) = self.exact {
40 FloatStrategy::Exact(v)
41 } else {
42 let min_v = self.min.ok_or_else(|| {
43 TemplateError::InvalidConstraint(format!(
44 "'{name}': float requires either 'exact' or both 'min' and 'max'"
45 ))
46 })?;
47 let max_v = self.max.ok_or_else(|| {
48 TemplateError::InvalidConstraint(format!(
49 "'{name}': float requires either 'exact' or both 'min' and 'max'"
50 ))
51 })?;
52 if min_v > max_v {
53 return Err(TemplateError::InvalidConstraint(format!(
54 "'{name}': float min ({min_v}) > max ({max_v})"
55 )));
56 }
57 FloatStrategy::Range {
58 min: min_v,
59 max: max_v,
60 }
61 };
62
63 Ok(TemplateDef::Float(FloatDef { strategy, decimals }))
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use crate::request_template::validators::Validator;
71
72 fn v(exact: Option<f64>, min: Option<f64>, max: Option<f64>) -> FloatValidator {
73 FloatValidator {
74 exact,
75 min,
76 max,
77 details: None,
78 }
79 }
80
81 #[test]
82 fn validates_exact() {
83 assert!(v(Some(1.0), None, None).validate("x").is_ok());
84 }
85
86 #[test]
87 fn validates_range() {
88 assert!(v(None, Some(1.0), Some(5.0)).validate("x").is_ok());
89 }
90
91 #[test]
92 fn rejects_min_greater_than_max() {
93 assert!(v(None, Some(5.0), Some(1.0)).validate("x").is_err());
94 }
95
96 #[test]
97 fn rejects_missing_min() {
98 assert!(v(None, None, Some(5.0)).validate("x").is_err());
99 }
100
101 #[test]
102 fn rejects_missing_max() {
103 assert!(v(None, Some(1.0), None).validate("x").is_err());
104 }
105}