use std::ops::Deref;
use Maybe::*;
#[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)
}
}
}