use std::collections::HashSet;
use crate::error::{StatorError, StatorResult};
use crate::objects::heap_object::HeapObject;
#[derive(Debug, Default)]
pub struct JsWeakSet {
entries: HashSet<usize>,
}
pub fn weak_set_new() -> JsWeakSet {
JsWeakSet::default()
}
pub fn weak_set_from_iterable(values: Vec<*mut HeapObject>) -> StatorResult<JsWeakSet> {
let mut set = weak_set_new();
for value in values {
weak_set_add(&mut set, value)?;
}
Ok(set)
}
pub fn weak_set_add(set: &mut JsWeakSet, value: *mut HeapObject) -> StatorResult<()> {
if value.is_null() {
return Err(StatorError::TypeError(
"WeakSet value must be an object".into(),
));
}
set.entries.insert(value as usize);
Ok(())
}
pub fn weak_set_has(set: &JsWeakSet, value: *mut HeapObject) -> bool {
if value.is_null() {
return false;
}
set.entries.contains(&(value as usize))
}
pub fn weak_set_delete(set: &mut JsWeakSet, value: *mut HeapObject) -> bool {
if value.is_null() {
return false;
}
set.entries.remove(&(value as usize))
}
pub fn weak_set_remove_object(set: &mut JsWeakSet, value: *mut HeapObject) {
if !value.is_null() {
set.entries.remove(&(value as usize));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_weak_set_add_and_has() {
let mut ws = weak_set_new();
let mut obj = HeapObject::new_null();
let ptr = &raw mut obj;
assert!(weak_set_add(&mut ws, ptr).is_ok());
assert!(weak_set_has(&ws, ptr));
}
#[test]
fn test_weak_set_has_missing_returns_false() {
let ws = weak_set_new();
let mut obj = HeapObject::new_null();
assert!(!weak_set_has(&ws, &raw mut obj));
}
#[test]
fn test_weak_set_add_duplicate_is_noop() {
let mut ws = weak_set_new();
let mut obj = HeapObject::new_null();
let ptr = &raw mut obj;
weak_set_add(&mut ws, ptr).unwrap();
weak_set_add(&mut ws, ptr).unwrap(); assert!(weak_set_has(&ws, ptr));
}
#[test]
fn test_weak_set_delete_existing() {
let mut ws = weak_set_new();
let mut obj = HeapObject::new_null();
let ptr = &raw mut obj;
weak_set_add(&mut ws, ptr).unwrap();
assert!(weak_set_delete(&mut ws, ptr));
assert!(!weak_set_has(&ws, ptr));
}
#[test]
fn test_weak_set_delete_missing_returns_false() {
let mut ws = weak_set_new();
let mut obj = HeapObject::new_null();
assert!(!weak_set_delete(&mut ws, &raw mut obj));
}
#[test]
fn test_weak_set_null_add_returns_error() {
let mut ws = weak_set_new();
assert!(weak_set_add(&mut ws, std::ptr::null_mut()).is_err());
}
#[test]
fn test_weak_set_null_has_returns_false() {
let ws = weak_set_new();
assert!(!weak_set_has(&ws, std::ptr::null_mut()));
}
#[test]
fn test_weak_set_null_delete_returns_false() {
let mut ws = weak_set_new();
assert!(!weak_set_delete(&mut ws, std::ptr::null_mut()));
}
#[test]
fn test_weak_set_from_iterable_populates_entries() {
let mut a = HeapObject::new_null();
let mut b = HeapObject::new_null();
let ws = weak_set_from_iterable(vec![&raw mut a, &raw mut b]).unwrap();
assert!(weak_set_has(&ws, &raw mut a));
assert!(weak_set_has(&ws, &raw mut b));
}
#[test]
fn test_weak_set_from_iterable_rejects_null_value() {
let err = weak_set_from_iterable(vec![std::ptr::null_mut()]).unwrap_err();
assert!(matches!(err, StatorError::TypeError(_)));
}
#[test]
fn test_weak_set_members_are_distinct_by_address() {
let mut ws = weak_set_new();
let mut a = HeapObject::new_null();
let mut b = HeapObject::new_null();
let pa = &raw mut a;
let pb = &raw mut b;
weak_set_add(&mut ws, pa).unwrap();
assert!(weak_set_has(&ws, pa));
assert!(!weak_set_has(&ws, pb));
}
#[test]
fn test_weak_set_remove_object_clears_entry() {
let mut ws = weak_set_new();
let mut obj = HeapObject::new_null();
let ptr = &raw mut obj;
weak_set_add(&mut ws, ptr).unwrap();
weak_set_remove_object(&mut ws, ptr);
assert!(!weak_set_has(&ws, ptr));
}
#[test]
fn test_weak_set_remove_object_null_is_noop() {
let mut ws = weak_set_new();
weak_set_remove_object(&mut ws, std::ptr::null_mut());
}
}