Skip to main content

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.
  • ControlFlow and ValidateNested in the prelude.
  • A validate_traversal example.

Changed

  • #[derive(Spec)] now emits an impl ValidateNested alongside the impl FromFields. Nothing about the parser changed.
  • The bound on every generated Lower impl moves from where S: Validate to where S: Validate + ValidateNested. A spec that derives Spec satisfies the second half automatically.
  • A nested spec without a Validate impl 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"] }