Skip to main content

Validated

Trait Validated 

Source
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:

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:

  1. 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.

  2. InvalidReason is diagnostic only. The InvalidReason type 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.

  3. InvalidReason is cheaply constructible. Constructing an InvalidReason on 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 AsValidated or IntoValidated impls from one or more precursor types. A Validated impl 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. Validated pins the error type to the target and specifies its role (diagnostic only).
  • FromStr: fallible parsing from &str with an associated Err. Similar shape, but single-source and not a trait family for both borrowing and owning conversions.
  • Borrow: infallible borrowing with a Hash/Eq/Ord agreement contract. Validated makes no hash-agreement claim; conversions are permitted to produce views with different hashing semantics.

Required Associated Types§

Source

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.

Implementations on Foreign Types§

Source§

impl Validated for char

Source§

impl Validated for str

Source§

impl Validated for CString

Source§

impl Validated for String

Source§

impl Validated for CStr

Source§

impl Validated for NonZeroI8

Source§

impl Validated for NonZeroI16

Source§

impl Validated for NonZeroI32

Source§

impl Validated for NonZeroI64

Source§

impl Validated for NonZeroI128

Source§

impl Validated for NonZeroIsize

Source§

impl Validated for NonZeroU8

Source§

impl Validated for NonZeroU16

Source§

impl Validated for NonZeroU32

Source§

impl Validated for NonZeroU64

Source§

impl Validated for NonZeroU128

Source§

impl Validated for NonZeroUsize

Implementors§