use alloc::boxed::Box;
use alloc::collections::BTreeSet;
use crate::{PtrConst, PtrMut, PtrUninit};
use crate::{
Def, Facet, IterVTable, OxPtrMut, OxPtrUninit, SetDef, SetVTable, Shape, ShapeBuilder,
TypeNameFn, TypeNameOpts, TypeOpsIndirect, TypeParam, VTableIndirect, Variance, VarianceDep,
VarianceDesc,
};
type BTreeSetIterator<'mem, T> = alloc::collections::btree_set::Iter<'mem, T>;
unsafe extern "C" fn btreeset_init_in_place_with_capacity<T>(
uninit: PtrUninit,
_capacity: usize,
) -> PtrMut {
unsafe { uninit.put(BTreeSet::<T>::new()) }
}
unsafe extern "C" fn btreeset_insert<T: Eq + Ord + 'static>(ptr: PtrMut, item: PtrMut) -> bool {
unsafe {
let set = ptr.as_mut::<BTreeSet<T>>();
let item = item.read::<T>();
set.insert(item)
}
}
unsafe extern "C" fn btreeset_len<T: 'static>(ptr: PtrConst) -> usize {
unsafe { ptr.get::<BTreeSet<T>>().len() }
}
unsafe extern "C" fn btreeset_contains<T: Eq + Ord + 'static>(
ptr: PtrConst,
item: PtrConst,
) -> bool {
unsafe { ptr.get::<BTreeSet<T>>().contains(item.get()) }
}
unsafe extern "C" fn btreeset_iter_init<T: 'static>(ptr: PtrConst) -> PtrMut {
unsafe {
let set = ptr.get::<BTreeSet<T>>();
let iter: BTreeSetIterator<'_, T> = set.iter();
let iter_state = Box::new(iter);
PtrMut::new(Box::into_raw(iter_state) as *mut u8)
}
}
unsafe fn btreeset_iter_next<T: 'static>(iter_ptr: PtrMut) -> Option<PtrConst> {
unsafe {
let state = iter_ptr.as_mut::<BTreeSetIterator<'static, T>>();
state.next().map(|value| PtrConst::new(value as *const T))
}
}
unsafe fn btreeset_iter_next_back<T: 'static>(iter_ptr: PtrMut) -> Option<PtrConst> {
unsafe {
let state = iter_ptr.as_mut::<BTreeSetIterator<'static, T>>();
state
.next_back()
.map(|value| PtrConst::new(value as *const T))
}
}
unsafe extern "C" fn btreeset_iter_dealloc<T>(iter_ptr: PtrMut) {
unsafe {
drop(Box::from_raw(
iter_ptr.as_ptr::<BTreeSetIterator<'_, T>>() as *mut BTreeSetIterator<'_, T>
));
}
}
unsafe extern "C" fn btreeset_from_slice<T: Eq + Ord + 'static>(
set: PtrUninit,
elements_ptr: *mut u8,
count: usize,
) -> PtrMut {
unsafe {
let elements = elements_ptr as *mut T;
let mut btreeset = BTreeSet::<T>::new();
for i in 0..count {
let elem = core::ptr::read(elements.add(i));
btreeset.insert(elem);
}
set.put(btreeset)
}
}
unsafe fn btreeset_drop<T>(ox: OxPtrMut) {
unsafe {
core::ptr::drop_in_place(ox.ptr().as_ptr::<BTreeSet<T>>() as *mut BTreeSet<T>);
}
}
unsafe fn btreeset_default<T>(ox: OxPtrUninit) -> bool {
unsafe { ox.put(BTreeSet::<T>::new()) };
true
}
unsafe impl<'a, T> Facet<'a> for BTreeSet<T>
where
T: Facet<'a> + core::cmp::Eq + core::cmp::Ord + 'static,
{
const SHAPE: &'static crate::Shape = &const {
const fn build_set_vtable<T: Eq + Ord + 'static>() -> SetVTable {
SetVTable::builder()
.init_in_place_with_capacity(btreeset_init_in_place_with_capacity::<T>)
.insert(btreeset_insert::<T>)
.len(btreeset_len::<T>)
.contains(btreeset_contains::<T>)
.iter_vtable(IterVTable {
init_with_value: Some(btreeset_iter_init::<T>),
next: btreeset_iter_next::<T>,
next_back: Some(btreeset_iter_next_back::<T>),
size_hint: None,
dealloc: btreeset_iter_dealloc::<T>,
})
.from_slice(Some(btreeset_from_slice::<T>))
.build()
}
const fn build_type_name<'a, T: Facet<'a>>() -> TypeNameFn {
fn type_name_impl<'a, T: Facet<'a>>(
_shape: &'static Shape,
f: &mut core::fmt::Formatter<'_>,
opts: TypeNameOpts,
) -> core::fmt::Result {
write!(f, "BTreeSet")?;
if let Some(opts) = opts.for_children() {
write!(f, "<")?;
T::SHAPE.write_type_name(f, opts)?;
write!(f, ">")?;
} else {
write!(f, "<…>")?;
}
Ok(())
}
type_name_impl::<T>
}
ShapeBuilder::for_sized::<Self>("BTreeSet")
.module_path("alloc::collections::btree_set")
.type_name(build_type_name::<T>())
.vtable_indirect(&VTableIndirect::EMPTY)
.type_ops_indirect(
&const {
TypeOpsIndirect {
drop_in_place: btreeset_drop::<T>,
default_in_place: Some(btreeset_default::<T>),
clone_into: None,
is_truthy: None,
}
},
)
.def(Def::Set(SetDef::new(
&const { build_set_vtable::<T>() },
T::SHAPE,
)))
.type_params(&[TypeParam {
name: "T",
shape: T::SHAPE,
}])
.inner(T::SHAPE)
.variance(VarianceDesc {
base: Variance::Bivariant,
deps: &const { [VarianceDep::covariant(T::SHAPE)] },
})
.build()
};
}
#[cfg(test)]
mod tests {
use core::ptr::NonNull;
use alloc::collections::BTreeSet;
use alloc::string::String;
use alloc::vec::Vec;
use super::*;
#[test]
fn test_btreesetset_type_params() {
let [type_param_1] = <BTreeSet<i32>>::SHAPE.type_params else {
panic!("BTreeSet<T> should have 1 type param")
};
assert_eq!(type_param_1.shape(), i32::SHAPE);
}
#[test]
fn test_btreeset_vtable_1_new_insert_iter_drop() {
facet_testhelpers::setup();
let btreeset_shape = <BTreeSet<String>>::SHAPE;
let btreeset_def = btreeset_shape
.def
.into_set()
.expect("BTreeSet<T> should have a set definition");
let btreeset_uninit_ptr = btreeset_shape.allocate().unwrap();
let btreeset_ptr =
unsafe { (btreeset_def.vtable.init_in_place_with_capacity)(btreeset_uninit_ptr, 0) };
let btreeset_actual_length = unsafe { (btreeset_def.vtable.len)(btreeset_ptr.as_const()) };
assert_eq!(btreeset_actual_length, 0);
let strings = ["foo", "bar", "bazz", "fizzbuzz", "fifth thing"];
let mut btreeset_length = 0;
for string in strings {
let mut new_value = string.to_string();
let did_insert = unsafe {
(btreeset_def.vtable.insert)(
btreeset_ptr,
PtrMut::new(NonNull::from(&mut new_value).as_ptr()),
)
};
core::mem::forget(new_value);
assert!(did_insert, "expected value to be inserted in the BTreeSet");
btreeset_length += 1;
let btreeset_actual_length =
unsafe { (btreeset_def.vtable.len)(btreeset_ptr.as_const()) };
assert_eq!(btreeset_actual_length, btreeset_length);
}
for string in strings {
let mut new_value = string.to_string();
let did_insert = unsafe {
(btreeset_def.vtable.insert)(
btreeset_ptr,
PtrMut::new(NonNull::from(&mut new_value).as_ptr()),
)
};
core::mem::forget(new_value);
assert!(
!did_insert,
"expected value to not be inserted in the BTreeSet"
);
let btreeset_actual_length =
unsafe { (btreeset_def.vtable.len)(btreeset_ptr.as_const()) };
assert_eq!(btreeset_actual_length, btreeset_length);
}
let iter_init_with_value_fn = btreeset_def.vtable.iter_vtable.init_with_value.unwrap();
let btreeset_iter_ptr = unsafe { iter_init_with_value_fn(btreeset_ptr.as_const()) };
let mut iter_items = Vec::<&str>::new();
loop {
let item_ptr = unsafe { (btreeset_def.vtable.iter_vtable.next)(btreeset_iter_ptr) };
let Some(item_ptr) = item_ptr else {
break;
};
let item = unsafe { item_ptr.get::<String>() };
iter_items.push(&**item);
}
unsafe {
(btreeset_def.vtable.iter_vtable.dealloc)(btreeset_iter_ptr);
}
let mut strings_sorted = strings.to_vec();
strings_sorted.sort();
assert_eq!(iter_items, strings_sorted);
unsafe {
btreeset_shape
.call_drop_in_place(btreeset_ptr)
.expect("BTreeSet<T> should have drop_in_place");
}
unsafe { btreeset_shape.deallocate_mut(btreeset_ptr).unwrap() };
}
}