confval v0.5.0
This release adds a way to automatically ensure all nested specs are validated.
Highlights
One call validates the whole spec tree
Validate gains a validate_all method that runs a spec type's own rules and then descends into every
#[confval(nested)] field, recursively.
A Validate impl covers one spec type's own fields, so reaching a nested block used to mean calling into it manually
from the parent spec's Validate impl.
Forgetting that call left the nested block unvalidated with nothing to indicate it.
spec.validate_all(&mut report);
The descent comes from #[derive(Spec)], so a nested block added later is validated without editing a validator.
See Validation for the full picture.
Existing Validate impls do not change
Validate::validate keeps its signature and stays the only method you have to write.
validate_all and descend are provided methods, so an impl written against v0.4.0 compiles unchanged.
Added
Validate::validate_all, the entry point that runs a spec's rules and then its nested children.Validate::descend, which decides whether the children of a block are visited.ValidateNested, the traversal trait that#[derive(Spec)]implements for you.ControlFlowandValidateNestedin the prelude.- A
validate_traversalexample.
Changed
#[derive(Spec)]now emits animpl ValidateNestedalongside theimpl FromFields. Nothing about the parser changed.- The bound on every generated
Lowerimpl moves fromwhere S: Validatetowhere S: Validate + ValidateNested. A spec that derivesSpecsatisfies the second half automatically. - A nested spec without a
Validateimpl is now a compile error at its parent rather than a block that is skipped.
Upgrading
Replace the top level spec.validate(&mut report) with spec.validate_all(&mut report).
Delete any calls into child specs from your Validate impls.
A leftover call reports the child's issues twice, so it is worth a grep to find the calls and remove them:
grep -rn ".validate(" crates/
A spec with a handwritten FromFields has no derive to generate its traversal and needs its own impl ValidateNested.
The lowering bound reports the missing impl.
[dependencies]
confval = { version = "0.5", features = ["derive", "hcl", "color"] }