use serde_json::Value;
use crate::error::{IssueCode, SizeOrigin, VldError};
use crate::schema::VldSchema;
use super::{Num, ZNumber};
#[derive(Clone, Default)]
pub struct ZF32 {
inner: ZNumber,
}
fn widen(v: f32) -> f64 {
v.to_string().parse().unwrap_or(f64::from(v))
}
macro_rules! bound_methods {
($($(#[$doc:meta])* $name:ident),+ $(,)?) => {$(
$(#[$doc])*
pub fn $name(mut self, val: f32) -> Self {
self.inner = self.inner.$name(widen(val));
self
}
)+};
}
macro_rules! flag_methods {
($($(#[$doc:meta])* $name:ident),+ $(,)?) => {$(
$(#[$doc])*
pub fn $name(mut self) -> Self {
self.inner = self.inner.$name();
self
}
)+};
}
impl ZF32 {
pub fn new() -> Self {
Self::default()
}
pub fn type_error(mut self, msg: impl Into<String>) -> Self {
self.inner = self.inner.type_error(msg);
self
}
pub fn with_messages<F>(mut self, f: F) -> Self
where
F: Fn(&str) -> Option<String> + Send + Sync + 'static,
{
self.inner = self.inner.with_messages(f);
self
}
bound_methods! {
min,
max,
gt,
gte,
lt,
lte,
multiple_of,
}
flag_methods! {
positive,
negative,
non_negative,
non_positive,
coerce,
}
}
impl VldSchema for ZF32 {
type Output = f32;
fn parse_value(&self, value: &Value) -> Result<f32, VldError> {
let f = self.inner.extract_number(value)?;
let out = f as f32;
let limit = f64::from(f32::MAX);
if out == f32::NEG_INFINITY {
return Err(VldError::from_code_with_value(
IssueCode::TooSmall {
origin: SizeOrigin::Number,
minimum: (-limit).into(),
inclusive: true,
},
value,
));
}
if out == f32::INFINITY {
return Err(VldError::from_code_with_value(
IssueCode::TooBig {
origin: SizeOrigin::Number,
maximum: limit.into(),
inclusive: true,
},
value,
));
}
self.inner.validate(Num::F(widen(out)), value)?;
Ok(out)
}
}
#[cfg(feature = "openapi")]
impl crate::openapi::JsonSchema for ZF32 {
fn json_schema(&self) -> serde_json::Value {
let max = Num::F(f64::from(f32::MAX));
let min = Num::F(f64::from(f32::MIN));
let mut schema = self.inner.schema("number", Some((min, max)));
schema["format"] = serde_json::json!("float");
schema
}
}
#[cfg(feature = "openapi")]
impl crate::openapi::CollectNestedSchemas for ZF32 {}
#[cfg(all(test, feature = "openapi"))]
mod schema_tests {
use crate::openapi::JsonSchema;
#[test]
fn f32_schema_carries_the_type_range() {
let s = crate::f32().json_schema();
assert_eq!(s["minimum"], serde_json::json!(f64::from(f32::MIN)));
assert_eq!(s["maximum"], serde_json::json!(f64::from(f32::MAX)));
let s = crate::f32().min(0.5).json_schema();
assert_eq!(s["minimum"], serde_json::json!(0.5));
}
}