1//! Wrapper type for by-address hashing and comparison.
2//!
3//! [`ByAddress`] can be used to wrap any pointer type (i.e. any type that implements the Deref
4//! trait). This includes references, raw pointers, smart pointers like `Rc<T>` and `Box<T>`, and
5//! specialized pointer-like types such as `Vec<T>` and `String`.
6//!
7//! Comparison, ordering, and hashing of the wrapped pointer will be based on the address of its
8//! contents, rather than their value.
9//!
10//! ```
11//! use by_address::ByAddress;
12//! use std::rc::Rc;
13//!
14//! let rc = Rc::new(5);
15//! let x = ByAddress(rc.clone());
16//! let y = ByAddress(rc.clone());
17//!
18//! // x and y are two pointers to the same address:
19//! assert_eq!(x, y);
20//!
21//! let z = ByAddress(Rc::new(5));
22//!
23//! // *x and *z have the same value, but not the same address:
24//! assert_ne!(x, z);
25//! ```
26//!
27//! If `T` is a pointer to an unsized type, then comparison of `ByAddress<T>` uses the
28//! entire fat pointer, not just the "thin" data address. This means that two slice pointers
29//! are consider equal only if they have the same starting address *and* length.
30//!
31//! ```
32//! # use by_address::ByAddress;
33//! #
34//! let v = [1, 2, 3, 4];
35//!
36//! assert_eq!(ByAddress(&v[0..4]), ByAddress(&v[0..4])); // Same address and length.
37//! assert_ne!(ByAddress(&v[0..4]), ByAddress(&v[0..2])); // Same address, different length.
38//! ```
39//!
40//! You can use [`ByThinAddress`] instead if you want to compare slices by starting address only,
41//! or trait objects by data pointer only.
42//!
43//! You can use wrapped pointers as keys in hashed or ordered collections, like BTreeMap/BTreeSet
44//! or HashMap/HashSet, even if the target of the pointer doesn't implement hashing or ordering.
45//! This even includes pointers to trait objects, which usually don't implement the Eq trait
46//! because it is not object-safe.
47//!
48//! ```
49//! # use by_address::ByAddress;
50//! # use std::collections::HashSet;
51//! #
52//! /// Call each item in `callbacks`, skipping any duplicate references.
53//! fn call_each_once(callbacks: &[&dyn Fn()]) {
54//! let mut seen: HashSet<ByAddress<&dyn Fn()>> = HashSet::new();
55//! for &f in callbacks {
56//! if seen.insert(ByAddress(f)) {
57//! f();
58//! }
59//! }
60//! }
61//! ```
62//!
63//! However, note that comparing fat pointers to trait objects can be unreliable because of
64//! [Rust issue #46139](https://github.com/rust-lang/rust/issues/46139). In some cases,
65//! [`ByThinAddress`] may be more useful.
66//!
67//! This crate does not depend on libstd, so it can be used in [`no_std`] projects.
68//!
69//! [`no_std`]: https://doc.rust-lang.org/book/first-edition/using-rust-without-the-standard-library.html
7071// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
72// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
73// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
74// option. This file may not be copied, modified, or distributed
75// except according to those terms.
7677#![no_std]
7879use core::cmp::Ordering;
80use core::convert::AsRef;
81use core::fmt::{Debug, Display, Formatter};
82use core::hash::{Hash, Hasher};
83use core::ops::{Deref, DerefMut};
84use core::ptr;
8586/// Wrapper for pointer types that implements by-address comparison.
87///
88/// See the [crate-level documentation](index.html) for details.
89///
90/// Equality tests and hashes on fat pointers (`&dyn Trait`, `&[T]`, `&str`, etc)
91/// include the attribute of the fat pointer.
92///
93/// However, note that comparing fat pointers to trait objects can be unreliable because of
94/// [Rust issue #46139](https://github.com/rust-lang/rust/issues/46139). In some cases,
95/// [`ByThinAddress`] may be more useful.
96#[repr(transparent)]
97#[derive(Copy, Clone, Default)]
98pub struct ByAddress<T>(pub T)
99where
100T: ?Sized + Deref;
101102impl<T> ByAddress<T>
103where
104T: ?Sized + Deref,
105{
106/// Convenience method for pointer casts.
107fn addr(&self) -> *const T::Target {
108&*self.0
109}
110111/// Convert `&T` to `&ByAddress<T>`.
112pub fn from_ref(r: &T) -> &Self {
113// SAFETY: `struct ByAddress` is `repr(transparent)`.
114unsafe {
115&*(r as *const T as *const Self)
116 }
117 }
118}
119120struct DebugAdapter<'a, T>(&'a T)
121where
122T: ?Sized + Deref + Debug;
123124impl<'a, T> Debug for DebugAdapter<'a, T>
125where
126T: ?Sized + Deref + Debug,
127{
128fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
129self.0.fmt(f)?;
130 f.write_str(" @ ")?;
131 (self.0.deref() as *const T::Target).fmt(f)?;
132Ok(())
133 }
134}
135136impl<T> Debug for ByAddress<T>
137where
138T: ?Sized + Deref + Debug,
139{
140fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
141 f.debug_tuple("ByAddress")
142 .field(&DebugAdapter(&self.0))
143 .finish()
144 }
145}
146147impl<T> Display for ByAddress<T>
148where
149T: ?Sized + Deref + Display,
150{
151fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
152self.0.fmt(f)
153 }
154}
155156/// Raw pointer equality
157impl<T> PartialEq for ByAddress<T>
158where
159T: ?Sized + Deref,
160{
161fn eq(&self, other: &Self) -> bool {
162 ptr::eq(self.addr(), other.addr())
163 }
164}
165impl<T> Eq for ByAddress<T> where T: ?Sized + Deref {}
166167/// Raw pointer ordering
168impl<T> Ord for ByAddress<T>
169where
170T: ?Sized + Deref,
171{
172fn cmp(&self, other: &Self) -> Ordering {
173self.addr().cmp(&other.addr())
174 }
175}
176177/// Raw pointer comparison
178impl<T> PartialOrd for ByAddress<T>
179where
180T: ?Sized + Deref,
181{
182fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
183Some(self.addr().cmp(&other.addr()))
184 }
185}
186187/// Raw pointer hashing
188impl<T> Hash for ByAddress<T>
189where
190T: ?Sized + Deref,
191{
192fn hash<H: Hasher>(&self, state: &mut H) {
193self.addr().hash(state)
194 }
195}
196197// Generic conversion traits:
198199impl<T> Deref for ByAddress<T>
200where
201T: ?Sized + Deref,
202{
203type Target = T;
204205fn deref(&self) -> &Self::Target {
206&self.0
207}
208}
209210impl<T> DerefMut for ByAddress<T>
211where
212T: ?Sized + Deref,
213{
214fn deref_mut(&mut self) -> &mut Self::Target {
215&mut self.0
216}
217}
218219impl<T, U> AsRef<U> for ByAddress<T>
220where
221T: ?Sized + Deref + AsRef<U>,
222{
223fn as_ref(&self) -> &U {
224self.0.as_ref()
225 }
226}
227228impl<T, U> AsMut<U> for ByAddress<T>
229where
230T: ?Sized + Deref + AsMut<U>,
231{
232fn as_mut(&mut self) -> &mut U {
233self.0.as_mut()
234 }
235}
236237impl<T> From<T> for ByAddress<T>
238where
239T: Deref,
240{
241fn from(t: T) -> ByAddress<T> {
242 ByAddress(t)
243 }
244}
245246/// Similar to [`ByAddress`], but omits the attributes of fat pointers.
247///
248/// This means that two slices with the same starting element but different lengths will be
249/// considered equal.
250///
251/// Two trait objects with the same data pointer but different vtables will also be considered
252/// equal. (In particular, this may happen for traits that are implemented on zero-sized types,
253/// including `Fn` and other closure traits.)
254#[repr(transparent)]
255#[derive(Copy, Clone, Default)]
256pub struct ByThinAddress<T>(pub T)
257where
258T: ?Sized + Deref;
259260impl<T> ByThinAddress<T>
261where
262T: ?Sized + Deref,
263{
264/// Convenience method for pointer casts.
265fn addr(&self) -> *const T::Target {
266&*self.0
267}
268269/// Convert `&T` to `&ByThinAddress<T>`.
270pub fn from_ref(r: &T) -> &Self {
271// SAFETY: `struct ByAddress` is `repr(transparent)`.
272unsafe {
273&*(r as *const T as *const Self)
274 }
275 }
276}
277278impl<T> Debug for ByThinAddress<T>
279where
280T: ?Sized + Deref + Debug,
281{
282fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
283 f.debug_tuple("ByThinAddress")
284 .field(&DebugAdapter(&self.0))
285 .finish()
286 }
287}
288289impl<T> Display for ByThinAddress<T>
290where
291T: ?Sized + Deref + Display,
292{
293fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
294self.0.fmt(f)
295 }
296}
297298/// Raw pointer equality
299impl<T> PartialEq for ByThinAddress<T>
300where
301T: ?Sized + Deref,
302{
303fn eq(&self, other: &Self) -> bool {
304 core::ptr::eq(self.addr() as *const (), other.addr() as *const _)
305 }
306}
307impl<T> Eq for ByThinAddress<T> where T: ?Sized + Deref {}
308309/// Raw pointer ordering
310impl<T> Ord for ByThinAddress<T>
311where
312T: ?Sized + Deref,
313{
314fn cmp(&self, other: &Self) -> Ordering {
315 (self.addr() as *const ()).cmp(&(other.addr() as *const ()))
316 }
317}
318319/// Raw pointer comparison
320impl<T> PartialOrd for ByThinAddress<T>
321where
322T: ?Sized + Deref,
323{
324fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
325Some((self.addr() as *const ()).cmp(&(other.addr() as *const ())))
326 }
327}
328329/// Raw pointer hashing
330impl<T> Hash for ByThinAddress<T>
331where
332T: ?Sized + Deref,
333{
334fn hash<H: Hasher>(&self, state: &mut H) {
335 (self.addr() as *const ()).hash(state)
336 }
337}
338339// Generic conversion traits:
340341impl<T> Deref for ByThinAddress<T>
342where
343T: ?Sized + Deref,
344{
345type Target = T;
346347fn deref(&self) -> &Self::Target {
348&self.0
349}
350}
351352impl<T> DerefMut for ByThinAddress<T>
353where
354T: ?Sized + Deref,
355{
356fn deref_mut(&mut self) -> &mut Self::Target {
357&mut self.0
358}
359}
360361impl<T, U> AsRef<U> for ByThinAddress<T>
362where
363T: ?Sized + Deref + AsRef<U>,
364{
365fn as_ref(&self) -> &U {
366self.0.as_ref()
367 }
368}
369370#[cfg(test)]
371mod tests {
372extern crate std;
373use std::format;
374375use crate::{ByAddress, ByThinAddress};
376377trait A: std::fmt::Debug {
378fn test(&self) {}
379 }
380trait B: A {
381fn test2(&self) {}
382 }
383384#[derive(Debug)]
385struct Test {}
386impl A for Test {}
387impl B for Test {}
388389fn force_vtable<O: B>(v: &O) -> &dyn A {
390 v
391 }
392393#[test]
394fn test_thin_ptr_fail() {
395let t = Test {};
396let tr1: &dyn A = &t;
397let tr2: &dyn A = force_vtable(&t);
398399let a = ByAddress(tr1);
400let b = ByAddress(tr2);
401402assert_ne!(a, b);
403 }
404405#[test]
406fn test_thin_ptr_success() {
407let t = Test {};
408let tr1: &dyn A = &t;
409let tr2: &dyn A = force_vtable(&t);
410411let a = ByThinAddress(tr1);
412let b = ByThinAddress(tr2);
413414assert_eq!(a, b);
415 }
416417#[test]
418fn test_debug() {
419let x = &1;
420let b = ByAddress(x);
421let expected = format!("ByAddress(1 @ {:p})", x);
422let actual = format!("{:?}", b);
423assert_eq!(expected, actual);
424425let t = ByThinAddress(x);
426let expected = format!("ByThinAddress(1 @ {:p})", x);
427let actual = format!("{:?}", t);
428assert_eq!(expected, actual);
429 }
430}