1b8a62b91Sopenharmony_ci/// A macro for [`CStr`] literals. 2b8a62b91Sopenharmony_ci/// 3b8a62b91Sopenharmony_ci/// This can make passing string literals to rustix APIs more efficient, since 4b8a62b91Sopenharmony_ci/// most underlying system calls with string arguments expect NUL-terminated 5b8a62b91Sopenharmony_ci/// strings, and passing strings to rustix as `CStr`s means that rustix doesn't 6b8a62b91Sopenharmony_ci/// need to copy them into a separate buffer to NUL-terminate them. 7b8a62b91Sopenharmony_ci/// 8b8a62b91Sopenharmony_ci/// [`CStr`]: crate::ffi::CStr 9b8a62b91Sopenharmony_ci/// 10b8a62b91Sopenharmony_ci/// # Examples 11b8a62b91Sopenharmony_ci/// 12b8a62b91Sopenharmony_ci/// ```rust,no_run 13b8a62b91Sopenharmony_ci/// # #[cfg(feature = "fs")] 14b8a62b91Sopenharmony_ci/// # fn main() -> rustix::io::Result<()> { 15b8a62b91Sopenharmony_ci/// use rustix::cstr; 16b8a62b91Sopenharmony_ci/// use rustix::fs::{cwd, statat, AtFlags}; 17b8a62b91Sopenharmony_ci/// 18b8a62b91Sopenharmony_ci/// let metadata = statat(cwd(), cstr!("test.txt"), AtFlags::empty())?; 19b8a62b91Sopenharmony_ci/// # Ok(()) 20b8a62b91Sopenharmony_ci/// # } 21b8a62b91Sopenharmony_ci/// # #[cfg(not(feature = "fs"))] 22b8a62b91Sopenharmony_ci/// # fn main() {} 23b8a62b91Sopenharmony_ci/// ``` 24b8a62b91Sopenharmony_ci#[allow(unused_macros)] 25b8a62b91Sopenharmony_ci#[macro_export] 26b8a62b91Sopenharmony_cimacro_rules! cstr { 27b8a62b91Sopenharmony_ci ($str:literal) => {{ 28b8a62b91Sopenharmony_ci // Check for NUL manually, to ensure safety. 29b8a62b91Sopenharmony_ci // 30b8a62b91Sopenharmony_ci // In release builds, with strings that don't contain NULs, this 31b8a62b91Sopenharmony_ci // constant-folds away. 32b8a62b91Sopenharmony_ci // 33b8a62b91Sopenharmony_ci // We don't use std's `CStr::from_bytes_with_nul`; as of this writing, 34b8a62b91Sopenharmony_ci // that function isn't defined as `#[inline]` in std and doesn't 35b8a62b91Sopenharmony_ci // constant-fold away. 36b8a62b91Sopenharmony_ci assert!( 37b8a62b91Sopenharmony_ci !$str.bytes().any(|b| b == b'\0'), 38b8a62b91Sopenharmony_ci "cstr argument contains embedded NUL bytes", 39b8a62b91Sopenharmony_ci ); 40b8a62b91Sopenharmony_ci 41b8a62b91Sopenharmony_ci #[allow(unsafe_code, unused_unsafe)] 42b8a62b91Sopenharmony_ci { 43b8a62b91Sopenharmony_ci // Now that we know the string doesn't have embedded NULs, we can call 44b8a62b91Sopenharmony_ci // `from_bytes_with_nul_unchecked`, which as of this writing is defined 45b8a62b91Sopenharmony_ci // as `#[inline]` and completely optimizes away. 46b8a62b91Sopenharmony_ci // 47b8a62b91Sopenharmony_ci // Safety: We have manually checked that the string does not contain 48b8a62b91Sopenharmony_ci // embedded NULs above, and we append or own NUL terminator here. 49b8a62b91Sopenharmony_ci unsafe { 50b8a62b91Sopenharmony_ci $crate::ffi::CStr::from_bytes_with_nul_unchecked(concat!($str, "\0").as_bytes()) 51b8a62b91Sopenharmony_ci } 52b8a62b91Sopenharmony_ci } 53b8a62b91Sopenharmony_ci }}; 54b8a62b91Sopenharmony_ci} 55b8a62b91Sopenharmony_ci 56b8a62b91Sopenharmony_ci#[test] 57b8a62b91Sopenharmony_cifn test_cstr() { 58b8a62b91Sopenharmony_ci use crate::ffi::CString; 59b8a62b91Sopenharmony_ci use alloc::borrow::ToOwned; 60b8a62b91Sopenharmony_ci assert_eq!(cstr!(""), &*CString::new("").unwrap()); 61b8a62b91Sopenharmony_ci assert_eq!(cstr!("").to_owned(), CString::new("").unwrap()); 62b8a62b91Sopenharmony_ci assert_eq!(cstr!("hello"), &*CString::new("hello").unwrap()); 63b8a62b91Sopenharmony_ci assert_eq!(cstr!("hello").to_owned(), CString::new("hello").unwrap()); 64b8a62b91Sopenharmony_ci} 65b8a62b91Sopenharmony_ci 66b8a62b91Sopenharmony_ci#[test] 67b8a62b91Sopenharmony_ci#[should_panic] 68b8a62b91Sopenharmony_cifn test_invalid_cstr() { 69b8a62b91Sopenharmony_ci let _ = cstr!("hello\0world"); 70b8a62b91Sopenharmony_ci} 71b8a62b91Sopenharmony_ci 72b8a62b91Sopenharmony_ci#[test] 73b8a62b91Sopenharmony_ci#[should_panic] 74b8a62b91Sopenharmony_cifn test_invalid_empty_cstr() { 75b8a62b91Sopenharmony_ci let _ = cstr!("\0"); 76b8a62b91Sopenharmony_ci} 77