ext4_view/
label.rs

1// Copyright 2025 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use crate::format::{BytesDisplay, format_bytes_debug};
10use core::fmt::{self, Debug, Formatter};
11use core::str::Utf8Error;
12
13/// Filesystem label.
14///
15/// The label is at most 16 bytes, and may contain null bytes. The
16/// encoding is not specified.
17#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
18pub struct Label([u8; 16]);
19
20impl Label {
21    /// Create a label from raw bytes.
22    #[must_use]
23    pub const fn new(bytes: [u8; 16]) -> Self {
24        Self(bytes)
25    }
26
27    /// Convert the label to a UTF-8 string, if possible.
28    ///
29    /// The first null byte, and any following bytes, are excluded from
30    /// the conversion.
31    pub fn to_str(&self) -> Result<&str, Utf8Error> {
32        core::str::from_utf8(self.as_bytes_up_to_first_null())
33    }
34
35    /// Get the raw bytes of the label. This may include null bytes.
36    #[must_use]
37    pub const fn as_bytes(&self) -> &[u8; 16] {
38        &self.0
39    }
40
41    /// Get the bytes up to the first null, or all of the bytes if there
42    /// is no null byte.
43    #[must_use]
44    fn as_bytes_up_to_first_null(&self) -> &[u8] {
45        if let Some(index) = self.0.iter().position(|c| *c == 0) {
46            &self.0[..index]
47        } else {
48            &self.0
49        }
50    }
51
52    /// Get an object that implements [`Display`] to allow conveniently
53    /// printing labels that may or may not be valid UTF-8. Non-UTF-8
54    /// characters will be replaced with '�'.
55    ///
56    /// Null bytes are not included.
57    ///
58    /// [`Display`]: core::fmt::Display
59    pub fn display(&self) -> BytesDisplay {
60        BytesDisplay(self.as_bytes_up_to_first_null())
61    }
62}
63
64impl Debug for Label {
65    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
66        format_bytes_debug(self.as_bytes_up_to_first_null(), f)
67    }
68}