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")]
232#[cfg(any(not(target_os = "wasi"), not(target_env = "p2"), wasip2))]
233impl Arg for &OsStr {
234 #[inline]
235 fn as_str(&self) -> io::Result<&str> {
236 self.to_str().ok_or(io::Errno::INVAL)
237 }
238
239 #[inline]
240 fn to_string_lossy(&self) -> Cow<'_, str> {
241 OsStr::to_string_lossy(self)
242 }
243
244 #[inline]
245 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
246 Ok(Cow::Owned(
247 CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
248 ))
249 }
250
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")]
272#[cfg(any(not(target_os = "wasi"), not(target_env = "p2"), wasip2))]
273impl Arg for &OsString {
274 #[inline]
275 fn as_str(&self) -> io::Result<&str> {
276 OsString::as_os_str(self).to_str().ok_or(io::Errno::INVAL)
277 }
278
279 #[inline]
280 fn to_string_lossy(&self) -> Cow<'_, str> {
281 self.as_os_str().to_string_lossy()
282 }
283
284 #[inline]
285 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
286 Ok(Cow::Owned(
287 CString::new(OsString::as_os_str(self).as_bytes())
288 .map_err(|_cstr_err| io::Errno::INVAL)?,
289 ))
290 }
291
292 #[inline]
293 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
294 where
295 Self: 'b,
296 {
297 self.as_os_str().into_c_str()
298 }
299
300 #[inline]
301 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
302 where
303 Self: Sized,
304 F: FnOnce(&CStr) -> io::Result<T>,
305 {
306 with_c_str(self.as_bytes(), f)
307 }
308}
309
310#[cfg(feature = "std")]
311#[cfg(any(not(target_os = "wasi"), not(target_env = "p2"), wasip2))]
312impl Arg for OsString {
313 #[inline]
314 fn as_str(&self) -> io::Result<&str> {
315 self.as_os_str().to_str().ok_or(io::Errno::INVAL)
316 }
317
318 #[inline]
319 fn to_string_lossy(&self) -> Cow<'_, str> {
320 self.as_os_str().to_string_lossy()
321 }
322
323 #[inline]
324 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
325 Ok(Cow::Owned(
326 CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
327 ))
328 }
329
330 #[inline]
331 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
332 where
333 Self: 'b,
334 {
335 Ok(Cow::Owned(
336 CString::new(self.into_vec()).map_err(|_cstr_err| io::Errno::INVAL)?,
337 ))
338 }
339
340 #[inline]
341 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
342 where
343 Self: Sized,
344 F: FnOnce(&CStr) -> io::Result<T>,
345 {
346 f(&CString::new(self.into_vec()).map_err(|_cstr_err| io::Errno::INVAL)?)
347 }
348}
349
350#[cfg(feature = "std")]
351#[cfg(any(not(target_os = "wasi"), not(target_env = "p2"), wasip2))]
352impl Arg for &Path {
353 #[inline]
354 fn as_str(&self) -> io::Result<&str> {
355 self.as_os_str().to_str().ok_or(io::Errno::INVAL)
356 }
357
358 #[inline]
359 fn to_string_lossy(&self) -> Cow<'_, str> {
360 Path::to_string_lossy(self)
361 }
362
363 #[inline]
364 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
365 Ok(Cow::Owned(
366 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
367 ))
368 }
369
370 #[inline]
371 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
372 where
373 Self: 'b,
374 {
375 Ok(Cow::Owned(
376 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
377 ))
378 }
379
380 #[inline]
381 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
382 where
383 Self: Sized,
384 F: FnOnce(&CStr) -> io::Result<T>,
385 {
386 with_c_str(self.as_os_str().as_bytes(), f)
387 }
388}
389
390#[cfg(feature = "std")]
391#[cfg(any(not(target_os = "wasi"), not(target_env = "p2"), wasip2))]
392impl Arg for &PathBuf {
393 #[inline]
394 fn as_str(&self) -> io::Result<&str> {
395 PathBuf::as_path(self)
396 .as_os_str()
397 .to_str()
398 .ok_or(io::Errno::INVAL)
399 }
400
401 #[inline]
402 fn to_string_lossy(&self) -> Cow<'_, str> {
403 self.as_path().to_string_lossy()
404 }
405
406 #[inline]
407 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
408 Ok(Cow::Owned(
409 CString::new(PathBuf::as_path(self).as_os_str().as_bytes())
410 .map_err(|_cstr_err| io::Errno::INVAL)?,
411 ))
412 }
413
414 #[inline]
415 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
416 where
417 Self: 'b,
418 {
419 self.as_path().into_c_str()
420 }
421
422 #[inline]
423 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
424 where
425 Self: Sized,
426 F: FnOnce(&CStr) -> io::Result<T>,
427 {
428 with_c_str(self.as_os_str().as_bytes(), f)
429 }
430}
431
432#[cfg(feature = "std")]
433#[cfg(any(not(target_os = "wasi"), not(target_env = "p2"), wasip2))]
434impl Arg for PathBuf {
435 #[inline]
436 fn as_str(&self) -> io::Result<&str> {
437 self.as_os_str().to_str().ok_or(io::Errno::INVAL)
438 }
439
440 #[inline]
441 fn to_string_lossy(&self) -> Cow<'_, str> {
442 self.as_os_str().to_string_lossy()
443 }
444
445 #[inline]
446 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
447 Ok(Cow::Owned(
448 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
449 ))
450 }
451
452 #[inline]
453 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
454 where
455 Self: 'b,
456 {
457 Ok(Cow::Owned(
458 CString::new(self.into_os_string().into_vec()).map_err(|_cstr_err| io::Errno::INVAL)?,
459 ))
460 }
461
462 #[inline]
463 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
464 where
465 Self: Sized,
466 F: FnOnce(&CStr) -> io::Result<T>,
467 {
468 f(
469 &CString::new(self.into_os_string().into_vec())
470 .map_err(|_cstr_err| io::Errno::INVAL)?,
471 )
472 }
473}
474
475impl Arg for &CStr {
476 #[inline]
477 fn as_str(&self) -> io::Result<&str> {
478 self.to_str().map_err(|_utf8_err| io::Errno::INVAL)
479 }
480
481 #[cfg(feature = "alloc")]
482 #[inline]
483 fn to_string_lossy(&self) -> Cow<'_, str> {
484 CStr::to_string_lossy(self)
485 }
486
487 #[cfg(feature = "alloc")]
488 #[inline]
489 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
490 Ok(Cow::Borrowed(self))
491 }
492
493 #[cfg(feature = "alloc")]
494 #[inline]
495 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
496 where
497 Self: 'b,
498 {
499 Ok(Cow::Borrowed(self))
500 }
501
502 #[inline]
503 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
504 where
505 Self: Sized,
506 F: FnOnce(&CStr) -> io::Result<T>,
507 {
508 f(self)
509 }
510}
511
512#[cfg(feature = "alloc")]
513impl Arg for &CString {
514 #[inline]
515 fn as_str(&self) -> io::Result<&str> {
516 unimplemented!()
517 }
518
519 #[inline]
520 fn to_string_lossy(&self) -> Cow<'_, str> {
521 unimplemented!()
522 }
523
524 #[inline]
525 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
526 Ok(Cow::Borrowed(self))
527 }
528
529 #[inline]
530 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
531 where
532 Self: 'b,
533 {
534 Ok(Cow::Borrowed(self))
535 }
536
537 #[inline]
538 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
539 where
540 Self: Sized,
541 F: FnOnce(&CStr) -> io::Result<T>,
542 {
543 f(self)
544 }
545}
546
547#[cfg(feature = "alloc")]
548impl Arg for CString {
549 #[inline]
550 fn as_str(&self) -> io::Result<&str> {
551 self.to_str().map_err(|_utf8_err| io::Errno::INVAL)
552 }
553
554 #[inline]
555 fn to_string_lossy(&self) -> Cow<'_, str> {
556 CStr::to_string_lossy(self)
557 }
558
559 #[inline]
560 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
561 Ok(Cow::Borrowed(self))
562 }
563
564 #[inline]
565 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
566 where
567 Self: 'b,
568 {
569 Ok(Cow::Owned(self))
570 }
571
572 #[inline]
573 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
574 where
575 Self: Sized,
576 F: FnOnce(&CStr) -> io::Result<T>,
577 {
578 f(&self)
579 }
580}
581
582#[cfg(feature = "alloc")]
583impl<'a> Arg for Cow<'a, str> {
584 #[inline]
585 fn as_str(&self) -> io::Result<&str> {
586 Ok(self)
587 }
588
589 #[inline]
590 fn to_string_lossy(&self) -> Cow<'_, str> {
591 Cow::Borrowed(self)
592 }
593
594 #[inline]
595 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
596 Ok(Cow::Owned(
597 CString::new(self.as_ref()).map_err(|_cstr_err| io::Errno::INVAL)?,
598 ))
599 }
600
601 #[inline]
602 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
603 where
604 Self: 'b,
605 {
606 Ok(Cow::Owned(
607 match self {
608 Cow::Owned(s) => CString::new(s),
609 Cow::Borrowed(s) => CString::new(s),
610 }
611 .map_err(|_cstr_err| io::Errno::INVAL)?,
612 ))
613 }
614
615 #[inline]
616 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
617 where
618 Self: Sized,
619 F: FnOnce(&CStr) -> io::Result<T>,
620 {
621 with_c_str(self.as_bytes(), f)
622 }
623}
624
625#[cfg(feature = "std")]
626#[cfg(any(not(target_os = "wasi"), not(target_env = "p2"), wasip2))]
627impl<'a> Arg for Cow<'a, OsStr> {
628 #[inline]
629 fn as_str(&self) -> io::Result<&str> {
630 (**self).to_str().ok_or(io::Errno::INVAL)
631 }
632
633 #[inline]
634 fn to_string_lossy(&self) -> Cow<'_, str> {
635 (**self).to_string_lossy()
636 }
637
638 #[inline]
639 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
640 Ok(Cow::Owned(
641 CString::new(self.as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
642 ))
643 }
644
645 #[inline]
646 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
647 where
648 Self: 'b,
649 {
650 Ok(Cow::Owned(
651 match self {
652 Cow::Owned(os) => CString::new(os.into_vec()),
653 Cow::Borrowed(os) => CString::new(os.as_bytes()),
654 }
655 .map_err(|_cstr_err| io::Errno::INVAL)?,
656 ))
657 }
658
659 #[inline]
660 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
661 where
662 Self: Sized,
663 F: FnOnce(&CStr) -> io::Result<T>,
664 {
665 with_c_str(self.as_bytes(), f)
666 }
667}
668
669#[cfg(feature = "alloc")]
670impl<'a> Arg for Cow<'a, CStr> {
671 #[inline]
672 fn as_str(&self) -> io::Result<&str> {
673 self.to_str().map_err(|_utf8_err| io::Errno::INVAL)
674 }
675
676 #[inline]
677 fn to_string_lossy(&self) -> Cow<'_, str> {
678 let borrow: &CStr = core::borrow::Borrow::borrow(self);
679 borrow.to_string_lossy()
680 }
681
682 #[inline]
683 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
684 Ok(Cow::Borrowed(self))
685 }
686
687 #[inline]
688 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
689 where
690 Self: 'b,
691 {
692 Ok(self)
693 }
694
695 #[inline]
696 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
697 where
698 Self: Sized,
699 F: FnOnce(&CStr) -> io::Result<T>,
700 {
701 f(&self)
702 }
703}
704
705#[cfg(feature = "std")]
706#[cfg(any(not(target_os = "wasi"), not(target_env = "p2"), wasip2))]
707impl<'a> Arg for Component<'a> {
708 #[inline]
709 fn as_str(&self) -> io::Result<&str> {
710 self.as_os_str().to_str().ok_or(io::Errno::INVAL)
711 }
712
713 #[inline]
714 fn to_string_lossy(&self) -> Cow<'_, str> {
715 self.as_os_str().to_string_lossy()
716 }
717
718 #[inline]
719 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
720 Ok(Cow::Owned(
721 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
722 ))
723 }
724
725 #[inline]
726 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
727 where
728 Self: 'b,
729 {
730 Ok(Cow::Owned(
731 CString::new(self.as_os_str().as_bytes()).map_err(|_cstr_err| io::Errno::INVAL)?,
732 ))
733 }
734
735 #[inline]
736 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
737 where
738 Self: Sized,
739 F: FnOnce(&CStr) -> io::Result<T>,
740 {
741 with_c_str(self.as_os_str().as_bytes(), f)
742 }
743}
744
745#[cfg(feature = "std")]
746#[cfg(any(not(target_os = "wasi"), not(target_env = "p2"), wasip2))]
747impl<'a> Arg for Components<'a> {
748 #[inline]
749 fn as_str(&self) -> io::Result<&str> {
750 self.as_path().to_str().ok_or(io::Errno::INVAL)
751 }
752
753 #[inline]
754 fn to_string_lossy(&self) -> Cow<'_, str> {
755 self.as_path().to_string_lossy()
756 }
757
758 #[inline]
759 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
760 Ok(Cow::Owned(
761 CString::new(self.as_path().as_os_str().as_bytes())
762 .map_err(|_cstr_err| io::Errno::INVAL)?,
763 ))
764 }
765
766 #[inline]
767 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
768 where
769 Self: 'b,
770 {
771 Ok(Cow::Owned(
772 CString::new(self.as_path().as_os_str().as_bytes())
773 .map_err(|_cstr_err| io::Errno::INVAL)?,
774 ))
775 }
776
777 #[inline]
778 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
779 where
780 Self: Sized,
781 F: FnOnce(&CStr) -> io::Result<T>,
782 {
783 with_c_str(self.as_path().as_os_str().as_bytes(), f)
784 }
785}
786
787#[cfg(feature = "std")]
788#[cfg(any(not(target_os = "wasi"), not(target_env = "p2"), wasip2))]
789impl<'a> Arg for Iter<'a> {
790 #[inline]
791 fn as_str(&self) -> io::Result<&str> {
792 self.as_path().to_str().ok_or(io::Errno::INVAL)
793 }
794
795 #[inline]
796 fn to_string_lossy(&self) -> Cow<'_, str> {
797 self.as_path().to_string_lossy()
798 }
799
800 #[inline]
801 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
802 Ok(Cow::Owned(
803 CString::new(self.as_path().as_os_str().as_bytes())
804 .map_err(|_cstr_err| io::Errno::INVAL)?,
805 ))
806 }
807
808 #[inline]
809 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
810 where
811 Self: 'b,
812 {
813 Ok(Cow::Owned(
814 CString::new(self.as_path().as_os_str().as_bytes())
815 .map_err(|_cstr_err| io::Errno::INVAL)?,
816 ))
817 }
818
819 #[inline]
820 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
821 where
822 Self: Sized,
823 F: FnOnce(&CStr) -> io::Result<T>,
824 {
825 with_c_str(self.as_path().as_os_str().as_bytes(), f)
826 }
827}
828
829impl Arg for &[u8] {
830 #[inline]
831 fn as_str(&self) -> io::Result<&str> {
832 str::from_utf8(self).map_err(|_utf8_err| io::Errno::INVAL)
833 }
834
835 #[cfg(feature = "alloc")]
836 #[inline]
837 fn to_string_lossy(&self) -> Cow<'_, str> {
838 String::from_utf8_lossy(self)
839 }
840
841 #[cfg(feature = "alloc")]
842 #[inline]
843 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
844 Ok(Cow::Owned(
845 CString::new(*self).map_err(|_cstr_err| io::Errno::INVAL)?,
846 ))
847 }
848
849 #[cfg(feature = "alloc")]
850 #[inline]
851 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
852 where
853 Self: 'b,
854 {
855 Ok(Cow::Owned(
856 CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?,
857 ))
858 }
859
860 #[inline]
861 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
862 where
863 Self: Sized,
864 F: FnOnce(&CStr) -> io::Result<T>,
865 {
866 with_c_str(self, f)
867 }
868}
869
870#[cfg(feature = "alloc")]
871impl Arg for &Vec<u8> {
872 #[inline]
873 fn as_str(&self) -> io::Result<&str> {
874 str::from_utf8(self).map_err(|_utf8_err| io::Errno::INVAL)
875 }
876
877 #[cfg(feature = "alloc")]
878 #[inline]
879 fn to_string_lossy(&self) -> Cow<'_, str> {
880 String::from_utf8_lossy(self)
881 }
882
883 #[cfg(feature = "alloc")]
884 #[inline]
885 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
886 Ok(Cow::Owned(
887 CString::new(self.as_slice()).map_err(|_cstr_err| io::Errno::INVAL)?,
888 ))
889 }
890
891 #[cfg(feature = "alloc")]
892 #[inline]
893 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
894 where
895 Self: 'b,
896 {
897 Ok(Cow::Owned(
898 CString::new(self.as_slice()).map_err(|_cstr_err| io::Errno::INVAL)?,
899 ))
900 }
901
902 #[inline]
903 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
904 where
905 Self: Sized,
906 F: FnOnce(&CStr) -> io::Result<T>,
907 {
908 with_c_str(self, f)
909 }
910}
911
912#[cfg(feature = "alloc")]
913#[cfg(any(not(target_os = "wasi"), not(target_env = "p2"), wasip2))]
914impl Arg for Vec<u8> {
915 #[inline]
916 fn as_str(&self) -> io::Result<&str> {
917 str::from_utf8(self).map_err(|_utf8_err| io::Errno::INVAL)
918 }
919
920 #[cfg(feature = "alloc")]
921 #[inline]
922 fn to_string_lossy(&self) -> Cow<'_, str> {
923 String::from_utf8_lossy(self)
924 }
925
926 #[cfg(feature = "alloc")]
927 #[inline]
928 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
929 Ok(Cow::Owned(
930 CString::new(self.as_slice()).map_err(|_cstr_err| io::Errno::INVAL)?,
931 ))
932 }
933
934 #[cfg(feature = "alloc")]
935 #[inline]
936 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
937 where
938 Self: 'b,
939 {
940 Ok(Cow::Owned(
941 CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?,
942 ))
943 }
944
945 #[inline]
946 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
947 where
948 Self: Sized,
949 F: FnOnce(&CStr) -> io::Result<T>,
950 {
951 f(&CString::new(self).map_err(|_cstr_err| io::Errno::INVAL)?)
952 }
953}
954
955impl Arg for DecInt {
956 #[inline]
957 fn as_str(&self) -> io::Result<&str> {
958 Ok(self.as_str())
959 }
960
961 #[cfg(feature = "alloc")]
962 #[inline]
963 fn to_string_lossy(&self) -> Cow<'_, str> {
964 Cow::Borrowed(self.as_str())
965 }
966
967 #[cfg(feature = "alloc")]
968 #[inline]
969 fn as_cow_c_str(&self) -> io::Result<Cow<'_, CStr>> {
970 Ok(Cow::Borrowed(self.as_c_str()))
971 }
972
973 #[cfg(feature = "alloc")]
974 #[inline]
975 fn into_c_str<'b>(self) -> io::Result<Cow<'b, CStr>>
976 where
977 Self: 'b,
978 {
979 Ok(Cow::Owned(self.as_c_str().to_owned()))
980 }
981
982 #[inline]
983 fn into_with_c_str<T, F>(self, f: F) -> io::Result<T>
984 where
985 Self: Sized,
986 F: FnOnce(&CStr) -> io::Result<T>,
987 {
988 f(self.as_c_str())
989 }
990}
991
992#[allow(unsafe_code, clippy::int_plus_one)]
994#[inline]
995fn with_c_str<T, F>(bytes: &[u8], f: F) -> io::Result<T>
996where
997 F: FnOnce(&CStr) -> io::Result<T>,
998{
999 if bytes.len() >= SMALL_PATH_BUFFER_SIZE {
1007 return with_c_str_slow_path(bytes, f);
1008 }
1009
1010 let mut buf = MaybeUninit::<[u8; SMALL_PATH_BUFFER_SIZE]>::uninit();
1013 let buf_ptr = buf.as_mut_ptr().cast::<u8>();
1014
1015 debug_assert!(bytes.len() + 1 <= SMALL_PATH_BUFFER_SIZE);
1017
1018 unsafe {
1021 ptr::copy_nonoverlapping(bytes.as_ptr(), buf_ptr, bytes.len());
1022 buf_ptr.add(bytes.len()).write(b'\0');
1023 }
1024
1025 match CStr::from_bytes_with_nul(unsafe { slice::from_raw_parts(buf_ptr, bytes.len() + 1) }) {
1029 Ok(s) => f(s),
1030 Err(_) => Err(io::Errno::INVAL),
1031 }
1032}
1033
1034#[allow(unsafe_code, clippy::int_plus_one)]
1037#[cold]
1038fn with_c_str_slow_path<T, F>(bytes: &[u8], f: F) -> io::Result<T>
1039where
1040 F: FnOnce(&CStr) -> io::Result<T>,
1041{
1042 #[cfg(feature = "alloc")]
1043 {
1044 f(&CString::new(bytes).map_err(|_cstr_err| io::Errno::INVAL)?)
1045 }
1046
1047 #[cfg(not(feature = "alloc"))]
1048 {
1049 #[cfg(all(
1050 libc,
1051 not(any(
1052 target_os = "espidf",
1053 target_os = "horizon",
1054 target_os = "hurd",
1055 target_os = "vita",
1056 target_os = "wasi"
1057 ))
1058 ))]
1059 const LARGE_PATH_BUFFER_SIZE: usize = libc::PATH_MAX as usize;
1060 #[cfg(linux_raw)]
1061 const LARGE_PATH_BUFFER_SIZE: usize = linux_raw_sys::general::PATH_MAX as usize;
1062 #[cfg(any(
1063 target_os = "espidf",
1064 target_os = "horizon",
1065 target_os = "hurd",
1066 target_os = "vita",
1067 target_os = "wasi"
1068 ))]
1069 const LARGE_PATH_BUFFER_SIZE: usize = 4096 as usize; let mut buf = MaybeUninit::<[u8; LARGE_PATH_BUFFER_SIZE]>::uninit();
1074 let buf_ptr = buf.as_mut_ptr().cast::<u8>();
1075
1076 if bytes.len() + 1 > LARGE_PATH_BUFFER_SIZE {
1078 return Err(io::Errno::NAMETOOLONG);
1079 }
1080
1081 unsafe {
1084 ptr::copy_nonoverlapping(bytes.as_ptr(), buf_ptr, bytes.len());
1085 buf_ptr.add(bytes.len()).write(b'\0');
1086 }
1087
1088 match CStr::from_bytes_with_nul(unsafe { slice::from_raw_parts(buf_ptr, bytes.len() + 1) })
1092 {
1093 Ok(s) => f(s),
1094 Err(_) => Err(io::Errno::INVAL),
1095 }
1096 }
1097}