Skip to main content

zr/
lossy_utf8.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// Wraps a binary string that may contain non-UTF-8 bytes for formatting.
6/// Invalid bytes are formatted as `\u{FFFFD}`.
7pub fn from_utf8_lossy(bytes: &[u8]) -> LossyUtf8<'_> {
8    LossyUtf8(bytes)
9}
10
11pub struct LossyUtf8<'a>(&'a [u8]);
12
13impl core::fmt::Display for LossyUtf8<'_> {
14    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
15        let mut bytes = self.0;
16        while !bytes.is_empty() {
17            match core::str::from_utf8(bytes) {
18                Ok(s) => {
19                    f.write_str(s)?;
20                    break;
21                }
22                Err(err) => {
23                    let (valid, rest) = bytes.split_at(err.valid_up_to());
24                    if !valid.is_empty() {
25                        // SAFETY: `valid` was verified by `from_utf8`.
26                        let s = unsafe { core::str::from_utf8_unchecked(valid) };
27                        f.write_str(s)?;
28                    }
29                    f.write_str("\u{FFFD}")?;
30                    match err.error_len() {
31                        Some(len) => bytes = &rest[len..],
32                        None => break,
33                    }
34                }
35            }
36        }
37        Ok(())
38    }
39}