Skip to content

Several small improvements to EqStrUntilNul #580

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Changelog

## uefi - [Unreleased]
- Implementations for the trait `EqStrUntilNul` now allow `?Sized` inputs. This means that
you can write `some_cstr16.eq_str_until_nul("test")` instead of
`some_cstr16.eq_str_until_nul(&"test")` now.

## uefi-macros - [Unreleased]

Expand Down
10 changes: 7 additions & 3 deletions uefi/src/data_types/owned_strs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ impl PartialEq<&CStr16> for CString16 {
}
}

impl<StrType: AsRef<str>> EqStrUntilNul<StrType> for CString16 {
impl<StrType: AsRef<str> + ?Sized> EqStrUntilNul<StrType> for CString16 {
fn eq_str_until_nul(&self, other: &StrType) -> bool {
let this = self.as_ref();
this.eq_str_until_nul(other)
Expand Down Expand Up @@ -190,12 +190,16 @@ mod tests {
);
}

/// Tests the trait implementation of trait [EqStrUntilNul].
/// Tests the trait implementation of trait [`EqStrUntilNul]` for [`CString16`].
///
/// This tests that `String` and `str` from the standard library can be
/// checked for equality against a [`CString16`]. It checks both directions,
/// i.e., the equality is reflexive.
#[test]
fn test_cstring16_eq_std_str() {
let input = CString16::try_from("test").unwrap();

// test various comparisons with different order (left, right)
assert!(input.eq_str_until_nul("test")); // requires ?Sized constraint
assert!(input.eq_str_until_nul(&"test"));
assert!(input.eq_str_until_nul(&String::from("test")));

Expand Down
56 changes: 48 additions & 8 deletions uefi/src/data_types/strs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ impl fmt::Display for CStr8 {
}
}

impl<StrType: AsRef<str>> EqStrUntilNul<StrType> for CStr8 {
impl<StrType: AsRef<str> + ?Sized> EqStrUntilNul<StrType> for CStr8 {
fn eq_str_until_nul(&self, other: &StrType) -> bool {
let other = other.as_ref();

Expand All @@ -147,7 +147,8 @@ impl<StrType: AsRef<str>> EqStrUntilNul<StrType> for CStr8 {
.copied()
.map(char::from)
.zip(other.chars())
// this only works as CStr8 is guaranteed to have a fixed character length
// This only works as CStr8 is guaranteed to have a fixed character length
// (unlike UTF-8).
.take_while(|(l, r)| *l != '\0' && *r != '\0')
.any(|(l, r)| l != r);

Expand Down Expand Up @@ -345,7 +346,7 @@ impl CStr16 {
}
}

impl<StrType: AsRef<str>> EqStrUntilNul<StrType> for CStr16 {
impl<StrType: AsRef<str> + ?Sized> EqStrUntilNul<StrType> for CStr16 {
fn eq_str_until_nul(&self, other: &StrType) -> bool {
let other = other.as_ref();

Expand All @@ -354,7 +355,8 @@ impl<StrType: AsRef<str>> EqStrUntilNul<StrType> for CStr16 {
.copied()
.map(char::from)
.zip(other.chars())
// this only works as CStr16 is guaranteed to have a fixed character length
// This only works as CStr16 is guaranteed to have a fixed character length
// (unlike UTF-8 or UTF-16).
.take_while(|(l, r)| *l != '\0' && *r != '\0')
.any(|(l, r)| l != r);

Expand Down Expand Up @@ -416,10 +418,11 @@ impl<'a> UnalignedSlice<'a, u16> {
}
}

/// Trait that helps to compare Rust strings against CStr16 types.
/// A generic implementation of this trait enables us that we only have to
/// implement one direction (`left.eq_str_until_nul(&right)`) and we get
/// the other direction (`right.eq_str_until_nul(&left)`) for free.
/// The EqStrUntilNul trait helps to compare Rust strings against UEFI string types (UCS-2 strings).
/// The given generic implementation of this trait enables us that we only have to
/// implement one direction (`left.eq_str_until_nul(&right)`) for each UEFI string type and we
/// get the other direction (`right.eq_str_until_nul(&left)`) for free. Hence, the relation is
/// reflexive.
pub trait EqStrUntilNul<StrType: ?Sized> {
/// Checks if the provided Rust string `StrType` is equal to [Self] until the first null-byte
/// is found. An exception is the terminating null-byte of [Self] which is ignored.
Expand Down Expand Up @@ -575,4 +578,41 @@ mod tests {
const S: &CStr16 = cstr16!("ABC");
assert_eq!(S.to_u16_slice_with_nul(), [65, 66, 67, 0]);
}

/// Tests the trait implementation of trait [`EqStrUntilNul]` for [`CStr8`].
///
/// This tests that `String` and `str` from the standard library can be
/// checked for equality against a [`CStr8`]. It checks both directions,
/// i.e., the equality is reflexive.
#[test]
fn test_cstr8_eq_std_str() {
let input: &CStr8 = cstr8!("test");

// test various comparisons with different order (left, right)
assert!(input.eq_str_until_nul("test")); // requires ?Sized constraint
assert!(input.eq_str_until_nul(&"test"));
assert!(input.eq_str_until_nul(&String::from("test")));

// now other direction
assert!(String::from("test").eq_str_until_nul(input));
assert!("test".eq_str_until_nul(input));
}

/// Tests the trait implementation of trait [`EqStrUntilNul]` for [`CStr16`].
///
/// This tests that `String` and `str` from the standard library can be
/// checked for equality against a [`CStr16`]. It checks both directions,
/// i.e., the equality is reflexive.
#[test]
fn test_cstr16_eq_std_str() {
let input: &CStr16 = cstr16!("test");

assert!(input.eq_str_until_nul("test")); // requires ?Sized constraint
assert!(input.eq_str_until_nul(&"test"));
assert!(input.eq_str_until_nul(&String::from("test")));

// now other direction
assert!(String::from("test").eq_str_until_nul(input));
assert!("test".eq_str_until_nul(input));
}
}