Skip to content

Commit 5ade028

Browse files
authored
Merge pull request #1145 from nicholasbishop/bishop-rework-cstr16-macro
Replace `cstr16!` with a declarative macro
2 parents 2e5dea4 + ff7cc7a commit 5ade028

File tree

5 files changed

+49
-54
lines changed

5 files changed

+49
-54
lines changed

uefi-macros/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# uefi-macros - [Unreleased]
22

3+
## Removed
4+
- Removed the `cstr16` macro. Use the `cstr16` declarative macro exported by the
5+
`uefi` crate instead.
6+
37
# uefi-macros - 0.13.0 (2023-11-12)
48

59
## Changed

uefi-macros/src/lib.rs

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -288,47 +288,3 @@ pub fn cstr8(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
288288
.into(),
289289
}
290290
}
291-
292-
/// Builds a `CStr16` literal at compile time from a string literal.
293-
///
294-
/// This will throw a compile error if an invalid character is in the passed string.
295-
///
296-
/// # Example
297-
/// ```rust
298-
/// # use uefi_macros::cstr16;
299-
/// // Empty string
300-
/// assert_eq!(cstr16!().to_u16_slice_with_nul(), [0]);
301-
/// assert_eq!(cstr16!("").to_u16_slice_with_nul(), [0]);
302-
/// // Non-empty string
303-
/// assert_eq!(cstr16!("test €").to_u16_slice_with_nul(), [116, 101, 115, 116, 32, 8364, 0]);
304-
/// ```
305-
#[proc_macro]
306-
pub fn cstr16(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
307-
// Accept empty input.
308-
if input.is_empty() {
309-
return quote!(unsafe { ::uefi::CStr16::from_u16_with_nul_unchecked(&[0]) }).into();
310-
}
311-
let input: LitStr = parse_macro_input!(input);
312-
let input = input.value();
313-
// Accept "" input.
314-
if input.is_empty() {
315-
return quote!(unsafe { ::uefi::CStr16::from_u16_with_nul_unchecked(&[0]) }).into();
316-
}
317-
318-
// Accept any non-empty string input.
319-
match input
320-
.chars()
321-
.map(|c| u16::try_from(c as u32))
322-
.collect::<Result<Vec<u16>, _>>()
323-
{
324-
Ok(c) => {
325-
quote!(unsafe { ::uefi::CStr16::from_u16_with_nul_unchecked(&[ #(#c),* , 0 ]) }).into()
326-
}
327-
Err(_) => syn::Error::new_spanned(
328-
input,
329-
"There are UTF-8 characters that can't be transformed to UCS-2 character",
330-
)
331-
.into_compile_error()
332-
.into(),
333-
}
334-
}

uefi/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ log.workspace = true
3030
ptr_meta.workspace = true
3131
uguid.workspace = true
3232
cfg-if = "1.0.0"
33-
ucs2 = "0.3.2"
33+
ucs2 = "0.3.3"
3434
uefi-macros = "0.13.0"
3535
uefi-raw = "0.5.2"
3636
qemu-exit = { version = "3.0.2", optional = true }

uefi/src/lib.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ extern crate alloc;
100100
// see https://github.com/rust-lang/rust/issues/54647
101101
extern crate self as uefi;
102102

103+
/// Re-export ucs2_cstr so that it can be used in the implementation of the
104+
/// cstr16 macro. It is hidden since it's not intended to be used directly.
105+
#[doc(hidden)]
106+
pub use ucs2::ucs2_cstr;
107+
103108
#[macro_use]
104109
extern crate uefi_raw;
105110

@@ -108,7 +113,7 @@ pub mod data_types;
108113
#[cfg(feature = "alloc")]
109114
pub use data_types::CString16;
110115
pub use data_types::{CStr16, CStr8, Char16, Char8, Event, Guid, Handle, Identify};
111-
pub use uefi_macros::{cstr16, cstr8, entry};
116+
pub use uefi_macros::{cstr8, entry};
112117
pub use uguid::guid;
113118

114119
mod result;
@@ -133,25 +138,19 @@ pub(crate) mod polyfill;
133138

134139
pub mod helpers;
135140

141+
mod macros;
136142
mod util;
137143

138144
#[cfg(test)]
139145
// Crates that create procedural macros can't unit test the macros they export.
140146
// Therefore, we do some tests here.
141147
mod macro_tests {
142-
use crate::{cstr16, cstr8};
148+
use crate::cstr8;
143149

144150
#[test]
145151
fn cstr8_macro_literal() {
146152
let _empty1 = cstr8!();
147153
let _empty2 = cstr8!("");
148154
let _regular = cstr8!("foobar");
149155
}
150-
151-
#[test]
152-
fn cstr16_macro_literal() {
153-
let _empty1 = cstr16!();
154-
let _empty2 = cstr16!("");
155-
let _regular = cstr16!("foobar");
156-
}
157156
}

uefi/src/macros.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/// Encode a string literal as a [`&CStr16`].
2+
///
3+
/// The encoding is done at compile time, so the result can be used in a
4+
/// `const` item.
5+
///
6+
/// An empty string containing just a null character can be created with either
7+
/// `cstr16!()` or `cstr16!("")`.
8+
///
9+
/// # Example
10+
///
11+
/// ```
12+
/// use uefi::{CStr16, cstr16};
13+
///
14+
/// const S: &CStr16 = cstr16!("abc");
15+
/// assert_eq!(S.to_u16_slice_with_nul(), [97, 98, 99, 0]);
16+
///
17+
/// const EMPTY: &CStr16 = cstr16!();
18+
/// assert_eq!(EMPTY.to_u16_slice_with_nul(), [0]);
19+
/// assert_eq!(cstr16!(""), EMPTY);
20+
/// ```
21+
///
22+
/// [`&CStr16`]: crate::CStr16
23+
#[macro_export]
24+
macro_rules! cstr16 {
25+
() => {{
26+
const S: &[u16] = &[0];
27+
// SAFETY: `S` is a trivially correct UCS-2 C string.
28+
unsafe { $crate::CStr16::from_u16_with_nul_unchecked(S) }
29+
}};
30+
($s:literal) => {{
31+
const S: &[u16] = &$crate::ucs2_cstr!($s);
32+
// SAFETY: the ucs2_cstr macro always produces a valid UCS-2 string with
33+
// a trailing null character.
34+
unsafe { $crate::CStr16::from_u16_with_nul_unchecked(S) }
35+
}};
36+
}

0 commit comments

Comments
 (0)