Skip to content

Commit 0ab6a86

Browse files
committed
Make cstr! macro generic.
1 parent 6a0c368 commit 0ab6a86

File tree

3 files changed

+52
-10
lines changed

3 files changed

+52
-10
lines changed

library/core/src/ffi/c_str.rs

+46-8
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,7 @@ impl fmt::Debug for CStr {
177177
}
178178
}
179179

180-
/// Converts a string literal to a `&'static Cstr`.
181-
///
182-
/// # Panics
183-
///
184-
/// `cstr!` panics if the input contains any interior nul bytes.
180+
/// Converts a string or byte literal to a `&'static Cstr`.
185181
///
186182
/// # Examples
187183
///
@@ -193,18 +189,60 @@ impl fmt::Debug for CStr {
193189
/// const HELLO: &CStr = cstr!("Hello, world!");
194190
/// assert_eq!(HELLO.to_bytes_with_nul(), b"Hello, world!\0");
195191
/// ```
192+
///
193+
/// If the given expression contains any interior nul bytes this will
194+
/// result in a compilation error:
195+
///
196+
/// ```compile_fail
197+
/// #![feature(const_cstr_from_bytes)]
198+
///
199+
/// use core::ffi::CStr;
200+
///
201+
/// const HELLO: &CStr = cstr!("Hello, world!\0"); // compile fail!
202+
/// ```
196203
#[macro_export]
197204
#[unstable(feature = "cstr_macro", issue = "101607")]
198205
#[rustc_diagnostic_item = "core_cstr_macro"]
199206
macro_rules! cstr {
200-
($($s:expr),*) => {
201-
$crate::ffi::__cstr_macro_impl(concat!($($s,)* "\0").as_bytes())
207+
() => {
208+
cstr!("")
209+
};
210+
($s:literal) => {{
211+
const BYTES: &[u8] = $crate::ffi::__cstr_macro_impl_as_bytes($s);
212+
const BYTES_WITH_NUL: [u8; { BYTES.len() + 1 }] =
213+
$crate::ffi::__cstr_macro_impl_to_bytes_with_nul(BYTES);
214+
const CSTR: &$crate::ffi::CStr =
215+
$crate::ffi::__cstr_macro_impl_from_bytes_with_nul(&BYTES_WITH_NUL);
216+
CSTR
217+
}};
218+
}
219+
220+
#[unstable(feature = "cstr_macro", issue = "101607")]
221+
#[doc(hidden)]
222+
pub const fn __cstr_macro_impl_as_bytes<T>(v: &T) -> &[u8]
223+
where
224+
T: ?Sized + ~const AsRef<[u8]> + ~const crate::marker::Destruct,
225+
{
226+
v.as_ref()
227+
}
228+
229+
#[unstable(feature = "cstr_macro", issue = "101607")]
230+
#[doc(hidden)]
231+
pub const fn __cstr_macro_impl_to_bytes_with_nul<const N: usize>(bytes: &[u8]) -> [u8; N] {
232+
let mut bytes_with_nul = [0; N];
233+
234+
let mut i = 0;
235+
while i < bytes.len() {
236+
bytes_with_nul[i] = bytes[i];
237+
i += 1;
202238
}
239+
240+
bytes_with_nul
203241
}
204242

205243
#[unstable(feature = "cstr_macro", issue = "101607")]
206244
#[doc(hidden)]
207-
pub const fn __cstr_macro_impl(bytes: &[u8]) -> &CStr {
245+
pub const fn __cstr_macro_impl_from_bytes_with_nul(bytes: &[u8]) -> &CStr {
208246
match CStr::from_bytes_with_nul(bytes) {
209247
Ok(cstr) => cstr,
210248
Err(err) => panic!("{}", err.__description()),

library/core/src/ffi/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ mod c_str;
2121

2222
#[unstable(feature = "cstr_macro", issue = "101607")]
2323
#[doc(hidden)]
24-
pub use self::c_str::__cstr_macro_impl;
24+
pub use self::c_str::{
25+
__cstr_macro_impl_as_bytes, __cstr_macro_impl_from_bytes_with_nul,
26+
__cstr_macro_impl_to_bytes_with_nul,
27+
};
2528

2629
macro_rules! type_alias_no_nz {
2730
{

library/core/src/str/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2560,7 +2560,8 @@ impl str {
25602560
}
25612561

25622562
#[stable(feature = "rust1", since = "1.0.0")]
2563-
impl AsRef<[u8]> for str {
2563+
#[rustc_const_unstable(feature = "cstr_macro", issue = "101607")]
2564+
impl const AsRef<[u8]> for str {
25642565
#[inline]
25652566
fn as_ref(&self) -> &[u8] {
25662567
self.as_bytes()

0 commit comments

Comments
 (0)