diff --git a/src/utils.rs b/src/utils.rs index 8d9b6764..bbf53631 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,7 @@ pub(crate) mod error; use std::{ + borrow::Cow, cmp, fmt, str::FromStr, time::{SystemTime, UNIX_EPOCH}, @@ -209,3 +210,44 @@ pub(crate) fn debug_slice_truncated( max_len, }) } + +/// Truncates a string to an approximate maximum length, replacing any extra +/// text with an ellipsis. +/// +/// Only to be used for debug logging, exact semantics are unspecified. +pub(crate) fn truncate_str_for_debug( + s: &str, + mut max_len: usize, +) -> Cow<'_, str> { + while max_len < s.len() && !s.is_char_boundary(max_len) { + max_len += 1; + } + + if s.len() <= max_len { + s.into() + } else { + #[allow(clippy::string_slice)] // we checked it's at a char boundary + format!("{}...", &s[..max_len]).into() + } +} + +#[cfg(test)] +mod tests { + use crate::utils::truncate_str_for_debug; + + #[test] + fn test_truncate_str_for_debug() { + assert_eq!(truncate_str_for_debug("short", 10), "short"); + assert_eq!( + truncate_str_for_debug("very long string", 10), + "very long ..." + ); + assert_eq!(truncate_str_for_debug("no info, only dots", 0), "..."); + assert_eq!(truncate_str_for_debug("", 0), ""); + assert_eq!(truncate_str_for_debug("unicรถde", 5), "unicรถ..."); + let ok_hand = "๐Ÿ‘Œ๐Ÿฝ"; + assert_eq!(truncate_str_for_debug(ok_hand, 1), "๐Ÿ‘Œ..."); + assert_eq!(truncate_str_for_debug(ok_hand, ok_hand.len() - 1), "๐Ÿ‘Œ๐Ÿฝ"); + assert_eq!(truncate_str_for_debug(ok_hand, ok_hand.len()), "๐Ÿ‘Œ๐Ÿฝ"); + } +}