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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
//! Wrapper type for by-address hashing and comparison. //! //! [ByAddress] can be used to wrap any pointer type (i.e. any type that implements the Deref //! trait). This includes references, raw pointers, smart pointers like `Rc<T>` and `Box<T>`, and //! specialized pointer-like types such as `Vec<T>` and `String`. //! //! Comparison, ordering, and hashing of the wrapped pointer will be based on the address of its //! contents, rather than their value. //! //! ``` //! use by_address::ByAddress; //! use std::rc::Rc; //! //! let rc = Rc::new(5); //! let x = ByAddress(rc.clone()); //! let y = ByAddress(rc.clone()); //! //! // x and y are two pointers to the same address: //! assert_eq!(x, y); //! //! let z = ByAddress(Rc::new(5)); //! //! // *x and *z have the same value, but not the same address: //! assert_ne!(x, z); //! ``` //! //! You can use wrapped pointers as keys in hashed or ordered collections, like BTreeMap/BTreeSet //! or HashMap/HashSet, even if the target of the pointer doesn't implement hashing or ordering. //! This even includes pointers to trait objects, which usually don't implement the Eq trait //! because it is not object-safe. //! //! ``` //! # use by_address::ByAddress; //! # use std::collections::HashSet; //! # //! /// Call each item in `callbacks`, skipping any duplicate references. //! fn call_each_once(callbacks: &[&Fn()]) { //! let mut seen: HashSet<ByAddress<&Fn()>> = HashSet::new(); //! for &f in callbacks { //! if seen.insert(ByAddress(f)) { //! f(); //! } //! } //! } //! ``` //! //! If `T` is a pointer to an unsized type, then comparison and ordering of `ByAddress<T>` compare //! the entire fat pointer, not just the "thin" data address. This means that two slice pointers //! are consider equal only if they have the same starting address *and* length. //! //! ``` //! # use by_address::ByAddress; //! # //! let v = [1, 2, 3, 4]; //! //! assert_eq!(ByAddress(&v[0..4]), ByAddress(&v[0..4])); // Same address and length. //! assert_ne!(ByAddress(&v[0..4]), ByAddress(&v[0..2])); // Same address, different length. //! ``` //! //! This crate does not depend on libstd, so it can be used in [`no_std`] projects. //! //! [`no_std`]: https://doc.rust-lang.org/book/first-edition/using-rust-without-the-standard-library.html //! [ByAddress]: struct.ByAddress.html // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![no_std] use core::cmp::Ordering; use core::convert::AsRef; use core::hash::{Hash, Hasher}; use core::ops::{Deref, DerefMut}; /// Wrapper for pointer types that implements by-address comparison. /// /// See the [crate-level documentation](index.html) for details. #[derive(Copy, Clone, Debug, Default)] pub struct ByAddress<T>(pub T) where T: ?Sized + Deref; impl<T> ByAddress<T> where T: ?Sized + Deref { /// Convenience method for pointer casts. fn addr(&self) -> *const T::Target { &*self.0 } } /// Raw pointer equality impl<T> PartialEq for ByAddress<T> where T: ?Sized + Deref { fn eq(&self, other: &Self) -> bool { self.addr() == other.addr() } } impl<T> Eq for ByAddress<T> where T: ?Sized + Deref {} /// Raw pointer ordering impl<T> Ord for ByAddress<T> where T: ?Sized + Deref { fn cmp(&self, other: &Self) -> Ordering { self.addr().cmp(&other.addr()) } } /// Raw pointer comparison impl<T> PartialOrd for ByAddress<T> where T: ?Sized + Deref { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.addr().cmp(&other.addr())) } } /// Raw pointer hashing impl<T> Hash for ByAddress<T> where T: ?Sized + Deref { fn hash<H: Hasher>(&self, state: &mut H) { self.addr().hash(state) } } // Generic conversion traits: impl<T> Deref for ByAddress<T> where T: ?Sized + Deref { type Target = T; fn deref(&self) -> &Self::Target { &self.0 } } impl<T> DerefMut for ByAddress<T> where T: ?Sized + Deref { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl<T, U> AsRef<U> for ByAddress<T> where T: ?Sized + Deref + AsRef<U> { fn as_ref(&self) -> &U { self.0.as_ref() } } impl<T, U> AsMut<U> for ByAddress<T> where T: ?Sized + Deref + AsMut<U> { fn as_mut(&mut self) -> &mut U { self.0.as_mut() } } impl<T> From<T> for ByAddress<T> where T: Deref { fn from(t: T) -> ByAddress<T> { ByAddress(t) } }