Skip to content

Commit 04e34b5

Browse files
authored
Merge pull request #4 from steffahn/visible_stablehasheq
Make `StableHashEq` visible for improved crate documentation, and add some more trait implementations.
2 parents 30c5252 + 0daf488 commit 04e34b5

File tree

2 files changed

+215
-72
lines changed

2 files changed

+215
-72
lines changed

src/lib.rs

Lines changed: 17 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,12 @@ use std::hash::{BuildHasher, Hash};
222222

223223
mod inner;
224224
mod read;
225+
mod stable_hash_eq;
225226
mod values;
226227
mod write;
227228

229+
pub use stable_hash_eq::StableHashEq;
230+
228231
/// Handles to the read and write halves of an `evmap`.
229232
pub mod handles {
230233
pub use crate::write::WriteHandle;
@@ -307,7 +310,7 @@ where
307310
/// yield the same hash if given the same sequence of inputs.
308311
pub unsafe fn with_hasher<S2>(self, hash_builder: S2) -> Options<M, S2>
309312
where
310-
S2: BuildHasher,
313+
S2: BuildHasher + Clone,
311314
{
312315
Options {
313316
meta: self.meta,
@@ -327,13 +330,13 @@ where
327330

328331
/// Create the map, and construct the read and write handles used to access it.
329332
///
330-
/// If you want to use arbitrary types for the keys and values, use [`assert_stable`].
333+
/// If you want to use arbitrary types for the keys and values, use [`assert_stable`][Options::assert_stable].
331334
#[allow(clippy::type_complexity)]
332335
pub fn construct<K, V>(self) -> (WriteHandle<K, V, M, S>, ReadHandle<K, V, M, S>)
333336
where
334-
K: sealed::StableHashEq + Eq + Hash + Clone,
337+
K: StableHashEq + Clone,
335338
S: BuildHasher + Clone,
336-
V: sealed::StableHashEq + Eq + Hash,
339+
V: StableHashEq,
337340
M: 'static + Clone,
338341
{
339342
unsafe { self.assert_stable() }
@@ -345,7 +348,8 @@ where
345348
///
346349
/// This method is safe to call as long as the implementation of `Hash` and `Eq` for both `K`
347350
/// and `V` are deterministic. That is, they must always yield the same result if given the
348-
/// same inputs.
351+
/// same inputs. For keys of type `K`, the result must also be consistent between different clones
352+
/// of the same key.
349353
#[allow(clippy::type_complexity)]
350354
pub unsafe fn assert_stable<K, V>(self) -> (WriteHandle<K, V, M, S>, ReadHandle<K, V, M, S>)
351355
where
@@ -378,8 +382,8 @@ pub fn new<K, V>() -> (
378382
ReadHandle<K, V, (), RandomState>,
379383
)
380384
where
381-
K: sealed::StableHashEq + Eq + Hash + Clone,
382-
V: sealed::StableHashEq + Eq + Hash,
385+
K: StableHashEq + Clone,
386+
V: StableHashEq,
383387
{
384388
Options::default().construct()
385389
}
@@ -392,7 +396,8 @@ where
392396
///
393397
/// This method is safe to call as long as the implementation of `Hash` and `Eq` for both `K` and
394398
/// `V` are deterministic. That is, they must always yield the same result if given the same
395-
/// inputs.
399+
/// inputs. For keys of type `K`, the result must also be consistent between different clones
400+
/// of the same key.
396401
#[allow(clippy::type_complexity)]
397402
pub unsafe fn new_assert_stable<K, V>() -> (
398403
WriteHandle<K, V, (), RandomState>,
@@ -412,8 +417,10 @@ where
412417
/// # Safety
413418
///
414419
/// This method is safe to call as long as the implementation of `Hash` and `Eq` for both `K` and
415-
/// `V`, and the implementation of `Hasher` for `S` are deterministic. That is, they must always
416-
/// yield the same result if given the same inputs.
420+
/// `V`, and the implementation of `BuildHasher` for `S` and [`Hasher`][std::hash::Hasher]
421+
/// for <code>S::[Hasher][BuildHasher::Hasher]</code> are deterministic. That is, they must always
422+
/// yield the same result if given the same inputs. For keys of type `K` and hashers of type `S`,
423+
/// their behavior must also be consistent between different clones of the same value.
417424
#[allow(clippy::type_complexity)]
418425
pub unsafe fn with_hasher<K, V, M, S>(
419426
meta: M,
@@ -430,65 +437,3 @@ where
430437
.with_meta(meta)
431438
.assert_stable()
432439
}
433-
434-
mod sealed {
435-
#[allow(unreachable_pub)]
436-
pub unsafe trait StableHashEq: std::hash::Hash + Eq {}
437-
438-
macro_rules! yes_its_stable {
439-
($($t:ty),*) => {
440-
$(unsafe impl StableHashEq for $t {})*
441-
};
442-
}
443-
444-
yes_its_stable!(u8, u16, u32, u64, u128, usize);
445-
yes_its_stable!(i8, i16, i32, i64, i128, isize);
446-
yes_its_stable!(bool, char, String);
447-
448-
unsafe impl<'a, T: StableHashEq> StableHashEq for &'a [T] {}
449-
unsafe impl<'a, T: StableHashEq> StableHashEq for &'a T {}
450-
unsafe impl<'a> StableHashEq for &'a str {}
451-
452-
use std::collections::{BTreeMap, BTreeSet, VecDeque};
453-
unsafe impl<T: StableHashEq> StableHashEq for Vec<T> {}
454-
unsafe impl<T: StableHashEq> StableHashEq for VecDeque<T> {}
455-
unsafe impl<T: StableHashEq> StableHashEq for BTreeSet<T> {}
456-
unsafe impl<K, V> StableHashEq for BTreeMap<K, V>
457-
where
458-
K: StableHashEq,
459-
V: StableHashEq,
460-
{
461-
}
462-
463-
unsafe impl StableHashEq for () {}
464-
unsafe impl<T1> StableHashEq for (T1,) where T1: StableHashEq {}
465-
unsafe impl<T1, T2> StableHashEq for (T1, T2)
466-
where
467-
T1: StableHashEq,
468-
T2: StableHashEq,
469-
{
470-
}
471-
unsafe impl<T1, T2, T3> StableHashEq for (T1, T2, T3)
472-
where
473-
T1: StableHashEq,
474-
T2: StableHashEq,
475-
T3: StableHashEq,
476-
{
477-
}
478-
unsafe impl<T1, T2, T3, T4> StableHashEq for (T1, T2, T3, T4)
479-
where
480-
T1: StableHashEq,
481-
T2: StableHashEq,
482-
T3: StableHashEq,
483-
T4: StableHashEq,
484-
{
485-
}
486-
487-
macro_rules! arr {
488-
($($n:literal),*) => {
489-
$(unsafe impl<T: StableHashEq> StableHashEq for [T; $n] {})*
490-
}
491-
}
492-
493-
arr!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
494-
}

src/stable_hash_eq.rs

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/// [Sealed] trait for types in [`std`] that are known to implement
2+
/// `Hash` and `Eq` deterministically.
3+
///
4+
/// Furthermore, if `T: Clone + StableHashEq`, then `T::clone` is
5+
/// deterministic too, in the sense that the behavior with regards
6+
/// to `Hash` and `Eq` methods stays consistent between both clones.
7+
///
8+
/// _This trait is sealed and cannot be implemented outside of the `evmap` crate._
9+
///
10+
/// [Sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
11+
pub trait StableHashEq: Hash + Eq + sealed_hash_eq::Sealed {}
12+
13+
mod sealed_hash_eq {
14+
pub trait Sealed {}
15+
}
16+
17+
macro_rules! stable_hash_eq {
18+
($(
19+
$({$($a:lifetime),*$(,)?$($T:ident$(:?$Sized:ident)?),*$(,)?}
20+
$({$($manual_bounds:tt)*})?)? $Type:ty,
21+
)*) => {
22+
stable_hash_eq!{#
23+
$(
24+
$({$($a)*$($T$(:?$Sized$Sized)?)*})? $($({where $($manual_bounds)*})?
25+
{
26+
where $(
27+
$T: StableHashEq,
28+
)*
29+
})?
30+
$Type,
31+
)*
32+
}
33+
};
34+
(#$(
35+
$({$($a:lifetime)*$($T:ident$(:?Sized$Sized:ident)?)*}
36+
{$($where_bounds:tt)*}$({$($_t:tt)*})?)? $Type:ty,
37+
)*) => {
38+
$(
39+
impl$(<$($a,)*$($T$(:?$Sized)?,)*>)? StableHashEq for $Type
40+
$($($where_bounds)*)? {}
41+
impl$(<$($a,)*$($T$(:?$Sized)?,)*>)? sealed_hash_eq::Sealed for $Type
42+
$($($where_bounds)*)? {}
43+
)*
44+
};
45+
}
46+
47+
use std::{
48+
any::TypeId,
49+
borrow::Cow,
50+
cmp::{self, Reverse},
51+
collections::{BTreeMap, BTreeSet, LinkedList, VecDeque},
52+
convert::Infallible,
53+
ffi::{CStr, CString, OsStr, OsString},
54+
fmt,
55+
fs::FileType,
56+
hash::Hash,
57+
io::ErrorKind,
58+
marker::{PhantomData, PhantomPinned},
59+
mem::{Discriminant, ManuallyDrop},
60+
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
61+
num::{
62+
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
63+
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
64+
},
65+
ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
66+
path::{Component, Path, PathBuf, Prefix, PrefixComponent},
67+
ptr::NonNull,
68+
rc::Rc,
69+
sync::{atomic, Arc},
70+
task::Poll,
71+
thread::ThreadId,
72+
time::{Duration, Instant, SystemTime},
73+
};
74+
75+
stable_hash_eq! {
76+
cmp::Ordering,
77+
Infallible,
78+
ErrorKind,
79+
IpAddr,
80+
SocketAddr,
81+
atomic::Ordering,
82+
bool, char,
83+
i8, i16, i32, i64, i128,
84+
isize,
85+
str,
86+
u8, u16, u32, u64, u128,
87+
(),
88+
usize,
89+
TypeId,
90+
CStr,
91+
CString,
92+
OsStr,
93+
OsString,
94+
fmt::Error,
95+
FileType,
96+
PhantomPinned,
97+
Ipv4Addr,
98+
Ipv6Addr,
99+
SocketAddrV4,
100+
SocketAddrV6,
101+
NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize,
102+
NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
103+
RangeFull,
104+
Path,
105+
PathBuf,
106+
String,
107+
ThreadId,
108+
Duration,
109+
Instant,
110+
SystemTime,
111+
{'a} PrefixComponent<'a>,
112+
{'a} Cow<'a, str>,
113+
{'a} Cow<'a, CStr>,
114+
{'a} Cow<'a, OsStr>,
115+
{'a} Cow<'a, Path>,
116+
{'a, T}{T: Clone + StableHashEq} Cow<'a, [T]>,
117+
{'a, T}{T: Clone + StableHashEq} Cow<'a, T>,
118+
{'a, T: ?Sized} &'a T,
119+
{'a, T: ?Sized} &'a mut T,
120+
{'a} Component<'a>,
121+
{'a} Prefix<'a>,
122+
{A: ?Sized} (A,),
123+
{T} VecDeque<T>,
124+
{A, B: ?Sized} (A, B),
125+
{A, B, C: ?Sized} (A, B, C),
126+
{A, B, C, D: ?Sized} (A, B, C, D),
127+
{A, B, C, D, E: ?Sized} (A, B, C, D, E),
128+
{A, B, C, D, E, F: ?Sized} (A, B, C, D, E, F),
129+
{A, B, C, D, E, F, G: ?Sized} (A, B, C, D, E, F, G),
130+
{A, B, C, D, E, F, G, H: ?Sized} (A, B, C, D, E, F, G, H),
131+
{A, B, C, D, E, F, G, H, I: ?Sized} (A, B, C, D, E, F, G, H, I),
132+
{A, B, C, D, E, F, G, H, I, J: ?Sized} (A, B, C, D, E, F, G, H, I, J),
133+
{A, B, C, D, E, F, G, H, I, J, K: ?Sized} (A, B, C, D, E, F, G, H, I, J, K),
134+
{A, B, C, D, E, F, G, H, I, J, K, L: ?Sized} (A, B, C, D, E, F, G, H, I, J, K, L),
135+
{Idx} Range<Idx>,
136+
{Idx} RangeFrom<Idx>,
137+
{Idx} RangeInclusive<Idx>,
138+
{Idx} RangeTo<Idx>,
139+
{Idx} RangeToInclusive<Idx>,
140+
{K, V} BTreeMap<K, V>,
141+
}
142+
macro_rules! stable_hash_eq_fn {
143+
($({$($($A:ident),+)?})*) => {
144+
stable_hash_eq!{
145+
$(
146+
{Ret$(, $($A),+)?}{} fn($($($A),+)?) -> Ret,
147+
{Ret$(, $($A),+)?}{} extern "C" fn($($($A),+)?) -> Ret,
148+
$({Ret, $($A),+}{} extern "C" fn($($A),+, ...) -> Ret,)?
149+
{Ret$(, $($A),+)?}{} unsafe fn($($($A),+)?) -> Ret,
150+
{Ret$(, $($A),+)?}{} unsafe extern "C" fn($($($A),+)?) -> Ret,
151+
$({Ret, $($A),+}{} unsafe extern "C" fn($($A),+, ...) -> Ret,)?
152+
)*
153+
}
154+
};
155+
}
156+
stable_hash_eq_fn! {
157+
{}
158+
{A}
159+
{A, B}
160+
{A, B, C}
161+
{A, B, C, D}
162+
{A, B, C, D, E}
163+
{A, B, C, D, E, F}
164+
{A, B, C, D, E, F, G}
165+
{A, B, C, D, E, F, G, H}
166+
{A, B, C, D, E, F, G, H, I}
167+
{A, B, C, D, E, F, G, H, I, J}
168+
{A, B, C, D, E, F, G, H, I, J, K}
169+
{A, B, C, D, E, F, G, H, I, J, K, L}
170+
}
171+
stable_hash_eq! {
172+
{T} Bound<T>,
173+
{T} Option<T>,
174+
{T} Poll<T>,
175+
{T: ?Sized}{} *const T,
176+
{T: ?Sized}{} *mut T,
177+
{T} [T],
178+
{T: ?Sized} Box<T>,
179+
{T} Reverse<T>,
180+
{T} BTreeSet<T>,
181+
{T} LinkedList<T>,
182+
{T: ?Sized}{} PhantomData<T>,
183+
{T}{} Discriminant<T>,
184+
{T} ManuallyDrop<T>,
185+
{T} Wrapping<T>,
186+
{T: ?Sized}{} NonNull<T>,
187+
{T: ?Sized} Rc<T>,
188+
{T: ?Sized} Arc<T>,
189+
{T} Vec<T>,
190+
{T, E} Result<T, E>,
191+
{T} [T; 0], {T} [T; 1], {T} [T; 2], {T} [T; 3], {T} [T; 4],
192+
{T} [T; 5], {T} [T; 6], {T} [T; 7], {T} [T; 8], {T} [T; 9],
193+
{T} [T; 10], {T} [T; 11], {T} [T; 12], {T} [T; 13], {T} [T; 14],
194+
{T} [T; 15], {T} [T; 16], {T} [T; 17], {T} [T; 18], {T} [T; 19],
195+
{T} [T; 20], {T} [T; 21], {T} [T; 22], {T} [T; 23], {T} [T; 24],
196+
{T} [T; 25], {T} [T; 26], {T} [T; 27], {T} [T; 28], {T} [T; 29],
197+
{T} [T; 30], {T} [T; 31], {T} [T; 32],
198+
}

0 commit comments

Comments
 (0)