use std::{collections::{HashMap, VecDeque},
fmt::Debug,
sync::{atomic::AtomicUsize, Arc, RwLock}};
use super::{arena_types::HasId,
ArenaMap,
FilterFn,
NodeRef,
ResultUidList,
WeakNodeRef};
use crate::utils::{call_if_some,
unwrap_arc_read_lock_and_call,
unwrap_arc_write_lock_and_call,
with_mut};
#[derive(Debug)]
pub struct Node<T>
where
T: Debug + Clone + Send + Sync,
{
pub id: usize,
pub parent_id: Option<usize>,
pub children_ids: VecDeque<usize>,
pub payload: T,
}
impl<T> HasId for Node<T>
where
T: Debug + Clone + Send + Sync,
{
type IdType = usize;
fn get_id(&self) -> usize { self.id.get_id() }
}
#[derive(Debug)]
pub struct Arena<T>
where
T: Debug + Clone + Send + Sync,
{
map: RwLock<ArenaMap<T>>,
atomic_counter: AtomicUsize,
}
impl<T> Arena<T>
where
T: Debug + Clone + Send + Sync,
{
#[allow(clippy::unwrap_in_result)]
pub fn filter_all_nodes_by(&self, filter_fn: &FilterFn<T>) -> ResultUidList {
if let Ok(map ) = self.map.read() {
let filtered_map = map
.iter()
.filter(|(id, node_ref)| {
filter_fn(**id, node_ref.read().unwrap().payload.clone())
})
.map(|(id, _node_ref)| *id)
.collect::<VecDeque<usize>>();
match filtered_map.len() {
0 => None,
_ => Some(filtered_map),
}
} else {
None
}
}
pub fn get_children_of(&self, node_id: usize) -> ResultUidList {
if !self.node_exists(node_id) {
return None;
}
let node_to_lookup = self.get_node_arc(node_id)?;
let result = if let Ok(node_to_lookup ) =
node_to_lookup.read()
{
if node_to_lookup.children_ids.is_empty() {
return None;
}
Some(node_to_lookup.children_ids.clone())
} else {
None
};
result
}
pub fn get_parent_of(&self, node_id: usize) -> Option<usize> {
if !self.node_exists(node_id) {
return None;
}
let node_to_lookup = self.get_node_arc(node_id)?;
let result = if let Ok(node_to_lookup ) =
node_to_lookup.read()
{
node_to_lookup.parent_id
} else {
None
};
result
}
pub fn node_exists(&self, node_id: usize) -> bool {
self.map.read().unwrap().contains_key(&node_id.get_id())
}
pub fn has_parent(&self, node_id: usize) -> bool {
if self.node_exists(node_id) {
let parent_id_opt = self.get_parent_of(node_id);
if let Some(parent_id) = parent_id_opt {
return self.node_exists(parent_id);
}
}
false
}
pub fn delete_node(&self, node_id: usize) -> ResultUidList {
if !self.node_exists(node_id) {
return None;
}
let deletion_list = self.tree_walk_dfs(node_id)?;
let remove_node_id_from_parent = |parent_id: usize| {
let parent_node_arc_opt = self.get_node_arc(parent_id);
if let Some(parent_node_arc) = parent_node_arc_opt {
if let Ok(mut parent_node ) =
parent_node_arc.write()
{
parent_node
.children_ids
.retain(|child_id| *child_id != node_id);
}
}
};
if self.has_parent(node_id) {
if let Some(parent_id) = self.get_parent_of(node_id) {
remove_node_id_from_parent(parent_id);
}
}
if let Ok(mut map ) = self.map.write() {
for node_id in &deletion_list {
map.remove(node_id);
}
}
deletion_list.into()
}
pub fn tree_walk_dfs(&self, node_id: usize) -> ResultUidList {
if !self.node_exists(node_id) {
return None;
}
let mut stack: VecDeque<usize> = VecDeque::from([node_id.get_id()]);
let mut it: VecDeque<usize> = VecDeque::new();
while let Some(node_id) = stack.pop_back() {
let node_ref = self.get_node_arc(node_id)?;
unwrap_arc_read_lock_and_call(&node_ref, &mut |node| {
it.push_back(node.get_id());
for child_id in node.children_ids.iter().rev() {
stack.push_back(*child_id);
}
});
}
match it.len() {
0 => None,
_ => Some(it),
}
}
pub fn tree_walk_bfs(&self, node_id: usize) -> ResultUidList {
if !self.node_exists(node_id) {
return None;
}
let mut queue: VecDeque<usize> = VecDeque::from([node_id.get_id()]);
let mut it: VecDeque<usize> = VecDeque::new();
while let Some(node_id) = queue.pop_front() {
let node_ref = self.get_node_arc(node_id)?;
unwrap_arc_read_lock_and_call(&node_ref, &mut |node| {
it.push_back(node.get_id());
for child_id in node.children_ids.iter() {
queue.push_back(*child_id);
}
});
}
match it.len() {
0 => None,
_ => Some(it),
}
}
pub fn get_node_arc_weak(&self, node_id: usize) -> Option<WeakNodeRef<T>> {
if !self.node_exists(node_id) {
return None;
}
if let Ok(map) = self.map.read() {
map.get(&node_id.get_id()) .map(Arc::downgrade) } else {
None
}
}
pub fn get_node_arc(&self, node_id: usize) -> Option<NodeRef<T>> {
if !self.node_exists(node_id) {
return None;
}
if let Ok(map) = self.map.read() {
map.get(&node_id.get_id()).cloned() } else {
None
}
}
pub fn add_new_node(&mut self, payload: T, maybe_parent_id: Option<usize>) -> usize {
let parent_id_arg_provided = maybe_parent_id.is_some();
if parent_id_arg_provided {
let parent_id = maybe_parent_id.unwrap();
if !self.node_exists(parent_id) {
panic!("Parent node doesn't exist.");
}
}
let new_node_id = self.generate_uid();
with_mut(&mut self.map.write().unwrap(), &mut |map| {
let value = Arc::new(RwLock::new(Node {
id: new_node_id,
parent_id: if parent_id_arg_provided {
let parent_id = maybe_parent_id.unwrap();
Some(parent_id.get_id())
} else {
None
},
children_ids: VecDeque::new(),
payload: payload.clone(),
}));
map.insert(new_node_id, value);
});
if let Some(parent_id) = maybe_parent_id {
let maybe_parent_node_arc = self.get_node_arc(parent_id);
call_if_some(&maybe_parent_node_arc, &|parent_node_arc| {
unwrap_arc_write_lock_and_call(parent_node_arc, &mut |parent_node| {
parent_node.children_ids.push_back(new_node_id);
});
});
}
new_node_id
}
fn generate_uid(&self) -> usize {
self.atomic_counter
.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
}
pub fn new() -> Self {
Arena {
map: RwLock::new(HashMap::new()),
atomic_counter: AtomicUsize::new(0),
}
}
}
impl<T> Default for Arena<T>
where
T: Debug + Clone + Send + Sync,
{
fn default() -> Self { Self::new() }
}