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#[repr(transparent)]
18#[derive(Eq, Ord, PartialOrd, PartialEq, Hash)]
19pub struct Ustr {
20 bytes: [u8],
22}
23
24static NULL: [u8; 1] = [0];
25
26impl Ustr {
27 pub fn empty() -> &'static Self {
29 static E: [u8; 1] = [0];
30 unsafe { Self::from_bytes_unchecked(&E[..]) }
31 }
32
33 pub fn null() -> &'static Self {
37 unsafe { Self::from_bytes_unchecked(&NULL[..]) }
38 }
39
40 pub fn is_null(&self) -> bool {
42 self.bytes.as_ptr() == NULL.as_ptr()
43 }
44
45 pub unsafe fn from_bytes_unchecked(s: &[u8]) -> &Self {
51 &*(s as *const _ as *const _)
52 }
53
54 pub unsafe fn from_bytes_unchecked_mut(s: &mut [u8]) -> &mut Self {
60 &mut *(s as *mut _ as *mut _)
61 }
62
63 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 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 pub fn as_bytes_with_nul(&self) -> &[u8] {
85 &self.bytes
86 }
87
88 #[allow(clippy::should_implement_trait)] pub fn from_str(s: &str) -> Option<&Self> {
91 Self::from_bytes(s.as_bytes())
92 }
93
94 pub fn from_c_str(s: &CStr) -> &Self {
96 unsafe { Self::from_bytes_unchecked(s.to_bytes_with_nul()) }
97 }
98
99 pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a Self {
105 Self::from_c_str(CStr::from_ptr(ptr))
106 }
107
108 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 pub fn as_c_str(&self) -> Result<&CStr, FromBytesWithNulError> {
123 CStr::from_bytes_with_nul(&self.bytes)
124 }
125
126 pub fn from_os_str(s: &OsStr) -> Option<&Self> {
128 Self::from_bytes(s.as_bytes())
129 }
130
131 pub fn as_os_str_with_nul(&self) -> &OsStr {
133 OsStr::from_bytes(self.as_bytes_with_nul())
134 }
135
136 pub fn from_path(s: &Path) -> Option<&Self> {
138 Self::from_os_str(s.as_os_str())
139 }
140
141 pub fn as_path_with_nul(&self) -> &Path {
143 Path::new(self.as_os_str_with_nul())
144 }
145
146 pub fn len_with_nul(&self) -> usize {
148 self.bytes.len()
149 }
150
151 pub fn as_bstr(&self) -> &Bstr {
153 Bstr::from_bytes(&self.bytes[..self.bytes.len() - 1])
154 }
155
156 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 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}