pub trait Validated {
type InvalidReason;
}Expand description
A type whose values are guaranteed to satisfy a validation predicate.
Implementing Validated marks Self as the validated form of some
underlying data — typically a newtype around a raw type, or a ?Sized
view type like str over [[u8]]. The implementation asserts that
every value of Self that can be constructed through the crate’s
conversion traits satisfies the type’s invariant.
This trait does not itself perform validation. It declares the
canonical failure explanation for the type, via the InvalidReason
associated type. Conversions into Self — whether borrowing
(AsValidated) or owning (IntoValidated) — report failure
using this type.
§Scope
This trait models structural refinement — the validated type shares
a representation with its precursor and differs only in which values
are permitted. It is not intended for general fallible conversion,
such as parsing a string into a binary value with different layout.
For those cases, use FromStr or TryFrom.
§The role of InvalidReason
InvalidReason describes why a candidate value failed to satisfy
the predicate. It is purely diagnostic: it must not carry the
candidate value itself.
This restriction is deliberate. Precursor recovery — giving the caller back their unvalidated input on failure — is handled structurally by the conversion traits:
AsValidated::as_validatedreturns a reference into&self, so the caller retains access to the precursor through their existing binding.IntoValidated::into_validatedreturns the owned precursor alongside theInvalidReasonin the invalid branch ofMaybeValidOwned.
Keeping InvalidReason precursor-free allows a single
Validated impl to serve both borrowing and owning conversions
without duplicating data or forcing a clone on the owning path.
§Contract
Implementers of Validated promise the following:
-
Predicate stability. Whether a value of the underlying type satisfies the predicate must depend only on the value’s observable state, not on external state, time, or interior mutability. A value that was valid yesterday is valid today.
-
InvalidReasonis diagnostic only. TheInvalidReasontype must not contain the candidate value or a copy of it. It may contain positional information (byte offsets, field indices), expected-versus-actual summaries, or any other explanation, provided these are cheap to construct relative to the cost of validation itself. -
InvalidReasonis cheaply constructible. Constructing anInvalidReasonon the failure path should not be dramatically more expensive than running the validation itself. In particular, it should not allocate proportional to the candidate’s size.
These are logical contracts, not compiler-enforced ones. Violating
them will not cause undefined behavior, but will break the guarantees
that generic code written against Validated relies on.
§Examples
The canonical example is str as the validated form of [u8]:
fn assert_validated_utf8<T: Validated<InvalidReason = Utf8Error> + ?Sized>() {}
assert_validated_utf8::<str>();Utf8Error carries a valid_up_to: usize and an error_len: Option<u8>. It explains where UTF-8 validation failed, without
holding the [u8] that failed — the caller retains that through
their own binding or through IntoValidated’s return.
A custom newtype over [u8] restricting to ASCII:
#[repr(transparent)]
pub struct Ascii([u8]);
pub struct NonAsciiReason {
/// Byte offset of the first non-ASCII byte.
pub position: usize,
/// The offending byte value.
pub byte: u8,
}
impl Validated for Ascii {
type InvalidReason = NonAsciiReason;
}A refinement of an integer type:
fn assert_nonzero_reason<T: Validated<InvalidReason = ZeroReason>>() {}
assert_nonzero_reason::<NonZeroU32>();§When not to implement Validated
Validated is not a general-purpose “this type has an invariant”
marker. Implement it only when:
- The type is the canonical validated form of some underlying data,
in the sense that asking “is this underlying value a valid
Self?” is a meaningful question with a single canonical predicate. - You intend to provide
AsValidatedorIntoValidatedimpls from one or more precursor types. AValidatedimpl with no corresponding conversions is inert.
Types with multiple equally canonical predicates (e.g., a byte slice
that might be validated as UTF-8, as ASCII, or as valid JSON
depending on context) should be modeled by having multiple
validated target types, each implementing Validated with its own
InvalidReason, rather than a single type with a configurable
predicate.
§Relationship to other traits
Validated occupies a different niche from:
TryFrom: expresses any fallible conversion with a caller-chosen error type.Validatedpins the error type to the target and specifies its role (diagnostic only).FromStr: fallible parsing from&strwith an associatedErr. Similar shape, but single-source and not a trait family for both borrowing and owning conversions.Borrow: infallible borrowing with aHash/Eq/Ordagreement contract.Validatedmakes no hash-agreement claim; conversions are permitted to produce views with different hashing semantics.
Required Associated Types§
Sourcetype InvalidReason
type InvalidReason
The explanation returned when a candidate value fails to satisfy this type’s validation predicate.
Must be diagnostic-only: see the trait-level contract for the restrictions on what this type may contain.