use ascii::AsciiString;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
use std::ops::Deref;
use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
#[serde(try_from = "String", into = "String", expecting = "a string")]
pub struct String255(String);
#[derive(Error, Debug)]
#[error("String is too long. Maximum size is 255 bytes but is {0}.")]
pub struct String255TooLongError(pub usize);
impl String255 {
pub const NULL: Self = Self(String::new());
pub fn unchecked(from: &str) -> Self {
Self::try_from(from.to_string()).expect("ShortString::unchecked failed")
}
pub fn from_str_truncate(s: &str) -> Self {
if s.len() <= 255 {
Self::unchecked(s)
} else {
Self::unchecked(&s[..255])
}
}
pub fn is_null(&self) -> bool {
self.0.is_empty()
}
}
impl TryFrom<String> for String255 {
type Error = String255TooLongError;
fn try_from(value: String) -> Result<Self, Self::Error> {
if value.len() > 255 {
Err(String255TooLongError(value.len()))
} else {
Ok(Self(value))
}
}
}
impl TryFrom<AsciiString> for String255 {
type Error = String255TooLongError;
fn try_from(value: AsciiString) -> Result<Self, Self::Error> {
value.to_string().try_into()
}
}
impl Deref for String255 {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<String255> for String {
fn from(val: String255) -> Self {
val.0
}
}
impl Display for String255 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_truncate_short_string() {
let expected = String255::unchecked("Hello");
let actual = String255::from_str_truncate("Hello");
assert_eq!(expected, actual);
}
#[test]
fn test_truncate_len_254() {
let str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
assert_eq!(str.len(), 254);
let expected = String255::unchecked(str);
let actual = String255::from_str_truncate(str);
assert_eq!(expected, actual);
}
#[test]
fn test_truncate_len_255() {
let str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
assert_eq!(str.len(), 255);
let expected = String255::unchecked(str);
let actual = String255::from_str_truncate(str);
assert_eq!(expected, actual);
}
#[test]
fn test_truncate_len_256() {
let str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
assert_eq!(str.len(), 256);
let expected = String255::unchecked("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
assert_eq!(expected.len(), 255);
let actual = String255::from_str_truncate(str);
assert_eq!(expected, actual);
}
}