use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::str::FromStr;
#[derive(Debug, Clone, Default)]
pub struct Language(Option<String>);
impl Language {
pub fn new<S: Into<Option<String>>>(value: S) -> Result<Self, InvalidLanguageError> {
if let Some(string) = value.into() {
string.try_into()
} else {
Ok(Self(None))
}
}
pub fn into_inner(self) -> Option<String> {
self.0
}
pub fn as_str(&self) -> &str {
self.as_option_str().unwrap_or("en-US")
}
pub fn as_option_str(&self) -> Option<&str> {
self.0.as_deref()
}
pub fn is_empty(&self) -> bool {
self.0.is_none()
}
}
impl AsRef<str> for Language {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl PartialEq for Language {
fn eq(&self, other: &Self) -> bool {
self.as_ref() == other.as_ref()
}
}
impl PartialEq<&Self> for Language {
fn eq(&self, other: &&Self) -> bool {
self.as_ref() == other.as_ref()
}
}
impl PartialEq<&str> for Language {
fn eq(&self, other: &&str) -> bool {
self.as_ref() == *other
}
}
impl PartialEq<Language> for &str {
fn eq(&self, other: &Language) -> bool {
*self == other.as_ref()
}
}
impl FromStr for Language {
type Err = InvalidLanguageError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
String::from(s).try_into()
}
}
impl TryFrom<String> for Language {
type Error = InvalidLanguageError;
fn try_from(value: String) -> Result<Self, Self::Error> {
if value.is_empty() {
return Ok(Self(None));
}
let str = value.as_str();
for (i, chunk) in str.split('-').enumerate() {
let all_valid_chars = if i == 0 {
chunk.chars().all(|c| c.is_ascii_alphabetic())
} else {
chunk.chars().all(|c| c.is_ascii_alphanumeric())
};
if !all_valid_chars || chunk.is_empty() || chunk.len() > 8 {
return Err(InvalidLanguageError(value));
}
}
Ok(Self(Some(value)))
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct InvalidLanguageError(String);
impl std::fmt::Display for InvalidLanguageError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "invalid language value: {:?}", self.0)
}
}
impl std::error::Error for InvalidLanguageError {}
impl Serialize for Language {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self.as_option_str() {
Some(str) => serializer.serialize_str(str),
None => serializer.serialize_none(),
}
}
}
impl<'de> Deserialize<'de> for Language {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = <Option<String>>::deserialize(deserializer)?;
Language::new(value).map_err(D::Error::custom)
}
}