]> git.proxmox.com Git - rustc.git/blob - vendor/rustix-0.37.11/src/path/arg.rs
New upstream version 1.72.1+dfsg1
[rustc.git] / vendor / rustix-0.37.11 / src / path / arg.rs
1 //! Convenient and efficient string argument passing.
2 //!
3 //! This module defines the `Arg` trait and implements it for several common
4 //! string types. This allows users to pass any of these string types directly
5 //! to rustix APIs with string arguments, and it allows rustix to implement
6 //! NUL-termination without the need for copying where possible.
7
8 use crate::ffi::{CStr, CString};
9 use crate::io;
10 #[cfg(feature = "itoa")]
11 use crate::path::DecInt;
12 use crate::path::SMALL_PATH_BUFFER_SIZE;
13 use alloc::borrow::Cow;
14 #[cfg(feature = "itoa")]
15 use alloc::borrow::ToOwned;
16 use alloc::string::String;
17 use alloc::vec::Vec;
18 use core::mem::MaybeUninit;
19 use core::{ptr, slice, str};
20 #[cfg(feature = "std")]
21 use std::ffi::{OsStr, OsString};
22 #[cfg(feature = "std")]
23 #[cfg(target_os = "hermit")]
24 use std::os::hermit::ext::ffi::{OsStrExt, OsStringExt};
25 #[cfg(feature = "std")]
26 #[cfg(unix)]
27 use std::os::unix::ffi::{OsStrExt, OsStringExt};
28 #[cfg(feature = "std")]
29 #[cfg(target_os = "vxworks")]
30 use std::os::vxworks::ext::ffi::{OsStrExt, OsStringExt};
31 #[cfg(feature = "std")]
32 #[cfg(target_os = "wasi")]
33 use std::os::wasi::ffi::{OsStrExt, OsStringExt};
34 #[cfg(feature = "std")]
35 use std::path::{Component, Components, Iter, Path, PathBuf};
36
37 /// A trait for passing path arguments.
38 ///
39 /// This is similar to [`AsRef`]`<`[`Path`]`>`, but is implemented for more
40 /// kinds of strings and can convert into more kinds of strings.
41 ///
42 /// # Example
43 ///
44 /// ```
45 /// # #[cfg(any(feature = "fs", feature = "net"))]
46 /// use rustix::ffi::CStr;
47 /// use rustix::io;
48 /// # #[cfg(any(feature = "fs", feature = "net"))]
49 /// use rustix::path::Arg;
50 ///
51 /// # #[cfg(any(feature = "fs", feature = "net"))]
52 /// pub fn touch<P: Arg>(path: P) -> io::Result<()> {
53 /// let path = path.into_c_str()?;
54 /// _touch(&path)
55 /// }
56 ///
57 /// # #[cfg(any(feature = "fs", feature = "net"))]
58 /// fn _touch(path: &CStr) -> io::Result<()> {
59 /// // implementation goes here
60 /// Ok(())
61 /// }
62 /// ```
63 ///
64 /// Users can then call `touch("foo")`, `touch(cstr!("foo"))`,
65 /// `touch(Path::new("foo"))`, or many other things.
66 ///
67 /// [`AsRef`]: std::convert::AsRef
68 pub trait Arg {
69 /// Returns a view of this string as a string slice.
70 fn as_str(&self) -> io::Result<&str>;
71
72 /// Returns a potentially-lossy rendering of this string as a `Cow<'_,
73 /// str>`.
74 fn to_string_lossy(&self) -> Cow<'_, str>;
75
76 /// Returns a view of this string as a maybe-owned [`CStr`].
77 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>>;
78
79 /// Consumes `self` and returns a view of this string as a maybe-owned
80 /// [`CStr`].
81 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
82 where
83 Self: 'b;
84
85 /// Runs a closure with `self` passed in as a `&CStr`.
86 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
87 where
88 Self: Sized,
89 F: FnOnce(&CStr) -> io::Result<T>;
90 }
91
92 impl Arg for &str {
93 #[inline]
94 fn as_str(&self) -> io::Result<&str> {
95 Ok(self)
96 }
97
98 #[inline]
99 fn to_string_lossy(&self) -> Cow<'_, str> {
100 Cow::Borrowed(self)
101 }
102
103 #[inline]
104 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
105 Ok(Cow::Owned(
106 CString::new(*self).map_err(|_cstr_err| io::Errno::INVAL)?,
107 ))
108 }
109
110 #[inline]
111 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
112 where
113 Self: 'b,
114 {
115 Ok(Cow::Owned(
116 CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?,
117 ))
118 }
119
120 #[inline]
121 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
122 where
123 Self: Sized,
124 F: FnOnce(&CStr) -> io::Result<T>,
125 {
126 with_c_str(self.as_bytes(), f)
127 }
128 }
129
130 impl Arg for &String {
131 #[inline]
132 fn as_str(&self) -> io::Result<&str> {
133 Ok(self)
134 }
135
136 #[inline]
137 fn to_string_lossy(&self) -> Cow<'_, str> {
138 Cow::Borrowed(self)
139 }
140
141 #[inline]
142 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
143 Ok(Cow::Owned(
144 CString::new(String::as_str(self)).map_err(|_cstr_err| io::Errno::INVAL)?,
145 ))
146 }
147
148 #[inline]
149 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
150 where
151 Self: 'b,
152 {
153 self.as_str().into_c_str()
154 }
155
156 #[inline]
157 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
158 where
159 Self: Sized,
160 F: FnOnce(&CStr) -> io::Result<T>,
161 {
162 with_c_str(self.as_bytes(), f)
163 }
164 }
165
166 impl Arg for String {
167 #[inline]
168 fn as_str(&self) -> io::Result<&str> {
169 Ok(self)
170 }
171
172 #[inline]
173 fn to_string_lossy(&self) -> Cow<'_, str> {
174 Cow::Borrowed(self)
175 }
176
177 #[inline]
178 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
179 Ok(Cow::Owned(
180 CString::new(self.as_str()).map_err(|_cstr_err| io::Errno::INVAL)?,
181 ))
182 }
183
184 #[inline]
185 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
186 where
187 Self: 'b,
188 {
189 Ok(Cow::Owned(
190 CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?,
191 ))
192 }
193
194 #[inline]
195 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
196 where
197 Self: Sized,
198 F: FnOnce(&CStr) -> io::Result<T>,
199 {
200 f(&CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?)
201 }
202 }
203
204 #[cfg(feature = "std")]
205 impl Arg for &OsStr {
206 #[inline]
207 fn as_str(&self) -> io::Result<&str> {
208 self.to_str().ok_or(io::Errno::INVAL)
209 }
210
211 #[inline]
212 fn to_string_lossy(&self) -> Cow<'_, str> {
213 OsStr::to_string_lossy(self)
214 }
215
216 #[inline]
217 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
218 Ok(Cow::Owned(
219 CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
220 ))
221 }
222
223 #[inline]
224 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
225 where
226 Self: 'b,
227 {
228 Ok(Cow::Owned(
229 CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
230 ))
231 }
232
233 #[inline]
234 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
235 where
236 Self: Sized,
237 F: FnOnce(&CStr) -> io::Result<T>,
238 {
239 with_c_str(self.as_bytes(), f)
240 }
241 }
242
243 #[cfg(feature = "std")]
244 impl Arg for &OsString {
245 #[inline]
246 fn as_str(&self) -> io::Result<&str> {
247 OsString::as_os_str(self).to_str().ok_or(io::Errno::INVAL)
248 }
249
250 #[inline]
251 fn to_string_lossy(&self) -> Cow<'_, str> {
252 self.as_os_str().to_string_lossy()
253 }
254
255 #[inline]
256 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
257 Ok(Cow::Owned(
258 CString::new(OsString::as_os_str(self).as_bytes())
259 .map_err(|_cstr_err| io::Errno::INVAL)?,
260 ))
261 }
262
263 #[inline]
264 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
265 where
266 Self: 'b,
267 {
268 self.as_os_str().into_c_str()
269 }
270
271 #[inline]
272 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
273 where
274 Self: Sized,
275 F: FnOnce(&CStr) -> io::Result<T>,
276 {
277 with_c_str(self.as_bytes(), f)
278 }
279 }
280
281 #[cfg(feature = "std")]
282 impl Arg for OsString {
283 #[inline]
284 fn as_str(&self) -> io::Result<&str> {
285 self.as_os_str().to_str().ok_or(io::Errno::INVAL)
286 }
287
288 #[inline]
289 fn to_string_lossy(&self) -> Cow<'_, str> {
290 self.as_os_str().to_string_lossy()
291 }
292
293 #[inline]
294 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
295 Ok(Cow::Owned(
296 CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
297 ))
298 }
299
300 #[inline]
301 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
302 where
303 Self: 'b,
304 {
305 Ok(Cow::Owned(
306 CString::new(self.into_vec()).map_err(|_cstr_err| io::Errno::INVAL)?,
307 ))
308 }
309
310 #[inline]
311 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
312 where
313 Self: Sized,
314 F: FnOnce(&CStr) -> io::Result<T>,
315 {
316 f(&CString::new(self.into_vec()).map_err(|_cstr_err| io::Errno::INVAL)?)
317 }
318 }
319
320 #[cfg(feature = "std")]
321 impl Arg for &Path {
322 #[inline]
323 fn as_str(&self) -> io::Result<&str> {
324 self.as_os_str().to_str().ok_or(io::Errno::INVAL)
325 }
326
327 #[inline]
328 fn to_string_lossy(&self) -> Cow<'_, str> {
329 Path::to_string_lossy(self)
330 }
331
332 #[inline]
333 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
334 Ok(Cow::Owned(
335 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
336 ))
337 }
338
339 #[inline]
340 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
341 where
342 Self: 'b,
343 {
344 Ok(Cow::Owned(
345 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
346 ))
347 }
348
349 #[inline]
350 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
351 where
352 Self: Sized,
353 F: FnOnce(&CStr) -> io::Result<T>,
354 {
355 with_c_str(self.as_os_str().as_bytes(), f)
356 }
357 }
358
359 #[cfg(feature = "std")]
360 impl Arg for &PathBuf {
361 #[inline]
362 fn as_str(&self) -> io::Result<&str> {
363 PathBuf::as_path(self)
364 .as_os_str()
365 .to_str()
366 .ok_or(io::Errno::INVAL)
367 }
368
369 #[inline]
370 fn to_string_lossy(&self) -> Cow<'_, str> {
371 self.as_path().to_string_lossy()
372 }
373
374 #[inline]
375 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
376 Ok(Cow::Owned(
377 CString::new(PathBuf::as_path(self).as_os_str().as_bytes())
378 .map_err(|_cstr_err| io::Errno::INVAL)?,
379 ))
380 }
381
382 #[inline]
383 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
384 where
385 Self: 'b,
386 {
387 self.as_path().into_c_str()
388 }
389
390 #[inline]
391 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
392 where
393 Self: Sized,
394 F: FnOnce(&CStr) -> io::Result<T>,
395 {
396 with_c_str(self.as_os_str().as_bytes(), f)
397 }
398 }
399
400 #[cfg(feature = "std")]
401 impl Arg for PathBuf {
402 #[inline]
403 fn as_str(&self) -> io::Result<&str> {
404 self.as_os_str().to_str().ok_or(io::Errno::INVAL)
405 }
406
407 #[inline]
408 fn to_string_lossy(&self) -> Cow<'_, str> {
409 self.as_os_str().to_string_lossy()
410 }
411
412 #[inline]
413 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
414 Ok(Cow::Owned(
415 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
416 ))
417 }
418
419 #[inline]
420 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
421 where
422 Self: 'b,
423 {
424 Ok(Cow::Owned(
425 CString::new(self.into_os_string().into_vec()).map_err(|_cstr_err| io::Errno::INVAL)?,
426 ))
427 }
428
429 #[inline]
430 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
431 where
432 Self: Sized,
433 F: FnOnce(&CStr) -> io::Result<T>,
434 {
435 f(
436 &CString::new(self.into_os_string().into_vec())
437 .map_err(|_cstr_err| io::Errno::INVAL)?,
438 )
439 }
440 }
441
442 impl Arg for &CStr {
443 #[inline]
444 fn as_str(&self) -> io::Result<&str> {
445 self.to_str().map_err(|_utf8_err| io::Errno::INVAL)
446 }
447
448 #[inline]
449 fn to_string_lossy(&self) -> Cow<'_, str> {
450 CStr::to_string_lossy(self)
451 }
452
453 #[inline]
454 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
455 Ok(Cow::Borrowed(self))
456 }
457
458 #[inline]
459 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
460 where
461 Self: 'b,
462 {
463 Ok(Cow::Borrowed(self))
464 }
465
466 #[inline]
467 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
468 where
469 Self: Sized,
470 F: FnOnce(&CStr) -> io::Result<T>,
471 {
472 f(self)
473 }
474 }
475
476 impl Arg for &CString {
477 #[inline]
478 fn as_str(&self) -> io::Result<&str> {
479 unimplemented!()
480 }
481
482 #[inline]
483 fn to_string_lossy(&self) -> Cow<'_, str> {
484 unimplemented!()
485 }
486
487 #[inline]
488 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
489 Ok(Cow::Borrowed(self))
490 }
491
492 #[inline]
493 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
494 where
495 Self: 'b,
496 {
497 Ok(Cow::Borrowed(self))
498 }
499
500 #[inline]
501 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
502 where
503 Self: Sized,
504 F: FnOnce(&CStr) -> io::Result<T>,
505 {
506 f(self)
507 }
508 }
509
510 impl Arg for CString {
511 #[inline]
512 fn as_str(&self) -> io::Result<&str> {
513 self.to_str().map_err(|_utf8_err| io::Errno::INVAL)
514 }
515
516 #[inline]
517 fn to_string_lossy(&self) -> Cow<'_, str> {
518 CStr::to_string_lossy(self)
519 }
520
521 #[inline]
522 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
523 Ok(Cow::Borrowed(self))
524 }
525
526 #[inline]
527 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
528 where
529 Self: 'b,
530 {
531 Ok(Cow::Owned(self))
532 }
533
534 #[inline]
535 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
536 where
537 Self: Sized,
538 F: FnOnce(&CStr) -> io::Result<T>,
539 {
540 f(&self)
541 }
542 }
543
544 impl<'a> Arg for Cow<'a, str> {
545 #[inline]
546 fn as_str(&self) -> io::Result<&str> {
547 Ok(self)
548 }
549
550 #[inline]
551 fn to_string_lossy(&self) -> Cow<'_, str> {
552 Cow::Borrowed(self)
553 }
554
555 #[inline]
556 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
557 Ok(Cow::Owned(
558 CString::new(self.as_ref()).map_err(|_cstr_err| io::Errno::INVAL)?,
559 ))
560 }
561
562 #[inline]
563 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
564 where
565 Self: 'b,
566 {
567 Ok(Cow::Owned(
568 match self {
569 Cow::Owned(s) => CString::new(s),
570 Cow::Borrowed(s) => CString::new(s),
571 }
572 .map_err(|_cstr_err| io::Errno::INVAL)?,
573 ))
574 }
575
576 #[inline]
577 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
578 where
579 Self: Sized,
580 F: FnOnce(&CStr) -> io::Result<T>,
581 {
582 with_c_str(self.as_bytes(), f)
583 }
584 }
585
586 #[cfg(feature = "std")]
587 impl<'a> Arg for Cow<'a, OsStr> {
588 #[inline]
589 fn as_str(&self) -> io::Result<&str> {
590 (**self).to_str().ok_or(io::Errno::INVAL)
591 }
592
593 #[inline]
594 fn to_string_lossy(&self) -> Cow<'_, str> {
595 (**self).to_string_lossy()
596 }
597
598 #[inline]
599 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
600 Ok(Cow::Owned(
601 CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
602 ))
603 }
604
605 #[inline]
606 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
607 where
608 Self: 'b,
609 {
610 Ok(Cow::Owned(
611 match self {
612 Cow::Owned(os) => CString::new(os.into_vec()),
613 Cow::Borrowed(os) => CString::new(os.as_bytes()),
614 }
615 .map_err(|_cstr_err| io::Errno::INVAL)?,
616 ))
617 }
618
619 #[inline]
620 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
621 where
622 Self: Sized,
623 F: FnOnce(&CStr) -> io::Result<T>,
624 {
625 with_c_str(self.as_bytes(), f)
626 }
627 }
628
629 impl<'a> Arg for Cow<'a, CStr> {
630 #[inline]
631 fn as_str(&self) -> io::Result<&str> {
632 self.to_str().map_err(|_utf8_err| io::Errno::INVAL)
633 }
634
635 #[inline]
636 fn to_string_lossy(&self) -> Cow<'_, str> {
637 let borrow: &CStr = core::borrow::Borrow::borrow(self);
638 borrow.to_string_lossy()
639 }
640
641 #[inline]
642 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
643 Ok(Cow::Borrowed(self))
644 }
645
646 #[inline]
647 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
648 where
649 Self: 'b,
650 {
651 Ok(self)
652 }
653
654 #[inline]
655 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
656 where
657 Self: Sized,
658 F: FnOnce(&CStr) -> io::Result<T>,
659 {
660 f(&self)
661 }
662 }
663
664 #[cfg(feature = "std")]
665 impl<'a> Arg for Component<'a> {
666 #[inline]
667 fn as_str(&self) -> io::Result<&str> {
668 self.as_os_str().to_str().ok_or(io::Errno::INVAL)
669 }
670
671 #[inline]
672 fn to_string_lossy(&self) -> Cow<'_, str> {
673 self.as_os_str().to_string_lossy()
674 }
675
676 #[inline]
677 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
678 Ok(Cow::Owned(
679 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
680 ))
681 }
682
683 #[inline]
684 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
685 where
686 Self: 'b,
687 {
688 Ok(Cow::Owned(
689 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
690 ))
691 }
692
693 #[inline]
694 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
695 where
696 Self: Sized,
697 F: FnOnce(&CStr) -> io::Result<T>,
698 {
699 with_c_str(self.as_os_str().as_bytes(), f)
700 }
701 }
702
703 #[cfg(feature = "std")]
704 impl<'a> Arg for Components<'a> {
705 #[inline]
706 fn as_str(&self) -> io::Result<&str> {
707 self.as_path().to_str().ok_or(io::Errno::INVAL)
708 }
709
710 #[inline]
711 fn to_string_lossy(&self) -> Cow<'_, str> {
712 self.as_path().to_string_lossy()
713 }
714
715 #[inline]
716 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
717 Ok(Cow::Owned(
718 CString::new(self.as_path().as_os_str().as_bytes())
719 .map_err(|_cstr_err| io::Errno::INVAL)?,
720 ))
721 }
722
723 #[inline]
724 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
725 where
726 Self: 'b,
727 {
728 Ok(Cow::Owned(
729 CString::new(self.as_path().as_os_str().as_bytes())
730 .map_err(|_cstr_err| io::Errno::INVAL)?,
731 ))
732 }
733
734 #[inline]
735 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
736 where
737 Self: Sized,
738 F: FnOnce(&CStr) -> io::Result<T>,
739 {
740 with_c_str(self.as_path().as_os_str().as_bytes(), f)
741 }
742 }
743
744 #[cfg(feature = "std")]
745 impl<'a> Arg for Iter<'a> {
746 #[inline]
747 fn as_str(&self) -> io::Result<&str> {
748 self.as_path().to_str().ok_or(io::Errno::INVAL)
749 }
750
751 #[inline]
752 fn to_string_lossy(&self) -> Cow<'_, str> {
753 self.as_path().to_string_lossy()
754 }
755
756 #[inline]
757 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
758 Ok(Cow::Owned(
759 CString::new(self.as_path().as_os_str().as_bytes())
760 .map_err(|_cstr_err| io::Errno::INVAL)?,
761 ))
762 }
763
764 #[inline]
765 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
766 where
767 Self: 'b,
768 {
769 Ok(Cow::Owned(
770 CString::new(self.as_path().as_os_str().as_bytes())
771 .map_err(|_cstr_err| io::Errno::INVAL)?,
772 ))
773 }
774
775 #[inline]
776 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
777 where
778 Self: Sized,
779 F: FnOnce(&CStr) -> io::Result<T>,
780 {
781 with_c_str(self.as_path().as_os_str().as_bytes(), f)
782 }
783 }
784
785 impl Arg for &[u8] {
786 #[inline]
787 fn as_str(&self) -> io::Result<&str> {
788 str::from_utf8(self).map_err(|_utf8_err| io::Errno::INVAL)
789 }
790
791 #[inline]
792 fn to_string_lossy(&self) -> Cow<'_, str> {
793 String::from_utf8_lossy(self)
794 }
795
796 #[inline]
797 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
798 Ok(Cow::Owned(
799 CString::new(*self).map_err(|_cstr_err| io::Errno::INVAL)?,
800 ))
801 }
802
803 #[inline]
804 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
805 where
806 Self: 'b,
807 {
808 Ok(Cow::Owned(
809 CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?,
810 ))
811 }
812
813 #[inline]
814 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
815 where
816 Self: Sized,
817 F: FnOnce(&CStr) -> io::Result<T>,
818 {
819 with_c_str(self, f)
820 }
821 }
822
823 impl Arg for &Vec<u8> {
824 #[inline]
825 fn as_str(&self) -> io::Result<&str> {
826 str::from_utf8(self).map_err(|_utf8_err| io::Errno::INVAL)
827 }
828
829 #[inline]
830 fn to_string_lossy(&self) -> Cow<'_, str> {
831 String::from_utf8_lossy(self)
832 }
833
834 #[inline]
835 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
836 Ok(Cow::Owned(
837 CString::new(self.as_slice()).map_err(|_cstr_err| io::Errno::INVAL)?,
838 ))
839 }
840
841 #[inline]
842 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
843 where
844 Self: 'b,
845 {
846 Ok(Cow::Owned(
847 CString::new(self.as_slice()).map_err(|_cstr_err| io::Errno::INVAL)?,
848 ))
849 }
850
851 #[inline]
852 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
853 where
854 Self: Sized,
855 F: FnOnce(&CStr) -> io::Result<T>,
856 {
857 with_c_str(self, f)
858 }
859 }
860
861 impl Arg for Vec<u8> {
862 #[inline]
863 fn as_str(&self) -> io::Result<&str> {
864 str::from_utf8(self).map_err(|_utf8_err| io::Errno::INVAL)
865 }
866
867 #[inline]
868 fn to_string_lossy(&self) -> Cow<'_, str> {
869 String::from_utf8_lossy(self)
870 }
871
872 #[inline]
873 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
874 Ok(Cow::Owned(
875 CString::new(self.as_slice()).map_err(|_cstr_err| io::Errno::INVAL)?,
876 ))
877 }
878
879 #[inline]
880 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
881 where
882 Self: 'b,
883 {
884 Ok(Cow::Owned(
885 CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?,
886 ))
887 }
888
889 #[inline]
890 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
891 where
892 Self: Sized,
893 F: FnOnce(&CStr) -> io::Result<T>,
894 {
895 f(&CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?)
896 }
897 }
898
899 #[cfg(feature = "itoa")]
900 impl Arg for DecInt {
901 #[inline]
902 fn as_str(&self) -> io::Result<&str> {
903 Ok(self.as_str())
904 }
905
906 #[inline]
907 fn to_string_lossy(&self) -> Cow<'_, str> {
908 Cow::Borrowed(self.as_str())
909 }
910
911 #[inline]
912 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
913 Ok(Cow::Borrowed(self.as_c_str()))
914 }
915
916 #[inline]
917 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
918 where
919 Self: 'b,
920 {
921 Ok(Cow::Owned(self.as_c_str().to_owned()))
922 }
923
924 #[inline]
925 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
926 where
927 Self: Sized,
928 F: FnOnce(&CStr) -> io::Result<T>,
929 {
930 f(self.as_c_str())
931 }
932 }
933
934 /// Runs a closure with `bytes` passed in as a `&CStr`.
935 #[allow(unsafe_code, clippy::int_plus_one)]
936 #[inline]
937 fn with_c_str<T, F>(bytes: &[u8], f: F) -> io::Result<T>
938 where
939 F: FnOnce(&CStr) -> io::Result<T>,
940 {
941 // Most paths are less than `SMALL_PATH_BUFFER_SIZE` long. The rest can go
942 // through the dynamic allocation path. If you're opening many files in a
943 // directory with a long path, consider opening the directory and using
944 // `openat` to open the files under it, which will avoid this, and is often
945 // faster in the OS as well.
946
947 // Test with >= so that we have room for the trailing NUL.
948 if bytes.len() >= SMALL_PATH_BUFFER_SIZE {
949 return with_c_str_slow_path(bytes, f);
950 }
951
952 // Taken from
953 // <https://github.com/rust-lang/rust/blob/a00f8ba7fcac1b27341679c51bf5a3271fa82df3/library/std/src/sys/common/small_c_string.rs>
954 let mut buf = MaybeUninit::<[u8; SMALL_PATH_BUFFER_SIZE]>::uninit();
955 let buf_ptr = buf.as_mut_ptr() as *mut u8;
956
957 // This helps test our safety condition below.
958 debug_assert!(bytes.len() + 1 <= SMALL_PATH_BUFFER_SIZE);
959
960 // SAFETY: `bytes.len() < SMALL_PATH_BUFFER_SIZE` which means we have space for
961 // `bytes.len() + 1` u8s:
962 unsafe {
963 ptr::copy_nonoverlapping(bytes.as_ptr(), buf_ptr, bytes.len());
964 buf_ptr.add(bytes.len()).write(0);
965 }
966
967 // SAFETY: we just wrote the bytes above and they will remain valid for the
968 // duration of f b/c buf doesn't get dropped until the end of the function.
969 match CStr::from_bytes_with_nul(unsafe { slice::from_raw_parts(buf_ptr, bytes.len() + 1) }) {
970 Ok(s) => f(s),
971 Err(_) => Err(io::Errno::INVAL),
972 }
973 }
974
975 /// The slow path which handles any length. In theory OS's only support up
976 /// to `PATH_MAX`, but we let the OS enforce that.
977 #[cold]
978 fn with_c_str_slow_path<T, F>(bytes: &[u8], f: F) -> io::Result<T>
979 where
980 F: FnOnce(&CStr) -> io::Result<T>,
981 {
982 f(&CString::new(bytes).map_err(|_cstr_err| io::Errno::INVAL)?)
983 }