1#![doc = include_str!("types.md")]
2
3use crate::{
4 Error, Result,
5 util::{PrettyBytes, cow_map},
6};
7use libc::c_char;
8use ref_cast::{RefCastCustom, ref_cast_custom};
9#[cfg(unix)] use std::os::unix::prelude::{OsStrExt as _, OsStringExt as _};
10use std::{
11 borrow::Cow,
12 cmp,
13 ffi::{CStr, CString, OsStr},
14 fmt,
15 path::{Path, PathBuf},
16};
17
18#[derive(Eq, Ord, Hash)]
20#[derive(RefCastCustom)]
21#[repr(transparent)]
23pub struct BStr([u8]);
24#[zoet::zoet]
25impl BStr {
26 #[ref_cast_custom]
28 pub const fn from_bytes(s: &[u8]) -> &Self;
29
30 pub fn from(s: &(impl AsRef<[u8]> + ?Sized)) -> &Self {
32 Self::from_bytes(s.as_ref())
33 }
34
35 #[zoet(Default)]
37 pub const fn default() -> &'static Self {
38 Self::from_bytes(b"")
39 }
40
41 #[zoet(AsRef)]
43 pub const fn as_bytes(&self) -> &[u8] {
44 &self.0
45 }
46
47 #[zoet(AsRef)]
49 pub fn as_os_str(&self) -> &OsStr {
50 OsStr::from_bytes(self.as_bytes())
51 }
52
53 #[zoet(From, ToOwned)]
55 pub fn to_bstring(&self) -> BString {
56 BString(self.0.to_owned())
57 }
58
59 #[zoet(From)]
61 pub const fn as_cow<'a>(&'a self) -> Cow<'a, Self> {
62 Cow::Borrowed(self)
63 }
64
65 #[allow(dead_code, reason = "functions only used by Debug impl are incorrectly warned as dead")]
66 #[zoet(Debug)]
67 fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
68 let pretty = PrettyBytes::new(self);
69 f.debug_tuple("BStr").field(&pretty).finish()
70 }
71}
72
73#[derive(Clone, Eq, Ord, Hash, Default)]
75#[repr(transparent)]
77pub struct BString(Vec<u8>);
78
79#[zoet::zoet]
80impl BString {
81 #[zoet(From)]
83 pub const fn from_vec(s: Vec<u8>) -> Self {
84 Self(s)
85 }
86
87 pub fn from(s: impl Into<Vec<u8>>) -> Self {
89 Self(s.into())
90 }
91
92 #[zoet(From)]
94 pub fn into_inner(self) -> Vec<u8> {
95 self.0
96 }
97
98 #[zoet(AsRef)]
100 const fn as_bytes(&self) -> &[u8] {
101 self.0.as_slice()
102 }
103
104 #[zoet(AsMut)]
106 pub const fn as_mut_vec(&mut self) -> &mut Vec<u8> {
107 &mut self.0
108 }
109
110 #[zoet(AsRef, Borrow, Deref)]
112 pub const fn as_bstr(&self) -> &BStr {
113 BStr::from_bytes(self.0.as_slice())
114 }
115
116 #[zoet(From)]
118 pub const fn into_cow(self) -> Cow<BStr, 'static> {
119 Cow::Owned(self)
120 }
121
122 #[allow(dead_code, reason = "functions only used by Debug impl are incorrectly warned as dead")]
123 #[zoet(Debug)]
124 fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
125 let pretty = PrettyBytes::new(self.as_bytes());
126 f.debug_tuple("BString").field(&pretty).finish()
127 }
128}
129
130#[derive(Eq, Ord, Hash)]
132#[derive(RefCastCustom)]
133#[repr(transparent)]
135pub struct ZStr(CStr);
136#[zoet::zoet]
137impl ZStr {
138 #[ref_cast_custom]
140 pub const fn from_cstr(s: &CStr) -> &Self;
141
142 #[zoet(AsRef)]
148 pub const fn as_bytes(&self) -> &[u8] {
149 self.0.to_bytes()
150 }
151
152 #[zoet(AsRef)]
154 pub const fn as_bstr(&self) -> &BStr {
155 BStr::from_bytes(self.as_bytes())
156 }
157
158 #[zoet(AsRef)]
160 pub const fn as_cstr(&self) -> &CStr {
161 &self.0
162 }
163
164 #[zoet(AsRef)]
166 pub fn as_os_str(&self) -> &OsStr {
167 OsStr::from_bytes(self.as_bytes())
168 }
169
170 pub const fn as_ptr(&self) -> *const c_char {
172 self.0.as_ptr()
173 }
174
175 #[zoet(From, ToOwned)]
177 pub fn to_zstring(&self) -> ZString {
178 ZString(self.0.to_owned())
179 }
180
181 #[zoet(From)]
183 pub const fn as_cow<'a>(&'a self) -> Cow<'a, ZStr> {
184 Cow::Borrowed(self)
185 }
186
187 #[allow(dead_code, reason = "functions only used by Debug impl are incorrectly warned as dead")]
188 #[zoet(Debug)]
189 fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
190 let pretty = PrettyBytes::new(self);
191 f.debug_tuple("ZStr").field(&pretty).finish()
192 }
193}
194
195#[derive(Clone, Eq, Ord, Hash)]
197#[repr(transparent)]
199pub struct ZString(CString);
200#[zoet::zoet]
201impl ZString {
202 #[zoet(From)]
204 pub const fn from_cstring(s: CString) -> Self {
205 Self(s)
206 }
207
208 #[zoet(From)]
210 pub fn into_inner(self) -> CString {
211 self.0
212 }
213
214 #[zoet(AsRef)]
216 pub fn as_bytes(&self) -> &[u8] {
217 self.0.as_bytes()
218 }
219
220 #[zoet(AsRef, Borrow, Deref)]
222 pub fn as_zstr(&self) -> &ZStr {
223 ZStr::from_cstr(self.0.as_c_str())
224 }
225
226 #[zoet(From)]
228 pub fn into_cow(self) -> Cow<ZStr, 'static> {
229 Cow::Owned(self)
230 }
231
232 #[allow(dead_code, reason = "functions only used by Debug impl are incorrectly warned as dead")]
233 #[zoet(Debug)]
234 fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
235 let pretty = PrettyBytes::new(self.as_bytes());
236 f.debug_tuple("ZString").field(&pretty).finish()
237 }
238}
239
240impl ZString {
241 pub fn try_from_bytes(t: impl Into<Vec<u8>>) -> Result<Self> {
247 CString::new(t.into())
248 .map(Self)
249 .map_err(|_| Error::UnexpectedNul)
250 }
251
252 pub unsafe fn prepend_unchecked(&mut self, prefix: &[u8]) {
261 let mut buf = std::mem::take(&mut self.0).into_bytes_with_nul();
272 buf.extend(prefix);
274 buf.rotate_right(prefix.len());
276 self.0 = unsafe { CString::from_vec_with_nul_unchecked(buf) };
282 }
283}
284
285macro_rules! make_partial_ord {
286 ($TYPE:ty) => {
287 #[zoet::zoet]
288 impl $TYPE {
289 #[zoet(PartialEq, PartialOrd)]
290 fn partial_cmp<T: AsRef<[u8]> + ?Sized>(&self, rhs: &T) -> cmp::Ordering {
291 self.as_bytes().cmp(rhs.as_ref())
292 }
293 }
294 };
295}
296
297make_partial_ord! { BStr }
298make_partial_ord! { BString }
299make_partial_ord! { ZStr }
300make_partial_ord! { ZString }
301
302pub trait IntoZString<'a> {
320 fn into_zstring(self) -> Result<Cow<'a, ZStr>>;
327}
328
329impl<'a> IntoZString<'a> for &'a CStr {
331 #[inline]
332 fn into_zstring(self) -> Result<Cow<'a, ZStr>> {
333 Ok(ZStr::from_cstr(self).into())
334 }
335}
336impl IntoZString<'static> for CString {
337 #[inline]
338 fn into_zstring(self) -> Result<Cow<'static, ZStr>> {
339 Ok(ZString::from(self).into())
340 }
341}
342impl<'a> IntoZString<'a> for Cow<'a, CStr> {
343 #[inline]
344 fn into_zstring(self) -> Result<Cow<'a, ZStr>> {
345 Ok(cow_map(self, ZStr::from_cstr, ZString::from_cstring))
346 }
347}
348impl<'a> IntoZString<'a> for &'a ZStr {
349 #[inline]
350 fn into_zstring(self) -> Result<Cow<'a, ZStr>> {
351 Ok(self.into())
352 }
353}
354impl IntoZString<'static> for ZString {
355 #[inline]
356 fn into_zstring(self) -> Result<Cow<'static, ZStr>> {
357 Ok(self.into())
358 }
359}
360impl<'a> IntoZString<'a> for Cow<'a, ZStr> {
361 #[inline]
362 fn into_zstring(self) -> Result<Cow<'a, ZStr>> {
363 Ok(self)
364 }
365}
366
367impl IntoZString<'static> for &BStr {
369 #[inline]
370 fn into_zstring(self) -> Result<Cow<'static, ZStr>> {
371 self.to_owned().into_zstring()
372 }
373}
374impl IntoZString<'static> for BString {
375 #[inline]
376 fn into_zstring(self) -> Result<Cow<'static, ZStr>> {
377 ZString::try_from_bytes(self.0).map(Into::into)
378 }
379}
380
381impl IntoZString<'static> for PathBuf {
383 fn into_zstring(self) -> Result<Cow<'static, ZStr>> {
384 self.into_os_string().into_vec().into_zstring()
385 }
386}
387impl IntoZString<'static> for &Path {
388 fn into_zstring(self) -> Result<Cow<'static, ZStr>> {
389 self.as_os_str().as_bytes().into_zstring()
390 }
391}
392
393impl IntoZString<'static> for Vec<u8> {
396 fn into_zstring(self) -> Result<Cow<'static, ZStr>> {
397 let s = CString::new(self).map_err(|_nul_error| Error::UnexpectedNul)?;
398 s.into_zstring()
399 }
400}
401impl IntoZString<'static> for String {
402 fn into_zstring(self) -> Result<Cow<'static, ZStr>> {
403 self.into_bytes().into_zstring()
404 }
405}
406
407impl IntoZString<'static> for &[u8] {
419 fn into_zstring(self) -> Result<Cow<'static, ZStr>> {
420 self.to_vec().into_zstring()
421 }
422}
423impl IntoZString<'static> for &str {
424 fn into_zstring(self) -> Result<Cow<'static, ZStr>> {
425 self.to_owned().into_zstring()
426 }
427}
428
429