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