about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-07-25 18:57:58 +0200
committerGitHub <noreply@github.com>2024-07-25 18:57:58 +0200
commit512277ff70082a9614b277e8c460c99702d17723 (patch)
tree50c4d6108e671fbc7429485ea63fdc967d0e7752
parentc96311bf8a172726e7772cc8a7ea7768f464705b (diff)
parentcf9816c17e1c265af2906a8a5a7c025be3f3dccb (diff)
downloadrust-512277ff70082a9614b277e8c460c99702d17723.tar.gz
rust-512277ff70082a9614b277e8c460c99702d17723.zip
Rollup merge of #128137 - GrigorenkoPV:cstr-derive, r=dtolnay
CStr: derive PartialEq, Eq; add test for Ord

While working on #128046, I've spotted a peculiarity: `CStr` has `PartialEq, Eq, PartialOrd, Ord` implemented manually and not derived.

While we can't derive `PartialOrd, Ord` (due to inner `[c_char]` being `[i8]` or `[u8]` on different platforms), we *can* derive `PartialEq, Eq` (I think), allowing as to remove `#[allow(clippy::derived_hash_with_manual_eq)]` as well.

(I really hope `c_char: Eq` on all platforms)
-rw-r--r--library/core/src/ffi/c_str.rs15
-rw-r--r--library/core/tests/ffi.rs1
-rw-r--r--library/core/tests/ffi/cstr.rs15
-rw-r--r--library/core/tests/lib.rs1
4 files changed, 21 insertions, 11 deletions
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index c9111254082..ae42ae3baf4 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -94,7 +94,7 @@ use crate::str;
 /// ```
 ///
 /// [str]: prim@str "str"
-#[derive(Hash)]
+#[derive(PartialEq, Eq, Hash)]
 #[stable(feature = "core_c_str", since = "1.64.0")]
 #[rustc_has_incoherent_inherent_impls]
 #[lang = "CStr"]
@@ -104,7 +104,6 @@ use crate::str;
 // want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under
 // `cfg(doc)`. This is an ad-hoc implementation of attribute privacy.
 #[repr(transparent)]
-#[allow(clippy::derived_hash_with_manual_eq)]
 pub struct CStr {
     // FIXME: this should not be represented with a DST slice but rather with
     //        just a raw `c_char` along with some form of marker to make
@@ -678,15 +677,9 @@ impl CStr {
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl PartialEq for CStr {
-    #[inline]
-    fn eq(&self, other: &CStr) -> bool {
-        self.to_bytes().eq(other.to_bytes())
-    }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Eq for CStr {}
+// `.to_bytes()` representations are compared instead of the inner `[c_char]`s,
+// because `c_char` is `i8` (not `u8`) on some platforms.
+// That is why this is implemented manually and not derived.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl PartialOrd for CStr {
     #[inline]
diff --git a/library/core/tests/ffi.rs b/library/core/tests/ffi.rs
new file mode 100644
index 00000000000..2b33fbd95f0
--- /dev/null
+++ b/library/core/tests/ffi.rs
@@ -0,0 +1 @@
+mod cstr;
diff --git a/library/core/tests/ffi/cstr.rs b/library/core/tests/ffi/cstr.rs
new file mode 100644
index 00000000000..9bf4c21a9ab
--- /dev/null
+++ b/library/core/tests/ffi/cstr.rs
@@ -0,0 +1,15 @@
+use core::ffi::CStr;
+
+#[test]
+fn compares_as_u8s() {
+    let a: &CStr = c"Hello!"; // Starts with ascii
+    let a_bytes: &[u8] = a.to_bytes();
+    assert!((..0b1000_0000).contains(&a_bytes[0]));
+
+    let b: &CStr = c"こんにちは!"; // Starts with non ascii
+    let b_bytes: &[u8] = b.to_bytes();
+    assert!((0b1000_0000..).contains(&b_bytes[0]));
+
+    assert_eq!(Ord::cmp(a, b), Ord::cmp(a_bytes, b_bytes));
+    assert_eq!(PartialOrd::partial_cmp(a, b), PartialOrd::partial_cmp(a_bytes, b_bytes));
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 83a615fcd8b..04aaa3f35b7 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -132,6 +132,7 @@ mod clone;
 mod cmp;
 mod const_ptr;
 mod convert;
+mod ffi;
 mod fmt;
 mod future;
 mod hash;