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