1 //! Convenient and efficient string argument passing.
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.
8 use crate::ffi
::{CStr, CString}
;
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
;
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")]
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}
;
37 /// A trait for passing path arguments.
39 /// This is similar to [`AsRef`]`<`[`Path`]`>`, but is implemented for more
40 /// kinds of strings and can convert into more kinds of strings.
45 /// # #[cfg(any(feature = "fs", feature = "net"))]
46 /// use rustix::ffi::CStr;
48 /// # #[cfg(any(feature = "fs", feature = "net"))]
49 /// use rustix::path::Arg;
51 /// # #[cfg(any(feature = "fs", feature = "net"))]
52 /// pub fn touch<P: Arg>(path: P) -> io::Result<()> {
53 /// let path = path.into_c_str()?;
57 /// # #[cfg(any(feature = "fs", feature = "net"))]
58 /// fn _touch(path: &CStr) -> io::Result<()> {
59 /// // implementation goes here
64 /// Users can then call `touch("foo")`, `touch(cstr!("foo"))`,
65 /// `touch(Path::new("foo"))`, or many other things.
67 /// [`AsRef`]: std::convert::AsRef
69 /// Returns a view of this string as a string slice.
70 fn as_str(&self) -> io
::Result
<&str>;
72 /// Returns a potentially-lossy rendering of this string as a `Cow<'_,
74 fn to_string_lossy(&self) -> Cow
<'_
, str>;
76 /// Returns a view of this string as a maybe-owned [`CStr`].
77 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>>;
79 /// Consumes `self` and returns a view of this string as a maybe-owned
81 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
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
>
89 F
: FnOnce(&CStr
) -> io
::Result
<T
>;
94 fn as_str(&self) -> io
::Result
<&str> {
99 fn to_string_lossy(&self) -> Cow
<'_
, str> {
104 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
106 CString
::new(*self).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
111 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
116 CString
::new(self).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
121 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
124 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
126 with_c_str(self.as_bytes(), f
)
130 impl Arg
for &String
{
132 fn as_str(&self) -> io
::Result
<&str> {
137 fn to_string_lossy(&self) -> Cow
<'_
, str> {
142 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
144 CString
::new(String
::as_str(self)).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
149 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
153 self.as_str().into_c_str()
157 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
160 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
162 with_c_str(self.as_bytes(), f
)
166 impl Arg
for String
{
168 fn as_str(&self) -> io
::Result
<&str> {
173 fn to_string_lossy(&self) -> Cow
<'_
, str> {
178 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
180 CString
::new(self.as_str()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
185 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
190 CString
::new(self).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
195 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
198 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
200 f(&CString
::new(self).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
)
204 #[cfg(feature = "std")]
205 impl Arg
for &OsStr
{
207 fn as_str(&self) -> io
::Result
<&str> {
208 self.to_str().ok_or(io
::Errno
::INVAL
)
212 fn to_string_lossy(&self) -> Cow
<'_
, str> {
213 OsStr
::to_string_lossy(self)
217 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
219 CString
::new(self.as_bytes()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
224 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
229 CString
::new(self.as_bytes()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
234 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
237 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
239 with_c_str(self.as_bytes(), f
)
243 #[cfg(feature = "std")]
244 impl Arg
for &OsString
{
246 fn as_str(&self) -> io
::Result
<&str> {
247 OsString
::as_os_str(self).to_str().ok_or(io
::Errno
::INVAL
)
251 fn to_string_lossy(&self) -> Cow
<'_
, str> {
252 self.as_os_str().to_string_lossy()
256 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
258 CString
::new(OsString
::as_os_str(self).as_bytes())
259 .map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
264 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
268 self.as_os_str().into_c_str()
272 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
275 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
277 with_c_str(self.as_bytes(), f
)
281 #[cfg(feature = "std")]
282 impl Arg
for OsString
{
284 fn as_str(&self) -> io
::Result
<&str> {
285 self.as_os_str().to_str().ok_or(io
::Errno
::INVAL
)
289 fn to_string_lossy(&self) -> Cow
<'_
, str> {
290 self.as_os_str().to_string_lossy()
294 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
296 CString
::new(self.as_bytes()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
301 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
306 CString
::new(self.into_vec()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
311 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
314 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
316 f(&CString
::new(self.into_vec()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
)
320 #[cfg(feature = "std")]
323 fn as_str(&self) -> io
::Result
<&str> {
324 self.as_os_str().to_str().ok_or(io
::Errno
::INVAL
)
328 fn to_string_lossy(&self) -> Cow
<'_
, str> {
329 Path
::to_string_lossy(self)
333 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
335 CString
::new(self.as_os_str().as_bytes()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
340 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
345 CString
::new(self.as_os_str().as_bytes()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
350 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
353 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
355 with_c_str(self.as_os_str().as_bytes(), f
)
359 #[cfg(feature = "std")]
360 impl Arg
for &PathBuf
{
362 fn as_str(&self) -> io
::Result
<&str> {
363 PathBuf
::as_path(self)
366 .ok_or(io
::Errno
::INVAL
)
370 fn to_string_lossy(&self) -> Cow
<'_
, str> {
371 self.as_path().to_string_lossy()
375 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
377 CString
::new(PathBuf
::as_path(self).as_os_str().as_bytes())
378 .map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
383 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
387 self.as_path().into_c_str()
391 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
394 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
396 with_c_str(self.as_os_str().as_bytes(), f
)
400 #[cfg(feature = "std")]
401 impl Arg
for PathBuf
{
403 fn as_str(&self) -> io
::Result
<&str> {
404 self.as_os_str().to_str().ok_or(io
::Errno
::INVAL
)
408 fn to_string_lossy(&self) -> Cow
<'_
, str> {
409 self.as_os_str().to_string_lossy()
413 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
415 CString
::new(self.as_os_str().as_bytes()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
420 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
425 CString
::new(self.into_os_string().into_vec()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
430 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
433 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
436 &CString
::new(self.into_os_string().into_vec())
437 .map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
444 fn as_str(&self) -> io
::Result
<&str> {
445 self.to_str().map_err(|_utf8_err
| io
::Errno
::INVAL
)
449 fn to_string_lossy(&self) -> Cow
<'_
, str> {
450 CStr
::to_string_lossy(self)
454 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
455 Ok(Cow
::Borrowed(self))
459 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
463 Ok(Cow
::Borrowed(self))
467 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
470 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
476 impl Arg
for &CString
{
478 fn as_str(&self) -> io
::Result
<&str> {
483 fn to_string_lossy(&self) -> Cow
<'_
, str> {
488 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
489 Ok(Cow
::Borrowed(self))
493 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
497 Ok(Cow
::Borrowed(self))
501 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
504 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
510 impl Arg
for CString
{
512 fn as_str(&self) -> io
::Result
<&str> {
513 self.to_str().map_err(|_utf8_err
| io
::Errno
::INVAL
)
517 fn to_string_lossy(&self) -> Cow
<'_
, str> {
518 CStr
::to_string_lossy(self)
522 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
523 Ok(Cow
::Borrowed(self))
527 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
535 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
538 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
544 impl<'a
> Arg
for Cow
<'a
, str> {
546 fn as_str(&self) -> io
::Result
<&str> {
551 fn to_string_lossy(&self) -> Cow
<'_
, str> {
556 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
558 CString
::new(self.as_ref()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
563 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
569 Cow
::Owned(s
) => CString
::new(s
),
570 Cow
::Borrowed(s
) => CString
::new(s
),
572 .map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
577 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
580 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
582 with_c_str(self.as_bytes(), f
)
586 #[cfg(feature = "std")]
587 impl<'a
> Arg
for Cow
<'a
, OsStr
> {
589 fn as_str(&self) -> io
::Result
<&str> {
590 (**self).to_str().ok_or(io
::Errno
::INVAL
)
594 fn to_string_lossy(&self) -> Cow
<'_
, str> {
595 (**self).to_string_lossy()
599 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
601 CString
::new(self.as_bytes()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
606 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
612 Cow
::Owned(os
) => CString
::new(os
.into_vec()),
613 Cow
::Borrowed(os
) => CString
::new(os
.as_bytes()),
615 .map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
620 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
623 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
625 with_c_str(self.as_bytes(), f
)
629 impl<'a
> Arg
for Cow
<'a
, CStr
> {
631 fn as_str(&self) -> io
::Result
<&str> {
632 self.to_str().map_err(|_utf8_err
| io
::Errno
::INVAL
)
636 fn to_string_lossy(&self) -> Cow
<'_
, str> {
637 let borrow
: &CStr
= core
::borrow
::Borrow
::borrow(self);
638 borrow
.to_string_lossy()
642 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
643 Ok(Cow
::Borrowed(self))
647 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
655 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
658 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
664 #[cfg(feature = "std")]
665 impl<'a
> Arg
for Component
<'a
> {
667 fn as_str(&self) -> io
::Result
<&str> {
668 self.as_os_str().to_str().ok_or(io
::Errno
::INVAL
)
672 fn to_string_lossy(&self) -> Cow
<'_
, str> {
673 self.as_os_str().to_string_lossy()
677 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
679 CString
::new(self.as_os_str().as_bytes()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
684 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
689 CString
::new(self.as_os_str().as_bytes()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
694 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
697 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
699 with_c_str(self.as_os_str().as_bytes(), f
)
703 #[cfg(feature = "std")]
704 impl<'a
> Arg
for Components
<'a
> {
706 fn as_str(&self) -> io
::Result
<&str> {
707 self.as_path().to_str().ok_or(io
::Errno
::INVAL
)
711 fn to_string_lossy(&self) -> Cow
<'_
, str> {
712 self.as_path().to_string_lossy()
716 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
718 CString
::new(self.as_path().as_os_str().as_bytes())
719 .map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
724 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
729 CString
::new(self.as_path().as_os_str().as_bytes())
730 .map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
735 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
738 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
740 with_c_str(self.as_path().as_os_str().as_bytes(), f
)
744 #[cfg(feature = "std")]
745 impl<'a
> Arg
for Iter
<'a
> {
747 fn as_str(&self) -> io
::Result
<&str> {
748 self.as_path().to_str().ok_or(io
::Errno
::INVAL
)
752 fn to_string_lossy(&self) -> Cow
<'_
, str> {
753 self.as_path().to_string_lossy()
757 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
759 CString
::new(self.as_path().as_os_str().as_bytes())
760 .map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
765 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
770 CString
::new(self.as_path().as_os_str().as_bytes())
771 .map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
776 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
779 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
781 with_c_str(self.as_path().as_os_str().as_bytes(), f
)
787 fn as_str(&self) -> io
::Result
<&str> {
788 str::from_utf8(self).map_err(|_utf8_err
| io
::Errno
::INVAL
)
792 fn to_string_lossy(&self) -> Cow
<'_
, str> {
793 String
::from_utf8_lossy(self)
797 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
799 CString
::new(*self).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
804 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
809 CString
::new(self).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
814 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
817 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
823 impl Arg
for &Vec
<u8> {
825 fn as_str(&self) -> io
::Result
<&str> {
826 str::from_utf8(self).map_err(|_utf8_err
| io
::Errno
::INVAL
)
830 fn to_string_lossy(&self) -> Cow
<'_
, str> {
831 String
::from_utf8_lossy(self)
835 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
837 CString
::new(self.as_slice()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
842 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
847 CString
::new(self.as_slice()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
852 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
855 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
861 impl Arg
for Vec
<u8> {
863 fn as_str(&self) -> io
::Result
<&str> {
864 str::from_utf8(self).map_err(|_utf8_err
| io
::Errno
::INVAL
)
868 fn to_string_lossy(&self) -> Cow
<'_
, str> {
869 String
::from_utf8_lossy(self)
873 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
875 CString
::new(self.as_slice()).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
880 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
885 CString
::new(self).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
,
890 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
893 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
895 f(&CString
::new(self).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
)
899 #[cfg(feature = "itoa")]
900 impl Arg
for DecInt
{
902 fn as_str(&self) -> io
::Result
<&str> {
907 fn to_string_lossy(&self) -> Cow
<'_
, str> {
908 Cow
::Borrowed(self.as_str())
912 fn as_cow_c_str(&self) -> io
::Result
<Cow
<'_
, CStr
>> {
913 Ok(Cow
::Borrowed(self.as_c_str()))
917 fn into_c_str
<'b
>(self) -> io
::Result
<Cow
<'b
, CStr
>>
921 Ok(Cow
::Owned(self.as_c_str().to_owned()))
925 fn into_with_c_str
<T
, F
>(self, f
: F
) -> io
::Result
<T
>
928 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
934 /// Runs a closure with `bytes` passed in as a `&CStr`.
935 #[allow(unsafe_code, clippy::int_plus_one)]
937 fn with_c_str
<T
, F
>(bytes
: &[u8], f
: F
) -> io
::Result
<T
>
939 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
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.
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
);
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;
957 // This helps test our safety condition below.
958 debug_assert
!(bytes
.len() + 1 <= SMALL_PATH_BUFFER_SIZE
);
960 // SAFETY: `bytes.len() < SMALL_PATH_BUFFER_SIZE` which means we have space for
961 // `bytes.len() + 1` u8s:
963 ptr
::copy_nonoverlapping(bytes
.as_ptr(), buf_ptr
, bytes
.len());
964 buf_ptr
.add(bytes
.len()).write(0);
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) }
) {
971 Err(_
) => Err(io
::Errno
::INVAL
),
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.
978 fn with_c_str_slow_path
<T
, F
>(bytes
: &[u8], f
: F
) -> io
::Result
<T
>
980 F
: FnOnce(&CStr
) -> io
::Result
<T
>,
982 f(&CString
::new(bytes
).map_err(|_cstr_err
| io
::Errno
::INVAL
)?
)