diff options
Diffstat (limited to 'vendor/rustix/src/cstr.rs')
-rw-r--r-- | vendor/rustix/src/cstr.rs | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/vendor/rustix/src/cstr.rs b/vendor/rustix/src/cstr.rs new file mode 100644 index 000000000..5e3364380 --- /dev/null +++ b/vendor/rustix/src/cstr.rs @@ -0,0 +1,76 @@ +/// A macro for [`CStr`] literals. +/// +/// This can make passing string literals to rustix APIs more efficient, since +/// most underlying system calls with string arguments expect NUL-terminated +/// strings, and passing strings to rustix as `CStr`s means that rustix doesn't +/// need to copy them into a separate buffer to NUL-terminate them. +/// +/// [`CStr`]: crate::ffi::CStr +/// +/// # Examples +/// +/// ```rust,no_run +/// # #[cfg(feature = "fs")] +/// # fn main() -> rustix::io::Result<()> { +/// use rustix::cstr; +/// use rustix::fs::{cwd, statat, AtFlags}; +/// +/// let metadata = statat(cwd(), cstr!("test.txt"), AtFlags::empty())?; +/// # Ok(()) +/// # } +/// # #[cfg(not(feature = "fs"))] +/// # fn main() {} +/// ``` +#[allow(unused_macros)] +#[macro_export] +macro_rules! cstr { + ($str:literal) => {{ + // Check for NUL manually, to ensure safety. + // + // In release builds, with strings that don't contain NULs, this + // constant-folds away. + // + // We don't use std's `CStr::from_bytes_with_nul`; as of this writing, + // that function isn't defined as `#[inline]` in std and doesn't + // constant-fold away. + assert!( + !$str.bytes().any(|b| b == b'\0'), + "cstr argument contains embedded NUL bytes", + ); + + #[allow(unsafe_code, unused_unsafe)] + { + // Now that we know the string doesn't have embedded NULs, we can call + // `from_bytes_with_nul_unchecked`, which as of this writing is defined + // as `#[inline]` and completely optimizes away. + // + // Safety: We have manually checked that the string does not contain + // embedded NULs above, and we append or own NUL terminator here. + unsafe { + $crate::ffi::CStr::from_bytes_with_nul_unchecked(concat!($str, "\0").as_bytes()) + } + } + }}; +} + +#[test] +fn test_cstr() { + use crate::ffi::CString; + use alloc::borrow::ToOwned; + assert_eq!(cstr!(""), &*CString::new("").unwrap()); + assert_eq!(cstr!("").to_owned(), CString::new("").unwrap()); + assert_eq!(cstr!("hello"), &*CString::new("hello").unwrap()); + assert_eq!(cstr!("hello").to_owned(), CString::new("hello").unwrap()); +} + +#[test] +#[should_panic] +fn test_invalid_cstr() { + let _ = cstr!("hello\0world"); +} + +#[test] +#[should_panic] +fn test_invalid_empty_cstr() { + let _ = cstr!("\0"); +} |