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: &[&Fn()]) {
54//! let mut seen: HashSet<ByAddress<&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
70
71// 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.
76
77#![no_std]
78
79use core::cmp::Ordering;
80use core::convert::AsRef;
81use core::fmt::{Debug, Display, Formatter};
82use core::hash::{Hash, Hasher};
83use core::ops::{Deref, DerefMut};
84
85/// Wrapper for pointer types that implements by-address comparison.
86///
87/// See the [crate-level documentation](index.html) for details.
88///
89/// Note that equality tests and hashes on fat pointers (`&dyn Trait`, `&[T]`, `&str`, etc)
90/// include the attribute of the fat pointer. If this is not desired, use [`ByThinAddress`].
91#[derive(Copy, Clone, Default)]
92pub struct ByAddress<T>(pub T)
93where
94 T: ?Sized + Deref;
95
96impl<T> ByAddress<T>
97where
98 T: ?Sized + Deref,
99{
100 /// Convenience method for pointer casts.
101 fn addr(&self) -> *const T::Target {
102 &*self.0
103 }
104}
105
106struct DebugAdapter<'a, T>(&'a T)
107where
108 T: ?Sized + Deref + Debug;
109
110impl<'a, T> Debug for DebugAdapter<'a, T>
111where
112 T: ?Sized + Deref + Debug,
113{
114 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
115 self.0.fmt(f)?;
116 f.write_str(data:" @ ")?;
117 (self.0.deref() as *const T::Target).fmt(f)?;
118 Ok(())
119 }
120}
121
122impl<T> Debug for ByAddress<T>
123where
124 T: ?Sized + Deref + Debug,
125{
126 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
127 f&mut DebugTuple<'_, '_>.debug_tuple(name:"ByAddress")
128 .field(&DebugAdapter(&self.0))
129 .finish()
130 }
131}
132
133impl<T> Display for ByAddress<T>
134where
135 T: ?Sized + Deref + Display,
136{
137 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
138 self.0.fmt(f)
139 }
140}
141
142/// Raw pointer equality
143impl<T> PartialEq for ByAddress<T>
144where
145 T: ?Sized + Deref,
146{
147 fn eq(&self, other: &Self) -> bool {
148 self.addr() == other.addr()
149 }
150}
151impl<T> Eq for ByAddress<T> where T: ?Sized + Deref {}
152
153/// Raw pointer ordering
154impl<T> Ord for ByAddress<T>
155where
156 T: ?Sized + Deref,
157{
158 fn cmp(&self, other: &Self) -> Ordering {
159 self.addr().cmp(&other.addr())
160 }
161}
162
163/// Raw pointer comparison
164impl<T> PartialOrd for ByAddress<T>
165where
166 T: ?Sized + Deref,
167{
168 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
169 Some(self.addr().cmp(&other.addr()))
170 }
171}
172
173/// Raw pointer hashing
174impl<T> Hash for ByAddress<T>
175where
176 T: ?Sized + Deref,
177{
178 fn hash<H: Hasher>(&self, state: &mut H) {
179 self.addr().hash(state)
180 }
181}
182
183// Generic conversion traits:
184
185impl<T> Deref for ByAddress<T>
186where
187 T: ?Sized + Deref,
188{
189 type Target = T;
190
191 fn deref(&self) -> &Self::Target {
192 &self.0
193 }
194}
195
196impl<T> DerefMut for ByAddress<T>
197where
198 T: ?Sized + Deref,
199{
200 fn deref_mut(&mut self) -> &mut Self::Target {
201 &mut self.0
202 }
203}
204
205impl<T, U> AsRef<U> for ByAddress<T>
206where
207 T: ?Sized + Deref + AsRef<U>,
208{
209 fn as_ref(&self) -> &U {
210 self.0.as_ref()
211 }
212}
213
214impl<T, U> AsMut<U> for ByAddress<T>
215where
216 T: ?Sized + Deref + AsMut<U>,
217{
218 fn as_mut(&mut self) -> &mut U {
219 self.0.as_mut()
220 }
221}
222
223impl<T> From<T> for ByAddress<T>
224where
225 T: Deref,
226{
227 fn from(t: T) -> ByAddress<T> {
228 ByAddress(t)
229 }
230}
231
232/// Similar to [`ByAddress`], but omits the attributes of fat pointers.
233#[derive(Copy, Clone, Default)]
234pub struct ByThinAddress<T>(pub T)
235where
236 T: ?Sized + Deref;
237
238impl<T> ByThinAddress<T>
239where
240 T: ?Sized + Deref,
241{
242 /// Convenience method for pointer casts.
243 fn addr(&self) -> *const T::Target {
244 &*self.0
245 }
246}
247
248impl<T> Debug for ByThinAddress<T>
249where
250 T: ?Sized + Deref + Debug,
251{
252 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
253 f&mut DebugTuple<'_, '_>.debug_tuple(name:"ByThinAddress")
254 .field(&DebugAdapter(&self.0))
255 .finish()
256 }
257}
258
259impl<T> Display for ByThinAddress<T>
260where
261 T: ?Sized + Deref + Display,
262{
263 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
264 self.0.fmt(f)
265 }
266}
267
268/// Raw pointer equality
269impl<T> PartialEq for ByThinAddress<T>
270where
271 T: ?Sized + Deref,
272{
273 fn eq(&self, other: &Self) -> bool {
274 core::ptr::eq(self.addr() as *const (), b:other.addr() as *const _)
275 }
276}
277impl<T> Eq for ByThinAddress<T> where T: ?Sized + Deref {}
278
279/// Raw pointer ordering
280impl<T> Ord for ByThinAddress<T>
281where
282 T: ?Sized + Deref,
283{
284 fn cmp(&self, other: &Self) -> Ordering {
285 (self.addr() as *const ()).cmp(&(other.addr() as *const ()))
286 }
287}
288
289/// Raw pointer comparison
290impl<T> PartialOrd for ByThinAddress<T>
291where
292 T: ?Sized + Deref,
293{
294 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
295 Some((self.addr() as *const ()).cmp(&(other.addr() as *const ())))
296 }
297}
298
299/// Raw pointer hashing
300impl<T> Hash for ByThinAddress<T>
301where
302 T: ?Sized + Deref,
303{
304 fn hash<H: Hasher>(&self, state: &mut H) {
305 (self.addr() as *const ()).hash(state)
306 }
307}
308
309// Generic conversion traits:
310
311impl<T> Deref for ByThinAddress<T>
312where
313 T: ?Sized + Deref,
314{
315 type Target = T;
316
317 fn deref(&self) -> &Self::Target {
318 &self.0
319 }
320}
321
322impl<T> DerefMut for ByThinAddress<T>
323where
324 T: ?Sized + Deref,
325{
326 fn deref_mut(&mut self) -> &mut Self::Target {
327 &mut self.0
328 }
329}
330
331impl<T, U> AsRef<U> for ByThinAddress<T>
332where
333 T: ?Sized + Deref + AsRef<U>,
334{
335 fn as_ref(&self) -> &U {
336 self.0.as_ref()
337 }
338}
339
340#[cfg(test)]
341mod tests {
342 extern crate std;
343 use std::format;
344
345 use crate::{ByAddress, ByThinAddress};
346
347 trait A: std::fmt::Debug {
348 fn test(&self) {}
349 }
350 trait B: A {
351 fn test2(&self) {}
352 }
353
354 #[derive(Debug)]
355 struct Test {}
356 impl A for Test {}
357 impl B for Test {}
358
359 fn force_vtable<O: B>(v: &O) -> &dyn A {
360 v
361 }
362
363 #[test]
364 fn test_thin_ptr_fail() {
365 let t = Test {};
366 let tr1: &dyn A = &t;
367 let tr2: &dyn A = force_vtable(&t);
368
369 let a = ByAddress(tr1);
370 let b = ByAddress(tr2);
371
372 assert_ne!(a, b);
373 }
374
375 #[test]
376 fn test_thin_ptr_success() {
377 let t = Test {};
378 let tr1: &dyn A = &t;
379 let tr2: &dyn A = force_vtable(&t);
380
381 let a = ByThinAddress(tr1);
382 let b = ByThinAddress(tr2);
383
384 assert_eq!(a, b);
385 }
386
387 #[test]
388 fn test_debug() {
389 let x = &1;
390 let b = ByAddress(x);
391 let expected = format!("ByAddress(1 @ {:p})", x);
392 let actual = format!("{:?}", b);
393 assert_eq!(expected, actual);
394
395 let t = ByThinAddress(x);
396 let expected = format!("ByThinAddress(1 @ {:p})", x);
397 let actual = format!("{:?}", t);
398 assert_eq!(expected, actual);
399 }
400}
401