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