Skip to main content

ps_str/utf8_encoder/variants/
bytes.rs

1use crate::{Utf8Encoder, CHARS};
2
3impl<T: AsRef<[u8]>> Utf8Encoder for T {
4    /// Converts a byte sequence into a UTF-8 string, replacing invalid bytes
5    /// with fallback characters.
6    ///
7    /// This method processes bytes sequentially, attempting to parse valid UTF-8
8    /// sequences. When valid UTF-8 is encountered, it is appended directly to the
9    /// result string. When an invalid UTF-8 sequence is detected, the valid portion
10    /// preceding the error is appended, then the offending byte is replaced, and
11    /// processing continues from the next byte.
12    ///
13    /// # Returns
14    ///
15    /// A `String` containing the decoded content, guaranteed to be valid UTF-8
16    /// even if the input contained invalid byte sequences.
17    ///
18    /// # Example
19    ///
20    /// ```
21    /// use ps_str::Utf8Encoder;
22    ///
23    /// let bytes = b"Hello\xFFWorld";
24    /// let result = bytes.to_utf8_string();
25    ///
26    /// assert_eq!(result, "Hello˙World");
27    /// ```
28    fn to_utf8_string(&self) -> String {
29        let bytes = self.as_ref();
30        let mut result = String::with_capacity(bytes.len());
31        let mut i = 0;
32
33        while i < bytes.len() {
34            match std::str::from_utf8(&bytes[i..]) {
35                Ok(valid_str) => {
36                    result.push_str(valid_str);
37                    break;
38                }
39                Err(e) => {
40                    if e.valid_up_to() > 0 {
41                        let valid_part = &bytes[i..i + e.valid_up_to()];
42
43                        // SAFETY: valid_up_to() guarantees this slice contains only complete, valid UTF-8 characters
44                        result.push_str(unsafe { std::str::from_utf8_unchecked(valid_part) });
45                        i += e.valid_up_to();
46                    }
47
48                    if let Some(c) = bytes.get(i) {
49                        result.push(CHARS[*c as usize]);
50                        i += 1;
51                    }
52                }
53            }
54        }
55
56        result
57    }
58}