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

facet-rs / facet / 15221452970

24 May 2025 12:26AM UTC coverage: 57.643% (+0.1%) from 57.538%
15221452970

Pull #666

github

web-flow
Merge e32d9af09 into 48c76b4b0
Pull Request #666: Add indirection to vtable fns to fix cyclic types

779 of 1499 new or added lines in 35 files covered. (51.97%)

14 existing lines in 5 files now uncovered.

9880 of 17140 relevant lines covered (57.64%)

137.68 hits per line

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

56.29
/facet-core/src/impls_alloc/btreeset.rs
1
use core::hash::Hash;
2

3
use alloc::boxed::Box;
4
use alloc::collections::BTreeSet;
5

6
use crate::ptr::{PtrConst, PtrMut};
7

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

13
type BTreeSetIterator<'mem, T> = alloc::collections::btree_set::Iter<'mem, T>;
14

15
unsafe impl<'a, T> Facet<'a> for BTreeSet<T>
16
where
17
    T: Facet<'a> + core::cmp::Eq + core::cmp::Ord,
18
{
19
    const VTABLE: &'static ValueVTable = &const {
20
        ValueVTable::builder::<Self>()
NEW
21
            .marker_traits(|| {
×
22
                MarkerTraits::SEND
UNCOV
23
                    .union(MarkerTraits::SYNC)
×
UNCOV
24
                    .union(MarkerTraits::EQ)
×
UNCOV
25
                    .union(MarkerTraits::UNPIN)
×
NEW
26
                    .intersection(T::SHAPE.vtable.marker_traits())
×
NEW
27
            })
×
28
            .type_name(|f, opts| {
×
29
                if let Some(opts) = opts.for_children() {
×
30
                    write!(f, "BTreeSet<")?;
×
31
                    (T::SHAPE.vtable.type_name)(f, opts)?;
×
32
                    write!(f, ">")
×
33
                } else {
34
                    write!(f, "BTreeSet<⋯>")
×
35
                }
36
            })
×
NEW
37
            .default_in_place(|| Some(|target| unsafe { target.put(Self::default()) }))
×
NEW
38
            .eq(|| Some(|a, b| a == b))
×
NEW
39
            .debug(|| {
×
NEW
40
                if (T::SHAPE.vtable.debug)().is_some() {
×
NEW
41
                    Some(|value, f| {
×
NEW
42
                        let t_debug = <VTableView<T>>::of().debug().unwrap();
×
NEW
43
                        write!(f, "{{")?;
×
NEW
44
                        for (i, item) in value.iter().enumerate() {
×
NEW
45
                            if i > 0 {
×
NEW
46
                                write!(f, ", ")?;
×
NEW
47
                            }
×
NEW
48
                            (t_debug)(item, f)?;
×
49
                        }
NEW
50
                        write!(f, "}}")
×
NEW
51
                    })
×
52
                } else {
NEW
53
                    None
×
54
                }
NEW
55
            })
×
NEW
56
            .clone_into(|| {
×
NEW
57
                if (T::SHAPE.vtable.clone_into)().is_some() {
×
58
                    Some(|src, dst| unsafe {
NEW
59
                        let set = src;
×
NEW
60
                        let mut new_set = BTreeSet::new();
×
61

NEW
62
                        let t_clone_into = <VTableView<T>>::of().clone_into().unwrap();
×
63

NEW
64
                        for item in set {
×
65
                            use crate::TypedPtrUninit;
66
                            use core::mem::MaybeUninit;
67

NEW
68
                            let mut new_item = MaybeUninit::<T>::uninit();
×
NEW
69
                            let uninit_item = TypedPtrUninit::new(new_item.as_mut_ptr());
×
70

NEW
71
                            (t_clone_into)(item, uninit_item);
×
72

NEW
73
                            new_set.insert(new_item.assume_init());
×
74
                        }
75

NEW
76
                        dst.put(new_set)
×
NEW
77
                    })
×
78
                } else {
NEW
79
                    None
×
80
                }
NEW
81
            })
×
NEW
82
            .hash(|| {
×
NEW
83
                if (T::SHAPE.vtable.hash)().is_some() {
×
84
                    Some(|set, hasher_this, hasher_write_fn| unsafe {
85
                        use crate::HasherProxy;
NEW
86
                        let t_hash = <VTableView<T>>::of().hash().unwrap();
×
NEW
87
                        let mut hasher = HasherProxy::new(hasher_this, hasher_write_fn);
×
NEW
88
                        set.len().hash(&mut hasher);
×
NEW
89
                        for item in set {
×
NEW
90
                            (t_hash)(item, hasher_this, hasher_write_fn);
×
NEW
91
                        }
×
NEW
92
                    })
×
93
                } else {
NEW
94
                    None
×
95
                }
NEW
96
            })
×
97
            .build()
98
    };
99

100
    const SHAPE: &'static Shape<'static> = &const {
101
        Shape::builder_for_sized::<Self>()
102
            .type_params(&[TypeParam {
103
                name: "T",
104
                shape: || T::SHAPE,
105
            }])
106
            .ty(Type::User(UserType::Opaque))
107
            .def(Def::Set(
108
                SetDef::builder()
109
                    .t(|| T::SHAPE)
110
                    .vtable(
111
                        &const {
112
                            SetVTable::builder()
113
                                .init_in_place_with_capacity(|uninit, _capacity| unsafe {
114
                                    uninit.put(Self::new())
1✔
115
                                })
1✔
116
                                .insert(|ptr, item| unsafe {
117
                                    let set = ptr.as_mut::<BTreeSet<T>>();
10✔
118
                                    let item = item.read::<T>();
10✔
119
                                    set.insert(item)
10✔
120
                                })
10✔
121
                                .len(|ptr| unsafe {
122
                                    let set = ptr.get::<BTreeSet<T>>();
11✔
123
                                    set.len()
11✔
124
                                })
11✔
125
                                .contains(|ptr, item| unsafe {
126
                                    let set = ptr.get::<BTreeSet<T>>();
×
127
                                    set.contains(item.get())
×
128
                                })
×
129
                                .iter_vtable(
130
                                    IterVTable::builder()
131
                                        .init_with_value(|ptr| {
1✔
132
                                            let set = unsafe { ptr.get::<BTreeSet<T>>() };
1✔
133
                                            let iter: BTreeSetIterator<'_, T> = set.iter();
1✔
134
                                            let iter_state = Box::new(iter);
1✔
135
                                            PtrMut::new(Box::into_raw(iter_state) as *mut u8)
1✔
136
                                        })
1✔
137
                                        .next(|iter_ptr| {
6✔
138
                                            let state = unsafe {
6✔
139
                                                iter_ptr.as_mut::<BTreeSetIterator<'_, T>>()
6✔
140
                                            };
141
                                            state
6✔
142
                                                .next()
6✔
143
                                                .map(|value| PtrConst::new(value as *const T))
6✔
144
                                        })
6✔
145
                                        .next_back(|iter_ptr| {
×
146
                                            let state = unsafe {
×
147
                                                iter_ptr.as_mut::<BTreeSetIterator<'_, T>>()
×
148
                                            };
149
                                            state
×
150
                                                .next_back()
×
151
                                                .map(|value| PtrConst::new(value as *const T))
×
152
                                        })
×
153
                                        .dealloc(|iter_ptr| unsafe {
154
                                            drop(Box::from_raw(
1✔
155
                                                iter_ptr.as_ptr::<BTreeSetIterator<'_, T>>()
1✔
156
                                                    as *mut BTreeSetIterator<'_, T>,
1✔
157
                                            ));
158
                                        })
1✔
159
                                        .build(),
160
                                )
161
                                .build()
162
                        },
163
                    )
164
                    .build(),
165
            ))
166
            .build()
167
    };
168
}
169

170
#[cfg(test)]
171
mod tests {
172
    use alloc::collections::BTreeSet;
173
    use alloc::string::String;
174
    use alloc::vec::Vec;
175

176
    use super::*;
177

178
    #[test]
179
    fn test_btreesetset_type_params() {
1✔
180
        let [type_param_1] = <BTreeSet<i32>>::SHAPE.type_params else {
1✔
181
            panic!("BTreeSet<T> should have 1 type param")
×
182
        };
183
        assert_eq!(type_param_1.shape(), i32::SHAPE);
1✔
184
    }
1✔
185

186
    #[test]
187
    fn test_btreeset_vtable_1_new_insert_iter_drop() -> eyre::Result<()> {
1✔
188
        facet_testhelpers::setup();
1✔
189

190
        let btreeset_shape = <BTreeSet<String>>::SHAPE;
1✔
191
        let btreeset_def = btreeset_shape
1✔
192
            .def
1✔
193
            .into_set()
1✔
194
            .expect("BTreeSet<T> should have a set definition");
1✔
195

196
        // Allocate memory for the BTreeSet
197
        let btreeset_uninit_ptr = btreeset_shape.allocate()?;
1✔
198

199
        // Create the BTreeSet
200
        let btreeset_ptr =
1✔
201
            unsafe { (btreeset_def.vtable.init_in_place_with_capacity_fn)(btreeset_uninit_ptr, 0) };
1✔
202

203
        // The BTreeSet is empty, so ensure its length is 0
204
        let btreeset_actual_length =
1✔
205
            unsafe { (btreeset_def.vtable.len_fn)(btreeset_ptr.as_const()) };
1✔
206
        assert_eq!(btreeset_actual_length, 0);
1✔
207

208
        // 5 sample values to insert
209
        let strings = ["foo", "bar", "bazz", "fizzbuzz", "fifth thing"];
1✔
210

211
        // Insert the 5 values into the BTreeSet
212
        let mut btreeset_length = 0;
1✔
213
        for string in strings {
6✔
214
            // Create the value
215
            let mut new_value = string.to_string();
5✔
216

217
            // Insert the value
218
            let did_insert = unsafe {
5✔
219
                (btreeset_def.vtable.insert_fn)(btreeset_ptr, PtrMut::new(&raw mut new_value))
5✔
220
            };
221

222
            // The value now belongs to the BTreeSet, so forget it
223
            core::mem::forget(new_value);
5✔
224

225
            assert!(did_insert, "expected value to be inserted in the BTreeSet");
5✔
226

227
            // Ensure the BTreeSet's length increased by 1
228
            btreeset_length += 1;
5✔
229
            let btreeset_actual_length =
5✔
230
                unsafe { (btreeset_def.vtable.len_fn)(btreeset_ptr.as_const()) };
5✔
231
            assert_eq!(btreeset_actual_length, btreeset_length);
5✔
232
        }
233

234
        // Insert the same 5 values again, ensuring they are deduplicated
235
        for string in strings {
6✔
236
            // Create the value
237
            let mut new_value = string.to_string();
5✔
238

239
            // Try to insert the value
240
            let did_insert = unsafe {
5✔
241
                (btreeset_def.vtable.insert_fn)(btreeset_ptr, PtrMut::new(&raw mut new_value))
5✔
242
            };
243

244
            // The value now belongs to the BTreeSet, so forget it
245
            core::mem::forget(new_value);
5✔
246

247
            assert!(
5✔
248
                !did_insert,
5✔
249
                "expected value to not be inserted in the BTreeSet"
×
250
            );
251

252
            // Ensure the BTreeSet's length did not increase
253
            let btreeset_actual_length =
5✔
254
                unsafe { (btreeset_def.vtable.len_fn)(btreeset_ptr.as_const()) };
5✔
255
            assert_eq!(btreeset_actual_length, btreeset_length);
5✔
256
        }
257

258
        // Create a new iterator over the BTreeSet
259
        let iter_init_with_value_fn = btreeset_def.vtable.iter_vtable.init_with_value.unwrap();
1✔
260
        let btreeset_iter_ptr = unsafe { iter_init_with_value_fn(btreeset_ptr.as_const()) };
1✔
261

262
        // Collect all the items from the BTreeSet's iterator
263
        let mut iter_items = Vec::<&str>::new();
1✔
264
        loop {
265
            // Get the next item from the iterator
266
            let item_ptr = unsafe { (btreeset_def.vtable.iter_vtable.next)(btreeset_iter_ptr) };
6✔
267
            let Some(item_ptr) = item_ptr else {
6✔
268
                break;
1✔
269
            };
270

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

273
            // Add the item into the list of items returned from the iterator
274
            iter_items.push(&**item);
5✔
275
        }
276

277
        // Deallocate the iterator
278
        unsafe {
1✔
279
            (btreeset_def.vtable.iter_vtable.dealloc)(btreeset_iter_ptr);
1✔
280
        }
1✔
281

282
        // BTrees iterate in sorted order, so ensure the iterator returned
283
        // each item in order
284
        let mut strings_sorted = strings.to_vec();
1✔
285
        strings_sorted.sort();
1✔
286
        assert_eq!(iter_items, strings_sorted);
1✔
287

288
        // Get the function pointer for dropping the BTreeSet
289
        let drop_fn =
1✔
290
            (btreeset_shape.vtable.drop_in_place)().expect("BTreeSet<T> should have drop_in_place");
1✔
291

292
        // Drop the BTreeSet in place
293
        unsafe { drop_fn(btreeset_ptr) };
1✔
294

295
        // Deallocate the memory
296
        unsafe { btreeset_shape.deallocate_mut(btreeset_ptr)? };
1✔
297

298
        Ok(())
1✔
299
    }
1✔
300
}
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