Thanks to visit codestin.com
Credit goes to docs.rs

uapi/ustr/
ustr.rs

1use crate::{c::c_char, Bstr, Ustring};
2use std::{
3    ffi::{CStr, FromBytesWithNulError, OsStr},
4    fmt,
5    fmt::{Debug, Formatter},
6    ops::{Deref, DerefMut},
7    os::unix::ffi::OsStrExt,
8    path::Path,
9    ptr, slice,
10};
11
12/// Thin wrapper for a `[u8]` that has a trailing nul byte
13///
14/// NOTE: `Ustr` derefs to `Bstr` derefs to `[u8]`. Rustdoc might not show all available methods.
15///
16/// See also the crate documentation.
17#[repr(transparent)]
18#[derive(Eq, Ord, PartialOrd, PartialEq, Hash)]
19pub struct Ustr {
20    // invariant: last byte is 0
21    bytes: [u8],
22}
23
24static NULL: [u8; 1] = [0];
25
26impl Ustr {
27    /// Returns an empty `Ustr`
28    pub fn empty() -> &'static Self {
29        static E: [u8; 1] = [0];
30        unsafe { Self::from_bytes_unchecked(&E[..]) }
31    }
32
33    /// Returns the unique `&Ustr` for which `self.is_null() == true`
34    ///
35    /// Apart from `self.is_null()`, the returned value is indistinguishable from  `Ustr::empty()`.
36    pub fn null() -> &'static Self {
37        unsafe { Self::from_bytes_unchecked(&NULL[..]) }
38    }
39
40    /// Returns `true` iff this `Ustr` was constructed via `Ustr::null()`
41    pub fn is_null(&self) -> bool {
42        self.bytes.as_ptr() == NULL.as_ptr()
43    }
44
45    /// Transmutes the argument into `&Ustr`
46    ///
47    /// # Safety
48    ///
49    /// `s` must have a trailing nul byte.
50    pub unsafe fn from_bytes_unchecked(s: &[u8]) -> &Self {
51        &*(s as *const _ as *const _)
52    }
53
54    /// Transmutes the argument into `&mut Ustr`
55    ///
56    /// # Safety
57    ///
58    /// `s` must have a trailing nul byte.
59    pub unsafe fn from_bytes_unchecked_mut(s: &mut [u8]) -> &mut Self {
60        &mut *(s as *mut _ as *mut _)
61    }
62
63    /// Converts the argument into `&Ustr` after checking that it has a trailing nul byte
64    ///
65    /// Otherwise `None` is returned.
66    pub fn from_bytes(s: &[u8]) -> Option<&Self> {
67        if s.is_empty() || s[s.len() - 1] != 0 {
68            return None;
69        }
70        Some(unsafe { Self::from_bytes_unchecked(s) })
71    }
72
73    /// Converts the argument into `&mut Ustr` after checking that it has a trailing nul byte
74    ///
75    /// Otherwise `None` is returned.
76    pub fn from_bytes_mut(s: &mut [u8]) -> Option<&mut Self> {
77        if s.is_empty() || s[s.len() - 1] != 0 {
78            return None;
79        }
80        Some(unsafe { Self::from_bytes_unchecked_mut(s) })
81    }
82
83    /// Transmutes `self` into `&[u8]`
84    pub fn as_bytes_with_nul(&self) -> &[u8] {
85        &self.bytes
86    }
87
88    /// Shortcut for `Ustr::from_bytes(s.as_bytes())`
89    #[allow(clippy::should_implement_trait)] // https://github.com/rust-lang/rust-clippy/issues/5612
90    pub fn from_str(s: &str) -> Option<&Self> {
91        Self::from_bytes(s.as_bytes())
92    }
93
94    /// Transmutes the argument into `&Ustr`
95    pub fn from_c_str(s: &CStr) -> &Self {
96        unsafe { Self::from_bytes_unchecked(s.to_bytes_with_nul()) }
97    }
98
99    /// Shortcut for `Ustr::from_c_str(CStr::from_ptr(ptr))`
100    ///
101    /// # Safety
102    ///
103    /// Like `CStr::from_ptr`
104    pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a Self {
105        Self::from_c_str(CStr::from_ptr(ptr))
106    }
107
108    /// Shortcut for `Ustr::from_bytes_unchecked_mut(CStr::from_ptr_mut(ptr).as_bytes_with_nul_mut())`
109    ///
110    /// (`CStr::from_ptr_mut` does not actually exist so check the source if you want to know the
111    /// truth.)
112    ///
113    /// # Safety
114    ///
115    /// Like `CStr::from_ptr`
116    pub unsafe fn from_ptr_mut<'a>(ptr: *mut c_char) -> &'a mut Self {
117        let len = Self::from_ptr(ptr).len_with_nul();
118        Self::from_bytes_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut _, len))
119    }
120
121    /// Shortcut for `CStr::from_bytes_with_nul(self.as_bytes_with_nul())`
122    pub fn as_c_str(&self) -> Result<&CStr, FromBytesWithNulError> {
123        CStr::from_bytes_with_nul(&self.bytes)
124    }
125
126    /// Shortcut for `Ustr::from_bytes(s.as_bytes())`
127    pub fn from_os_str(s: &OsStr) -> Option<&Self> {
128        Self::from_bytes(s.as_bytes())
129    }
130
131    /// Shortcut for `OsStr::from_bytes(self.as_bytes_with_nul())`
132    pub fn as_os_str_with_nul(&self) -> &OsStr {
133        OsStr::from_bytes(self.as_bytes_with_nul())
134    }
135
136    /// Shortcut for `Ustr::from_os_str(s.as_os_str())`
137    pub fn from_path(s: &Path) -> Option<&Self> {
138        Self::from_os_str(s.as_os_str())
139    }
140
141    /// Shortcut for `Path::new(self.as_os_str_with_nul())`
142    pub fn as_path_with_nul(&self) -> &Path {
143        Path::new(self.as_os_str_with_nul())
144    }
145
146    /// Returns the length of the underlying `[u8]` including the trailing nul byte
147    pub fn len_with_nul(&self) -> usize {
148        self.bytes.len()
149    }
150
151    /// Returns the `&Bstr` created by dropping the trailing nul byte
152    pub fn as_bstr(&self) -> &Bstr {
153        Bstr::from_bytes(&self.bytes[..self.bytes.len() - 1])
154    }
155
156    /// Returns the `&mut Bstr` created by dropping the trailing nul byte
157    pub fn as_bstr_mut(&mut self) -> &mut Bstr {
158        let len = self.bytes.len();
159        Bstr::from_bytes_mut(&mut self.bytes[..len - 1])
160    }
161
162    /// Returns `ptr::null()` if `self.is_null()`, otherwise `self.as_ptr()`.
163    pub fn as_ptr_null(&self) -> *const c_char {
164        if self.is_null() {
165            ptr::null()
166        } else {
167            self.as_ptr()
168        }
169    }
170}
171
172impl ToOwned for Ustr {
173    type Owned = Ustring;
174
175    fn to_owned(&self) -> Self::Owned {
176        self.to_ustring()
177    }
178}
179
180impl Deref for Ustr {
181    type Target = Bstr;
182
183    fn deref(&self) -> &Self::Target {
184        self.as_bstr()
185    }
186}
187
188impl DerefMut for Ustr {
189    fn deref_mut(&mut self) -> &mut Self::Target {
190        self.as_bstr_mut()
191    }
192}
193
194impl AsRef<[u8]> for Ustr {
195    fn as_ref(&self) -> &[u8] {
196        self.as_bytes()
197    }
198}
199
200impl AsMut<[u8]> for Ustr {
201    fn as_mut(&mut self) -> &mut [u8] {
202        self.as_bytes_mut()
203    }
204}
205
206impl AsRef<Ustr> for CStr {
207    fn as_ref(&self) -> &Ustr {
208        Ustr::from_c_str(self)
209    }
210}
211
212impl AsRef<OsStr> for Ustr {
213    fn as_ref(&self) -> &OsStr {
214        self.as_os_str()
215    }
216}
217
218impl AsRef<Path> for Ustr {
219    fn as_ref(&self) -> &Path {
220        self.as_path()
221    }
222}
223
224impl Debug for Ustr {
225    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
226        Debug::fmt(self.as_os_str(), f)
227    }
228}