nintypes 0.2.11

Nintondo shared types
Documentation
use std::ops::Deref;
use Maybe::*;

/// Wrapper around T that behaves like Option<T> except it will pass any defined value for parsing to T.
/// <br/> <b>Some serializers like postcard are not supported and will panic at runtime!</b>
///
/// # Example
/// ```rust
/// use nintypes::common::api::Maybe;
///
/// #[derive(serde::Serialize, serde::Deserialize)]
/// pub struct Test {
///     // default is required for serde::Deserialize
///     // skip_serializing_if is required for serde::Serialize
///     #[serde(default, skip_serializing_if="Maybe::is_undefined")]
///     pub test: Maybe<Option<u32>>,
/// }
///
/// // if test is Maybe<Option<u32>>
/// // json {"test": 42} <-> Test { test: Maybe::Just(Some(42)) }
/// // json {"test": null} <-> Test { test: Maybe::Just(None) }
/// // json {} <-> Test { test: Maybe::Undefined }
/// ```
#[derive(serde::Serialize, serde::Deserialize, Debug, Default, Clone, Copy)]
#[serde(untagged)]
pub enum Maybe<T> {
    Just(T),

    #[default]
    Nothing,
}

impl<T> Maybe<T> {
    pub fn is_undefined(&self) -> bool {
        matches!(self, Self::Nothing)
    }
    pub fn is_defined(&self) -> bool {
        !self.is_undefined()
    }
    pub fn defined(self) -> Option<T> {
        match self {
            Maybe::Just(x) => Some(x),
            Maybe::Nothing => None,
        }
    }

    #[inline]
    pub fn map<U, F>(self, f: F) -> Maybe<U>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Just(x) => Just(f(x)),
            Nothing => Nothing,
        }
    }

    pub const fn as_ref(&self) -> Maybe<&T> {
        match *self {
            Just(ref x) => Just(x),
            Nothing => Nothing,
        }
    }

    pub fn as_deref(&self) -> Maybe<&T::Target>
    where
        T: Deref,
    {
        self.as_ref().map(|t| t.deref())
    }
}

#[cfg(feature = "validator")]
mod impl_validator {
    use super::Maybe;

    impl<T: validator::Validate> validator::Validate for Maybe<Option<T>> {
        fn validate(&self) -> Result<(), validator::ValidationErrors> {
            match self {
                Maybe::Just(Some(x)) => x.validate(),
                _ => Ok(()),
            }
        }
    }
    impl<'a, T: validator::ValidateArgs<'a>> validator::ValidateArgs<'a> for Maybe<Option<T>> {
        type Args = T::Args;
        fn validate_with_args(&self, args: Self::Args) -> Result<(), validator::ValidationErrors> {
            match self {
                Maybe::Just(Some(x)) => x.validate_with_args(args),
                _ => Ok(()),
            }
        }
    }
    impl<T: validator::ValidateContains> validator::ValidateContains for Maybe<Option<T>> {
        fn validate_contains(&self, needle: &str) -> bool {
            match self {
                Maybe::Just(Some(x)) => x.validate_contains(needle),
                _ => true,
            }
        }
    }
    impl<T: validator::ValidateEmail> validator::ValidateEmail for Maybe<Option<T>> {
        fn as_email_string(&'_ self) -> Option<std::borrow::Cow<'_, str>> {
            match self {
                Maybe::Just(Some(x)) => x.as_email_string(),
                _ => None,
            }
        }
    }
    impl<T: validator::ValidateIp> validator::ValidateIp for Maybe<Option<T>> {
        fn validate_ipv4(&self) -> bool {
            match self {
                Maybe::Just(Some(x)) => x.validate_ipv4(),
                _ => true,
            }
        }

        fn validate_ipv6(&self) -> bool {
            match self {
                Maybe::Just(Some(x)) => x.validate_ipv6(),
                _ => true,
            }
        }

        fn validate_ip(&self) -> bool {
            match self {
                Maybe::Just(Some(x)) => x.validate_ip(),
                _ => true,
            }
        }
    }
    impl<T: validator::ValidateLength<L>, L: PartialEq + PartialOrd> validator::ValidateLength<L> for Maybe<Option<T>> {
        fn length(&self) -> Option<L> {
            match self {
                Maybe::Just(Some(x)) => x.length(),
                _ => None,
            }
        }
    }
    impl<T: validator::ValidateRange<R>, R> validator::ValidateRange<R> for Maybe<Option<T>> {
        fn greater_than(&self, max: R) -> Option<bool> {
            match self {
                Maybe::Just(Some(x)) => x.greater_than(max),
                _ => None,
            }
        }

        fn less_than(&self, min: R) -> Option<bool> {
            match self {
                Maybe::Just(Some(x)) => x.less_than(min),
                _ => None,
            }
        }
    }
    impl<T: validator::ValidateRegex> validator::ValidateRegex for Maybe<Option<T>> {
        fn validate_regex(&self, regex: impl validator::AsRegex) -> bool {
            match self {
                Maybe::Just(Some(x)) => x.validate_regex(regex),
                _ => true,
            }
        }
    }
    impl<T: validator::ValidateRequired> validator::ValidateRequired for Maybe<Option<T>> {
        fn is_some(&self) -> bool {
            self.is_defined()
        }
    }
    impl<T: validator::ValidateUrl> validator::ValidateUrl for Maybe<Option<T>> {
        fn as_url_string(&'_ self) -> Option<std::borrow::Cow<'_, str>> {
            match self {
                Maybe::Just(Some(x)) => x.as_url_string(),
                _ => None,
            }
        }
    }
}

#[cfg(feature = "schema")]
mod impl_schema {
    use super::Maybe;

    impl<T: schemars::JsonSchema> schemars::JsonSchema for Maybe<T> {
        fn schema_name() -> std::borrow::Cow<'static, str> {
            format!("Maybe_{}", T::schema_name()).into()
        }

        fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
            Option::<T>::json_schema(generator)
        }
    }
}