Skip to main content

ShouldBe

Enum ShouldBe 

Source
pub enum ShouldBe<T> {
    AndIs(T),
    ButIsnt(WhyNot),
}
Expand description

Represents a value that “should be” deserialized to type T, or provides information about why it failed to.

This wrapper type can be used as an error recovery mechanism in #[derive(Deserialize)] structs to “containerize” local failures, without failing the deserialization process: deserializing into a ShouldBe<T> will always succeed, producing a ShouldBe object that either wraps a valid T value, or the error (and the corresponding pre-deserialized value, if deserializing from a Value) that caused the failure.

You can think of ShouldBe<T> as a more versatile Result<T, Error> that exposes the equality, ordering, hashing, cloning, and (de)serialization semantics of T (and indeed, ShouldBe<T> is Into<Result<T, Error>>), while also providing a more ergonomic API for inspecting the error case.

§Example

use serde::{Serialize as _, Deserialize as _};

#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Inner {
    field: i32,
}

#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Outer {
   items: Vec<ShouldBe<Inner>>,
}

fn main() -> Result<(), dbt_yaml::Error> {
   let yaml = r#"
       items:
         - field: 1
         - field: "2"
         - x: 3
   "#;
   let value: Value = dbt_yaml::from_str(&yaml)?;

   let outer: Outer = value.into_typed(|_, _, _| {}, |_| Ok(None))?;
   assert_eq!(outer.items.len(), 3);
   assert_eq!(outer.items[0].as_ref(), Some(&Inner { field: 1 }));
   assert!(outer.items[1].isnt());
   assert_eq!(outer.items[1].as_err_msg().unwrap(),
              "invalid type: string \"2\", expected i32 at line 4 column 19");
   assert!(outer.items[2].isnt());
   assert_eq!(outer.items[2].as_err_msg().unwrap(),
              "missing field `field` at line 5 column 12");

   Ok(())
}

§Clone semantics

ShouldBe<T> is cloneable as long as T is cloneable. Cloning a ShouldBe::AndIs variant clones the inner T value. Cloning a ShouldBe::ButIsnt variant, however, does not clone the inner Error, as Error is not cloneable. Instead, the cloned ShouldBe::ButIsnt will share the same underlying Error instance as the original. The same is true for the raw Value stored within a ShouldBe::ButIsnt, if one exists.

§Inspecting errors

ShouldBe provides two methods to inspect the error that caused a failed deserialization: ShouldBe::as_err_msg and ShouldBe::take_err, which return the error message and the original Error instance, respectively.

If you only need the error message, then ShouldBe::as_err_msg is always available on a ShouldBe::ButIsnt variant and can be called at any time. If you need the original Error instance, however, you must be aware of the ownership semantics of ShouldBe::take_err: the captured Error instance within a ShouldBe::ButIsnt is never directly observable from outside, and the only way to access it is by extracting it via ShouldBe::take_err. This method transfers ownership of the Error out of the ShouldBe instance to the caller. This means that ShouldBe::take_err will return Some(Error) only the first time it is called on all ShouldBe instances cloned from the same ShouldBe::ButIsnt instance (see “Clone semantics”); subsequent calls will return None. This is generally what you’d want when handling errors, as it guarantees that each unique error is only handled once regardless of how many times the ShouldBe::ButIsnt instance has been cloned.

§Inspecting the raw Value

If a ShouldBe::ButIsnt instance was deserialized from a Value, it will also capture the corresponding Value object that failed to deserialize. You can access it via the ShouldBe::as_ref_raw method.

§Example


fn main() -> Result<(), dbt_yaml::Error> {
   let yaml = "k: v\n";
   let value: Value = dbt_yaml::from_str(&yaml)?;
   let should_be: ShouldBe<i32> = value.to_typed(|_, _, _| {}, |_| Ok(None))?;

   assert!(should_be.isnt());
   assert_eq!(should_be.as_err_msg().unwrap(),
             "invalid type: map, expected i32 at line 1 column 1");
   
   let cloned = should_be.clone();
   assert!(cloned.isnt());
   // Take the error from the original instance
   let err = should_be.take_err().unwrap();
   assert_eq!(err.location().unwrap().index, 0);
   // Subsequent calls to take_err() return None
   assert!(should_be.take_err().is_none());
   assert!(cloned.take_err().is_none());
   // But the error message is still available
   assert_eq!(cloned.as_err_msg().unwrap(),
            "invalid type: map, expected i32 at line 1 column 1");
   // The raw Value is also available
   assert_eq!(should_be.as_ref_raw().unwrap(), &value);
   assert_eq!(cloned.as_ref_raw().unwrap(), &value);

   Ok(())
}

§Serializing a ShouldBe<T>

You can serialize a ShouldBe<T> instance as long as T is serializable. When serializing a ShouldBe::AndIs variant, the inner T value is serialized as usual. When serializing a ShouldBe::ButIsnt variant, if it contains a raw Value (i.e., it was deserialized from a Value), then the raw Value is serialized; otherwise, an error is raised and serialization fails.


fn main() -> Result<(), dbt_yaml::Error> {
  let yaml = "k: v\n";
  let value: Value = dbt_yaml::from_str(&yaml)?;
  let should_be: ShouldBe<i32> = value.into_typed(|_, _, _| {}, |_| Ok(None))?;

  assert!(should_be.isnt());
  let serialized = dbt_yaml::to_string(&should_be)?;
  assert_eq!(serialized, yaml);

  Ok(())
}

Variants§

§

AndIs(T)

On successful deserialization, will contain the expected value of type T.

§

ButIsnt(WhyNot)

On failed deserialization, will contain the error and raw value (if deserialized from a Value) that caused the failure.

Implementations§

Source§

impl<T> ShouldBe<T>

Source

pub fn as_ref(&self) -> Option<&T>

Returns a reference to the inner T value if it exists

Source

pub fn as_ref_mut(&mut self) -> Option<&mut T>

Returns a mutable reference to the inner T value if it exists

Source

pub fn as_ref_raw(&self) -> Option<&Value>

Returns a reference to the raw Value if this object represents a failed deserialization.

Source

pub fn as_err_msg(&self) -> Option<&str>

Returns the error message if this object represents a failed deserialization.

Source

pub fn is(&self) -> bool

True if this object wraps a valid T value, false otherwise.

Source

pub fn isnt(&self) -> bool

True if this object represents a failed deserialization, false otherwise.

Source

pub fn into_inner(self) -> Option<T>

Consumes self, returning the inner T value if it exists.

Source

pub fn take_err(&self) -> Option<Error>

Extracts the contained Error instance, if any.

This method transfers ownership of the Error out of the ShouldBe instance to the caller. See the ShouldBe documentation for more details.

Trait Implementations§

Source§

impl<T: Clone> Clone for ShouldBe<T>

Source§

fn clone(&self) -> ShouldBe<T>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T> Debug for ShouldBe<T>
where T: Debug,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T> Default for ShouldBe<T>
where T: Default,

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de, T> Deserialize<'de> for ShouldBe<T>

Source§

fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl<T> From<ShouldBe<T>> for Option<T>

Source§

fn from(should_be: ShouldBe<T>) -> Self

Converts to this type from the input type.
Source§

impl<T> From<ShouldBe<T>> for Result<T, Error>

Source§

fn from(should_be: ShouldBe<T>) -> Self

Converts to this type from the input type.
Source§

impl<T> From<T> for ShouldBe<T>

Source§

fn from(value: T) -> Self

Converts to this type from the input type.
Source§

impl<T> Hash for ShouldBe<T>
where T: Hash,

Source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl<T> Ord for ShouldBe<T>
where T: Ord,

Source§

fn cmp(&self, other: &Self) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

impl<T> PartialEq for ShouldBe<T>
where T: PartialEq,

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T> PartialOrd for ShouldBe<T>
where T: PartialOrd,

Source§

fn partial_cmp(&self, other: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl<T> Serialize for ShouldBe<T>
where T: Serialize,

Source§

fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl<T> Eq for ShouldBe<T>
where T: Eq,

Auto Trait Implementations§

§

impl<T> Freeze for ShouldBe<T>
where T: Freeze,

§

impl<T> RefUnwindSafe for ShouldBe<T>
where T: RefUnwindSafe,

§

impl<T> Send for ShouldBe<T>
where T: Send,

§

impl<T> Sync for ShouldBe<T>
where T: Sync,

§

impl<T> Unpin for ShouldBe<T>
where T: Unpin,

§

impl<T> UnsafeUnpin for ShouldBe<T>
where T: UnsafeUnpin,

§

impl<T> UnwindSafe for ShouldBe<T>
where T: UnwindSafe,

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Comparable<K> for Q
where Q: Ord + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn compare(&self, key: &K) -> Ordering

Compare self to key and return their ordering.
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<!> for T

Source§

fn from(t: !) -> T

Converts to this type from the input type.
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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

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

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,