deser_validate/lib.rs
1//! Validation for [deser](https://docs.rs/deser).
2//!
3//! Values are validated while they are deserialized, so errors point at the
4//! value in the input (with its line, column and path) like the errors of
5//! the format. Validators are types (see [`Validator`]), so they are
6//! named in adapters and in the types of fields:
7//!
8//! * The [`Check<V>`](Check) adapter (`#[deser(as = Check<V>)]`) fails the
9//! deserialization if the value is invalid. The type of the field does
10//! not change. On a type (`#[deser(deserialize_as = Check<V, _>)]`) it
11//! checks the whole value, for rules that span fields.
12//! * [`Validated<T, V>`](Validated) keeps all errors of the value in it
13//! instead of failing, so the value around it can still be
14//! deserialized. This also covers errors like a string that is given
15//! where a number is expected.
16//! * A [`Validation`] reports all problems of an input.
17//!
18//! ```
19//! use deser::Deserialize;
20//! use deser_validate::{
21//! Check, Email, MaxLen, NonEmpty, Validated, Validation,
22//! };
23//!
24//! #[derive(Deserialize)]
25//! struct Signup {
26//! // must be valid, or the signup is invalid
27//! #[deser(as = Check<(NonEmpty, MaxLen<32>)>)]
28//! name: String,
29//! // kept even if it is invalid
30//! email: Validated<String, Email>,
31//! newsletter: bool,
32//! }
33//!
34//! let input = r#"{"name": "", "email": "jane@", "newsletter": "yes"}"#;
35//! let validation = Validation::new();
36//! let rv = deser_json::Deserializer::from_str(input)
37//! .deserialize_with::<Signup, _>(|driver| validation.setup(driver));
38//! let report = validation.finish(rv).into_result().err().unwrap();
39//! let issues: Vec<_> = report
40//! .iter()
41//! .map(|issue| {
42//! format!("{}: {}", issue.path().unwrap(), issue.message())
43//! })
44//! .collect();
45//! assert_eq!(
46//! issues,
47//! [
48//! "name: invalid value: must not be empty",
49//! "email: invalid value: must be an email address",
50//! "newsletter: unexpected string, expected bool",
51//! ]
52//! );
53//! ```
54//!
55//! Types that are always valid are newtypes which check themselves:
56//!
57//! ```
58//! use deser::Deserialize;
59//! use deser_validate::Check;
60//!
61//! #[derive(Deserialize)]
62//! #[deser(transparent)]
63//! pub struct Email(#[deser(as = Check<deser_validate::Email>)] String);
64//! ```
65//!
66//! # Validators
67//!
68//! The validators of this crate are [`NonEmpty`], [`Len`] (and [`MinLen`]
69//! and [`MaxLen`]), [`Range`] (and [`Min`] and [`Max`]), [`Email`] and
70//! [`Each`], which validates the items of collections. Tuples of
71//! validators require all of them. The [`validator!`] macro creates
72//! validators from conditions and functions:
73//!
74//! ```
75//! use deser::Deserialize;
76//! use deser_validate::{Check, validator};
77//!
78//! // a condition and a message
79//! validator!(NonZero(port: &u16) => *port != 0, "must not be zero");
80//!
81//! // a function
82//! fn check_host(host: &str) -> Result<(), String> {
83//! match host.contains(' ') {
84//! true => Err(format!("`{}` is not a host name", host)),
85//! false => Ok(()),
86//! }
87//! }
88//! validator!(HostName(host: &str) = check_host);
89//!
90//! #[derive(Deserialize)]
91//! struct Server {
92//! #[deser(as = Check<HostName>)]
93//! host: String,
94//! #[deser(as = Check<NonZero>)]
95//! port: u16,
96//! }
97//! ```
98//!
99//! Validators of types with generics or lifetimes implement [`Validator`]
100//! themselves, the macro does not support them.
101//!
102//! Validators report a [`Violation`] with a code and parameters for
103//! programs and a message for humans. Errors have the violation attached.
104//!
105//! # Naming Validators
106//!
107//! Validators are named for the property that valid values have, as a
108//! noun or an adjective: `Email`, `Slug`, `NonEmpty`, `NonZero`,
109//! `MaxLen<64>`. They read as `Check<NonZero>` and do not need affixes like
110//! `Valid`, `Is` or `Rules`. Negations start with `Non` (like
111//! [`NonZero`](std::num::NonZero)). Validators of a whole type name the
112//! rule they check (`OrderedBounds`, not `BoundsRules`), combinators name
113//! their structure ([`Each`]). The code of a violation is the name of the
114//! validator in snake case (`max_len`, `non_zero`), for the validators of
115//! this crate and the ones [`validator!`] creates.
116#![doc(html_logo_url = "https://raw.githubusercontent.com/mitsuhiko/deser/main/artwork/logo.svg")]
117
118mod check;
119mod macros;
120mod report;
121mod validated;
122mod validator;
123mod validators;
124
125pub use self::check::Check;
126#[doc(hidden)]
127pub use self::macros::__private;
128pub use self::macros::{IntoViolation, ValidationResult};
129pub use self::report::{Issue, Outcome, Report, Validation};
130pub use self::validated::Validated;
131pub use self::validator::{Param, Validator, Violation};
132pub use self::validators::{
133 Each, Email, Integer, Len, Length, Max, MaxLen, Min, MinLen, NonEmpty, Range,
134};
135
136// the examples of the readme are tested
137#[cfg(doctest)]
138#[doc = include_str!("../README.md")]
139struct ReadmeDoctests;