facet_core/impls/alloc/
btreeset.rs1use alloc::boxed::Box;
2use alloc::collections::BTreeSet;
3
4use crate::{PtrConst, PtrMut, PtrUninit};
5
6use crate::{
7 Def, Facet, IterVTable, OxPtrMut, SetDef, SetVTable, Shape, ShapeBuilder, TypeNameFn,
8 TypeNameOpts, TypeOpsIndirect, TypeParam, VTableIndirect,
9};
10
11type BTreeSetIterator<'mem, T> = alloc::collections::btree_set::Iter<'mem, T>;
12
13unsafe fn btreeset_init_in_place_with_capacity<T>(uninit: PtrUninit, _capacity: usize) -> PtrMut {
14 unsafe { uninit.put(BTreeSet::<T>::new()) }
15}
16
17unsafe fn btreeset_insert<T: Eq + Ord + 'static>(ptr: PtrMut, item: PtrMut) -> bool {
18 unsafe {
19 let set = ptr.as_mut::<BTreeSet<T>>();
20 let item = item.read::<T>();
21 set.insert(item)
22 }
23}
24
25unsafe fn btreeset_len<T: 'static>(ptr: PtrConst) -> usize {
26 unsafe { ptr.get::<BTreeSet<T>>().len() }
27}
28
29unsafe fn btreeset_contains<T: Eq + Ord + 'static>(ptr: PtrConst, item: PtrConst) -> bool {
30 unsafe { ptr.get::<BTreeSet<T>>().contains(item.get()) }
31}
32
33unsafe fn btreeset_iter_init<T: 'static>(ptr: PtrConst) -> PtrMut {
34 unsafe {
35 let set = ptr.get::<BTreeSet<T>>();
36 let iter: BTreeSetIterator<'_, T> = set.iter();
37 let iter_state = Box::new(iter);
38 PtrMut::new(Box::into_raw(iter_state) as *mut u8)
39 }
40}
41
42unsafe fn btreeset_iter_next<T: 'static>(iter_ptr: PtrMut) -> Option<PtrConst> {
43 unsafe {
44 let state = iter_ptr.as_mut::<BTreeSetIterator<'static, T>>();
45 state.next().map(|value| PtrConst::new(value as *const T))
46 }
47}
48
49unsafe fn btreeset_iter_next_back<T: 'static>(iter_ptr: PtrMut) -> Option<PtrConst> {
50 unsafe {
51 let state = iter_ptr.as_mut::<BTreeSetIterator<'static, T>>();
52 state
53 .next_back()
54 .map(|value| PtrConst::new(value as *const T))
55 }
56}
57
58unsafe fn btreeset_iter_dealloc<T>(iter_ptr: PtrMut) {
59 unsafe {
60 drop(Box::from_raw(
61 iter_ptr.as_ptr::<BTreeSetIterator<'_, T>>() as *mut BTreeSetIterator<'_, T>
62 ));
63 }
64}
65
66unsafe fn btreeset_drop<T>(ox: OxPtrMut) {
68 unsafe {
69 core::ptr::drop_in_place(ox.ptr().as_ptr::<BTreeSet<T>>() as *mut BTreeSet<T>);
70 }
71}
72
73unsafe fn btreeset_default<T>(ox: OxPtrMut) {
75 unsafe { ox.ptr().as_uninit().put(BTreeSet::<T>::new()) };
76}
77
78unsafe impl<'a, T> Facet<'a> for BTreeSet<T>
79where
80 T: Facet<'a> + core::cmp::Eq + core::cmp::Ord + 'static,
81{
82 const SHAPE: &'static crate::Shape = &const {
83 const fn build_set_vtable<T: Eq + Ord + 'static>() -> SetVTable {
84 SetVTable::builder()
85 .init_in_place_with_capacity(btreeset_init_in_place_with_capacity::<T>)
86 .insert(btreeset_insert::<T>)
87 .len(btreeset_len::<T>)
88 .contains(btreeset_contains::<T>)
89 .iter_vtable(IterVTable {
90 init_with_value: Some(btreeset_iter_init::<T>),
91 next: btreeset_iter_next::<T>,
92 next_back: Some(btreeset_iter_next_back::<T>),
93 size_hint: None,
94 dealloc: btreeset_iter_dealloc::<T>,
95 })
96 .build()
97 }
98
99 const fn build_type_name<'a, T: Facet<'a>>() -> TypeNameFn {
100 fn type_name_impl<'a, T: Facet<'a>>(
101 _shape: &'static Shape,
102 f: &mut core::fmt::Formatter<'_>,
103 opts: TypeNameOpts,
104 ) -> core::fmt::Result {
105 write!(f, "BTreeSet")?;
106 if let Some(opts) = opts.for_children() {
107 write!(f, "<")?;
108 T::SHAPE.write_type_name(f, opts)?;
109 write!(f, ">")?;
110 } else {
111 write!(f, "<…>")?;
112 }
113 Ok(())
114 }
115 type_name_impl::<T>
116 }
117
118 ShapeBuilder::for_sized::<Self>("BTreeSet")
119 .type_name(build_type_name::<T>())
120 .vtable_indirect(&VTableIndirect::EMPTY)
121 .type_ops_indirect(
122 &const {
123 TypeOpsIndirect {
124 drop_in_place: btreeset_drop::<T>,
125 default_in_place: Some(btreeset_default::<T>),
126 clone_into: None,
127 is_truthy: None,
128 }
129 },
130 )
131 .def(Def::Set(SetDef::new(
132 &const { build_set_vtable::<T>() },
133 T::SHAPE,
134 )))
135 .type_params(&[TypeParam {
136 name: "T",
137 shape: T::SHAPE,
138 }])
139 .build()
140 };
141}
142
143#[cfg(test)]
144mod tests {
145 use core::ptr::NonNull;
146
147 use alloc::collections::BTreeSet;
148 use alloc::string::String;
149 use alloc::vec::Vec;
150
151 use super::*;
152
153 #[test]
154 fn test_btreesetset_type_params() {
155 let [type_param_1] = <BTreeSet<i32>>::SHAPE.type_params else {
156 panic!("BTreeSet<T> should have 1 type param")
157 };
158 assert_eq!(type_param_1.shape(), i32::SHAPE);
159 }
160
161 #[test]
162 fn test_btreeset_vtable_1_new_insert_iter_drop() {
163 facet_testhelpers::setup();
164
165 let btreeset_shape = <BTreeSet<String>>::SHAPE;
166 let btreeset_def = btreeset_shape
167 .def
168 .into_set()
169 .expect("BTreeSet<T> should have a set definition");
170
171 let btreeset_uninit_ptr = btreeset_shape.allocate().unwrap();
173
174 let btreeset_ptr =
176 unsafe { (btreeset_def.vtable.init_in_place_with_capacity)(btreeset_uninit_ptr, 0) };
177
178 let btreeset_actual_length = unsafe { (btreeset_def.vtable.len)(btreeset_ptr.as_const()) };
180 assert_eq!(btreeset_actual_length, 0);
181
182 let strings = ["foo", "bar", "bazz", "fizzbuzz", "fifth thing"];
184
185 let mut btreeset_length = 0;
187 for string in strings {
188 let mut new_value = string.to_string();
190
191 let did_insert = unsafe {
193 (btreeset_def.vtable.insert)(
194 btreeset_ptr,
195 PtrMut::new(NonNull::from(&mut new_value).as_ptr()),
196 )
197 };
198
199 core::mem::forget(new_value);
201
202 assert!(did_insert, "expected value to be inserted in the BTreeSet");
203
204 btreeset_length += 1;
206 let btreeset_actual_length =
207 unsafe { (btreeset_def.vtable.len)(btreeset_ptr.as_const()) };
208 assert_eq!(btreeset_actual_length, btreeset_length);
209 }
210
211 for string in strings {
213 let mut new_value = string.to_string();
215
216 let did_insert = unsafe {
218 (btreeset_def.vtable.insert)(
219 btreeset_ptr,
220 PtrMut::new(NonNull::from(&mut new_value).as_ptr()),
221 )
222 };
223
224 core::mem::forget(new_value);
226
227 assert!(
228 !did_insert,
229 "expected value to not be inserted in the BTreeSet"
230 );
231
232 let btreeset_actual_length =
234 unsafe { (btreeset_def.vtable.len)(btreeset_ptr.as_const()) };
235 assert_eq!(btreeset_actual_length, btreeset_length);
236 }
237
238 let iter_init_with_value_fn = btreeset_def.vtable.iter_vtable.init_with_value.unwrap();
240 let btreeset_iter_ptr = unsafe { iter_init_with_value_fn(btreeset_ptr.as_const()) };
241
242 let mut iter_items = Vec::<&str>::new();
244 loop {
245 let item_ptr = unsafe { (btreeset_def.vtable.iter_vtable.next)(btreeset_iter_ptr) };
247 let Some(item_ptr) = item_ptr else {
248 break;
249 };
250
251 let item = unsafe { item_ptr.get::<String>() };
252
253 iter_items.push(&**item);
255 }
256
257 unsafe {
259 (btreeset_def.vtable.iter_vtable.dealloc)(btreeset_iter_ptr);
260 }
261
262 let mut strings_sorted = strings.to_vec();
265 strings_sorted.sort();
266 assert_eq!(iter_items, strings_sorted);
267
268 unsafe {
270 btreeset_shape
271 .call_drop_in_place(btreeset_ptr)
272 .expect("BTreeSet<T> should have drop_in_place");
273 }
274
275 unsafe { btreeset_shape.deallocate_mut(btreeset_ptr).unwrap() };
277 }
278}