• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

facet-rs / facet / 15787779743

20 Jun 2025 09:01PM UTC coverage: 61.487% (+1.8%) from 59.711%
15787779743

Pull #774

github

web-flow
Merge dd04260c9 into ec93ce66e
Pull Request #774: split up Partial::end into smaller bits

147 of 165 new or added lines in 2 files covered. (89.09%)

1817 existing lines in 50 files now uncovered.

10564 of 17181 relevant lines covered (61.49%)

161.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.81
/facet-core/src/impls_std/hashset.rs
1
use core::hash::BuildHasher;
2
use std::collections::HashSet;
3

4
use crate::ptr::{PtrConst, PtrMut};
5

6
use crate::{
7
    Def, Facet, IterVTable, MarkerTraits, SetDef, SetVTable, Shape, Type, TypeParam, UserType,
8
    ValueVTable,
9
};
10

11
type HashSetIterator<'mem, T> = std::collections::hash_set::Iter<'mem, T>;
12

13
unsafe impl<'a, T, S> Facet<'a> for HashSet<T, S>
14
where
15
    T: Facet<'a> + core::cmp::Eq + core::hash::Hash,
16
    S: Facet<'a> + Default + BuildHasher,
17
{
18
    const VTABLE: &'static ValueVTable = &const {
19
        ValueVTable::builder::<Self>()
20
            .marker_traits(|| {
×
21
                MarkerTraits::SEND
22
                    .union(MarkerTraits::SYNC)
×
23
                    .union(MarkerTraits::EQ)
×
24
                    .union(MarkerTraits::UNPIN)
×
25
                    .intersection(T::SHAPE.vtable.marker_traits())
×
26
            })
×
27
            .type_name(|f, opts| {
×
28
                if let Some(opts) = opts.for_children() {
×
29
                    write!(f, "{}<", Self::SHAPE.type_identifier)?;
×
30
                    (T::SHAPE.vtable.type_name())(f, opts)?;
×
31
                    write!(f, ">")
×
32
                } else {
33
                    write!(f, "HashSet<⋯>")
×
34
                }
35
            })
×
36
            .default_in_place(|| Some(|target| unsafe { target.put(Self::default()) }))
×
37
            .build()
38
    };
39

40
    const SHAPE: &'static Shape<'static> = &const {
41
        Shape::builder_for_sized::<Self>()
42
            .type_identifier("HashSet")
43
            .type_params(&[
44
                TypeParam {
45
                    name: "T",
46
                    shape: || T::SHAPE,
47
                },
48
                TypeParam {
49
                    name: "S",
50
                    shape: || S::SHAPE,
51
                },
52
            ])
53
            .ty(Type::User(UserType::Opaque))
54
            .def(Def::Set(
55
                SetDef::builder()
56
                    .t(|| T::SHAPE)
57
                    .vtable(
58
                        &const {
59
                            SetVTable::builder()
60
                                .init_in_place_with_capacity(|uninit, capacity| unsafe {
61
                                    uninit
1✔
62
                                        .put(Self::with_capacity_and_hasher(capacity, S::default()))
1✔
63
                                })
1✔
64
                                .insert(|ptr, item| unsafe {
65
                                    let set = ptr.as_mut::<HashSet<T>>();
10✔
66
                                    let item = item.read::<T>();
10✔
67
                                    set.insert(item)
10✔
68
                                })
10✔
69
                                .len(|ptr| unsafe {
70
                                    let set = ptr.get::<HashSet<T>>();
11✔
71
                                    set.len()
11✔
72
                                })
11✔
73
                                .contains(|ptr, item| unsafe {
UNCOV
74
                                    let set = ptr.get::<HashSet<T>>();
×
UNCOV
75
                                    set.contains(item.get())
×
76
                                })
×
77
                                .iter_vtable(
78
                                    IterVTable::builder()
79
                                        .init_with_value(|ptr| unsafe {
80
                                            let set = ptr.get::<HashSet<T>>();
1✔
81
                                            let iter: HashSetIterator<'_, T> = set.iter();
1✔
82
                                            let iter_state = Box::new(iter);
1✔
83
                                            PtrMut::new(Box::into_raw(iter_state) as *mut u8)
1✔
84
                                        })
1✔
85
                                        .next(|iter_ptr| unsafe {
86
                                            let state = iter_ptr.as_mut::<HashSetIterator<'_, T>>();
6✔
87
                                            state.next().map(|value| PtrConst::new(value))
6✔
88
                                        })
6✔
89
                                        .dealloc(|iter_ptr| unsafe {
90
                                            drop(Box::from_raw(
1✔
91
                                                iter_ptr.as_ptr::<HashSetIterator<'_, T>>()
1✔
92
                                                    as *mut HashSetIterator<'_, T>,
1✔
93
                                            ));
94
                                        })
1✔
95
                                        .build(),
96
                                )
97
                                .build()
98
                        },
99
                    )
100
                    .build(),
101
            ))
102
            .build()
103
    };
104
}
105

106
#[cfg(test)]
107
mod tests {
108
    use alloc::string::String;
109
    use std::collections::HashSet;
110
    use std::hash::RandomState;
111

112
    use super::*;
113

114
    #[test]
115
    fn test_hashset_type_params() {
1✔
116
        // HashSet should have a type param for both its value type
117
        // and its hasher state
118
        let [type_param_1, type_param_2] = <HashSet<i32>>::SHAPE.type_params else {
1✔
UNCOV
119
            panic!("HashSet<T> should have 2 type params")
×
120
        };
121
        assert_eq!(type_param_1.shape(), i32::SHAPE);
1✔
122
        assert_eq!(type_param_2.shape(), RandomState::SHAPE);
1✔
123
    }
1✔
124

125
    #[test]
126
    fn test_hashset_vtable_1_new_insert_iter_drop() -> eyre::Result<()> {
1✔
127
        facet_testhelpers::setup();
1✔
128

129
        let hashset_shape = <HashSet<String>>::SHAPE;
1✔
130
        let hashset_def = hashset_shape
1✔
131
            .def
1✔
132
            .into_set()
1✔
133
            .expect("HashSet<T> should have a set definition");
1✔
134

135
        // Allocate memory for the HashSet
136
        let hashset_uninit_ptr = hashset_shape.allocate()?;
1✔
137

138
        // Create the HashSet with a capacity of 3
139
        let hashset_ptr =
1✔
140
            unsafe { (hashset_def.vtable.init_in_place_with_capacity_fn)(hashset_uninit_ptr, 3) };
1✔
141

142
        // The HashSet is empty, so ensure its length is 0
143
        let hashset_actual_length = unsafe { (hashset_def.vtable.len_fn)(hashset_ptr.as_const()) };
1✔
144
        assert_eq!(hashset_actual_length, 0);
1✔
145

146
        // 5 sample values to insert
147
        let strings = ["foo", "bar", "bazz", "fizzbuzz", "fifth thing"];
1✔
148

149
        // Insert the 5 values into the HashSet
150
        let mut hashset_length = 0;
1✔
151
        for string in strings {
6✔
152
            // Create the value
153
            let mut new_value = string.to_string();
5✔
154

155
            // Insert the value
156
            let did_insert = unsafe {
5✔
157
                (hashset_def.vtable.insert_fn)(hashset_ptr, PtrMut::new(&raw mut new_value))
5✔
158
            };
159

160
            // The value now belongs to the HashSet, so forget it
161
            core::mem::forget(new_value);
5✔
162

163
            assert!(did_insert, "expected value to be inserted in the HashSet");
5✔
164

165
            // Ensure the HashSet's length increased by 1
166
            hashset_length += 1;
5✔
167
            let hashset_actual_length =
5✔
168
                unsafe { (hashset_def.vtable.len_fn)(hashset_ptr.as_const()) };
5✔
169
            assert_eq!(hashset_actual_length, hashset_length);
5✔
170
        }
171

172
        // Insert the same 5 values again, ensuring they are deduplicated
173
        for string in strings {
6✔
174
            // Create the value
175
            let mut new_value = string.to_string();
5✔
176

177
            // Try to insert the value
178
            let did_insert = unsafe {
5✔
179
                (hashset_def.vtable.insert_fn)(hashset_ptr, PtrMut::new(&raw mut new_value))
5✔
180
            };
181

182
            // The value now belongs to the HashSet, so forget it
183
            core::mem::forget(new_value);
5✔
184

185
            assert!(
5✔
186
                !did_insert,
5✔
UNCOV
187
                "expected value to not be inserted in the HashSet"
×
188
            );
189

190
            // Ensure the HashSet's length did not increase
191
            let hashset_actual_length =
5✔
192
                unsafe { (hashset_def.vtable.len_fn)(hashset_ptr.as_const()) };
5✔
193
            assert_eq!(hashset_actual_length, hashset_length);
5✔
194
        }
195

196
        // Create a new iterator over the HashSet
197
        let iter_init_with_value_fn = hashset_def.vtable.iter_vtable.init_with_value.unwrap();
1✔
198
        let hashset_iter_ptr = unsafe { iter_init_with_value_fn(hashset_ptr.as_const()) };
1✔
199

200
        // Collect all the items from the HashSet's iterator
201
        let mut iter_items = HashSet::<&str>::new();
1✔
202
        loop {
203
            // Get the next item from the iterator
204
            let item_ptr = unsafe { (hashset_def.vtable.iter_vtable.next)(hashset_iter_ptr) };
6✔
205
            let Some(item_ptr) = item_ptr else {
6✔
206
                break;
1✔
207
            };
208

209
            let item = unsafe { item_ptr.get::<String>() };
5✔
210

211
            // Insert the item into the set of items returned from the iterator
212
            let did_insert = iter_items.insert(&**item);
5✔
213

214
            assert!(did_insert, "HashSet iterator returned duplicate item");
5✔
215
        }
216

217
        // Deallocate the iterator
218
        unsafe {
1✔
219
            (hashset_def.vtable.iter_vtable.dealloc)(hashset_iter_ptr);
1✔
220
        }
1✔
221

222
        // Ensure the iterator returned all of the strings
223
        assert_eq!(iter_items, strings.iter().copied().collect::<HashSet<_>>());
1✔
224

225
        // Get the function pointer for dropping the HashSet
226
        let drop_fn = (hashset_shape.vtable.sized().unwrap().drop_in_place)()
1✔
227
            .expect("HashSet<T> should have drop_in_place");
1✔
228

229
        // Drop the HashSet in place
230
        unsafe { drop_fn(hashset_ptr) };
1✔
231

232
        // Deallocate the memory
233
        unsafe { hashset_shape.deallocate_mut(hashset_ptr)? };
1✔
234

235
        Ok(())
1✔
236
    }
1✔
237
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc