Skip to content

Commit 91a189f

Browse files
committed
impl Trace for IndexMap with any BuildHasher
Also implement GcDeserialize for IndexMap with any BuildHasher. Only requirement is `S: 'static` (so we know it's NullTrace).
1 parent 4a94810 commit 91a189f

File tree

4 files changed

+129
-105
lines changed

4 files changed

+129
-105
lines changed

src/manually_traced/core.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,9 @@ macro_rules! deser_tuple_impl {
154154
let _hack = PhantomData::<$param>;
155155
len += 1;
156156
)*
157-
Ok(deser.deserialize_tuple(len, TupleVisitor {
157+
deser.deserialize_tuple(len, TupleVisitor {
158158
marker: PhantomData, ctx
159-
})?)
159+
})
160160
}
161161
}
162162
};

src/manually_traced/indexmap.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
use std::hash::Hash;
2-
31
use indexmap::{IndexMap, IndexSet};
42

5-
#[cfg(feature="serde1")]
6-
use crate::serde::GcDeserialize;
73
use crate::prelude::*;
84

95
use zerogc_derive::unsafe_gc_impl;
106

117
unsafe_gc_impl! {
12-
target => IndexMap<K, V>,
13-
params => [K: TraceImmutable, V],
8+
target => IndexMap<K, V, S>,
9+
params => [K: TraceImmutable, V, S: 'static],
1410
bounds => {
15-
GcDeserialize => { where K: GcDeserialize<'gc, 'deserialize, Id> + Eq + Hash, V: GcDeserialize<'gc, 'deserialize, Id> }
11+
Trace => { where K: TraceImmutable, V: Trace, S: 'static },
12+
TraceImmutable => { where K: TraceImmutable, V: TraceImmutable, S: 'static },
13+
TrustedDrop => { where K: TrustedDrop, V: TrustedDrop, S: 'static },
14+
GcSafe => { where K: GcSafe<'gc, Id>, V: GcSafe<'gc, Id>, S: 'static },
1615
},
1716
null_trace => { where K: NullTrace, V: NullTrace },
1817
NEEDS_TRACE => K::NEEDS_TRACE || V::NEEDS_TRACE,
@@ -23,19 +22,22 @@ unsafe_gc_impl! {
2322
visitor.visit_immutable::<K>(key)?;
2423
visitor.#visit_func::<V>(value)?;
2524
}
25+
// NOTE: S: 'static implies S: NullTrace
2626
Ok(())
2727
},
28-
deserialize => unstable_horrible_hack,
2928
}
3029

3130

3231
unsafe_gc_impl! {
33-
target => IndexSet<T>,
34-
params => [T: TraceImmutable],
32+
target => IndexSet<T, S>,
33+
params => [T: TraceImmutable, S: 'static],
34+
null_trace => { where T: NullTrace },
3535
bounds => {
36-
GcDeserialize => { where T: GcDeserialize<'gc, 'deserialize, Id> + Eq + Hash }
36+
Trace => { where T: TraceImmutable, S: 'static },
37+
TraceImmutable => { where T: TraceImmutable, S: 'static },
38+
TrustedDrop => { where T: TrustedDrop, S: 'static },
39+
GcSafe => { where T: GcSafe<'gc, Id>, S: 'static },
3740
},
38-
null_trace => { where T: NullTrace },
3941
NEEDS_TRACE => T::NEEDS_TRACE,
4042
NEEDS_DROP => true, // Internal memory
4143
collector_id => *,
@@ -45,5 +47,4 @@ unsafe_gc_impl! {
4547
}
4648
Ok(())
4749
},
48-
deserialize => unstable_horrible_hack,
4950
}

src/manually_traced/stdlib.rs

Lines changed: 0 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,9 @@
44
//! but anything that requires the rest of the stdlib (including collections and allocations),
55
//! should go in this module.
66
use std::collections::{HashMap, HashSet};
7-
#[cfg(feature = "serde1")]
8-
use std::hash::{Hash, BuildHasher};
9-
#[cfg(feature = "serde1")]
10-
use std::marker::PhantomData;
117

128
use zerogc_derive::unsafe_gc_impl;
139

14-
#[cfg(feature="serde1")]
15-
use crate::serde::GcDeserialize;
1610
use crate::prelude::*;
1711

1812

@@ -27,8 +21,6 @@ unsafe_gc_impl! {
2721
TraceImmutable => { where K: TraceImmutable, V: TraceImmutable, S: 'static },
2822
TrustedDrop => { where K: TrustedDrop, V: TrustedDrop, S: 'static },
2923
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 }
3224
},
3325
null_trace => { where K: NullTrace, V: NullTrace, S: NullTrace },
3426
NEEDS_TRACE => K::NEEDS_TRACE || V::NEEDS_TRACE,
@@ -42,47 +34,6 @@ unsafe_gc_impl! {
4234
// NOTE: Because S: 'static, we can assume S: NullTrace
4335
Ok(())
4436
},
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-
},
8637
}
8738

8839

@@ -97,7 +48,6 @@ unsafe_gc_impl! {
9748
TraceImmutable => { where T: TraceImmutable, S: 'static },
9849
TrustedDrop => { where T: TrustedDrop, S: 'static },
9950
GcSafe => { where T: TraceImmutable + GcSafe<'gc, Id>, S: 'static },
100-
GcDeserialize => { where T: GcDeserialize<'gc, 'deserialize, Id> + Eq + Hash, S: BuildHasher + Default }
10151
},
10252
null_trace => { where T: NullTrace, S: 'static },
10353
NEEDS_TRACE => T::NEEDS_TRACE,
@@ -110,42 +60,4 @@ unsafe_gc_impl! {
11060
// NOTE: Because S: 'static, we can assume S: NullTrace
11161
Ok(())
11262
},
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-
},
15163
}

src/serde.rs

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,18 @@
99
//! As a workaround, zerogc introduces a `GcDeserialize` type,
1010
//! indicating an implementation of [serde::Deserialize]
1111
//! that requires a [GcContext].
12+
use std::collections::{HashMap, HashSet};
1213
use std::marker::PhantomData;
14+
use std::hash::{BuildHasher, Hash};
1315

14-
use crate::array::{GcArray, GcString};
15-
use serde::{Serialize, de::{self, Deserializer, Visitor, DeserializeSeed}, ser::SerializeSeq};
16+
use serde::Serialize;
17+
use serde::de::{self, Deserializer, Visitor, DeserializeSeed, MapAccess, SeqAccess};
18+
use serde::ser::SerializeSeq;
19+
20+
#[cfg(feature = "indexmap")]
21+
use indexmap::{IndexMap, IndexSet};
1622

23+
use crate::array::{GcArray, GcString};
1724
use crate::prelude::*;
1825

1926
#[doc(hidden)]
@@ -161,3 +168,107 @@ impl<'de, 'gc, Id: CollectorId, T: GcDeserialize<'gc, 'de, Id>> DeserializeSeed<
161168
T::deserialize_gc(self.context, deserializer)
162169
}
163170
}
171+
172+
macro_rules! impl_for_map {
173+
($target:ident <K, V, S> $(where $($bounds:tt)*)?) => {
174+
impl<'gc, 'de, Id: CollectorId,
175+
K: Eq + Hash + GcDeserialize<'gc, 'de, Id>,
176+
V: GcDeserialize<'gc, 'de, Id>,
177+
S: BuildHasher + Default
178+
> GcDeserialize<'gc, 'de, Id> for $target<K, V, S> $(where $($bounds)*)* {
179+
fn deserialize_gc<D: Deserializer<'de>>(ctx: &'gc <Id::System as GcSystem>::Context, deserializer: D) -> Result<Self, D::Error> {
180+
struct MapVisitor<
181+
'gc, 'de, Id: CollectorId,
182+
K: GcDeserialize<'gc, 'de, Id>,
183+
V: GcDeserialize<'gc, 'de, Id>,
184+
S: BuildHasher + Default
185+
> {
186+
ctx: &'gc <Id::System as GcSystem>::Context,
187+
marker: PhantomData<(&'de S, K, V)>
188+
}
189+
impl<'gc, 'de, Id: CollectorId,
190+
K: Eq + Hash + GcDeserialize<'gc, 'de, Id>,
191+
V: GcDeserialize<'gc, 'de, Id>,
192+
S: BuildHasher + Default
193+
> Visitor<'de> for MapVisitor<'gc, 'de, Id, K, V, S> {
194+
type Value = $target<K, V, S>;
195+
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
196+
f.write_str(concat!("a ", stringify!($target)))
197+
}
198+
#[inline]
199+
fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
200+
where A: MapAccess<'de>, {
201+
let mut values = $target::<K, V, S>::with_capacity_and_hasher(
202+
access.size_hint().unwrap_or(0).min(1024),
203+
S::default()
204+
);
205+
while let Some((key, value)) = access.next_entry_seed(
206+
GcDeserializeSeed::new(self.ctx),
207+
GcDeserializeSeed::new(self.ctx)
208+
)? {
209+
values.insert(key, value);
210+
}
211+
212+
Ok(values)
213+
}
214+
}
215+
let visitor: MapVisitor<Id, K, V, S> = MapVisitor { ctx, marker: PhantomData };
216+
deserializer.deserialize_map(visitor)
217+
}
218+
}
219+
};
220+
}
221+
222+
macro_rules! impl_for_set {
223+
($target:ident <T, S> $(where $($bounds:tt)*)?) => {
224+
impl<'gc, 'de, Id: CollectorId,
225+
T: Eq + Hash + GcDeserialize<'gc, 'de, Id>,
226+
S: BuildHasher + Default
227+
> GcDeserialize<'gc, 'de, Id> for $target<T, S> $(where $($bounds)*)* {
228+
fn deserialize_gc<D: Deserializer<'de>>(ctx: &'gc <Id::System as GcSystem>::Context, deserializer: D) -> Result<Self, D::Error> {
229+
struct SetVisitor<
230+
'gc, 'de, Id: CollectorId,
231+
T: GcDeserialize<'gc, 'de, Id>,
232+
S: BuildHasher + Default
233+
> {
234+
ctx: &'gc <Id::System as GcSystem>::Context,
235+
marker: PhantomData<fn(&'de (), S) -> T>
236+
}
237+
impl<'gc, 'de, Id: CollectorId,
238+
T: Eq + Hash + GcDeserialize<'gc, 'de, Id>,
239+
S: BuildHasher + Default
240+
> Visitor<'de> for SetVisitor<'gc, 'de, Id, T, S> {
241+
type Value = $target<T, S>;
242+
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
243+
f.write_str(concat!("a ", stringify!($target)))
244+
}
245+
#[inline]
246+
fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
247+
where A: SeqAccess<'de>, {
248+
let mut values = $target::<T, S>::with_capacity_and_hasher(
249+
access.size_hint().unwrap_or(0).min(1024),
250+
S::default()
251+
);
252+
while let Some(value) = access.next_element_seed(
253+
GcDeserializeSeed::new(self.ctx)
254+
)? {
255+
values.insert(value);
256+
}
257+
258+
Ok(values)
259+
}
260+
}
261+
let visitor: SetVisitor<Id, T, S> = SetVisitor { ctx, marker: PhantomData };
262+
deserializer.deserialize_seq(visitor)
263+
}
264+
}
265+
};
266+
}
267+
268+
269+
impl_for_map!(HashMap<K, V, S> where K: TraceImmutable, S: 'static);
270+
impl_for_set!(HashSet<T, S> where T: TraceImmutable, S: 'static);
271+
#[cfg(feature = "indexmap")]
272+
impl_for_map!(IndexMap<K, V, S> where K: TraceImmutable, S: 'static);
273+
#[cfg(feature = "indexmap")]
274+
impl_for_set!(IndexSet<T, S> where T: TraceImmutable, S: 'static);

0 commit comments

Comments
 (0)