reflected 0.30.0

Something like reflection
Documentation
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum OptionalType {
    Float,
    Integer,
    Text,
    Date,
    Decimal,
    Bool,
    Duration,
    DateTime,
}

impl OptionalType {
    pub const fn from_type(tp: &Type) -> Self {
        match tp {
            Type::Float => OptionalType::Float,
            Type::Integer => OptionalType::Integer,
            Type::Text => OptionalType::Text,
            Type::Date => OptionalType::Date,
            Type::Decimal => OptionalType::Decimal,
            Type::Bool => OptionalType::Bool,
            Type::Duration => OptionalType::Duration,
            Type::DateTime => OptionalType::DateTime,
            Type::Optional(_) | Type::Enum => unreachable!(),
        }
    }

    pub const fn to_non_optional(&self) -> Type {
        match self {
            OptionalType::Float => Type::Float,
            OptionalType::Integer => Type::Integer,
            OptionalType::Text => Type::Text,
            OptionalType::Date => Type::Date,
            OptionalType::Decimal => Type::Decimal,
            OptionalType::Bool => Type::Bool,
            OptionalType::Duration => Type::Duration,
            OptionalType::DateTime => Type::DateTime,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Type {
    Float,
    Integer,
    Text,
    Date,
    Decimal,
    Bool,
    Enum,
    Duration,
    DateTime,
    Optional(OptionalType),
}

impl Type {
    pub const fn to_optional(self) -> Self {
        Self::Optional(OptionalType::from_type(&self))
    }

    pub fn is_type(&self, tp: Self) -> bool {
        if self == &tp {
            return true;
        }

        if let Self::Optional(opt) = self
            && tp == opt.to_non_optional()
        {
            return true;
        }

        false
    }

    pub fn is_float(&self) -> bool {
        self.is_type(Self::Float)
    }

    pub fn is_integer(&self) -> bool {
        self.is_type(Self::Integer)
    }

    pub fn is_text(&self) -> bool {
        self.is_type(Self::Text)
    }

    pub fn is_date(&self) -> bool {
        self.is_type(Self::Date)
    }

    pub fn is_decimal(&self) -> bool {
        self.is_type(Self::Decimal)
    }

    pub fn is_bool(&self) -> bool {
        self.is_type(Self::Bool)
    }

    pub fn is_enum(&self) -> bool {
        self.is_type(Self::Enum)
    }

    pub fn is_duration(&self) -> bool {
        self.is_type(Self::Duration)
    }

    pub fn is_optional(&self) -> bool {
        matches!(self, Self::Optional(_))
    }

    pub fn get_optional(&self) -> Option<OptionalType> {
        match self {
            Self::Optional(op) => Some(*op),
            _ => None,
        }
    }

    pub fn is_number(&self) -> bool {
        self.is_integer() || self.is_float()
    }
}

#[cfg(test)]
mod test {
    use crate::Type;

    #[test]
    fn test() {
        assert!(Type::Float.is_float());
        assert!(Type::Float.to_optional().is_float());
    }
}