Skip to content

Commit

Permalink
Merge pull request rust-osdev#1013 from nicholasbishop/bishop-char-im…
Browse files Browse the repository at this point in the history
…prove

Add some new char and string convenience impls/methods
  • Loading branch information
phip1611 authored Dec 1, 2023
2 parents 9797333 + b936515 commit a6182b2
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 0 deletions.
4 changes: 4 additions & 0 deletions uefi/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# uefi - [Unreleased]

## Added
- Implemented `PartialEq<char>` for `Char8` and `Char16`.
- Added `CStr16::from_char16_with_nul` and `Char16::from_char16_with_nul_unchecked`.

# uefi - 0.26.0 (2023-11-12)

## Added
Expand Down
25 changes: 25 additions & 0 deletions uefi/src/data_types/chars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ impl fmt::Display for Char8 {
}
}

impl PartialEq<char> for Char8 {
fn eq(&self, other: &char) -> bool {
u32::from(self.0) == u32::from(*other)
}
}

/// Latin-1 version of the NUL character
pub const NUL_8: Char8 = Char8(0);

Expand Down Expand Up @@ -150,5 +156,24 @@ impl fmt::Display for Char16 {
}
}

impl PartialEq<char> for Char16 {
fn eq(&self, other: &char) -> bool {
u32::from(self.0) == u32::from(*other)
}
}

/// UCS-2 version of the NUL character
pub const NUL_16: Char16 = unsafe { Char16::from_u16_unchecked(0) };

#[cfg(test)]
mod tests {
use super::*;

/// Test that `Char8` and `Char16` can be directly compared with `char`.
#[test]
fn test_char_eq() {
let primitive_char: char = 'A';
assert_eq!(Char8(0x41), primitive_char);
assert_eq!(Char16(0x41), primitive_char);
}
}
73 changes: 73 additions & 0 deletions uefi/src/data_types/strs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,40 @@ impl CStr16 {
&*(codes as *const [u16] as *const Self)
}

/// Creates a `&CStr16` from a [`Char16`] slice, if the slice is
/// null-terminated and has no interior null characters.
pub fn from_char16_with_nul(chars: &[Char16]) -> Result<&Self, FromSliceWithNulError> {
// Fail early if the input is empty.
if chars.is_empty() {
return Err(FromSliceWithNulError::NotNulTerminated);
}

// Find the index of the first null char.
if let Some(null_index) = chars.iter().position(|c| *c == NUL_16) {
// Verify the null character is at the end.
if null_index == chars.len() - 1 {
// Safety: the input is null-terminated and has no interior nulls.
Ok(unsafe { Self::from_char16_with_nul_unchecked(chars) })
} else {
Err(FromSliceWithNulError::InteriorNul(null_index))
}
} else {
Err(FromSliceWithNulError::NotNulTerminated)
}
}

/// Unsafely creates a `&CStr16` from a `Char16` slice.
///
/// # Safety
///
/// It's the callers responsibility to ensure chars is null-terminated and
/// has no interior null characters.
#[must_use]
pub const unsafe fn from_char16_with_nul_unchecked(chars: &[Char16]) -> &Self {
let ptr: *const [Char16] = chars;
&*(ptr as *const Self)
}

/// Convert a [`&str`] to a `&CStr16`, backed by a buffer.
///
/// The input string must contain only characters representable with
Expand Down Expand Up @@ -615,6 +649,45 @@ mod tests {
assert_eq!(s.num_bytes(), 8);
}

#[test]
fn test_cstr16_from_char16_with_nul() {
// Invalid: empty input.
assert_eq!(
CStr16::from_char16_with_nul(&[]),
Err(FromSliceWithNulError::NotNulTerminated)
);

// Invalid: interior null.
assert_eq!(
CStr16::from_char16_with_nul(&[
Char16::try_from('a').unwrap(),
NUL_16,
Char16::try_from('b').unwrap(),
NUL_16
]),
Err(FromSliceWithNulError::InteriorNul(1))
);

// Invalid: no trailing null.
assert_eq!(
CStr16::from_char16_with_nul(&[
Char16::try_from('a').unwrap(),
Char16::try_from('b').unwrap(),
]),
Err(FromSliceWithNulError::NotNulTerminated)
);

// Valid.
assert_eq!(
CStr16::from_char16_with_nul(&[
Char16::try_from('a').unwrap(),
Char16::try_from('b').unwrap(),
NUL_16,
]),
Ok(cstr16!("ab"))
);
}

#[test]
fn test_cstr16_from_str_with_buf() {
let mut buf = [0; 4];
Expand Down

0 comments on commit a6182b2

Please sign in to comment.