facet_core/impls_alloc/
btreeset.rs

1use core::hash::Hash;
2
3use alloc::boxed::Box;
4use alloc::collections::BTreeSet;
5
6use crate::ptr::{PtrConst, PtrMut};
7
8use crate::{
9    Def, Facet, MarkerTraits, SetDef, SetIterVTable, SetVTable, Shape, Type, TypeParam, UserType,
10    VTableView, ValueVTable,
11};
12
13struct BTreeSetIterator<'mem, T> {
14    set: &'mem BTreeSet<T>,
15    next_bound: core::ops::Bound<&'mem T>,
16}
17
18impl<'mem, T> BTreeSetIterator<'mem, T>
19where
20    T: Ord,
21{
22    fn next(&mut self) -> Option<&'mem T> {
23        let mut range = self
24            .set
25            .range((self.next_bound, core::ops::Bound::Unbounded));
26        let next = range.next();
27
28        if let Some(next) = next {
29            self.next_bound = core::ops::Bound::Excluded(next);
30        }
31
32        next
33    }
34}
35
36unsafe impl<'a, T> Facet<'a> for BTreeSet<T>
37where
38    T: Facet<'a> + core::cmp::Eq + core::cmp::Ord,
39{
40    const VTABLE: &'static ValueVTable = &const {
41        let mut builder = ValueVTable::builder::<Self>()
42            .marker_traits(
43                MarkerTraits::SEND
44                    .union(MarkerTraits::SYNC)
45                    .union(MarkerTraits::EQ)
46                    .union(MarkerTraits::UNPIN)
47                    .intersection(T::SHAPE.vtable.marker_traits),
48            )
49            .type_name(|f, opts| {
50                if let Some(opts) = opts.for_children() {
51                    write!(f, "BTreeSet<")?;
52                    (T::SHAPE.vtable.type_name)(f, opts)?;
53                    write!(f, ">")
54                } else {
55                    write!(f, "BTreeSet<⋯>")
56                }
57            })
58            .default_in_place(|target| unsafe { target.put(Self::default()) })
59            .eq(|a, b| a == b);
60
61        if T::SHAPE.vtable.debug.is_some() {
62            builder = builder.debug(|value, f| {
63                let t_debug = <VTableView<T>>::of().debug().unwrap();
64                write!(f, "{{")?;
65                for (i, item) in value.iter().enumerate() {
66                    if i > 0 {
67                        write!(f, ", ")?;
68                    }
69                    (t_debug)(item, f)?;
70                }
71                write!(f, "}}")
72            });
73        }
74
75        if T::SHAPE.vtable.clone_into.is_some() {
76            builder = builder.clone_into(|src, dst| unsafe {
77                let set = src;
78                let mut new_set = BTreeSet::new();
79
80                let t_clone_into = <VTableView<T>>::of().clone_into().unwrap();
81
82                for item in set {
83                    use crate::TypedPtrUninit;
84                    use core::mem::MaybeUninit;
85
86                    let mut new_item = MaybeUninit::<T>::uninit();
87                    let uninit_item = TypedPtrUninit::new(new_item.as_mut_ptr());
88
89                    (t_clone_into)(item, uninit_item);
90
91                    new_set.insert(new_item.assume_init());
92                }
93
94                dst.put(new_set)
95            });
96        }
97
98        if T::SHAPE.vtable.hash.is_some() {
99            builder = builder.hash(|set, hasher_this, hasher_write_fn| unsafe {
100                use crate::HasherProxy;
101                let t_hash = <VTableView<T>>::of().hash().unwrap();
102                let mut hasher = HasherProxy::new(hasher_this, hasher_write_fn);
103                set.len().hash(&mut hasher);
104                for item in set {
105                    (t_hash)(item, hasher_this, hasher_write_fn);
106                }
107            });
108        }
109
110        builder.build()
111    };
112
113    const SHAPE: &'static Shape = &const {
114        Shape::builder_for_sized::<Self>()
115            .type_params(&[TypeParam {
116                name: "T",
117                shape: || T::SHAPE,
118            }])
119            .ty(Type::User(UserType::Opaque))
120            .def(Def::Set(
121                SetDef::builder()
122                    .t(|| T::SHAPE)
123                    .vtable(
124                        &const {
125                            SetVTable::builder()
126                                .init_in_place_with_capacity(|uninit, _capacity| unsafe {
127                                    uninit.put(Self::new())
128                                })
129                                .insert(|ptr, item| unsafe {
130                                    let set = ptr.as_mut::<BTreeSet<T>>();
131                                    let item = item.read::<T>();
132                                    set.insert(item)
133                                })
134                                .len(|ptr| unsafe {
135                                    let set = ptr.get::<BTreeSet<T>>();
136                                    set.len()
137                                })
138                                .contains(|ptr, item| unsafe {
139                                    let set = ptr.get::<BTreeSet<T>>();
140                                    set.contains(item.get())
141                                })
142                                .iter(|ptr| {
143                                    let set = unsafe { ptr.get::<BTreeSet<T>>() };
144                                    let iter_state = Box::new(BTreeSetIterator {
145                                        set,
146                                        next_bound: core::ops::Bound::Unbounded,
147                                    });
148                                    PtrMut::new(Box::into_raw(iter_state) as *mut u8)
149                                })
150                                .iter_vtable(
151                                    SetIterVTable::builder()
152                                        .next(|iter_ptr| {
153                                            let state = unsafe {
154                                                iter_ptr.as_mut::<BTreeSetIterator<'_, T>>()
155                                            };
156                                            state
157                                                .next()
158                                                .map(|value| PtrConst::new(value as *const T))
159                                        })
160                                        .dealloc(|iter_ptr| unsafe {
161                                            drop(Box::from_raw(
162                                                iter_ptr.as_ptr::<BTreeSetIterator<'_, T>>()
163                                                    as *mut BTreeSetIterator<'_, T>,
164                                            ));
165                                        })
166                                        .build(),
167                                )
168                                .build()
169                        },
170                    )
171                    .build(),
172            ))
173            .build()
174    };
175}
176
177#[cfg(test)]
178mod tests {
179    use alloc::collections::BTreeSet;
180    use alloc::string::String;
181    use alloc::vec::Vec;
182
183    use super::*;
184
185    #[test]
186    fn test_btreesetset_type_params() {
187        let [type_param_1] = <BTreeSet<i32>>::SHAPE.type_params else {
188            panic!("BTreeSet<T> should have 1 type param")
189        };
190        assert_eq!(type_param_1.shape(), i32::SHAPE);
191    }
192
193    #[test]
194    fn test_btreeset_vtable_1_new_insert_iter_drop() -> eyre::Result<()> {
195        facet_testhelpers::setup();
196
197        let btreeset_shape = <BTreeSet<String>>::SHAPE;
198        let btreeset_def = btreeset_shape
199            .def
200            .into_set()
201            .expect("BTreeSet<T> should have a set definition");
202
203        // Allocate memory for the BTreeSet
204        let btreeset_uninit_ptr = btreeset_shape.allocate()?;
205
206        // Create the BTreeSet
207        let btreeset_ptr =
208            unsafe { (btreeset_def.vtable.init_in_place_with_capacity_fn)(btreeset_uninit_ptr, 0) };
209
210        // The BTreeSet is empty, so ensure its length is 0
211        let btreeset_actual_length =
212            unsafe { (btreeset_def.vtable.len_fn)(btreeset_ptr.as_const()) };
213        assert_eq!(btreeset_actual_length, 0);
214
215        // 5 sample values to insert
216        let strings = ["foo", "bar", "bazz", "fizzbuzz", "fifth thing"];
217
218        // Insert the 5 values into the BTreeSet
219        let mut btreeset_length = 0;
220        for string in strings {
221            // Create the value
222            let mut new_value = string.to_string();
223
224            // Insert the value
225            let did_insert = unsafe {
226                (btreeset_def.vtable.insert_fn)(btreeset_ptr, PtrMut::new(&raw mut new_value))
227            };
228
229            // The value now belongs to the BTreeSet, so forget it
230            core::mem::forget(new_value);
231
232            assert!(did_insert, "expected value to be inserted in the BTreeSet");
233
234            // Ensure the BTreeSet's length increased by 1
235            btreeset_length += 1;
236            let btreeset_actual_length =
237                unsafe { (btreeset_def.vtable.len_fn)(btreeset_ptr.as_const()) };
238            assert_eq!(btreeset_actual_length, btreeset_length);
239        }
240
241        // Insert the same 5 values again, ensuring they are deduplicated
242        for string in strings {
243            // Create the value
244            let mut new_value = string.to_string();
245
246            // Try to insert the value
247            let did_insert = unsafe {
248                (btreeset_def.vtable.insert_fn)(btreeset_ptr, PtrMut::new(&raw mut new_value))
249            };
250
251            // The value now belongs to the BTreeSet, so forget it
252            core::mem::forget(new_value);
253
254            assert!(
255                !did_insert,
256                "expected value to not be inserted in the BTreeSet"
257            );
258
259            // Ensure the BTreeSet's length did not increase
260            let btreeset_actual_length =
261                unsafe { (btreeset_def.vtable.len_fn)(btreeset_ptr.as_const()) };
262            assert_eq!(btreeset_actual_length, btreeset_length);
263        }
264
265        // Create a new iterator over the BTreeSet
266        let btreeset_iter_ptr = unsafe { (btreeset_def.vtable.iter_fn)(btreeset_ptr.as_const()) };
267
268        // Collect all the items from the BTreeSet's iterator
269        let mut iter_items = Vec::<&str>::new();
270        loop {
271            // Get the next item from the iterator
272            let item_ptr = unsafe { (btreeset_def.vtable.iter_vtable.next)(btreeset_iter_ptr) };
273            let Some(item_ptr) = item_ptr else {
274                break;
275            };
276
277            let item = unsafe { item_ptr.get::<String>() };
278
279            // Add the item into the list of items returned from the iterator
280            iter_items.push(&**item);
281        }
282
283        // Deallocate the iterator
284        unsafe {
285            (btreeset_def.vtable.iter_vtable.dealloc)(btreeset_iter_ptr);
286        }
287
288        // BTrees iterate in sorted order, so ensure the iterator returned
289        // each item in order
290        let mut strings_sorted = strings.to_vec();
291        strings_sorted.sort();
292        assert_eq!(iter_items, strings_sorted);
293
294        // Get the function pointer for dropping the BTreeSet
295        let drop_fn = btreeset_shape
296            .vtable
297            .drop_in_place
298            .expect("BTreeSet<T> should have drop_in_place");
299
300        // Drop the BTreeSet in place
301        unsafe { drop_fn(btreeset_ptr) };
302
303        // Deallocate the memory
304        unsafe { btreeset_shape.deallocate_mut(btreeset_ptr)? };
305
306        Ok(())
307    }
308}