Coverage Report

Created: 2026-03-28 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/adhd/cras/server/ini/src/utf8cstring.rs
Line
Count
Source
1
// Copyright 2024 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use std::borrow::Borrow;
6
use std::ffi::CStr;
7
use std::hash::Hash;
8
9
/// A Null-terminated UTF-8 string that can be borrowed as `&str` and `&cstr`.
10
#[derive(PartialEq, Eq)]
11
pub struct Utf8CString {
12
    // Invariant: data must terminated with a single NULL.
13
    data: String,
14
}
15
16
impl TryFrom<String> for Utf8CString {
17
    type Error = anyhow::Error;
18
19
0
    fn try_from(mut value: String) -> Result<Self, Self::Error> {
20
0
        value.push('\0');
21
0
        CStr::from_bytes_with_nul(value.as_bytes())?;
22
0
        Ok(Self { data: value })
23
0
    }
24
}
25
26
impl Utf8CString {
27
    /// Return the contained string as a &str.
28
0
    pub fn as_str(&self) -> &str {
29
0
        self.data.strip_suffix('\0').unwrap()
30
0
    }
31
32
    /// Return the contained string as a &CStr.
33
0
    pub fn as_cstr(&self) -> &CStr {
34
0
        CStr::from_bytes_with_nul(self.data.as_bytes()).unwrap()
35
0
    }
36
}
37
38
impl Borrow<str> for Utf8CString {
39
0
    fn borrow(&self) -> &str {
40
0
        self.as_str()
41
0
    }
42
}
43
44
impl Hash for Utf8CString {
45
0
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
46
0
        self.as_str().hash(state);
47
0
    }
48
}
49
50
#[cfg(test)]
51
mod tests {
52
    use super::*;
53
54
    #[test]
55
    fn has_null() {
56
        assert!(Utf8CString::try_from(String::from("hello\0world")).is_err());
57
        assert!(Utf8CString::try_from(String::from("hello world\0")).is_err());
58
    }
59
60
    #[test]
61
    fn roundtrip_str() {
62
        let s = "hello world";
63
        assert_eq!(Utf8CString::try_from(s.to_string()).unwrap().as_str(), s);
64
    }
65
66
    #[test]
67
    fn roundtrip_cstr() {
68
        let s = "hello world";
69
        assert_eq!(
70
            Utf8CString::try_from(s.to_string()).unwrap().as_cstr(),
71
            c"hello world"
72
        );
73
    }
74
}