[][src]Macro byte_strings::c_str

macro_rules! c_str {
    (
        $($literal:expr),+ $(,)?
    ) => { ... };
}

Converts into a valid C string at compile time (no runtime cost)

This macro takes any number of comma-separated byte string literals, or string literals, and evaluates to (a static reference to) a C string made of all the bytes of the given literals concatenated left-to-right, with an appended null byte terminator.

Hence the macro evaluates to the type &'static ::std::ffi::CStr.

Example

This code runs with edition 2018
use ::byte_strings::c_str;

assert_eq!(
    c_str!("Hello, ", "World!"),
    ::std::ffi::CStr::from_bytes_with_nul(b"Hello, World!\0").unwrap(),
)

Compilation error

For the C string to be what should be expected, the arguments cannot contain any null byte. Else the compilation will fail.

Counter example

This example deliberately fails to compile
// error: input literals cannot contain null bytes
let Hello_W = c_str!("Hello, ", "W\0rld!");

Macro expansion:

For those curious, c_str!(b"Hello, ", b"World!") expands to:

{
    union transmute {
        src: &'static [u8],
        dst: &'static ::std::ffi::CStr,
    }

    const transmute_is_sound_guard: [();
        ::std::mem::size_of::<&'static [u8]>()
    ] = [();
        ::std::mem::size_of::<&'static ::std::ffi::CStr>()
    ];

    const __byte_strings__c_str: &'static ::std::ffi::CStr = unsafe {
        (transmute { src: b"Hello, World!\0" }).dst
    };

    __byte_strings__c_str
}

This trick is needed to circumvent the current restriction of procedural macros being able to expand to items only.

Since ::std::mem::transmute is not a const fn, union transmutation had to be used, although it allows using different sizes. To prevent Undefined Behaviour, a size-check guard using arrays was added.