use crate::error::Error;
use std::fmt;
const MAX_NAME_LENGTH: usize = 64;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ApiContextName(String);
impl ApiContextName {
pub fn new(name: &str) -> Result<Self, Error> {
if name.is_empty() {
return Err(Error::invalid_api_context_name(
name,
"name cannot be empty",
));
}
if name.len() > MAX_NAME_LENGTH {
return Err(Error::invalid_api_context_name(
name,
format!(
"name exceeds maximum length of {MAX_NAME_LENGTH} characters ({} given)",
name.len()
),
));
}
let first = name.as_bytes()[0];
if !first.is_ascii_alphanumeric() {
return Err(Error::invalid_api_context_name(
name,
"name must start with an ASCII letter or digit",
));
}
if let Some(invalid) = name
.chars()
.find(|c| !c.is_ascii_alphanumeric() && *c != '.' && *c != '-' && *c != '_')
{
return Err(Error::invalid_api_context_name(
name,
format!("contains invalid character '{invalid}'"),
));
}
Ok(Self(name.to_string()))
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl AsRef<str> for ApiContextName {
fn as_ref(&self) -> &str {
&self.0
}
}
impl std::ops::Deref for ApiContextName {
type Target = str;
fn deref(&self) -> &str {
&self.0
}
}
impl fmt::Display for ApiContextName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}