You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
79 lines
1.8 KiB
79 lines
1.8 KiB
use std::fmt; |
|
use std::iter::Iterator; |
|
use std::slice::Iter as SliceIter; |
|
use std::str::Chars; |
|
|
|
const MAX_DATA_LEN: usize = 2000; |
|
|
|
pub trait Strippable { |
|
type Item: fmt::Display; |
|
type TypeIter: Iterator<Item = Self::Item>; |
|
|
|
fn length(&self) -> usize; |
|
fn iterator(&self) -> Self::TypeIter; |
|
} |
|
|
|
impl<'a> Strippable for &'a str { |
|
type Item = char; |
|
type TypeIter = Chars<'a>; |
|
|
|
fn length(&self) -> usize { |
|
self.len() |
|
} |
|
|
|
fn iterator(&self) -> Self::TypeIter { |
|
self.chars() |
|
} |
|
} |
|
|
|
impl<'a> Strippable for &'a Vec<u8> { |
|
type Item = &'a u8; |
|
type TypeIter = SliceIter<'a, u8>; |
|
|
|
fn length(&self) -> usize { |
|
self.len() |
|
} |
|
|
|
fn iterator(&self) -> Self::TypeIter { |
|
self.iter() |
|
} |
|
} |
|
pub struct Stripped<'inner, Inner: Strippable + 'inner>(pub &'inner Inner); |
|
|
|
impl<'inner, Inner: Strippable + 'inner> Stripped<'inner, Inner> { |
|
fn iter(&self) -> Inner::TypeIter { |
|
self.0.iterator() |
|
} |
|
|
|
fn placeholder(&self) -> &'static str { |
|
if self.0.length() >= MAX_DATA_LEN { |
|
" <...>" |
|
} else { |
|
"" |
|
} |
|
} |
|
} |
|
|
|
impl<'inner, Inner: Strippable + 'inner> fmt::Display for Stripped<'inner, Inner> { |
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
|
let placeholder = self.placeholder(); |
|
for c in self.iter().take(MAX_DATA_LEN - placeholder.len()) { |
|
write!(f, "{}", c)?; |
|
} |
|
write!(f, "{}", placeholder) |
|
} |
|
} |
|
|
|
#[cfg(test)] |
|
mod tests { |
|
use super::*; |
|
use rstest::*; |
|
|
|
#[rstest] |
|
#[case("abc", 3)] |
|
#[case("abcde".repeat(50), MAX_DATA_LEN)] |
|
fn test_strip(#[case] input: impl Into<String>, #[case] result_len: usize) { |
|
let s = input.into(); |
|
assert_eq!(Stripped(&s.as_str()).to_string().len(), result_len); |
|
} |
|
}
|
|
|