Skip to content

Commit 841d624

Browse files
committed
macros: allow to create empty cstr8/16 slices
1 parent 4b08270 commit 841d624

File tree

3 files changed

+58
-4
lines changed

3 files changed

+58
-4
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
any effect.
5151
- The `unsafe_protocol` macro now accepts the path of a `Guid` constant in
5252
addition to a string literal.
53+
- The `cstr8` and the `cstr16` macros now both accept `(nothing)` and `""`
54+
(empty inputs) to create valid empty strings. They include the null-byte.
5355

5456
## uefi-services - [Unreleased]
5557

uefi-macros/src/lib.rs

+35-4
Original file line numberDiff line numberDiff line change
@@ -258,12 +258,26 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
258258
/// # Example
259259
/// ```
260260
/// # use uefi_macros::cstr8;
261+
/// // Empty string
262+
/// assert_eq!(cstr8!().to_u16_slice_with_nul(), [0]);
263+
/// assert_eq!(cstr8!("").to_u16_slice_with_nul(), [0]);
264+
/// // Non-empty string
261265
/// assert_eq!(cstr8!("test").to_bytes_with_nul(), [116, 101, 115, 116, 0]);
262266
/// ```
263267
#[proc_macro]
264268
pub fn cstr8(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
269+
// Accept empty input.
270+
if input.is_empty() {
271+
return quote!(unsafe { ::uefi::CStr16::from_u16_with_nul_unchecked(&[0]) }).into();
272+
}
265273
let input: LitStr = parse_macro_input!(input);
266274
let input = input.value();
275+
// Accept "" input.
276+
if input.is_empty() {
277+
return quote!(unsafe { ::uefi::CStr16::from_u16_with_nul_unchecked(&[0]) }).into();
278+
}
279+
280+
// Accept any non-empty string input.
267281
match input
268282
.chars()
269283
.map(u8::try_from)
@@ -283,14 +297,28 @@ pub fn cstr8(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
283297
/// This will throw a compile error if an invalid character is in the passed string.
284298
///
285299
/// # Example
286-
/// ```
300+
/// ```rust
287301
/// # use uefi_macros::cstr16;
302+
/// // Empty string
303+
/// assert_eq!(cstr16!().to_u16_slice_with_nul(), [0]);
304+
/// assert_eq!(cstr16!("").to_u16_slice_with_nul(), [0]);
305+
/// // Non-empty string
288306
/// assert_eq!(cstr16!("test €").to_u16_slice_with_nul(), [116, 101, 115, 116, 32, 8364, 0]);
289307
/// ```
290308
#[proc_macro]
291309
pub fn cstr16(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
310+
// Accept empty input.
311+
if input.is_empty() {
312+
return quote!(unsafe { ::uefi::CStr16::from_u16_with_nul_unchecked(&[0]) }).into();
313+
}
292314
let input: LitStr = parse_macro_input!(input);
293315
let input = input.value();
316+
// Accept "" input.
317+
if input.is_empty() {
318+
return quote!(unsafe { ::uefi::CStr16::from_u16_with_nul_unchecked(&[0]) }).into();
319+
}
320+
321+
// Accept any non-empty string input.
294322
match input
295323
.chars()
296324
.map(|c| u16::try_from(c as u32))
@@ -299,8 +327,11 @@ pub fn cstr16(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
299327
Ok(c) => {
300328
quote!(unsafe { ::uefi::CStr16::from_u16_with_nul_unchecked(&[ #(#c),* , 0 ]) }).into()
301329
}
302-
Err(_) => syn::Error::new_spanned(input, "invalid character in string")
303-
.into_compile_error()
304-
.into(),
330+
Err(_) => syn::Error::new_spanned(
331+
input,
332+
"There are UTF-8 characters that can't be transformed to UCS-2 character",
333+
)
334+
.into_compile_error()
335+
.into(),
305336
}
306337
}

uefi/src/lib.rs

+21
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,24 @@ pub(crate) mod mem;
127127
pub(crate) mod polyfill;
128128

129129
mod util;
130+
131+
#[cfg(test)]
132+
// Crates that create procedural macros can't unit test the macros they export.
133+
// Therefore, we do some tests here.
134+
mod macro_tests {
135+
use uefi_macros::{cstr16, cstr8};
136+
137+
#[test]
138+
fn cstr8_macro_literal() {
139+
let _empty1 = cstr8!();
140+
let _empty2 = cstr8!("");
141+
let _regular = cstr8!("foobar");
142+
}
143+
144+
#[test]
145+
fn cstr16_macro_literal() {
146+
let _empty1 = cstr16!();
147+
let _empty2 = cstr16!("");
148+
let _regular = cstr16!("foobar");
149+
}
150+
}

0 commit comments

Comments
 (0)