1use crate::ffi::CStr;
10use crate::io;
11#[cfg(feature = "itoa")]
12use crate::path::DecInt;
13use crate::path::SMALL_PATH_BUFFER_SIZE;
14#[cfg(all(feature = "alloc", feature = "itoa"))]
15use alloc::borrow::ToOwned;
16use core::mem::MaybeUninit;
17use core::{ptr, slice, str};
18#[cfg(feature = "std")]
19use std::ffi::{OsStr, OsString};
20#[cfg(all(feature = "std", target_os = "hermit"))]
21use std::os::hermit::ext::ffi::{OsStrExt, OsStringExt};
22#[cfg(all(feature = "std", unix))]
23use std::os::unix::ffi::{OsStrExt, OsStringExt};
24#[cfg(all(feature = "std", target_os = "vxworks"))]
25use std::os::vxworks::ext::ffi::{OsStrExt, OsStringExt};
26#[cfg(all(feature = "std", target_os = "wasi"))]
27use std::os::wasi::ffi::{OsStrExt, OsStringExt};
28#[cfg(feature = "std")]
29use std::path::{Component, Components, Iter, Path, PathBuf};
30#[cfg(feature = "alloc")]
31use {crate::ffi::CString, alloc::borrow::Cow};
32#[cfg(feature = "alloc")]
33use {alloc::string::String, alloc::vec::Vec};
34
35pub trait Arg {
67 fn as_str(&self) -> io::Result<&str>;
69
70 #[cfg(feature = "alloc")]
73 fn to_string_lossy(&self) -> Cow<'_, str>;
74
75 #[cfg(feature = "alloc")]
77 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>>;
78
79 #[cfg(feature = "alloc")]
82 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
83 where
84 Self: 'b;
85
86 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
88 where
89 Self: Sized,
90 F: FnOnce(&CStr) -> io::Result<T>;
91}
92
93pub fn option_into_with_c_str<T, F, A>(arg: Option<A>, f: F) -> io::Result<T>
95where
96 A: Arg + Sized,
97 F: FnOnce(Option<&CStr>) -> io::Result<T>,
98{
99 if let Some(arg) = arg {
100 arg.into_with_c_str(|p| f(Some(p)))
101 } else {
102 f(None)
103 }
104}
105
106impl Arg for &str {
107 #[inline]
108 fn as_str(&self) -> io::Result<&str> {
109 Ok(self)
110 }
111
112 #[cfg(feature = "alloc")]
113 #[inline]
114 fn to_string_lossy(&self) -> Cow<'_, str> {
115 Cow::Borrowed(self)
116 }
117
118 #[cfg(feature = "alloc")]
119 #[inline]
120 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
121 Ok(Cow::Owned(
122 CString::new(*self).map_err(|_cstr_err| io::Errno::INVAL)?,
123 ))
124 }
125
126 #[cfg(feature = "alloc")]
127 #[inline]
128 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
129 where
130 Self: 'b,
131 {
132 Ok(Cow::Owned(
133 CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?,
134 ))
135 }
136
137 #[inline]
138 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
139 where
140 Self: Sized,
141 F: FnOnce(&CStr) -> io::Result<T>,
142 {
143 with_c_str(self.as_bytes(), f)
144 }
145}
146
147#[cfg(feature = "alloc")]
148impl Arg for &String {
149 #[inline]
150 fn as_str(&self) -> io::Result<&str> {
151 Ok(self)
152 }
153
154 #[cfg(feature = "alloc")]
155 #[inline]
156 fn to_string_lossy(&self) -> Cow<'_, str> {
157 Cow::Borrowed(self)
158 }
159
160 #[cfg(feature = "alloc")]
161 #[inline]
162 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
163 Ok(Cow::Owned(
164 CString::new(String::as_str(self)).map_err(|_cstr_err| io::Errno::INVAL)?,
165 ))
166 }
167
168 #[cfg(feature = "alloc")]
169 #[inline]
170 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
171 where
172 Self: 'b,
173 {
174 self.as_str().into_c_str()
175 }
176
177 #[inline]
178 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
179 where
180 Self: Sized,
181 F: FnOnce(&CStr) -> io::Result<T>,
182 {
183 with_c_str(self.as_bytes(), f)
184 }
185}
186
187#[cfg(feature = "alloc")]
188impl Arg for String {
189 #[inline]
190 fn as_str(&self) -> io::Result<&str> {
191 Ok(self)
192 }
193
194 #[cfg(feature = "alloc")]
195 #[inline]
196 fn to_string_lossy(&self) -> Cow<'_, str> {
197 Cow::Borrowed(self)
198 }
199
200 #[cfg(feature = "alloc")]
201 #[inline]
202 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
203 Ok(Cow::Owned(
204 CString::new(self.as_str()).map_err(|_cstr_err| io::Errno::INVAL)?,
205 ))
206 }
207
208 #[cfg(feature = "alloc")]
209 #[inline]
210 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
211 where
212 Self: 'b,
213 {
214 Ok(Cow::Owned(
215 CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?,
216 ))
217 }
218
219 #[inline]
220 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
221 where
222 Self: Sized,
223 F: FnOnce(&CStr) -> io::Result<T>,
224 {
225 f(&CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?)
226 }
227}
228
229#[cfg(feature = "std")]
230impl Arg for &OsStr {
231 #[inline]
232 fn as_str(&self) -> io::Result<&str> {
233 self.to_str().ok_or(io::Errno::INVAL)
234 }
235
236 #[cfg(feature = "alloc")]
237 #[inline]
238 fn to_string_lossy(&self) -> Cow<'_, str> {
239 OsStr::to_string_lossy(self)
240 }
241
242 #[cfg(feature = "alloc")]
243 #[inline]
244 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
245 Ok(Cow::Owned(
246 CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
247 ))
248 }
249
250 #[cfg(feature = "alloc")]
251 #[inline]
252 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
253 where
254 Self: 'b,
255 {
256 Ok(Cow::Owned(
257 CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
258 ))
259 }
260
261 #[inline]
262 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
263 where
264 Self: Sized,
265 F: FnOnce(&CStr) -> io::Result<T>,
266 {
267 with_c_str(self.as_bytes(), f)
268 }
269}
270
271#[cfg(feature = "std")]
272impl Arg for &OsString {
273 #[inline]
274 fn as_str(&self) -> io::Result<&str> {
275 OsString::as_os_str(self).to_str().ok_or(io::Errno::INVAL)
276 }
277
278 #[cfg(feature = "alloc")]
279 #[inline]
280 fn to_string_lossy(&self) -> Cow<'_, str> {
281 self.as_os_str().to_string_lossy()
282 }
283
284 #[cfg(feature = "alloc")]
285 #[inline]
286 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
287 Ok(Cow::Owned(
288 CString::new(OsString::as_os_str(self).as_bytes())
289 .map_err(|_cstr_err| io::Errno::INVAL)?,
290 ))
291 }
292
293 #[cfg(feature = "alloc")]
294 #[inline]
295 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
296 where
297 Self: 'b,
298 {
299 self.as_os_str().into_c_str()
300 }
301
302 #[inline]
303 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
304 where
305 Self: Sized,
306 F: FnOnce(&CStr) -> io::Result<T>,
307 {
308 with_c_str(self.as_bytes(), f)
309 }
310}
311
312#[cfg(feature = "std")]
313impl Arg for OsString {
314 #[inline]
315 fn as_str(&self) -> io::Result<&str> {
316 self.as_os_str().to_str().ok_or(io::Errno::INVAL)
317 }
318
319 #[cfg(feature = "alloc")]
320 #[inline]
321 fn to_string_lossy(&self) -> Cow<'_, str> {
322 self.as_os_str().to_string_lossy()
323 }
324
325 #[cfg(feature = "alloc")]
326 #[inline]
327 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
328 Ok(Cow::Owned(
329 CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
330 ))
331 }
332
333 #[cfg(feature = "alloc")]
334 #[inline]
335 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
336 where
337 Self: 'b,
338 {
339 Ok(Cow::Owned(
340 CString::new(self.into_vec()).map_err(|_cstr_err| io::Errno::INVAL)?,
341 ))
342 }
343
344 #[inline]
345 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
346 where
347 Self: Sized,
348 F: FnOnce(&CStr) -> io::Result<T>,
349 {
350 f(&CString::new(self.into_vec()).map_err(|_cstr_err| io::Errno::INVAL)?)
351 }
352}
353
354#[cfg(feature = "std")]
355impl Arg for &Path {
356 #[inline]
357 fn as_str(&self) -> io::Result<&str> {
358 self.as_os_str().to_str().ok_or(io::Errno::INVAL)
359 }
360
361 #[cfg(feature = "alloc")]
362 #[inline]
363 fn to_string_lossy(&self) -> Cow<'_, str> {
364 Path::to_string_lossy(self)
365 }
366
367 #[cfg(feature = "alloc")]
368 #[inline]
369 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
370 Ok(Cow::Owned(
371 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
372 ))
373 }
374
375 #[cfg(feature = "alloc")]
376 #[inline]
377 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
378 where
379 Self: 'b,
380 {
381 Ok(Cow::Owned(
382 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
383 ))
384 }
385
386 #[inline]
387 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
388 where
389 Self: Sized,
390 F: FnOnce(&CStr) -> io::Result<T>,
391 {
392 with_c_str(self.as_os_str().as_bytes(), f)
393 }
394}
395
396#[cfg(feature = "std")]
397impl Arg for &PathBuf {
398 #[inline]
399 fn as_str(&self) -> io::Result<&str> {
400 PathBuf::as_path(self)
401 .as_os_str()
402 .to_str()
403 .ok_or(io::Errno::INVAL)
404 }
405
406 #[cfg(feature = "alloc")]
407 #[inline]
408 fn to_string_lossy(&self) -> Cow<'_, str> {
409 self.as_path().to_string_lossy()
410 }
411
412 #[cfg(feature = "alloc")]
413 #[inline]
414 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
415 Ok(Cow::Owned(
416 CString::new(PathBuf::as_path(self).as_os_str().as_bytes())
417 .map_err(|_cstr_err| io::Errno::INVAL)?,
418 ))
419 }
420
421 #[cfg(feature = "alloc")]
422 #[inline]
423 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
424 where
425 Self: 'b,
426 {
427 self.as_path().into_c_str()
428 }
429
430 #[inline]
431 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
432 where
433 Self: Sized,
434 F: FnOnce(&CStr) -> io::Result<T>,
435 {
436 with_c_str(self.as_os_str().as_bytes(), f)
437 }
438}
439
440#[cfg(feature = "std")]
441impl Arg for PathBuf {
442 #[inline]
443 fn as_str(&self) -> io::Result<&str> {
444 self.as_os_str().to_str().ok_or(io::Errno::INVAL)
445 }
446
447 #[cfg(feature = "alloc")]
448 #[inline]
449 fn to_string_lossy(&self) -> Cow<'_, str> {
450 self.as_os_str().to_string_lossy()
451 }
452
453 #[cfg(feature = "alloc")]
454 #[inline]
455 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
456 Ok(Cow::Owned(
457 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
458 ))
459 }
460
461 #[cfg(feature = "alloc")]
462 #[inline]
463 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
464 where
465 Self: 'b,
466 {
467 Ok(Cow::Owned(
468 CString::new(self.into_os_string().into_vec()).map_err(|_cstr_err| io::Errno::INVAL)?,
469 ))
470 }
471
472 #[inline]
473 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
474 where
475 Self: Sized,
476 F: FnOnce(&CStr) -> io::Result<T>,
477 {
478 f(
479 &CString::new(self.into_os_string().into_vec())
480 .map_err(|_cstr_err| io::Errno::INVAL)?,
481 )
482 }
483}
484
485impl Arg for &CStr {
486 #[inline]
487 fn as_str(&self) -> io::Result<&str> {
488 self.to_str().map_err(|_utf8_err| io::Errno::INVAL)
489 }
490
491 #[cfg(feature = "alloc")]
492 #[inline]
493 fn to_string_lossy(&self) -> Cow<'_, str> {
494 CStr::to_string_lossy(self)
495 }
496
497 #[cfg(feature = "alloc")]
498 #[inline]
499 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
500 Ok(Cow::Borrowed(self))
501 }
502
503 #[cfg(feature = "alloc")]
504 #[inline]
505 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
506 where
507 Self: 'b,
508 {
509 Ok(Cow::Borrowed(self))
510 }
511
512 #[inline]
513 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
514 where
515 Self: Sized,
516 F: FnOnce(&CStr) -> io::Result<T>,
517 {
518 f(self)
519 }
520}
521
522#[cfg(feature = "alloc")]
523impl Arg for &CString {
524 #[inline]
525 fn as_str(&self) -> io::Result<&str> {
526 unimplemented!()
527 }
528
529 #[cfg(feature = "alloc")]
530 #[inline]
531 fn to_string_lossy(&self) -> Cow<'_, str> {
532 unimplemented!()
533 }
534
535 #[cfg(feature = "alloc")]
536 #[inline]
537 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
538 Ok(Cow::Borrowed(self))
539 }
540
541 #[cfg(feature = "alloc")]
542 #[inline]
543 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
544 where
545 Self: 'b,
546 {
547 Ok(Cow::Borrowed(self))
548 }
549
550 #[inline]
551 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
552 where
553 Self: Sized,
554 F: FnOnce(&CStr) -> io::Result<T>,
555 {
556 f(self)
557 }
558}
559
560#[cfg(feature = "alloc")]
561impl Arg for CString {
562 #[inline]
563 fn as_str(&self) -> io::Result<&str> {
564 self.to_str().map_err(|_utf8_err| io::Errno::INVAL)
565 }
566
567 #[cfg(feature = "alloc")]
568 #[inline]
569 fn to_string_lossy(&self) -> Cow<'_, str> {
570 CStr::to_string_lossy(self)
571 }
572
573 #[cfg(feature = "alloc")]
574 #[inline]
575 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
576 Ok(Cow::Borrowed(self))
577 }
578
579 #[cfg(feature = "alloc")]
580 #[inline]
581 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
582 where
583 Self: 'b,
584 {
585 Ok(Cow::Owned(self))
586 }
587
588 #[inline]
589 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
590 where
591 Self: Sized,
592 F: FnOnce(&CStr) -> io::Result<T>,
593 {
594 f(&self)
595 }
596}
597
598#[cfg(feature = "alloc")]
599impl<'a> Arg for Cow<'a, str> {
600 #[inline]
601 fn as_str(&self) -> io::Result<&str> {
602 Ok(self)
603 }
604
605 #[cfg(feature = "alloc")]
606 #[inline]
607 fn to_string_lossy(&self) -> Cow<'_, str> {
608 Cow::Borrowed(self)
609 }
610
611 #[cfg(feature = "alloc")]
612 #[inline]
613 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
614 Ok(Cow::Owned(
615 CString::new(self.as_ref()).map_err(|_cstr_err| io::Errno::INVAL)?,
616 ))
617 }
618
619 #[cfg(feature = "alloc")]
620 #[inline]
621 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
622 where
623 Self: 'b,
624 {
625 Ok(Cow::Owned(
626 match self {
627 Cow::Owned(s) => CString::new(s),
628 Cow::Borrowed(s) => CString::new(s),
629 }
630 .map_err(|_cstr_err| io::Errno::INVAL)?,
631 ))
632 }
633
634 #[inline]
635 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
636 where
637 Self: Sized,
638 F: FnOnce(&CStr) -> io::Result<T>,
639 {
640 with_c_str(self.as_bytes(), f)
641 }
642}
643
644#[cfg(feature = "std")]
645#[cfg(feature = "alloc")]
646impl<'a> Arg for Cow<'a, OsStr> {
647 #[inline]
648 fn as_str(&self) -> io::Result<&str> {
649 (**self).to_str().ok_or(io::Errno::INVAL)
650 }
651
652 #[cfg(feature = "alloc")]
653 #[inline]
654 fn to_string_lossy(&self) -> Cow<'_, str> {
655 (**self).to_string_lossy()
656 }
657
658 #[cfg(feature = "alloc")]
659 #[inline]
660 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
661 Ok(Cow::Owned(
662 CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
663 ))
664 }
665
666 #[cfg(feature = "alloc")]
667 #[inline]
668 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
669 where
670 Self: 'b,
671 {
672 Ok(Cow::Owned(
673 match self {
674 Cow::Owned(os) => CString::new(os.into_vec()),
675 Cow::Borrowed(os) => CString::new(os.as_bytes()),
676 }
677 .map_err(|_cstr_err| io::Errno::INVAL)?,
678 ))
679 }
680
681 #[inline]
682 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
683 where
684 Self: Sized,
685 F: FnOnce(&CStr) -> io::Result<T>,
686 {
687 with_c_str(self.as_bytes(), f)
688 }
689}
690
691#[cfg(feature = "alloc")]
692impl<'a> Arg for Cow<'a, CStr> {
693 #[inline]
694 fn as_str(&self) -> io::Result<&str> {
695 self.to_str().map_err(|_utf8_err| io::Errno::INVAL)
696 }
697
698 #[cfg(feature = "alloc")]
699 #[inline]
700 fn to_string_lossy(&self) -> Cow<'_, str> {
701 let borrow: &CStr = core::borrow::Borrow::borrow(self);
702 borrow.to_string_lossy()
703 }
704
705 #[cfg(feature = "alloc")]
706 #[inline]
707 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
708 Ok(Cow::Borrowed(self))
709 }
710
711 #[cfg(feature = "alloc")]
712 #[inline]
713 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
714 where
715 Self: 'b,
716 {
717 Ok(self)
718 }
719
720 #[inline]
721 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
722 where
723 Self: Sized,
724 F: FnOnce(&CStr) -> io::Result<T>,
725 {
726 f(&self)
727 }
728}
729
730#[cfg(feature = "std")]
731impl<'a> Arg for Component<'a> {
732 #[inline]
733 fn as_str(&self) -> io::Result<&str> {
734 self.as_os_str().to_str().ok_or(io::Errno::INVAL)
735 }
736
737 #[cfg(feature = "alloc")]
738 #[inline]
739 fn to_string_lossy(&self) -> Cow<'_, str> {
740 self.as_os_str().to_string_lossy()
741 }
742
743 #[cfg(feature = "alloc")]
744 #[inline]
745 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
746 Ok(Cow::Owned(
747 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
748 ))
749 }
750
751 #[cfg(feature = "alloc")]
752 #[inline]
753 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
754 where
755 Self: 'b,
756 {
757 Ok(Cow::Owned(
758 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
759 ))
760 }
761
762 #[inline]
763 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
764 where
765 Self: Sized,
766 F: FnOnce(&CStr) -> io::Result<T>,
767 {
768 with_c_str(self.as_os_str().as_bytes(), f)
769 }
770}
771
772#[cfg(feature = "std")]
773impl<'a> Arg for Components<'a> {
774 #[inline]
775 fn as_str(&self) -> io::Result<&str> {
776 self.as_path().to_str().ok_or(io::Errno::INVAL)
777 }
778
779 #[cfg(feature = "alloc")]
780 #[inline]
781 fn to_string_lossy(&self) -> Cow<'_, str> {
782 self.as_path().to_string_lossy()
783 }
784
785 #[cfg(feature = "alloc")]
786 #[inline]
787 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
788 Ok(Cow::Owned(
789 CString::new(self.as_path().as_os_str().as_bytes())
790 .map_err(|_cstr_err| io::Errno::INVAL)?,
791 ))
792 }
793
794 #[cfg(feature = "alloc")]
795 #[inline]
796 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
797 where
798 Self: 'b,
799 {
800 Ok(Cow::Owned(
801 CString::new(self.as_path().as_os_str().as_bytes())
802 .map_err(|_cstr_err| io::Errno::INVAL)?,
803 ))
804 }
805
806 #[inline]
807 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
808 where
809 Self: Sized,
810 F: FnOnce(&CStr) -> io::Result<T>,
811 {
812 with_c_str(self.as_path().as_os_str().as_bytes(), f)
813 }
814}
815
816#[cfg(feature = "std")]
817impl<'a> Arg for Iter<'a> {
818 #[inline]
819 fn as_str(&self) -> io::Result<&str> {
820 self.as_path().to_str().ok_or(io::Errno::INVAL)
821 }
822
823 #[cfg(feature = "alloc")]
824 #[inline]
825 fn to_string_lossy(&self) -> Cow<'_, str> {
826 self.as_path().to_string_lossy()
827 }
828
829 #[cfg(feature = "alloc")]
830 #[inline]
831 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
832 Ok(Cow::Owned(
833 CString::new(self.as_path().as_os_str().as_bytes())
834 .map_err(|_cstr_err| io::Errno::INVAL)?,
835 ))
836 }
837
838 #[cfg(feature = "alloc")]
839 #[inline]
840 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
841 where
842 Self: 'b,
843 {
844 Ok(Cow::Owned(
845 CString::new(self.as_path().as_os_str().as_bytes())
846 .map_err(|_cstr_err| io::Errno::INVAL)?,
847 ))
848 }
849
850 #[inline]
851 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
852 where
853 Self: Sized,
854 F: FnOnce(&CStr) -> io::Result<T>,
855 {
856 with_c_str(self.as_path().as_os_str().as_bytes(), f)
857 }
858}
859
860impl Arg for &[u8] {
861 #[inline]
862 fn as_str(&self) -> io::Result<&str> {
863 str::from_utf8(self).map_err(|_utf8_err| io::Errno::INVAL)
864 }
865
866 #[cfg(feature = "alloc")]
867 #[inline]
868 fn to_string_lossy(&self) -> Cow<'_, str> {
869 String::from_utf8_lossy(self)
870 }
871
872 #[cfg(feature = "alloc")]
873 #[inline]
874 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
875 Ok(Cow::Owned(
876 CString::new(*self).map_err(|_cstr_err| io::Errno::INVAL)?,
877 ))
878 }
879
880 #[cfg(feature = "alloc")]
881 #[inline]
882 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
883 where
884 Self: 'b,
885 {
886 Ok(Cow::Owned(
887 CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?,
888 ))
889 }
890
891 #[inline]
892 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
893 where
894 Self: Sized,
895 F: FnOnce(&CStr) -> io::Result<T>,
896 {
897 with_c_str(self, f)
898 }
899}
900
901#[cfg(feature = "alloc")]
902impl Arg for &Vec<u8> {
903 #[inline]
904 fn as_str(&self) -> io::Result<&str> {
905 str::from_utf8(self).map_err(|_utf8_err| io::Errno::INVAL)
906 }
907
908 #[cfg(feature = "alloc")]
909 #[inline]
910 fn to_string_lossy(&self) -> Cow<'_, str> {
911 String::from_utf8_lossy(self)
912 }
913
914 #[cfg(feature = "alloc")]
915 #[inline]
916 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
917 Ok(Cow::Owned(
918 CString::new(self.as_slice()).map_err(|_cstr_err| io::Errno::INVAL)?,
919 ))
920 }
921
922 #[cfg(feature = "alloc")]
923 #[inline]
924 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
925 where
926 Self: 'b,
927 {
928 Ok(Cow::Owned(
929 CString::new(self.as_slice()).map_err(|_cstr_err| io::Errno::INVAL)?,
930 ))
931 }
932
933 #[inline]
934 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
935 where
936 Self: Sized,
937 F: FnOnce(&CStr) -> io::Result<T>,
938 {
939 with_c_str(self, f)
940 }
941}
942
943#[cfg(feature = "alloc")]
944impl Arg for Vec<u8> {
945 #[inline]
946 fn as_str(&self) -> io::Result<&str> {
947 str::from_utf8(self).map_err(|_utf8_err| io::Errno::INVAL)
948 }
949
950 #[cfg(feature = "alloc")]
951 #[inline]
952 fn to_string_lossy(&self) -> Cow<'_, str> {
953 String::from_utf8_lossy(self)
954 }
955
956 #[cfg(feature = "alloc")]
957 #[inline]
958 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
959 Ok(Cow::Owned(
960 CString::new(self.as_slice()).map_err(|_cstr_err| io::Errno::INVAL)?,
961 ))
962 }
963
964 #[cfg(feature = "alloc")]
965 #[inline]
966 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
967 where
968 Self: 'b,
969 {
970 Ok(Cow::Owned(
971 CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?,
972 ))
973 }
974
975 #[inline]
976 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
977 where
978 Self: Sized,
979 F: FnOnce(&CStr) -> io::Result<T>,
980 {
981 f(&CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?)
982 }
983}
984
985#[cfg(feature = "itoa")]
986impl Arg for DecInt {
987 #[inline]
988 fn as_str(&self) -> io::Result<&str> {
989 Ok(self.as_str())
990 }
991
992 #[cfg(feature = "alloc")]
993 #[inline]
994 fn to_string_lossy(&self) -> Cow<'_, str> {
995 Cow::Borrowed(self.as_str())
996 }
997
998 #[cfg(feature = "alloc")]
999 #[inline]
1000 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
1001 Ok(Cow::Borrowed(self.as_c_str()))
1002 }
1003
1004 #[cfg(feature = "alloc")]
1005 #[inline]
1006 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
1007 where
1008 Self: 'b,
1009 {
1010 Ok(Cow::Owned(self.as_c_str().to_owned()))
1011 }
1012
1013 #[inline]
1014 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
1015 where
1016 Self: Sized,
1017 F: FnOnce(&CStr) -> io::Result<T>,
1018 {
1019 f(self.as_c_str())
1020 }
1021}
1022
1023#[allow(unsafe_code, clippy::int_plus_one)]
1025#[inline]
1026fn with_c_str<T, F>(bytes: &[u8], f: F) -> io::Result<T>
1027where
1028 F: FnOnce(&CStr) -> io::Result<T>,
1029{
1030 if bytes.len() >= SMALL_PATH_BUFFER_SIZE {
1038 return with_c_str_slow_path(bytes, f);
1039 }
1040
1041 let mut buf = MaybeUninit::<[u8; SMALL_PATH_BUFFER_SIZE]>::uninit();
1044 let buf_ptr = buf.as_mut_ptr().cast::<u8>();
1045
1046 debug_assert!(bytes.len() + 1 <= SMALL_PATH_BUFFER_SIZE);
1048
1049 unsafe {
1052 ptr::copy_nonoverlapping(bytes.as_ptr(), buf_ptr, bytes.len());
1053 buf_ptr.add(bytes.len()).write(0);
1054 }
1055
1056 match CStr::from_bytes_with_nul(unsafe { slice::from_raw_parts(buf_ptr, bytes.len() + 1) }) {
1060 Ok(s) => f(s),
1061 Err(_) => Err(io::Errno::INVAL),
1062 }
1063}
1064
1065#[allow(unsafe_code, clippy::int_plus_one)]
1068#[cold]
1069fn with_c_str_slow_path<T, F>(bytes: &[u8], f: F) -> io::Result<T>
1070where
1071 F: FnOnce(&CStr) -> io::Result<T>,
1072{
1073 #[cfg(feature = "alloc")]
1074 {
1075 f(&CString::new(bytes).map_err(|_cstr_err| io::Errno::INVAL)?)
1076 }
1077
1078 #[cfg(not(feature = "alloc"))]
1079 {
1080 #[cfg(all(libc, not(any(target_os = "hurd", target_os = "wasi"))))]
1081 const LARGE_PATH_BUFFER_SIZE: usize = libc::PATH_MAX as usize;
1082 #[cfg(linux_raw)]
1083 const LARGE_PATH_BUFFER_SIZE: usize = linux_raw_sys::general::PATH_MAX as usize;
1084 #[cfg(any(target_os = "hurd", target_os = "wasi"))]
1085 const LARGE_PATH_BUFFER_SIZE: usize = 4096 as usize; let mut buf = MaybeUninit::<[u8; LARGE_PATH_BUFFER_SIZE]>::uninit();
1090 let buf_ptr = buf.as_mut_ptr().cast::<u8>();
1091
1092 if bytes.len() + 1 > LARGE_PATH_BUFFER_SIZE {
1094 return Err(io::Errno::NAMETOOLONG);
1095 }
1096
1097 unsafe {
1100 ptr::copy_nonoverlapping(bytes.as_ptr(), buf_ptr, bytes.len());
1101 buf_ptr.add(bytes.len()).write(0);
1102 }
1103
1104 match CStr::from_bytes_with_nul(unsafe { slice::from_raw_parts(buf_ptr, bytes.len() + 1) })
1108 {
1109 Ok(s) => f(s),
1110 Err(_) => Err(io::Errno::INVAL),
1111 }
1112 }
1113}