    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    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");
    }