use crate::toolbox::rule::*;
#[doc(hidden)]
pub type Rule<Mode> = AlphanumericRule<Mode>;
#[derive(Debug, thiserror::Error, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(untagged))]
pub enum Error {
#[error("value should be alphanumeric")]
Alphanumeric,
}
impl Error {
#[must_use]
pub(crate) fn code(&self) -> &'static str {
match self {
Self::Alphanumeric => "alphanumeric",
}
}
pub(crate) fn message(&self) -> &'static str {
match self {
Self::Alphanumeric => "value should be alphanumeric",
}
}
}
pub struct Ascii;
#[must_use]
pub struct AlphanumericRule<Mode> {
mode: PhantomData<Mode>,
}
impl AlphanumericRule<Unset> {
#[inline]
pub const fn new() -> Self {
Self { mode: PhantomData }
}
#[inline]
pub const fn ascii(self) -> AlphanumericRule<Ascii> {
AlphanumericRule { mode: PhantomData }
}
}
impl<I> crate::Rule<I> for AlphanumericRule<Unset>
where
I: AsRef<str>,
{
type Context = ();
fn validate(&self, _ctx: &Self::Context, item: &I) -> Result<()> {
let string = item.as_ref();
if string.chars().all(char::is_alphanumeric) {
Ok(())
} else {
Err(Error::Alphanumeric.into())
}
}
}
impl<I> crate::Rule<I> for AlphanumericRule<Ascii>
where
I: AsRef<str>,
{
type Context = ();
fn validate(&self, _ctx: &Self::Context, item: &I) -> Result<()> {
let string = item.as_ref();
if string.chars().all(|ch| ch.is_ascii_alphanumeric()) {
Ok(())
} else {
Err(Error::Alphanumeric.into())
}
}
}
#[cfg(test)]
mod test {
use crate::toolbox::test::*;
#[derive(Wary)]
#[wary(crate = "crate")]
struct Person<'name> {
#[validate(alphanumeric)]
name: Cow<'name, str>,
}
#[test]
fn test_alphanumeric_rule() {
let person = Person {
name: Cow::Borrowed("Hello"),
};
assert!(person.validate(&()).is_ok());
let person = Person {
name: Cow::Borrowed("hello world"),
};
assert!(person.validate(&()).is_err());
}
}