diff --git a/primitives/src/witness.rs b/primitives/src/witness.rs index b2242932a..f05456262 100644 --- a/primitives/src/witness.rs +++ b/primitives/src/witness.rs @@ -14,7 +14,7 @@ use internals::compact_size; use internals::wrap_debug::WrapDebug; use internals::slice::SliceExt; -use crate::prelude::Vec; +use crate::prelude::{Box, Vec}; /// The Witness is the data used to unlock bitcoin since the [SegWit upgrade]. /// @@ -238,6 +238,109 @@ fn decode_cursor(bytes: &[u8], start_of_indices: usize, index: usize) -> Option< bytes.get_array::<4>(start).map(|index_bytes| u32::from_ne_bytes(*index_bytes) as usize) } +// Note: we use `Borrow` in the following `PartialEq` impls specifically because of its additional +// constraints on equality semantics. +impl> PartialEq<[T]> for Witness { + fn eq(&self, rhs: &[T]) -> bool { + if self.len() != rhs.len() { + return false; + } + self.iter().zip(rhs).all(|(left, right)| left == right.borrow()) + } +} + +impl> PartialEq<&[T]> for Witness { + fn eq(&self, rhs: &&[T]) -> bool { + *self == **rhs + } +} + +impl> PartialEq for [T] { + fn eq(&self, rhs: &Witness) -> bool { + *rhs == *self + } +} + +impl> PartialEq for &[T] { + fn eq(&self, rhs: &Witness) -> bool { + *rhs == **self + } +} + +impl> PartialEq<[T; N]> for Witness { + fn eq(&self, rhs: &[T; N]) -> bool { + *self == *rhs.as_slice() + } +} + +impl> PartialEq<&[T; N]> for Witness { + fn eq(&self, rhs: &&[T; N]) -> bool { + *self == *rhs.as_slice() + } +} + +impl> PartialEq for [T; N] { + fn eq(&self, rhs: &Witness) -> bool { + *rhs == *self + } +} + +impl> PartialEq for &[T; N] { + fn eq(&self, rhs: &Witness) -> bool { + *rhs == **self + } +} + +impl> PartialEq> for Witness { + fn eq(&self, rhs: &Vec) -> bool { + *self == **rhs + } +} + +impl> PartialEq for Vec { + fn eq(&self, rhs: &Witness) -> bool { + *rhs == *self + } +} + +impl> PartialEq> for Witness { + fn eq(&self, rhs: &Box<[T]>) -> bool { + *self == **rhs + } +} + +impl> PartialEq for Box<[T]> { + fn eq(&self, rhs: &Witness) -> bool { + *rhs == *self + } +} + +impl> PartialEq> for Witness { + fn eq(&self, rhs: &alloc::rc::Rc<[T]>) -> bool { + *self == **rhs + } +} + +impl> PartialEq for alloc::rc::Rc<[T]> { + fn eq(&self, rhs: &Witness) -> bool { + *rhs == *self + } +} + +#[cfg(target_has_atomic = "ptr")] +impl> PartialEq> for Witness { + fn eq(&self, rhs: &alloc::sync::Arc<[T]>) -> bool { + *self == **rhs + } +} + +#[cfg(target_has_atomic = "ptr")] +impl> PartialEq for alloc::sync::Arc<[T]> { + fn eq(&self, rhs: &Witness) -> bool { + *rhs == *self + } +} + /// Debug implementation that displays the witness as a structured output containing: /// - Number of witness elements /// - Total bytes across all elements @@ -643,6 +746,27 @@ mod test { assert!(expected.is_empty()); } + #[test] + fn partial_eq() { + const EMPTY_BYTES: &[u8] = &[]; + assert_eq!(Vec::<&[u8]>::new(), Witness::new()); + macro_rules! ck { + ($container:expr) => { + { + let container = $container; + let witness = Witness::from(Clone::clone(&container)); + assert_eq!(witness, container, stringify!($container)); + } + } + } + ck!([EMPTY_BYTES]); + ck!([EMPTY_BYTES, EMPTY_BYTES]); + ck!([[42]]); + ck!([[42, 21]]); + ck!([&[42], EMPTY_BYTES]); + ck!([[42u8], [21]]); + } + #[test] #[cfg(feature = "serde")] fn serde_bincode_backward_compatibility() {