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

facet-rs / facet / 15134909761

20 May 2025 10:15AM UTC coverage: 57.211% (+0.05%) from 57.157%
15134909761

push

github

fasterthanlime
Add `next_back` impl for `BTreeSet` iter

0 of 7 new or added lines in 1 file covered. (0.0%)

101 existing lines in 5 files now uncovered.

9303 of 16261 relevant lines covered (57.21%)

132.28 hits per line

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

64.44
/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
        let mut builder = ValueVTable::builder::<Self>()
21
            .marker_traits(
22
                MarkerTraits::SEND
23
                    .union(MarkerTraits::SYNC)
24
                    .union(MarkerTraits::EQ)
25
                    .union(MarkerTraits::UNPIN)
26
                    .intersection(T::SHAPE.vtable.marker_traits),
27
            )
UNCOV
28
            .type_name(|f, opts| {
×
UNCOV
29
                if let Some(opts) = opts.for_children() {
×
UNCOV
30
                    write!(f, "BTreeSet<")?;
×
UNCOV
31
                    (T::SHAPE.vtable.type_name)(f, opts)?;
×
UNCOV
32
                    write!(f, ">")
×
33
                } else {
UNCOV
34
                    write!(f, "BTreeSet<⋯>")
×
35
                }
UNCOV
36
            })
×
UNCOV
37
            .default_in_place(|target| unsafe { target.put(Self::default()) })
×
UNCOV
38
            .eq(|a, b| a == b);
×
39

40
        if T::SHAPE.vtable.debug.is_some() {
UNCOV
41
            builder = builder.debug(|value, f| {
×
UNCOV
42
                let t_debug = <VTableView<T>>::of().debug().unwrap();
×
UNCOV
43
                write!(f, "{{")?;
×
UNCOV
44
                for (i, item) in value.iter().enumerate() {
×
UNCOV
45
                    if i > 0 {
×
UNCOV
46
                        write!(f, ", ")?;
×
UNCOV
47
                    }
×
UNCOV
48
                    (t_debug)(item, f)?;
×
49
                }
50
                write!(f, "}}")
×
51
            });
×
52
        }
53

54
        if T::SHAPE.vtable.clone_into.is_some() {
55
            builder = builder.clone_into(|src, dst| unsafe {
UNCOV
56
                let set = src;
×
57
                let mut new_set = BTreeSet::new();
×
58

59
                let t_clone_into = <VTableView<T>>::of().clone_into().unwrap();
×
60

UNCOV
61
                for item in set {
×
62
                    use crate::TypedPtrUninit;
63
                    use core::mem::MaybeUninit;
64

65
                    let mut new_item = MaybeUninit::<T>::uninit();
×
66
                    let uninit_item = TypedPtrUninit::new(new_item.as_mut_ptr());
×
67

68
                    (t_clone_into)(item, uninit_item);
×
69

UNCOV
70
                    new_set.insert(new_item.assume_init());
×
71
                }
72

UNCOV
73
                dst.put(new_set)
×
UNCOV
74
            });
×
75
        }
76

77
        if T::SHAPE.vtable.hash.is_some() {
78
            builder = builder.hash(|set, hasher_this, hasher_write_fn| unsafe {
79
                use crate::HasherProxy;
80
                let t_hash = <VTableView<T>>::of().hash().unwrap();
×
UNCOV
81
                let mut hasher = HasherProxy::new(hasher_this, hasher_write_fn);
×
82
                set.len().hash(&mut hasher);
×
UNCOV
83
                for item in set {
×
UNCOV
84
                    (t_hash)(item, hasher_this, hasher_write_fn);
×
UNCOV
85
                }
×
86
            });
×
87
        }
88

89
        builder.build()
90
    };
91

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

162
#[cfg(test)]
163
mod tests {
164
    use alloc::collections::BTreeSet;
165
    use alloc::string::String;
166
    use alloc::vec::Vec;
167

168
    use super::*;
169

170
    #[test]
171
    fn test_btreesetset_type_params() {
1✔
172
        let [type_param_1] = <BTreeSet<i32>>::SHAPE.type_params else {
1✔
UNCOV
173
            panic!("BTreeSet<T> should have 1 type param")
×
174
        };
175
        assert_eq!(type_param_1.shape(), i32::SHAPE);
1✔
176
    }
1✔
177

178
    #[test]
179
    fn test_btreeset_vtable_1_new_insert_iter_drop() -> eyre::Result<()> {
1✔
180
        facet_testhelpers::setup();
1✔
181

182
        let btreeset_shape = <BTreeSet<String>>::SHAPE;
1✔
183
        let btreeset_def = btreeset_shape
1✔
184
            .def
1✔
185
            .into_set()
1✔
186
            .expect("BTreeSet<T> should have a set definition");
1✔
187

188
        // Allocate memory for the BTreeSet
189
        let btreeset_uninit_ptr = btreeset_shape.allocate()?;
1✔
190

191
        // Create the BTreeSet
192
        let btreeset_ptr =
1✔
193
            unsafe { (btreeset_def.vtable.init_in_place_with_capacity_fn)(btreeset_uninit_ptr, 0) };
1✔
194

195
        // The BTreeSet is empty, so ensure its length is 0
196
        let btreeset_actual_length =
1✔
197
            unsafe { (btreeset_def.vtable.len_fn)(btreeset_ptr.as_const()) };
1✔
198
        assert_eq!(btreeset_actual_length, 0);
1✔
199

200
        // 5 sample values to insert
201
        let strings = ["foo", "bar", "bazz", "fizzbuzz", "fifth thing"];
1✔
202

203
        // Insert the 5 values into the BTreeSet
204
        let mut btreeset_length = 0;
1✔
205
        for string in strings {
6✔
206
            // Create the value
207
            let mut new_value = string.to_string();
5✔
208

209
            // Insert the value
210
            let did_insert = unsafe {
5✔
211
                (btreeset_def.vtable.insert_fn)(btreeset_ptr, PtrMut::new(&raw mut new_value))
5✔
212
            };
213

214
            // The value now belongs to the BTreeSet, so forget it
215
            core::mem::forget(new_value);
5✔
216

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

219
            // Ensure the BTreeSet's length increased by 1
220
            btreeset_length += 1;
5✔
221
            let btreeset_actual_length =
5✔
222
                unsafe { (btreeset_def.vtable.len_fn)(btreeset_ptr.as_const()) };
5✔
223
            assert_eq!(btreeset_actual_length, btreeset_length);
5✔
224
        }
225

226
        // Insert the same 5 values again, ensuring they are deduplicated
227
        for string in strings {
6✔
228
            // Create the value
229
            let mut new_value = string.to_string();
5✔
230

231
            // Try to insert the value
232
            let did_insert = unsafe {
5✔
233
                (btreeset_def.vtable.insert_fn)(btreeset_ptr, PtrMut::new(&raw mut new_value))
5✔
234
            };
235

236
            // The value now belongs to the BTreeSet, so forget it
237
            core::mem::forget(new_value);
5✔
238

239
            assert!(
5✔
240
                !did_insert,
5✔
UNCOV
241
                "expected value to not be inserted in the BTreeSet"
×
242
            );
243

244
            // Ensure the BTreeSet's length did not increase
245
            let btreeset_actual_length =
5✔
246
                unsafe { (btreeset_def.vtable.len_fn)(btreeset_ptr.as_const()) };
5✔
247
            assert_eq!(btreeset_actual_length, btreeset_length);
5✔
248
        }
249

250
        // Create a new iterator over the BTreeSet
251
        let iter_init_with_value_fn = btreeset_def.vtable.iter_vtable.init_with_value.unwrap();
1✔
252
        let btreeset_iter_ptr = unsafe { iter_init_with_value_fn(btreeset_ptr.as_const()) };
1✔
253

254
        // Collect all the items from the BTreeSet's iterator
255
        let mut iter_items = Vec::<&str>::new();
1✔
256
        loop {
257
            // Get the next item from the iterator
258
            let item_ptr = unsafe { (btreeset_def.vtable.iter_vtable.next)(btreeset_iter_ptr) };
6✔
259
            let Some(item_ptr) = item_ptr else {
6✔
260
                break;
1✔
261
            };
262

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

265
            // Add the item into the list of items returned from the iterator
266
            iter_items.push(&**item);
5✔
267
        }
268

269
        // Deallocate the iterator
270
        unsafe {
1✔
271
            (btreeset_def.vtable.iter_vtable.dealloc)(btreeset_iter_ptr);
1✔
272
        }
1✔
273

274
        // BTrees iterate in sorted order, so ensure the iterator returned
275
        // each item in order
276
        let mut strings_sorted = strings.to_vec();
1✔
277
        strings_sorted.sort();
1✔
278
        assert_eq!(iter_items, strings_sorted);
1✔
279

280
        // Get the function pointer for dropping the BTreeSet
281
        let drop_fn = btreeset_shape
1✔
282
            .vtable
1✔
283
            .drop_in_place
1✔
284
            .expect("BTreeSet<T> should have drop_in_place");
1✔
285

286
        // Drop the BTreeSet in place
287
        unsafe { drop_fn(btreeset_ptr) };
1✔
288

289
        // Deallocate the memory
290
        unsafe { btreeset_shape.deallocate_mut(btreeset_ptr)? };
1✔
291

292
        Ok(())
1✔
293
    }
1✔
294
}
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