use crate::{
Result,
db::{Entry, Group, Times, iconid::IconId},
};
use std::collections::VecDeque;
use uuid::Uuid;
pub type NodePtr = std::rc::Rc<std::cell::RefCell<dyn Node>>;
#[derive(Debug, Clone)]
pub struct SerializableNodePtr {
node_ptr: NodePtr,
}
impl PartialEq for SerializableNodePtr {
fn eq(&self, other: &Self) -> bool {
node_is_equals_to(&self.node_ptr, &other.node_ptr)
}
}
impl Eq for SerializableNodePtr {}
#[cfg(feature = "serialization")]
impl serde::ser::Serialize for SerializableNodePtr {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
self.node_ptr.borrow().serialize(serializer)
}
}
impl From<NodePtr> for SerializableNodePtr {
fn from(node: NodePtr) -> Self {
SerializableNodePtr { node_ptr: node }
}
}
impl From<&NodePtr> for SerializableNodePtr {
fn from(node: &NodePtr) -> Self {
SerializableNodePtr { node_ptr: node.clone() }
}
}
impl From<SerializableNodePtr> for NodePtr {
fn from(serializable: SerializableNodePtr) -> Self {
serializable.node_ptr
}
}
impl From<&SerializableNodePtr> for NodePtr {
fn from(serializable: &SerializableNodePtr) -> Self {
serializable.node_ptr.clone()
}
}
impl AsRef<NodePtr> for SerializableNodePtr {
fn as_ref(&self) -> &NodePtr {
&self.node_ptr
}
}
impl AsMut<NodePtr> for SerializableNodePtr {
fn as_mut(&mut self) -> &mut NodePtr {
&mut self.node_ptr
}
}
impl std::ops::Deref for SerializableNodePtr {
type Target = NodePtr;
fn deref(&self) -> &Self::Target {
&self.node_ptr
}
}
impl std::ops::DerefMut for SerializableNodePtr {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.node_ptr
}
}
pub fn rc_refcell_node<T: Node>(e: T) -> NodePtr {
std::rc::Rc::new(std::cell::RefCell::new(e)) as NodePtr
}
pub fn with_node<T, F, R>(node: &NodePtr, f: F) -> Option<R>
where
T: 'static,
F: FnOnce(&T) -> R,
{
node.borrow().downcast_ref::<T>().map(f)
}
pub fn with_node_mut<T, F, R>(node: &NodePtr, f: F) -> Option<R>
where
T: 'static,
F: FnOnce(&mut T) -> R,
{
node.borrow_mut().downcast_mut::<T>().map(f)
}
pub fn node_is_entry(entry: &NodePtr) -> bool {
with_node::<Entry, _, _>(entry, |_| true).unwrap_or(false)
}
pub fn node_is_group(group: &NodePtr) -> bool {
with_node::<Group, _, _>(group, |_| true).unwrap_or(false)
}
pub fn group_get_children(group: &NodePtr) -> Option<Vec<NodePtr>> {
with_node::<Group, _, _>(group, |g| g.get_children())
}
pub fn group_add_child(parent: &NodePtr, child: NodePtr, index: usize) -> Result<()> {
with_node_mut::<Group, _, _>(parent, |parent| {
parent.add_child(child, index);
Ok::<_, crate::Error>(())
})
.unwrap_or(Err("parent is not a group".into()))?;
Ok(())
}
pub fn group_remove_node_by_uuid(root: &NodePtr, uuid: Uuid) -> crate::Result<NodePtr> {
let root_uuid = root.borrow().get_uuid();
if root_uuid == uuid {
return Err("Cannot remove root node".into());
}
let node = search_node_by_uuid(root, uuid).ok_or("Node not found")?;
let parent_uuid = node.borrow().get_parent().ok_or("Node has no parent")?;
let err = format!("Parent \"{parent_uuid}\" not found");
let parent = search_node_by_uuid_with_specific_type::<Group>(root, parent_uuid).ok_or(err)?;
with_node_mut::<Group, _, _>(&parent, |parent| {
parent.children.retain(|c| c.borrow().get_uuid() != uuid);
Ok::<_, crate::Error>(())
})
.unwrap_or(Err(crate::Error::from("Not a group")))?;
Ok(node)
}
pub fn node_is_equals_to(node: &NodePtr, other: &NodePtr) -> bool {
if with_node::<Entry, _, _>(node, |e1| with_node::<Entry, _, _>(other, |e2| e1 == e2).unwrap_or(false)).unwrap_or(false) {
return true;
}
with_node::<Group, _, _>(node, |g1| with_node::<Group, _, _>(other, |g2| g1 == g2).unwrap_or(false)).unwrap_or(false)
}
pub fn search_node_by_uuid(root: &NodePtr, uuid: Uuid) -> Option<NodePtr> {
NodeIterator::new(root).find(|n| n.borrow().get_uuid() == uuid)
}
pub fn search_node_by_uuid_with_specific_type<'a, T>(root: &'a NodePtr, uuid: Uuid) -> Option<NodePtr>
where
T: 'a + 'static,
{
NodeIterator::new(root)
.filter(|n| with_node::<T, _, _>(n, |_| true).is_some())
.find(|n| n.borrow().get_uuid() == uuid)
}
#[cfg(feature = "serialization")]
pub trait Node: std::any::Any + std::fmt::Debug + erased_serde::Serialize {
fn duplicate(&self) -> NodePtr;
fn get_uuid(&self) -> Uuid;
fn set_uuid(&mut self, uuid: Uuid);
fn get_title(&self) -> Option<&str>;
fn set_title(&mut self, title: Option<&str>);
fn get_notes(&self) -> Option<&str>;
fn set_notes(&mut self, notes: Option<&str>);
fn get_icon_id(&self) -> Option<IconId>;
fn set_icon_id(&mut self, icon_id: Option<IconId>);
fn get_custom_icon_uuid(&self) -> Option<Uuid>;
fn get_times(&self) -> &Times;
fn get_times_mut(&mut self) -> &mut Times;
fn get_parent(&self) -> Option<Uuid>;
fn set_parent(&mut self, parent: Option<Uuid>);
}
#[cfg(feature = "serialization")]
erased_serde::serialize_trait_object!(Node);
#[cfg(not(feature = "serialization"))]
pub trait Node: std::any::Any + std::fmt::Debug {
fn duplicate(&self) -> NodePtr;
fn get_uuid(&self) -> Uuid;
fn set_uuid(&mut self, uuid: Uuid);
fn get_title(&self) -> Option<&str>;
fn set_title(&mut self, title: Option<&str>);
fn get_notes(&self) -> Option<&str>;
fn set_notes(&mut self, notes: Option<&str>);
fn get_icon_id(&self) -> Option<IconId>;
fn set_icon_id(&mut self, icon_id: Option<IconId>);
fn get_custom_icon_uuid(&self) -> Option<Uuid>;
fn get_times(&self) -> &Times;
fn get_times_mut(&mut self) -> &mut Times;
fn get_parent(&self) -> Option<Uuid>;
fn set_parent(&mut self, parent: Option<Uuid>);
}
impl dyn Node {
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
(self as &dyn std::any::Any).downcast_ref()
}
}
impl dyn Node {
pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
(self as &mut dyn std::any::Any).downcast_mut()
}
}
pub struct NodeIterator {
queue: VecDeque<NodePtr>,
}
impl NodeIterator {
pub fn new(root: &NodePtr) -> Self {
let mut queue = VecDeque::new();
queue.push_back(root.clone());
Self { queue }
}
}
impl Iterator for NodeIterator {
type Item = NodePtr;
fn next(&mut self) -> Option<Self::Item> {
let next = self.queue.pop_front()?;
if let Some(children) = group_get_children(&next) {
self.queue.extend(children);
}
Some(next)
}
}