use crate::Error;
use std::{fmt, str};
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct Content(String);
impl Content {
pub fn new<T: AsRef<str>>(value: T) -> Result<Self, Error> {
value.as_ref().parse()
}
pub unsafe fn new_unchecked<T: Into<String>>(value: T) -> Self {
Content(value.into())
}
pub fn validate(&self) -> crate::Result<()> {
validate(&self.0)
}
}
impl str::FromStr for Content {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
validate(s)?;
Ok(Content(s.to_string()))
}
}
impl AsRef<str> for Content {
fn as_ref(&self) -> &str {
&self.0
}
}
impl fmt::Display for Content {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
fn validate(text: &str) -> crate::Result<()> {
if text.is_empty() {
return Err(Error::EmptyContent);
}
if text.contains(&['\n', '\r']) {
return Err(Error::InvalidContent);
}
Ok(())
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn errors() {
assert_eq!(
"my\r\ngemlog".parse::<Content>().err(),
Some(Error::InvalidContent)
);
assert_eq!(
"my\ngemlog".parse::<Content>().err(),
Some(Error::InvalidContent)
);
assert_eq!("".parse::<Content>().err(), Some(Error::EmptyContent));
}
}