use syn::{Lit, Type};
use crate::{ArgValue, Error};
#[derive(Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
pub enum ValueClass {
Literal(LiteralClass),
Type(TypeClass),
Expr,
}
impl From<Lit> for ValueClass {
fn from(lit: Lit) -> Self { ValueClass::Literal(LiteralClass::from(lit)) }
}
impl From<&Lit> for ValueClass {
fn from(lit: &Lit) -> Self { ValueClass::Literal(LiteralClass::from(lit)) }
}
impl From<Type> for ValueClass {
fn from(ty: Type) -> Self { ValueClass::Type(TypeClass::from(ty)) }
}
impl From<&Type> for ValueClass {
fn from(ty: &Type) -> Self { ValueClass::Type(TypeClass::from(ty)) }
}
impl From<LiteralClass> for ValueClass {
fn from(cls: LiteralClass) -> Self { ValueClass::Literal(cls) }
}
impl From<TypeClass> for ValueClass {
fn from(cls: TypeClass) -> Self { ValueClass::Type(cls) }
}
impl ValueClass {
pub fn str() -> ValueClass { ValueClass::Literal(LiteralClass::Str) }
pub fn byte_str() -> ValueClass { ValueClass::Literal(LiteralClass::ByteStr) }
pub fn byte() -> ValueClass { ValueClass::Literal(LiteralClass::Byte) }
pub fn int() -> ValueClass { ValueClass::Literal(LiteralClass::Int) }
pub fn float() -> ValueClass { ValueClass::Literal(LiteralClass::Float) }
pub fn char() -> ValueClass { ValueClass::Literal(LiteralClass::Char) }
pub fn bool() -> ValueClass { ValueClass::Literal(LiteralClass::Bool) }
}
impl ValueClass {
pub fn check(
self,
value: &ArgValue,
attr: impl ToString,
arg: impl ToString,
) -> Result<(), Error> {
match (self, value) {
(ValueClass::Literal(lit), ArgValue::Literal(ref value)) => lit.check(value, attr, arg),
(ValueClass::Type(ty), ArgValue::Type(ref value)) => ty.check(value, attr, arg),
(ValueClass::Expr, ArgValue::Type(_) | ArgValue::Expr(_) | ArgValue::Literal(_)) => {
Ok(())
}
_ => Err(Error::ArgValueTypeMismatch {
attr: attr.to_string(),
arg: arg.to_string(),
}),
}
}
}
#[derive(Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
pub enum LiteralClass {
Str,
ByteStr,
Byte,
Char,
Int,
Float,
Bool,
Any,
}
impl From<Lit> for LiteralClass {
#[inline]
fn from(lit: Lit) -> Self { LiteralClass::from(&lit) }
}
impl From<&Lit> for LiteralClass {
fn from(lit: &Lit) -> Self {
match lit {
Lit::Str(_) => LiteralClass::Str,
Lit::ByteStr(_) => LiteralClass::ByteStr,
Lit::Byte(_) => LiteralClass::Byte,
Lit::Char(_) => LiteralClass::Char,
Lit::Int(_) => LiteralClass::Int,
Lit::Float(_) => LiteralClass::Float,
Lit::Bool(_) => LiteralClass::Bool,
Lit::Verbatim(_) => LiteralClass::Any,
}
}
}
impl LiteralClass {
pub fn check(self, lit: &Lit, attr: impl ToString, arg: impl ToString) -> Result<(), Error> {
if self == LiteralClass::Any {
Ok(())
} else if self != LiteralClass::from(lit) {
Err(Error::ArgValueTypeMismatch {
attr: attr.to_string(),
arg: arg.to_string(),
})
} else {
Ok(())
}
}
}
#[derive(Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
pub enum TypeClass {
Array,
BareFn,
Group,
ImplTrait,
Infer,
Macro,
Never,
Paren,
Path,
Ptr,
Reference,
Slice,
TraitObject,
Tuple,
Any,
}
impl From<Type> for TypeClass {
#[inline]
fn from(ty: Type) -> Self { TypeClass::from(&ty) }
}
impl From<&Type> for TypeClass {
fn from(ty: &Type) -> Self {
match ty {
Type::Array(_) => TypeClass::Array,
Type::BareFn(_) => TypeClass::BareFn,
Type::Group(_) => TypeClass::Group,
Type::ImplTrait(_) => TypeClass::ImplTrait,
Type::Infer(_) => TypeClass::Infer,
Type::Macro(_) => TypeClass::Macro,
Type::Never(_) => TypeClass::Never,
Type::Paren(_) => TypeClass::Paren,
Type::Path(_) => TypeClass::Path,
Type::Ptr(_) => TypeClass::Ptr,
Type::Reference(_) => TypeClass::Reference,
Type::Slice(_) => TypeClass::Slice,
Type::TraitObject(_) => TypeClass::TraitObject,
Type::Tuple(_) => TypeClass::Tuple,
Type::Verbatim(_) => TypeClass::Any,
_ => unreachable!(),
}
}
}
impl TypeClass {
pub fn check(self, ty: &Type, attr: impl ToString, arg: impl ToString) -> Result<(), Error> {
if self == TypeClass::Any {
Ok(())
} else if self != TypeClass::from(ty) {
Err(Error::ArgValueTypeMismatch {
attr: attr.to_string(),
arg: arg.to_string(),
})
} else {
Ok(())
}
}
}