facet_core/impls_alloc/
btreeset.rs1use 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 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 )
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 })
37 .default_in_place(|target| unsafe { target.put(Self::default()) })
38 .eq(|a, b| a == b);
39
40 if T::SHAPE.vtable.debug.is_some() {
41 builder = builder.debug(|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 }
53
54 if T::SHAPE.vtable.clone_into.is_some() {
55 builder = builder.clone_into(|src, dst| unsafe {
56 let set = src;
57 let mut new_set = BTreeSet::new();
58
59 let t_clone_into = <VTableView<T>>::of().clone_into().unwrap();
60
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
70 new_set.insert(new_item.assume_init());
71 }
72
73 dst.put(new_set)
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();
81 let mut hasher = HasherProxy::new(hasher_this, hasher_write_fn);
82 set.len().hash(&mut hasher);
83 for item in set {
84 (t_hash)(item, hasher_this, hasher_write_fn);
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())
107 })
108 .insert(|ptr, item| unsafe {
109 let set = ptr.as_mut::<BTreeSet<T>>();
110 let item = item.read::<T>();
111 set.insert(item)
112 })
113 .len(|ptr| unsafe {
114 let set = ptr.get::<BTreeSet<T>>();
115 set.len()
116 })
117 .contains(|ptr, item| unsafe {
118 let set = ptr.get::<BTreeSet<T>>();
119 set.contains(item.get())
120 })
121 .iter_vtable(
122 IterVTable::builder()
123 .init_with_value(|ptr| {
124 let set = unsafe { ptr.get::<BTreeSet<T>>() };
125 let iter: BTreeSetIterator<'_, T> = set.iter();
126 let iter_state = Box::new(iter);
127 PtrMut::new(Box::into_raw(iter_state) as *mut u8)
128 })
129 .next(|iter_ptr| {
130 let state = unsafe {
131 iter_ptr.as_mut::<BTreeSetIterator<'_, T>>()
132 };
133 state
134 .next()
135 .map(|value| PtrConst::new(value as *const T))
136 })
137 .next_back(|iter_ptr| {
138 let state = unsafe {
139 iter_ptr.as_mut::<BTreeSetIterator<'_, T>>()
140 };
141 state
142 .next_back()
143 .map(|value| PtrConst::new(value as *const T))
144 })
145 .dealloc(|iter_ptr| unsafe {
146 drop(Box::from_raw(
147 iter_ptr.as_ptr::<BTreeSetIterator<'_, T>>()
148 as *mut BTreeSetIterator<'_, T>,
149 ));
150 })
151 .build(),
152 )
153 .build()
154 },
155 )
156 .build(),
157 ))
158 .build()
159 };
160}
161
162#[cfg(test)]
163mod 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() {
172 let [type_param_1] = <BTreeSet<i32>>::SHAPE.type_params else {
173 panic!("BTreeSet<T> should have 1 type param")
174 };
175 assert_eq!(type_param_1.shape(), i32::SHAPE);
176 }
177
178 #[test]
179 fn test_btreeset_vtable_1_new_insert_iter_drop() -> eyre::Result<()> {
180 facet_testhelpers::setup();
181
182 let btreeset_shape = <BTreeSet<String>>::SHAPE;
183 let btreeset_def = btreeset_shape
184 .def
185 .into_set()
186 .expect("BTreeSet<T> should have a set definition");
187
188 let btreeset_uninit_ptr = btreeset_shape.allocate()?;
190
191 let btreeset_ptr =
193 unsafe { (btreeset_def.vtable.init_in_place_with_capacity_fn)(btreeset_uninit_ptr, 0) };
194
195 let btreeset_actual_length =
197 unsafe { (btreeset_def.vtable.len_fn)(btreeset_ptr.as_const()) };
198 assert_eq!(btreeset_actual_length, 0);
199
200 let strings = ["foo", "bar", "bazz", "fizzbuzz", "fifth thing"];
202
203 let mut btreeset_length = 0;
205 for string in strings {
206 let mut new_value = string.to_string();
208
209 let did_insert = unsafe {
211 (btreeset_def.vtable.insert_fn)(btreeset_ptr, PtrMut::new(&raw mut new_value))
212 };
213
214 core::mem::forget(new_value);
216
217 assert!(did_insert, "expected value to be inserted in the BTreeSet");
218
219 btreeset_length += 1;
221 let btreeset_actual_length =
222 unsafe { (btreeset_def.vtable.len_fn)(btreeset_ptr.as_const()) };
223 assert_eq!(btreeset_actual_length, btreeset_length);
224 }
225
226 for string in strings {
228 let mut new_value = string.to_string();
230
231 let did_insert = unsafe {
233 (btreeset_def.vtable.insert_fn)(btreeset_ptr, PtrMut::new(&raw mut new_value))
234 };
235
236 core::mem::forget(new_value);
238
239 assert!(
240 !did_insert,
241 "expected value to not be inserted in the BTreeSet"
242 );
243
244 let btreeset_actual_length =
246 unsafe { (btreeset_def.vtable.len_fn)(btreeset_ptr.as_const()) };
247 assert_eq!(btreeset_actual_length, btreeset_length);
248 }
249
250 let iter_init_with_value_fn = btreeset_def.vtable.iter_vtable.init_with_value.unwrap();
252 let btreeset_iter_ptr = unsafe { iter_init_with_value_fn(btreeset_ptr.as_const()) };
253
254 let mut iter_items = Vec::<&str>::new();
256 loop {
257 let item_ptr = unsafe { (btreeset_def.vtable.iter_vtable.next)(btreeset_iter_ptr) };
259 let Some(item_ptr) = item_ptr else {
260 break;
261 };
262
263 let item = unsafe { item_ptr.get::<String>() };
264
265 iter_items.push(&**item);
267 }
268
269 unsafe {
271 (btreeset_def.vtable.iter_vtable.dealloc)(btreeset_iter_ptr);
272 }
273
274 let mut strings_sorted = strings.to_vec();
277 strings_sorted.sort();
278 assert_eq!(iter_items, strings_sorted);
279
280 let drop_fn = btreeset_shape
282 .vtable
283 .drop_in_place
284 .expect("BTreeSet<T> should have drop_in_place");
285
286 unsafe { drop_fn(btreeset_ptr) };
288
289 unsafe { btreeset_shape.deallocate_mut(btreeset_ptr)? };
291
292 Ok(())
293 }
294}