truncating_arraystring/
lib.rs1pub use arrayvec::{ArrayString, CapacityError};
2use std::fmt;
3
4#[derive(Debug)]
5pub struct TruncatingArrayString<const CAP: usize>(pub ArrayString<CAP>);
6
7impl<const CAP: usize> TruncatingArrayString<CAP> {
8 pub fn new() -> Self {
9 Self(ArrayString::<CAP>::new())
10 }
11
12 pub fn try_push_str_truncate<'a>(&mut self, s: &'a str) -> Result<(), CapacityError<&'a str>> {
13 let remaining_capacity = self.0.capacity() - self.0.len();
14
15 if s.len() < remaining_capacity {
16 self.0.push_str(s);
17 Ok(())
18 } else {
19 let (fits, rest) = s.split_at(floor_char_boundary(s, remaining_capacity));
20 self.0.push_str(fits);
21 Err(CapacityError::new(rest))
22 }
23 }
24}
25
26impl<const CAP: usize> fmt::Display for TruncatingArrayString<CAP> {
27 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28 self.0.fmt(f)
29 }
30}
31
32impl<const CAP: usize> fmt::Write for TruncatingArrayString<CAP> {
33 fn write_char(&mut self, c: char) -> fmt::Result {
34 self.0.try_push(c).map_err(|_| fmt::Error)
35 }
36
37 fn write_str(&mut self, s: &str) -> fmt::Result {
38 self.try_push_str_truncate(s).map_err(|_| fmt::Error)
39 }
40}
41
42fn floor_char_boundary(s: &str, index: usize) -> usize {
44 if index >= s.len() {
45 s.len()
46 } else {
47 let lower_bound = index.saturating_sub(3);
48 let new_index = s.as_bytes()[lower_bound..=index]
49 .iter()
50 .rposition(|b| is_utf8_char_boundary(*b));
51
52 unsafe { lower_bound + new_index.unwrap_unchecked() }
54 }
55}
56
57const fn is_utf8_char_boundary(b: u8) -> bool {
59 (b as i8) >= -0x40
61}
62
63#[cfg(test)]
64mod tests {
65 use std::fmt::Write;
66 use super::*;
67
68 #[test]
69 fn it_truncates() {
70 let mut buf = TruncatingArrayString::<5>::new();
71 assert_eq!(write!(buf, "{}", "12"), Ok(()));
72 assert_eq!(write!(buf, "{}", "3456789"), Err(std::fmt::Error));
73 assert_eq!(&buf.0[..], "12345");
74 }
75
76 #[test]
77 fn it_truncates_at_char_boundary() {
78 let mut buf = TruncatingArrayString::<5>::new();
79 assert_eq!(write!(buf, "{}", "α"), Ok(()));
80 assert_eq!(write!(buf, "{}", "βγ"), Err(std::fmt::Error));
81 assert_eq!(&buf.0[..], "αβ");
82 }
83}