about summary refs log tree commit diff
path: root/library/core/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/core/src')
-rw-r--r--library/core/src/cmp.rs3
-rw-r--r--library/core/src/cmp/bytewise.rs8
-rw-r--r--library/core/src/intrinsics/mod.rs1
-rw-r--r--library/core/src/lib.rs2
-rw-r--r--library/core/src/macros/mod.rs2
-rw-r--r--library/core/src/num/nonzero.rs5
-rw-r--r--library/core/src/option.rs140
-rw-r--r--library/core/src/prelude/v1.rs2
-rw-r--r--library/core/src/slice/cmp.rs22
-rw-r--r--library/core/src/str/traits.rs3
10 files changed, 132 insertions, 56 deletions
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 03b120fbf0c..6419ae99113 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -381,7 +381,8 @@ pub struct AssertParamIsEq<T: Eq + PointeeSized> {
 ///
 /// assert_eq!(2.cmp(&1), Ordering::Greater);
 /// ```
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+#[derive(Clone, Copy, Eq, PartialOrd, Ord, Debug, Hash)]
+#[derive_const(PartialEq)]
 #[stable(feature = "rust1", since = "1.0.0")]
 // This is a lang item only so that `BinOp::Cmp` in MIR can return it.
 // It has no special behavior, but does require that the three variants
diff --git a/library/core/src/cmp/bytewise.rs b/library/core/src/cmp/bytewise.rs
index a06a5227fe2..7d61c9345ec 100644
--- a/library/core/src/cmp/bytewise.rs
+++ b/library/core/src/cmp/bytewise.rs
@@ -17,11 +17,15 @@ use crate::num::NonZero;
 /// - Neither `Self` nor `Rhs` have provenance, so integer comparisons are correct.
 /// - `<Self as PartialEq<Rhs>>::{eq,ne}` are equivalent to comparing the bytes.
 #[rustc_specialization_trait]
-pub(crate) unsafe trait BytewiseEq<Rhs = Self>: PartialEq<Rhs> + Sized {}
+#[const_trait]
+pub(crate) unsafe trait BytewiseEq<Rhs = Self>:
+    ~const PartialEq<Rhs> + Sized
+{
+}
 
 macro_rules! is_bytewise_comparable {
     ($($t:ty),+ $(,)?) => {$(
-        unsafe impl BytewiseEq for $t {}
+        unsafe impl const BytewiseEq for $t {}
     )+};
 }
 
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index fa27acac217..f90e6851d1f 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -2208,6 +2208,7 @@ pub const unsafe fn raw_eq<T>(a: &T, b: &T) -> bool;
 /// [valid]: crate::ptr#safety
 #[rustc_nounwind]
 #[rustc_intrinsic]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
 pub const unsafe fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32;
 
 /// See documentation of [`std::hint::black_box`] for details.
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index e08edde3b38..729de5ffc8f 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -103,6 +103,7 @@
 #![feature(cfg_select)]
 #![feature(cfg_target_has_reliable_f16_f128)]
 #![feature(const_carrying_mul_add)]
+#![feature(const_cmp)]
 #![feature(const_destruct)]
 #![feature(const_eval_select)]
 #![feature(core_intrinsics)]
@@ -146,6 +147,7 @@
 #![feature(const_trait_impl)]
 #![feature(decl_macro)]
 #![feature(deprecated_suggestion)]
+#![feature(derive_const)]
 #![feature(doc_cfg)]
 #![feature(doc_cfg_hide)]
 #![feature(doc_notable_trait)]
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 1b6dbc2f428..8ac6ce2242d 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1615,7 +1615,7 @@ pub(crate) mod builtin {
     /// See [the reference] for more info.
     ///
     /// [the reference]: ../../../reference/attributes/derive.html
-    #[unstable(feature = "derive_const", issue = "none")]
+    #[unstable(feature = "derive_const", issue = "118304")]
     #[rustc_builtin_macro]
     pub macro derive_const($item:item) {
         /* compiler built-in */
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 11d50e0f89f..b8900c4113a 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -200,9 +200,10 @@ impl<T> UseCloned for NonZero<T> where T: ZeroablePrimitive {}
 impl<T> Copy for NonZero<T> where T: ZeroablePrimitive {}
 
 #[stable(feature = "nonzero", since = "1.28.0")]
-impl<T> PartialEq for NonZero<T>
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T> const PartialEq for NonZero<T>
 where
-    T: ZeroablePrimitive + PartialEq,
+    T: ZeroablePrimitive + ~const PartialEq,
 {
     #[inline]
     fn eq(&self, other: &Self) -> bool {
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 9f432758a66..8036c59e893 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -577,6 +577,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::iter::{self, FusedIterator, TrustedLen};
+use crate::marker::Destruct;
 use crate::ops::{self, ControlFlow, Deref, DerefMut};
 use crate::panicking::{panic, panic_display};
 use crate::pin::Pin;
@@ -649,7 +650,8 @@ impl<T> Option<T> {
     #[must_use]
     #[inline]
     #[stable(feature = "is_some_and", since = "1.70.0")]
-    pub fn is_some_and(self, f: impl FnOnce(T) -> bool) -> bool {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn is_some_and(self, f: impl ~const FnOnce(T) -> bool + ~const Destruct) -> bool {
         match self {
             None => false,
             Some(x) => f(x),
@@ -697,7 +699,8 @@ impl<T> Option<T> {
     #[must_use]
     #[inline]
     #[stable(feature = "is_none_or", since = "1.82.0")]
-    pub fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn is_none_or(self, f: impl ~const FnOnce(T) -> bool + ~const Destruct) -> bool {
         match self {
             None => true,
             Some(x) => f(x),
@@ -1023,7 +1026,12 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unwrap_or(self, default: T) -> T {
+    #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn unwrap_or(self, default: T) -> T
+    where
+        T: ~const Destruct,
+    {
         match self {
             Some(x) => x,
             None => default,
@@ -1042,9 +1050,10 @@ impl<T> Option<T> {
     #[inline]
     #[track_caller]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unwrap_or_else<F>(self, f: F) -> T
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn unwrap_or_else<F>(self, f: F) -> T
     where
-        F: FnOnce() -> T,
+        F: ~const FnOnce() -> T + ~const Destruct,
     {
         match self {
             Some(x) => x,
@@ -1073,9 +1082,10 @@ impl<T> Option<T> {
     /// [`FromStr`]: crate::str::FromStr
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unwrap_or_default(self) -> T
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn unwrap_or_default(self) -> T
     where
-        T: Default,
+        T: ~const Default,
     {
         match self {
             Some(x) => x,
@@ -1139,9 +1149,10 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn map<U, F>(self, f: F) -> Option<U>
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn map<U, F>(self, f: F) -> Option<U>
     where
-        F: FnOnce(T) -> U,
+        F: ~const FnOnce(T) -> U + ~const Destruct,
     {
         match self {
             Some(x) => Some(f(x)),
@@ -1169,7 +1180,11 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "result_option_inspect", since = "1.76.0")]
-    pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn inspect<F>(self, f: F) -> Self
+    where
+        F: ~const FnOnce(&T) + ~const Destruct,
+    {
         if let Some(ref x) = self {
             f(x);
         }
@@ -1198,9 +1213,11 @@ impl<T> Option<T> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use = "if you don't need the returned value, use `if let` instead"]
-    pub fn map_or<U, F>(self, default: U, f: F) -> U
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn map_or<U, F>(self, default: U, f: F) -> U
     where
-        F: FnOnce(T) -> U,
+        F: ~const FnOnce(T) -> U + ~const Destruct,
+        U: ~const Destruct,
     {
         match self {
             Some(t) => f(t),
@@ -1243,10 +1260,11 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn map_or_else<U, D, F>(self, default: D, f: F) -> U
     where
-        D: FnOnce() -> U,
-        F: FnOnce(T) -> U,
+        D: ~const FnOnce() -> U + ~const Destruct,
+        F: ~const FnOnce(T) -> U + ~const Destruct,
     {
         match self {
             Some(t) => f(t),
@@ -1273,10 +1291,11 @@ impl<T> Option<T> {
     /// [default value]: Default::default
     #[inline]
     #[unstable(feature = "result_option_map_or_default", issue = "138099")]
-    pub fn map_or_default<U, F>(self, f: F) -> U
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn map_or_default<U, F>(self, f: F) -> U
     where
-        U: Default,
-        F: FnOnce(T) -> U,
+        U: ~const Default,
+        F: ~const FnOnce(T) -> U + ~const Destruct,
     {
         match self {
             Some(t) => f(t),
@@ -1307,7 +1326,8 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn ok_or<E>(self, err: E) -> Result<T, E> {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn ok_or<E: ~const Destruct>(self, err: E) -> Result<T, E> {
         match self {
             Some(v) => Ok(v),
             None => Err(err),
@@ -1332,9 +1352,10 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
     where
-        F: FnOnce() -> E,
+        F: ~const FnOnce() -> E + ~const Destruct,
     {
         match self {
             Some(v) => Ok(v),
@@ -1463,7 +1484,12 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn and<U>(self, optb: Option<U>) -> Option<U> {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn and<U>(self, optb: Option<U>) -> Option<U>
+    where
+        T: ~const Destruct,
+        U: ~const Destruct,
+    {
         match self {
             Some(_) => optb,
             None => None,
@@ -1502,9 +1528,10 @@ impl<T> Option<T> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_confusables("flat_map", "flatmap")]
-    pub fn and_then<U, F>(self, f: F) -> Option<U>
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn and_then<U, F>(self, f: F) -> Option<U>
     where
-        F: FnOnce(T) -> Option<U>,
+        F: ~const FnOnce(T) -> Option<U> + ~const Destruct,
     {
         match self {
             Some(x) => f(x),
@@ -1538,9 +1565,11 @@ impl<T> Option<T> {
     /// [`Some(t)`]: Some
     #[inline]
     #[stable(feature = "option_filter", since = "1.27.0")]
-    pub fn filter<P>(self, predicate: P) -> Self
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn filter<P>(self, predicate: P) -> Self
     where
-        P: FnOnce(&T) -> bool,
+        P: ~const FnOnce(&T) -> bool + ~const Destruct,
+        T: ~const Destruct,
     {
         if let Some(x) = self {
             if predicate(&x) {
@@ -1579,7 +1608,11 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn or(self, optb: Option<T>) -> Option<T> {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn or(self, optb: Option<T>) -> Option<T>
+    where
+        T: ~const Destruct,
+    {
         match self {
             x @ Some(_) => x,
             None => optb,
@@ -1601,9 +1634,13 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn or_else<F>(self, f: F) -> Option<T>
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn or_else<F>(self, f: F) -> Option<T>
     where
-        F: FnOnce() -> Option<T>,
+        F: ~const FnOnce() -> Option<T> + ~const Destruct,
+        //FIXME(const_hack): this `T: ~const Destruct` is unnecessary, but even precise live drops can't tell
+        // no value of type `T` gets dropped here
+        T: ~const Destruct,
     {
         match self {
             x @ Some(_) => x,
@@ -1634,7 +1671,11 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "option_xor", since = "1.37.0")]
-    pub fn xor(self, optb: Option<T>) -> Option<T> {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn xor(self, optb: Option<T>) -> Option<T>
+    where
+        T: ~const Destruct,
+    {
         match (self, optb) {
             (a @ Some(_), None) => a,
             (None, b @ Some(_)) => b,
@@ -1668,7 +1709,11 @@ impl<T> Option<T> {
     #[must_use = "if you intended to set a value, consider assignment instead"]
     #[inline]
     #[stable(feature = "option_insert", since = "1.53.0")]
-    pub fn insert(&mut self, value: T) -> &mut T {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn insert(&mut self, value: T) -> &mut T
+    where
+        T: ~const Destruct,
+    {
         *self = Some(value);
 
         // SAFETY: the code above just filled the option
@@ -1720,9 +1765,10 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "option_get_or_insert_default", since = "1.83.0")]
-    pub fn get_or_insert_default(&mut self) -> &mut T
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn get_or_insert_default(&mut self) -> &mut T
     where
-        T: Default,
+        T: ~const Default + ~const Destruct,
     {
         self.get_or_insert_with(T::default)
     }
@@ -1746,9 +1792,11 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "option_entry", since = "1.20.0")]
-    pub fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
     where
-        F: FnOnce() -> T,
+        F: ~const FnOnce() -> T + ~const Destruct,
+        T: ~const Destruct,
     {
         if let None = self {
             *self = Some(f());
@@ -1812,9 +1860,10 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "option_take_if", since = "1.80.0")]
-    pub fn take_if<P>(&mut self, predicate: P) -> Option<T>
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn take_if<P>(&mut self, predicate: P) -> Option<T>
     where
-        P: FnOnce(&mut T) -> bool,
+        P: ~const FnOnce(&mut T) -> bool + ~const Destruct,
     {
         if self.as_mut().map_or(false, predicate) { self.take() } else { None }
     }
@@ -1859,7 +1908,12 @@ impl<T> Option<T> {
     /// assert_eq!(x.zip(z), None);
     /// ```
     #[stable(feature = "option_zip_option", since = "1.46.0")]
-    pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)> {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn zip<U>(self, other: Option<U>) -> Option<(T, U)>
+    where
+        T: ~const Destruct,
+        U: ~const Destruct,
+    {
         match (self, other) {
             (Some(a), Some(b)) => Some((a, b)),
             _ => None,
@@ -1895,9 +1949,12 @@ impl<T> Option<T> {
     /// assert_eq!(x.zip_with(None, Point::new), None);
     /// ```
     #[unstable(feature = "option_zip", issue = "70086")]
-    pub fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
     where
-        F: FnOnce(T, U) -> R,
+        F: ~const FnOnce(T, U) -> R + ~const Destruct,
+        T: ~const Destruct,
+        U: ~const Destruct,
     {
         match (self, other) {
             (Some(a), Some(b)) => Some(f(a, b)),
@@ -2243,7 +2300,8 @@ impl<'a, T> From<&'a mut Option<T>> for Option<&'a mut T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> crate::marker::StructuralPartialEq for Option<T> {}
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialEq> PartialEq for Option<T> {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T: ~const PartialEq> const PartialEq for Option<T> {
     #[inline]
     fn eq(&self, other: &Self) -> bool {
         // Spelling out the cases explicitly optimizes better than
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index 7b9e04920d5..a4be66b90ca 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -80,7 +80,7 @@ pub use crate::macros::builtin::{
     alloc_error_handler, bench, derive, global_allocator, test, test_case,
 };
 
-#[unstable(feature = "derive_const", issue = "none")]
+#[unstable(feature = "derive_const", issue = "118304")]
 pub use crate::macros::builtin::derive_const;
 
 #[unstable(
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index 5ce72b46eee..1eda8bc1bec 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -8,9 +8,10 @@ use crate::num::NonZero;
 use crate::ops::ControlFlow;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, U> PartialEq<[U]> for [T]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T, U> const PartialEq<[U]> for [T]
 where
-    T: PartialEq<U>,
+    T: ~const PartialEq<U>,
 {
     fn eq(&self, other: &[U]) -> bool {
         SlicePartialEq::equal(self, other)
@@ -94,6 +95,8 @@ impl<T: PartialOrd> PartialOrd for [T] {
 
 #[doc(hidden)]
 // intermediate trait for specialization of slice's PartialEq
+#[const_trait]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
 trait SlicePartialEq<B> {
     fn equal(&self, other: &[B]) -> bool;
 
@@ -103,9 +106,10 @@ trait SlicePartialEq<B> {
 }
 
 // Generic slice equality
-impl<A, B> SlicePartialEq<B> for [A]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<A, B> const SlicePartialEq<B> for [A]
 where
-    A: PartialEq<B>,
+    A: ~const PartialEq<B>,
 {
     default fn equal(&self, other: &[B]) -> bool {
         if self.len() != other.len() {
@@ -115,11 +119,14 @@ where
         // Implemented as explicit indexing rather
         // than zipped iterators for performance reasons.
         // See PR https://github.com/rust-lang/rust/pull/116846
-        for idx in 0..self.len() {
+        // FIXME(const_hack): make this a `for idx in 0..self.len()` loop.
+        let mut idx = 0;
+        while idx < self.len() {
             // bound checks are optimized away
             if self[idx] != other[idx] {
                 return false;
             }
+            idx += 1;
         }
 
         true
@@ -128,9 +135,10 @@ where
 
 // When each element can be compared byte-wise, we can compare all the bytes
 // from the whole size in one call to the intrinsics.
-impl<A, B> SlicePartialEq<B> for [A]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<A, B> const SlicePartialEq<B> for [A]
 where
-    A: BytewiseEq<B>,
+    A: ~const BytewiseEq<B>,
 {
     fn equal(&self, other: &[B]) -> bool {
         if self.len() != other.len() {
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index 42ffc591b5b..d0f2b9226bf 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -23,7 +23,8 @@ impl Ord for str {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl PartialEq for str {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl const PartialEq for str {
     #[inline]
     fn eq(&self, other: &str) -> bool {
         self.as_bytes() == other.as_bytes()