Numbers
Constructors
| Constructor | Output | Notes |
|---|---|---|
vld::number() | f64 | any JSON number |
vld::number().int() | i64 | a ZInt (= ZInteger<i64>); rejects fractions |
vld::i8() … vld::i64(), vld::isize() | the integer type | exact, range-checked |
vld::u8() … vld::u64(), vld::usize() | the integer type | exact, range-checked |
vld::f32() | f32 | rejects values outside the finite f32 range |
Integers are read exactly: there is no f64 round trip, so vld::u64() accepts 18446744073709551615. A float with a fraction fails with not_int; a value outside the type range fails with too_small / too_big naming the type's bound.
use vld::prelude::*;
let port: u16 = vld::u16().min(1).parse("8080").unwrap();
assert_eq!(port, 8080);
assert!(vld::u16().parse("70000").is_err()); // above u16::MAX
assert!(vld::u8().parse("-1").is_err());
assert!(vld::i32().parse("1.5").is_err()); // not_int
assert_eq!(vld::u64().parse("18446744073709551615").unwrap(), u64::MAX);
Bounds
The same methods exist on number(), the integer schemas and f32(); the argument has the schema's own type (f64, u16, f32, …).
| Method | Check | Issue |
|---|---|---|
min(v) / gte(v) | >= v | too_small (inclusive) |
max(v) / lte(v) | <= v | too_big (inclusive) |
gt(v) | > v | too_small (exclusive) |
lt(v) | < v | too_big (exclusive) |
positive() / negative() | > 0 / < 0 | too_small / too_big (exclusive) |
non_negative() / non_positive() | >= 0 / <= 0 | too_small / too_big |
multiple_of(v) | divisible by v | not_multiple_of |
safe() | within -(2^53 - 1)..=2^53 - 1 | not_safe_integer |
When several bounds fail, the strictest one is reported. NaN never passes a bound.
multiple_of on floats uses a relative tolerance of 1e-9, so vld::number().multiple_of(0.1) accepts 0.3. A divisor of 0 rejects every value. vld::f32() compares at f32 precision, so vld::f32().max(0.1) accepts 0.1.
let price = vld::number().positive().multiple_of(0.01);
assert!(price.parse("19.99").is_ok());
assert!(price.parse("19.999").is_err());
let percent = vld::f32().min(0.0).max(100.0);
assert_eq!(percent.parse("12.5").unwrap(), 12.5_f32);
Coercion
By default only JSON numbers are accepted. coerce() also accepts numeric strings and booleans (true → 1, false → 0):
let n = vld::number().coerce();
assert_eq!(n.parse(r#""4.5""#).unwrap(), 4.5);
assert_eq!(n.parse("true").unwrap(), 1.0);
assert!(n.parse(r#""NaN""#).is_err());
let id = vld::u32().coerce();
assert_eq!(id.parse(r#""42""#).unwrap(), 42);
Web extractors coerce query, path, form, header and cookie values for you, so you rarely need coerce() there. See coercion rules.
Messages
type_error("...")— message for non-number input.int_error("...")on integer schemas — message for a number with a fraction.with_messages(|key| ...)— override by check key:too_small,too_big,not_positive,not_negative,not_non_negative,not_non_positive,not_multiple_of,not_safe, andnot_inton integer schemas.
JSON Schema
number() emits {"type": "number"}, integers {"type": "integer", "format": "int8" … "uint64"} with minimum / maximum from the type range intersected with your bounds, and f32() {"type": "number", "format": "float"}.