Skip to content

Commit 4a94810

Browse files
committed
Fix tracing HashMap with custom BuildHasher
Add TrustedDrop to the prelude
1 parent cdd4857 commit 4a94810

File tree

2 files changed

+109
-13
lines changed

2 files changed

+109
-13
lines changed

src/manually_traced/stdlib.rs

Lines changed: 108 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
//! should go in this module.
66
use std::collections::{HashMap, HashSet};
77
#[cfg(feature = "serde1")]
8-
use std::hash::Hash;
8+
use std::hash::{Hash, BuildHasher};
9+
#[cfg(feature = "serde1")]
10+
use std::marker::PhantomData;
911

1012
use zerogc_derive::unsafe_gc_impl;
1113

@@ -15,12 +17,20 @@ use crate::prelude::*;
1517

1618

1719
unsafe_gc_impl! {
18-
target => HashMap<K, V>,
19-
params => [K: TraceImmutable, V],
20+
target => HashMap<K, V, S>,
21+
params => [K: TraceImmutable, V, S: 'static],
2022
bounds => {
21-
GcDeserialize => { where K: GcDeserialize<'gc, 'deserialize, Id> + Eq + Hash, V: GcDeserialize<'gc, 'deserialize, Id> }
23+
/*
24+
* We require S: 'static so that we know S: NullTrace
25+
*/
26+
Trace => { where K: TraceImmutable, V: Trace, S: 'static },
27+
TraceImmutable => { where K: TraceImmutable, V: TraceImmutable, S: 'static },
28+
TrustedDrop => { where K: TrustedDrop, V: TrustedDrop, S: 'static },
29+
GcSafe => { where K: TraceImmutable + GcSafe<'gc, Id>, V: GcSafe<'gc, Id>, S: 'static },
30+
GcDeserialize => { where K: GcDeserialize<'gc, 'deserialize, Id> + Eq + Hash,
31+
V: GcDeserialize<'gc, 'deserialize, Id>, S: Default + BuildHasher }
2232
},
23-
null_trace => { where K: NullTrace, V: NullTrace },
33+
null_trace => { where K: NullTrace, V: NullTrace, S: NullTrace },
2434
NEEDS_TRACE => K::NEEDS_TRACE || V::NEEDS_TRACE,
2535
NEEDS_DROP => true, // Internal memory
2636
collector_id => *,
@@ -29,27 +39,113 @@ unsafe_gc_impl! {
2939
visitor.visit_immutable::<K>(key)?;
3040
visitor.#visit_func::<V>(value)?;
3141
}
42+
// NOTE: Because S: 'static, we can assume S: NullTrace
3243
Ok(())
3344
},
34-
deserialize => unstable_horrible_hack,
45+
deserialize => |ctx, deserializer| {
46+
use serde::de::{Visitor, MapAccess};
47+
use crate::serde::GcDeserializeSeed;
48+
struct MapVisitor<
49+
'gc, 'de, Id: CollectorId,
50+
K: GcDeserialize<'gc, 'de, Id>,
51+
V: GcDeserialize<'gc, 'de, Id>,
52+
S: BuildHasher + Default
53+
> {
54+
ctx: &'gc <Id::System as GcSystem>::Context,
55+
marker: PhantomData<fn(&'de (), S) -> (K, V)>
56+
}
57+
impl<'gc, 'de, Id: CollectorId,
58+
K: Eq + Hash + GcDeserialize<'gc, 'de, Id>,
59+
V: GcDeserialize<'gc, 'de, Id>,
60+
S: BuildHasher + Default
61+
> Visitor<'de> for MapVisitor<'gc, 'de, Id, K, V, S> {
62+
type Value = HashMap<K, V, S>;
63+
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
64+
f.write_str("a map")
65+
}
66+
#[inline]
67+
fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
68+
where A: MapAccess<'de>, {
69+
let mut values = HashMap::<K, V, S>::with_capacity_and_hasher(
70+
access.size_hint().unwrap_or(0).min(1024),
71+
S::default()
72+
);
73+
while let Some((key, value)) = access.next_entry_seed(
74+
GcDeserializeSeed::new(self.ctx),
75+
GcDeserializeSeed::new(self.ctx)
76+
)? {
77+
values.insert(key, value);
78+
}
79+
80+
Ok(values)
81+
}
82+
}
83+
let visitor: MapVisitor<Id, K, V, S> = MapVisitor { ctx, marker: PhantomData };
84+
deserializer.deserialize_map(visitor)
85+
},
3586
}
3687

3788

3889
unsafe_gc_impl! {
39-
target => HashSet<T>,
40-
params => [T: TraceImmutable],
90+
target => HashSet<T, S>,
91+
params => [T: TraceImmutable, S: 'static],
4192
bounds => {
42-
GcDeserialize => { where T: GcDeserialize<'gc, 'deserialize, Id> + Eq + Hash }
93+
/*
94+
* We require S: 'static so that we know S: NullTrace
95+
*/
96+
Trace => { where T: TraceImmutable, S: 'static },
97+
TraceImmutable => { where T: TraceImmutable, S: 'static },
98+
TrustedDrop => { where T: TrustedDrop, S: 'static },
99+
GcSafe => { where T: TraceImmutable + GcSafe<'gc, Id>, S: 'static },
100+
GcDeserialize => { where T: GcDeserialize<'gc, 'deserialize, Id> + Eq + Hash, S: BuildHasher + Default }
43101
},
44-
null_trace => { where T: NullTrace },
102+
null_trace => { where T: NullTrace, S: 'static },
45103
NEEDS_TRACE => T::NEEDS_TRACE,
46104
NEEDS_DROP => true, // Internal memory
47105
collector_id => *,
48106
visit => |self, visitor| {
49107
for val in self.iter() {
50108
visitor.visit_immutable::<T>(val)?;
51-
}
109+
}
110+
// NOTE: Because S: 'static, we can assume S: NullTrace
52111
Ok(())
53112
},
54-
deserialize => unstable_horrible_hack,
113+
deserialize => |ctx, deserializer| {
114+
use serde::de::{Visitor, SeqAccess};
115+
use crate::serde::GcDeserializeSeed;
116+
struct SetVisitor<
117+
'gc, 'de, Id: CollectorId,
118+
T: GcDeserialize<'gc, 'de, Id>,
119+
S: BuildHasher + Default
120+
> {
121+
ctx: &'gc <Id::System as GcSystem>::Context,
122+
marker: PhantomData<fn(&'de (), S) -> T>
123+
}
124+
impl<'gc, 'de, Id: CollectorId,
125+
T: Eq + Hash + GcDeserialize<'gc, 'de, Id>,
126+
S: BuildHasher + Default
127+
> Visitor<'de> for SetVisitor<'gc, 'de, Id, T, S> {
128+
type Value = HashSet<T, S>;
129+
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
130+
f.write_str("a set")
131+
}
132+
#[inline]
133+
fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
134+
where A: SeqAccess<'de>, {
135+
let mut values = HashSet::<T, S>::with_capacity_and_hasher(
136+
access.size_hint().unwrap_or(0).min(1024),
137+
S::default()
138+
);
139+
while let Some(value) = access.next_element_seed(
140+
GcDeserializeSeed::new(self.ctx)
141+
)? {
142+
values.insert(value);
143+
}
144+
145+
Ok(values)
146+
}
147+
}
148+
let visitor: SetVisitor<Id, T, S> = SetVisitor { ctx, marker: PhantomData };
149+
deserializer.deserialize_seq(visitor)
150+
},
55151
}

src/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub use crate::{
1919
};
2020
// Traits for user code to implement
2121
pub use crate::{
22-
GcSafe, GcRebrand, Trace, TraceImmutable, NullTrace
22+
GcSafe, GcRebrand, Trace, TraceImmutable, NullTrace, TrustedDrop
2323
};
2424
// Hack traits
2525
pub use crate::{GcBindHandle};

0 commit comments

Comments
 (0)