use crate::stringesc::StringLosslessExt;
pub trait CharClassExt {
fn is_token(&self) -> bool;
fn is_separator(&self) -> bool;
fn is_text_ws(&self) -> bool;
fn is_text_lws(&self) -> bool;
fn is_ws(&self) -> bool;
fn is_lws(&self) -> bool;
fn sequence_length(&self) -> u32;
}
impl CharClassExt for u8 {
fn is_token(&self) -> bool {
self.is_ascii() && !self.is_ascii_control() && !self.is_separator()
}
fn is_separator(&self) -> bool {
b"()<>@,;:\\\"/[]?={} \t".contains(self)
}
fn is_ws(&self) -> bool {
b"\t ".contains(self)
}
fn is_text_ws(&self) -> bool {
!self.is_ascii_control() || b" \t".contains(self)
}
fn is_text_lws(&self) -> bool {
!self.is_ascii_control() || b"\r\n \t".contains(self)
}
fn is_lws(&self) -> bool {
b"\r\n \t".contains(self)
}
fn sequence_length(&self) -> u32 {
match self.leading_ones() {
0 => 1,
1 => 1,
2 => 2,
3 => 3,
4 => 4,
_ => 0,
}
}
}
pub fn decode_and_trim_to_string(input: &[u8]) -> String {
let text = String::from_utf8_lossless(input);
trim(text)
}
fn trim(text: String) -> String {
let trimmed = text.trim();
if trimmed.len() != text.len() {
trimmed.to_string()
} else {
text
}
}
pub fn trim_trailing_crlf(buf: &[u8]) -> &[u8] {
if buf.ends_with(b"\r\n") {
&buf[0..buf.len() - 2]
} else if buf.ends_with(b"\n") {
&buf[0..buf.len() - 1]
} else {
buf
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_header_byte_ext() {
assert!(b'a'.is_token());
assert!(!b'\n'.is_token());
assert!(!b':'.is_token());
assert!(b':'.is_separator());
assert!(!b'a'.is_separator());
assert!(b'a'.is_text_lws());
assert!(b'\t'.is_text_lws());
assert!(b'\n'.is_text_lws());
assert!(!b'\x00'.is_text_lws());
assert!(b'\t'.is_lws());
assert!(!b'a'.is_lws());
assert_eq!(b'a'.sequence_length(), 1);
assert_eq!(b'\x80'.sequence_length(), 1);
assert_eq!(b'\xC4'.sequence_length(), 2);
assert_eq!(b'\xE3'.sequence_length(), 3);
assert_eq!(b'\xF0'.sequence_length(), 4);
assert_eq!(b'\xFF'.sequence_length(), 0);
}
#[test]
fn text_trim_trailing_crlf() {
assert_eq!(trim_trailing_crlf(b"abc\r\n\r\n"), b"abc\r\n");
assert_eq!(trim_trailing_crlf(b"abc\r\n"), b"abc");
assert_eq!(trim_trailing_crlf(b"abc\n\n"), b"abc\n");
assert_eq!(trim_trailing_crlf(b"abc\n"), b"abc");
}
}