use core::fmt;
use core::str::FromStr;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InboxScope(String);
impl InboxScope {
pub const MAX_LEN: usize = 128;
pub fn new(scope: impl Into<String>) -> Result<Self, InboxScopeError> {
let scope = scope.into();
if scope.is_empty() {
return Err(InboxScopeError::Empty);
}
if scope.chars().any(char::is_control) {
return Err(InboxScopeError::ControlCharacter);
}
if scope.len() > Self::MAX_LEN {
return Err(InboxScopeError::TooLong {
len: scope.len(),
max: Self::MAX_LEN,
});
}
Ok(Self(scope))
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for InboxScope {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl FromStr for InboxScope {
type Err = InboxScopeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::new(s)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum InboxScopeError {
Empty,
ControlCharacter,
TooLong {
len: usize,
max: usize,
},
}
impl fmt::Display for InboxScopeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Empty => f.write_str("scope must not be empty"),
Self::ControlCharacter => f.write_str("scope must not contain a control character"),
Self::TooLong { len, max } => {
write!(f, "scope length {len} exceeds the maximum of {max}")
}
}
}
}
impl std::error::Error for InboxScopeError {}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
mod serde_impls {
use serde::{Deserialize, Serialize, de::Error as _};
use super::InboxScope;
impl Serialize for InboxScope {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
s.collect_str(&self.0)
}
}
impl<'de> Deserialize<'de> for InboxScope {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let raw = String::deserialize(d)?;
Self::new(raw).map_err(D::Error::custom)
}
}
}