use crate::{Error, ID_MAX_BYTES, localpart_is_backwards_compatible, parse_id};
pub fn validate(s: &str) -> Result<(), Error> {
let colon_idx = parse_id(s, b'@')?;
let localpart = &s[1..colon_idx];
localpart_is_backwards_compatible(localpart)?;
Ok(())
}
pub fn validate_strict(s: &str) -> Result<(), Error> {
if s.len() > ID_MAX_BYTES {
return Err(Error::MaximumLengthExceeded);
}
let colon_idx = parse_id(s, b'@')?;
let localpart = &s[1..colon_idx];
if !localpart_is_fully_conforming(localpart)? {
return Err(Error::InvalidCharacters);
}
Ok(())
}
pub fn localpart_is_fully_conforming(localpart: &str) -> Result<bool, Error> {
if localpart.is_empty() {
return Err(Error::Empty);
}
let is_fully_conforming = localpart
.bytes()
.all(|b| matches!(b, b'0'..=b'9' | b'a'..=b'z' | b'-' | b'.' | b'=' | b'_' | b'/' | b'+'));
if !is_fully_conforming {
let is_invalid_historical = localpart.bytes().any(|b| b < 0x21 || b == b':' || b > 0x7E);
if is_invalid_historical {
return Err(Error::InvalidCharacters);
}
}
Ok(is_fully_conforming)
}