Structs

Lenient parsing

Validate each field separately, build the struct anyway and inspect per-field results.

parse() fails as a whole. Sometimes you want the opposite: keep the fields that are valid, use defaults for the rest and show what went wrong, for example when loading a user-edited settings file.

Lenient parsing is available on:

  • schema_validated! structs,
  • schema! structs plus impl_validate_fields!,
  • #[derive(Validate)] structs with #[vld(lenient)].

Every field type must implement Default and serde::Serialize.

validate_fields

validate_fields(input) checks each field on its own and returns Vec<FieldResult>:

use vld::prelude::*;

vld::schema_validated! {
    #[derive(Debug, Default, serde::Serialize)]
    pub struct Settings {
        pub name: String => vld::string().min(2),
        pub port: i64 => vld::number().int().min(1).max(65535),
        pub theme: String => vld::enumeration(&["light", "dark"]).with_default("light".into()),
    }
}

let fields = Settings::validate_fields(r#"{"name": "X", "port": 8080}"#).unwrap();
for f in &fields {
    println!("{f}");
}
// ✖ name: String must be at least 2 characters (received: "X")
// ✔ port: 8080
// ✔ theme: "light"

FieldResult has name, input (the raw value) and result: Result<Value, VldError>, plus is_ok() / is_err().

parse_lenient

parse_lenient(input) always builds the struct: valid fields get their parsed value, invalid ones Default::default(). It returns ParseResult<T>:

let r = Settings::parse_lenient(r#"{"name": "X", "port": 0}"#).unwrap();
assert_eq!(r.error_count(), 2);
assert_eq!(r.value.port, 0);           // Default
assert_eq!(r.value.theme, "light");     // schema default

for f in r.error_fields() {
    eprintln!("{f}");
}
let settings = r.into_value();
ParseResult methodReturns
value (field) / into_value() / into_parts()the struct, or the struct and the field results
fields() / field(name)all field results / one by name
valid_fields() / error_fields()filtered field results
is_valid() / has_errors() / valid_count() / error_count()summary
to_json_value() / to_json_string() / save_to_file(path)serialize the struct (needs T: Serialize)

Both functions still return Err when the input is not an object at all. A .catch(..) field never counts as an error: the fallback is a valid value.