1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Copyright (c) 2023 Zacharie Dubrulle
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! [![github]](https://github.com/Rayzeq/dyn-eq)
//! [![crates.io]](https://crates.io/crates/dyn-eq)
//! [![license]](https://www.mozilla.org/en-US/MPL/2.0/)
//! [![passively-maintained]](https://github.com/Rayzeq/dyn-eq/issues)
//!
//! [github]: https://img.shields.io/badge/github-rayzeq/dyn--eq-a?style=for-the-badge&logo=github
//! [crates.io]: https://img.shields.io/crates/v/dyn-eq?style=for-the-badge&logo=rust
//! [license]: https://img.shields.io/crates/l/dyn-eq?style=for-the-badge
//! [passively-maintained]: https://img.shields.io/badge/maintenance-passively--maintained-brightgreen?style=for-the-badge
//!
//! This crate provides a [`DynEq`] trait which permit comparing trait objects.
//! If the two objects are instances of different structs, they will always be
//! not equal. If they are instances of the same struct, the struct's [`Eq`]
//! will be used.
//!
//! ###### Todos
//!
//! Here's a list of things that could be done and could be nice to have, but I'll implement them only if someone ask:
//!   - [ ] Permit having `PartialEq` without `Eq` (implementation on `dyn Trait` will follow)
//!
//! # Features
//!
//! This crate has one feature: `alloc`, which is enabled by default. Disabling
//! this feature removes the dependency on the [`alloc`] crate, but you won't be
//! able to use [`DynEq`] for `Box<dyn Trait>`.
//!
//! [`alloc`]: https://doc.rust-lang.org/alloc/
//!
//! # Example
//!
//! ```
//! use dyn_eq::DynEq;
//!
//! trait MyTrait: DynEq {}
//! dyn_eq::eq_trait_object!(MyTrait);
//!
//! impl MyTrait for u8 {}
//! impl MyTrait for u16 {}
//!
//! let a: &dyn MyTrait = &5u8;
//! let a_bis: &dyn MyTrait = &5u8;
//! let b: &dyn MyTrait = &10u8;
//! let c: &dyn MyTrait = &5u16;
//! let d: &dyn MyTrait = &10u16;
//!
//! // Same type, same value
//! assert!(a == a_bis);
//! // Same type, different value
//! assert!(a != b);
//! // Different type, different value
//! assert!(a != d);
//! // Different type, same value
//! // Even if the value is the same, the fact that it's a diffrent type means it's not equal
//! assert!(a != c);
//!
//! // Now data structures containing Box<dyn MyTrait> can derive Eq (only when `alloc`
//! // feature is enabled).
//! # #[cfg(feature = "alloc")]
//! #[derive(PartialEq, Eq)]
//! struct Container {
//!     field: Box<dyn MyTrait>
//! }
//! ```
#![no_std]

#[cfg(feature = "alloc")]
extern crate alloc;

/// Re-export of [`alloc::boxed::Box`] for the macro.
///
#[cfg(feature = "alloc")]
#[doc(hidden)]
pub use alloc::boxed::Box;
use core::any::Any;

mod macros;

/// This trait is implemented by any type that implements [`Eq`].
///
/// [`Eq`]: ::core::cmp::PartialEq
pub trait DynEq: Any + private::Sealed {
	/// Upcast this reference to a `&dyn Any`, which can then be passed to [`dyn_eq`](DynEq::dyn_eq).
	#[doc(hidden)]
	fn as_any(&self) -> &dyn Any;

	/// This method tests for self and other values to be equal.
	#[doc(hidden)]
	fn dyn_eq(&self, other: &dyn Any) -> bool;
}

impl<T: Eq + 'static> DynEq for T {
	fn as_any(&self) -> &dyn Any {
		self
	}

	fn dyn_eq(&self, other: &dyn Any) -> bool {
		other.downcast_ref().map_or(false, |other| self == other)
	}
}

/// Private module to seal the [`DynEq`] trait
mod private {
	/// Sealing trait
	pub trait Sealed {}
	impl<T> Sealed for T where T: PartialEq {}
}