use crate::{JsData, JsValue, builtins::map::ordered_map::MapKey, object::JsObject};
use boa_gc::{Finalize, Trace, custom_trace};
use indexmap::IndexSet;
use std::fmt::Debug;
#[derive(Clone, Finalize, JsData)]
pub struct OrderedSet {
inner: IndexSet<MapKey>,
lock: u32,
empty_count: usize,
}
unsafe impl Trace for OrderedSet {
custom_trace!(this, mark, {
for v in &this.inner {
if let MapKey::Key(v) = v {
mark(v);
}
}
});
}
impl Debug for OrderedSet {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
self.inner.fmt(formatter)
}
}
impl Default for OrderedSet {
fn default() -> Self {
Self::new()
}
}
impl OrderedSet {
#[must_use]
pub fn new() -> Self {
Self {
inner: IndexSet::new(),
lock: 0,
empty_count: 0,
}
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
inner: IndexSet::with_capacity(capacity),
lock: 0,
empty_count: 0,
}
}
#[must_use]
pub fn full_len(&self) -> usize {
self.inner.len()
}
#[must_use]
pub fn len(&self) -> usize {
self.inner.len() - self.empty_count
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.inner.len() == 0
}
pub fn add(&mut self, value: JsValue) -> bool {
self.inner.insert(MapKey::Key(value))
}
pub fn delete(&mut self, value: &JsValue) -> bool {
if self.lock == 0 {
self.inner.shift_remove(value)
} else if self.inner.contains(value) {
self.inner.insert(MapKey::Empty(self.empty_count));
self.empty_count += 1;
self.inner.swap_remove(value)
} else {
false
}
}
#[inline]
pub fn clear(&mut self) {
self.inner.clear();
self.inner.shrink_to_fit();
self.empty_count = 0;
}
#[must_use]
pub fn contains(&self, value: &JsValue) -> bool {
self.inner.contains(value)
}
#[must_use]
pub fn get_index(&self, index: usize) -> Option<&JsValue> {
if let MapKey::Key(value) = self.inner.get_index(index)? {
Some(value)
} else {
None
}
}
pub fn iter(&self) -> impl Iterator<Item = &JsValue> {
self.inner.iter().filter_map(|v| {
if let MapKey::Key(v) = v {
Some(v)
} else {
None
}
})
}
pub(crate) fn lock(&mut self, set: JsObject) -> SetLock {
self.lock += 1;
SetLock(set)
}
fn unlock(&mut self) {
self.lock -= 1;
if self.lock == 0 {
self.inner.retain(|k| matches!(k, MapKey::Key(_)));
self.empty_count = 0;
}
}
}
#[derive(Debug, Trace)]
pub(crate) struct SetLock(JsObject);
impl Finalize for SetLock {
fn finalize(&self) {
self.0
.downcast_mut::<OrderedSet>()
.expect("SetLock does not point to a set")
.unlock();
}
}