vld/primitives/number/
f32.rs1use serde_json::Value;
2
3use crate::error::{IssueCode, SizeOrigin, VldError};
4use crate::schema::VldSchema;
5
6use super::{Num, ZNumber};
7
8#[derive(Clone, Default)]
26pub struct ZF32 {
27 inner: ZNumber,
28}
29
30fn widen(v: f32) -> f64 {
34 v.to_string().parse().unwrap_or(f64::from(v))
35}
36
37macro_rules! bound_methods {
38 ($($(#[$doc:meta])* $name:ident),+ $(,)?) => {$(
39 $(#[$doc])*
40 pub fn $name(mut self, val: f32) -> Self {
41 self.inner = self.inner.$name(widen(val));
42 self
43 }
44 )+};
45}
46
47macro_rules! flag_methods {
48 ($($(#[$doc:meta])* $name:ident),+ $(,)?) => {$(
49 $(#[$doc])*
50 pub fn $name(mut self) -> Self {
51 self.inner = self.inner.$name();
52 self
53 }
54 )+};
55}
56
57impl ZF32 {
58 pub fn new() -> Self {
60 Self::default()
61 }
62
63 pub fn type_error(mut self, msg: impl Into<String>) -> Self {
65 self.inner = self.inner.type_error(msg);
66 self
67 }
68
69 pub fn with_messages<F>(mut self, f: F) -> Self
71 where
72 F: Fn(&str) -> Option<String> + Send + Sync + 'static,
73 {
74 self.inner = self.inner.with_messages(f);
75 self
76 }
77
78 bound_methods! {
79 min,
81 max,
83 gt,
85 gte,
87 lt,
89 lte,
91 multiple_of,
93 }
94
95 flag_methods! {
96 positive,
98 negative,
100 non_negative,
102 non_positive,
104 coerce,
106 }
107}
108
109impl VldSchema for ZF32 {
110 type Output = f32;
111
112 fn parse_value(&self, value: &Value) -> Result<f32, VldError> {
113 let f = self.inner.extract_number(value)?;
114 let out = f as f32;
115 let limit = f64::from(f32::MAX);
118 if out == f32::NEG_INFINITY {
119 return Err(VldError::from_code_with_value(
120 IssueCode::TooSmall {
121 origin: SizeOrigin::Number,
122 minimum: (-limit).into(),
123 inclusive: true,
124 },
125 value,
126 ));
127 }
128 if out == f32::INFINITY {
129 return Err(VldError::from_code_with_value(
130 IssueCode::TooBig {
131 origin: SizeOrigin::Number,
132 maximum: limit.into(),
133 inclusive: true,
134 },
135 value,
136 ));
137 }
138 self.inner.validate(Num::F(widen(out)), value)?;
139 Ok(out)
140 }
141}
142
143#[cfg(feature = "openapi")]
144impl crate::openapi::JsonSchema for ZF32 {
145 fn json_schema(&self) -> serde_json::Value {
146 let max = Num::F(f64::from(f32::MAX));
148 let min = Num::F(f64::from(f32::MIN));
149 let mut schema = self.inner.schema("number", Some((min, max)));
150 schema["format"] = serde_json::json!("float");
151 schema
152 }
153}
154
155#[cfg(feature = "openapi")]
156impl crate::openapi::CollectNestedSchemas for ZF32 {}
157
158#[cfg(all(test, feature = "openapi"))]
159mod schema_tests {
160 use crate::openapi::JsonSchema;
161
162 #[test]
163 fn f32_schema_carries_the_type_range() {
164 let s = crate::f32().json_schema();
165 assert_eq!(s["minimum"], serde_json::json!(f64::from(f32::MIN)));
166 assert_eq!(s["maximum"], serde_json::json!(f64::from(f32::MAX)));
167 let s = crate::f32().min(0.5).json_schema();
168 assert_eq!(s["minimum"], serde_json::json!(0.5));
169 }
170}