Skip to content

Commit a6182b2

Browse files
authored
Merge pull request #1013 from nicholasbishop/bishop-char-improve
Add some new char and string convenience impls/methods
2 parents 9797333 + b936515 commit a6182b2

File tree

3 files changed

+102
-0
lines changed

3 files changed

+102
-0
lines changed

uefi/CHANGELOG.md

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

3+
## Added
4+
- Implemented `PartialEq<char>` for `Char8` and `Char16`.
5+
- Added `CStr16::from_char16_with_nul` and `Char16::from_char16_with_nul_unchecked`.
6+
37
# uefi - 0.26.0 (2023-11-12)
48

59
## Added

uefi/src/data_types/chars.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ impl fmt::Display for Char8 {
6666
}
6767
}
6868

69+
impl PartialEq<char> for Char8 {
70+
fn eq(&self, other: &char) -> bool {
71+
u32::from(self.0) == u32::from(*other)
72+
}
73+
}
74+
6975
/// Latin-1 version of the NUL character
7076
pub const NUL_8: Char8 = Char8(0);
7177

@@ -150,5 +156,24 @@ impl fmt::Display for Char16 {
150156
}
151157
}
152158

159+
impl PartialEq<char> for Char16 {
160+
fn eq(&self, other: &char) -> bool {
161+
u32::from(self.0) == u32::from(*other)
162+
}
163+
}
164+
153165
/// UCS-2 version of the NUL character
154166
pub const NUL_16: Char16 = unsafe { Char16::from_u16_unchecked(0) };
167+
168+
#[cfg(test)]
169+
mod tests {
170+
use super::*;
171+
172+
/// Test that `Char8` and `Char16` can be directly compared with `char`.
173+
#[test]
174+
fn test_char_eq() {
175+
let primitive_char: char = 'A';
176+
assert_eq!(Char8(0x41), primitive_char);
177+
assert_eq!(Char16(0x41), primitive_char);
178+
}
179+
}

uefi/src/data_types/strs.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,40 @@ impl CStr16 {
284284
&*(codes as *const [u16] as *const Self)
285285
}
286286

287+
/// Creates a `&CStr16` from a [`Char16`] slice, if the slice is
288+
/// null-terminated and has no interior null characters.
289+
pub fn from_char16_with_nul(chars: &[Char16]) -> Result<&Self, FromSliceWithNulError> {
290+
// Fail early if the input is empty.
291+
if chars.is_empty() {
292+
return Err(FromSliceWithNulError::NotNulTerminated);
293+
}
294+
295+
// Find the index of the first null char.
296+
if let Some(null_index) = chars.iter().position(|c| *c == NUL_16) {
297+
// Verify the null character is at the end.
298+
if null_index == chars.len() - 1 {
299+
// Safety: the input is null-terminated and has no interior nulls.
300+
Ok(unsafe { Self::from_char16_with_nul_unchecked(chars) })
301+
} else {
302+
Err(FromSliceWithNulError::InteriorNul(null_index))
303+
}
304+
} else {
305+
Err(FromSliceWithNulError::NotNulTerminated)
306+
}
307+
}
308+
309+
/// Unsafely creates a `&CStr16` from a `Char16` slice.
310+
///
311+
/// # Safety
312+
///
313+
/// It's the callers responsibility to ensure chars is null-terminated and
314+
/// has no interior null characters.
315+
#[must_use]
316+
pub const unsafe fn from_char16_with_nul_unchecked(chars: &[Char16]) -> &Self {
317+
let ptr: *const [Char16] = chars;
318+
&*(ptr as *const Self)
319+
}
320+
287321
/// Convert a [`&str`] to a `&CStr16`, backed by a buffer.
288322
///
289323
/// The input string must contain only characters representable with
@@ -615,6 +649,45 @@ mod tests {
615649
assert_eq!(s.num_bytes(), 8);
616650
}
617651

652+
#[test]
653+
fn test_cstr16_from_char16_with_nul() {
654+
// Invalid: empty input.
655+
assert_eq!(
656+
CStr16::from_char16_with_nul(&[]),
657+
Err(FromSliceWithNulError::NotNulTerminated)
658+
);
659+
660+
// Invalid: interior null.
661+
assert_eq!(
662+
CStr16::from_char16_with_nul(&[
663+
Char16::try_from('a').unwrap(),
664+
NUL_16,
665+
Char16::try_from('b').unwrap(),
666+
NUL_16
667+
]),
668+
Err(FromSliceWithNulError::InteriorNul(1))
669+
);
670+
671+
// Invalid: no trailing null.
672+
assert_eq!(
673+
CStr16::from_char16_with_nul(&[
674+
Char16::try_from('a').unwrap(),
675+
Char16::try_from('b').unwrap(),
676+
]),
677+
Err(FromSliceWithNulError::NotNulTerminated)
678+
);
679+
680+
// Valid.
681+
assert_eq!(
682+
CStr16::from_char16_with_nul(&[
683+
Char16::try_from('a').unwrap(),
684+
Char16::try_from('b').unwrap(),
685+
NUL_16,
686+
]),
687+
Ok(cstr16!("ab"))
688+
);
689+
}
690+
618691
#[test]
619692
fn test_cstr16_from_str_with_buf() {
620693
let mut buf = [0; 4];

0 commit comments

Comments
 (0)