use std::error::Error;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use crate::line::value::CharType::{Forbidden, NonValidating, Validating};
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
#[cfg_attr(
feature = "serde",
derive(serde_with::DeserializeFromStr, serde_with::SerializeDisplay)
)]
pub struct NeodesValue(String);
impl NeodesValue {
#[inline]
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl FromStr for NeodesValue {
type Err = NeodesValueError;
#[inline]
fn from_str(input: &str) -> Result<Self, Self::Err> {
let mut validated = false;
for c in input.chars() {
match CharType::from(c) {
Validating => validated = true,
Forbidden => {
return Err(NeodesValueError::ForbiddenCharacter);
}
_ => {}
}
}
if !validated {
return Err(NeodesValueError::MissingAlphanumericCharacter);
}
Ok(Self(input.to_string()))
}
}
impl Display for NeodesValue {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
enum CharType {
Validating,
NonValidating,
Forbidden,
}
impl From<char> for CharType {
#[inline]
fn from(c: char) -> Self {
match c {
'0'..='9'
| 'A'..='Z'
| 'a'..='z'
| 'À'..='Å'
| 'Ç'..='Ï'
| 'Ñ'..='Ö'
| 'Ù'..='Ý'
| 'à'..='å'
| 'ç'..='ï'
| 'ñ'..='ö'
| 'ù'..='ý'
| 'ÿ' => Validating,
' ' | '"' | '&'..='/' | ':' | '=' | '@' | '_' | '`' | '«' | '°' | '»' => {
NonValidating
}
_ => Forbidden,
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum NeodesValueError {
ForbiddenCharacter,
MissingAlphanumericCharacter,
}
impl Error for NeodesValueError {}
impl Display for NeodesValueError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
NeodesValueError::ForbiddenCharacter => {
write!(f, "Forbidden character")
}
NeodesValueError::MissingAlphanumericCharacter => {
write!(f, "Value must contain at least one validating character")
}
}
}
}