diff --git a/CHANGELOG.md b/CHANGELOG.md index f3733591c..f489ab376 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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] diff --git a/uefi/src/data_types/owned_strs.rs b/uefi/src/data_types/owned_strs.rs index b8192d8ca..eebae6b11 100644 --- a/uefi/src/data_types/owned_strs.rs +++ b/uefi/src/data_types/owned_strs.rs @@ -128,7 +128,7 @@ impl PartialEq<&CStr16> for CString16 { } } -impl> EqStrUntilNul for CString16 { +impl + ?Sized> EqStrUntilNul for CString16 { fn eq_str_until_nul(&self, other: &StrType) -> bool { let this = self.as_ref(); this.eq_str_until_nul(other) @@ -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"))); diff --git a/uefi/src/data_types/strs.rs b/uefi/src/data_types/strs.rs index 1df8c6935..014267a20 100644 --- a/uefi/src/data_types/strs.rs +++ b/uefi/src/data_types/strs.rs @@ -136,7 +136,7 @@ impl fmt::Display for CStr8 { } } -impl> EqStrUntilNul for CStr8 { +impl + ?Sized> EqStrUntilNul for CStr8 { fn eq_str_until_nul(&self, other: &StrType) -> bool { let other = other.as_ref(); @@ -147,7 +147,8 @@ impl> EqStrUntilNul 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); @@ -345,7 +346,7 @@ impl CStr16 { } } -impl> EqStrUntilNul for CStr16 { +impl + ?Sized> EqStrUntilNul for CStr16 { fn eq_str_until_nul(&self, other: &StrType) -> bool { let other = other.as_ref(); @@ -354,7 +355,8 @@ impl> EqStrUntilNul 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); @@ -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 { /// 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. @@ -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)); + } }