Skip to main content

Check

Struct Check 

Source
pub struct Check<V, A = Same>(/* private fields */);
Expand description

An adapter that validates values with V.

The value is deserialized with the adapter A (Same by default) and validated once it’s complete. If it’s invalid, deserialization fails with an error that points at the start of the value and has the Violation attached. The type of the field does not change, and the adapter composes with the other adapters and the containers:

use deser::Deserialize;
use deser::adapters::DisplayFromStr;
use deser_validate::{Check, Email, MaxLen, NonEmpty, validator};

validator!(NonZero(port: &u16) => *port != 0, "must not be zero");

#[derive(Deserialize, Debug)]
struct Server {
    #[deser(as = Check<NonZero>)]
    port: u16,
    #[deser(as = Vec<Check<Email>>)]
    admins: Vec<String>,
    #[deser(as = Option<Check<(NonEmpty, MaxLen<64>)>>)]
    name: Option<String>,
    // validates the value that `DisplayFromStr` parsed
    #[deser(as = Check<NonZero, DisplayFromStr>, default)]
    legacy_port: u16,
}

let json = r#"{"port": 0, "admins": []}"#;
let err = deser_json::from_str::<Server>(json).unwrap_err();
assert_eq!(
    err.to_string(),
    "Unexpected: invalid value: must not be zero at line 1 column 10"
);
let json = r#"{"port": 1, "admins": ["x"]}"#;
let err = deser_json::from_str::<Server>(json).unwrap_err();
assert_eq!(
    err.to_string(),
    "Unexpected: invalid value: must be an email address \
     at line 1 column 24"
);

Values that are missing (see DeserializeAs::initial_value_as) are only used if they are valid, otherwise the value is required. Serialization uses the inner adapter.

§Checks Across Fields

On a type, Check wraps its derived implementation (written as _). The validator then sees the whole value:

use deser::Deserialize;
use deser_validate::{Check, validator};

#[derive(Deserialize, Debug)]
#[deser(deserialize_as = Check<OrderedPorts, _>)]
struct PortRange {
    min: u16,
    max: u16,
}

validator!(
    OrderedPorts(range: &PortRange) => range.min <= range.max,
    "min is larger than max"
);

let json = r#"{"min": 90, "max": 80}"#;
let err = deser_json::from_str::<PortRange>(json).unwrap_err();
assert_eq!(
    err.to_string(),
    "Unexpected: invalid value: min is larger than max at line 1 column 1"
);

§Updates

When a value is updated (see Deserialize::deserialize_update), it’s updated with A and validated once the update is complete. Types that update in place (like derived structs) are merged and then validated as a whole. If the updated value is invalid, the update fails but the value keeps the update, like values keep what an update changed before it failed.

Trait Implementations§

Source§

impl<'de, T, V, A> DeserializeAs<'de, T> for Check<V, A>
where T: Send, V: Validator<T> + 'static, A: DeserializeAs<'de, T>,

Source§

fn deserialize_update_as<'out>( value: &'out mut T, state: &mut State, ) -> SinkHandle<'out, 'de>
where T: Send,

Updates the value with A and validates it once the update is complete.

Source§

fn deserialize_into_as<'out>( out: &'out mut Option<T>, state: &mut State, ) -> SinkHandle<'out, 'de>

Creates a sink that deserializes the value into the given slot. Read more
Source§

fn initial_value_as() -> Option<T>

Provides the value of a missing struct field. Read more
Source§

impl<T: ?Sized, V: 'static, A: SerializeAs<T>> SerializeAs<T> for Check<V, A>

Source§

fn serialize_as<'a>(value: &'a T, state: &mut State) -> Result<Chunk<'a>, Error>

Serializes the value. Read more
Source§

fn finish_as(value: &T, state: &mut State) -> Result<(), Error>

Invoked after the serialization finished. Read more
Source§

fn is_optional_as(value: &T) -> bool

Checks if the value represents an optional value. Read more
Source§

fn container_shape_as(value: &T) -> ContainerShape

Returns the shape of the value if it’s a map or sequence. Read more
Source§

fn describe_as(value: &T, d: &mut dyn Describe)

Describes the Rust shape of the value. Read more

Auto Trait Implementations§

§

impl<V, A> Freeze for Check<V, A>
where PhantomData<fn() -> (V, A)>: Freeze,

§

impl<V, A> RefUnwindSafe for Check<V, A>

§

impl<V, A> Send for Check<V, A>
where PhantomData<fn() -> (V, A)>: Send,

§

impl<V, A> Sync for Check<V, A>
where PhantomData<fn() -> (V, A)>: Sync,

§

impl<V, A> Unpin for Check<V, A>
where PhantomData<fn() -> (V, A)>: Unpin,

§

impl<V, A> UnsafeUnpin for Check<V, A>

§

impl<V, A> UnwindSafe for Check<V, A>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.