rdom 0.2.0

A Rust-based simulated DOM (browser-independent replacement for web_sys)
Documentation
//! Concrete (as opposed to abstract) types of nodes. Each node type is represented in this module.

use crate::internal_prelude::*;

use super::contents::{
    AttributeNodeStorage, CDataSectionNodeStorage, CommentNodeStorage, DocumentFragmentNodeStorage,
    DocumentNodeStorage, DocumentTypeNodeStorage, ProcessingInstructionNodeStorage,
    TextNodeStorage,
};
use super::{
    AnyNodeStorage, Buildable, NodeCommon, NodeContentsArc, NodeContentsWeak, NodeGraphStorage,
};
use crate::node_list::NodeList;
use std::convert::TryFrom;
crate::use_behaviors!(sandbox_member);

#[derive(Clone)]
/// A strongly-typed handle to a node with a strong reference.
/// `S` may be the underlying storage
/// type of any node.
pub struct ConcreteNodeArc<S: AnyNodeStorage> {
    pub(crate) contents: Arc<S>,
    pub(crate) common: Arc<NodeCommon>,
}

#[derive(Clone)]
/// A strongly-typed handle to a node with a weak reference.
/// `S` may be the underlying storage
/// type of any node.
pub struct ConcreteNodeWeak<S: AnyNodeStorage> {
    pub(crate) contents: Weak<S>,
    pub(crate) common: Weak<NodeCommon>,
}

macro_rules! impl_concrete {
    ($($ti:expr => $name:ident),*) => {
        paste::paste! {
            $(
                impl AnyNodeStorage for [<$name NodeStorage>] {}

                #[doc = "Convenience alias for a strong reference to a(n) " $name " node"]
                pub type [<$name NodeArc>] = ConcreteNodeArc<[<$name NodeStorage>]>;

                #[doc = "Convenience alias for a weak reference to a(n) " $name " node"]
                pub type [<$name NodeWeak>] = ConcreteNodeWeak<[<$name NodeStorage>]>;

                impl ConcreteNodeArc<[<$name NodeStorage>]> {
                    pub(crate) fn new(context: Weak<Sandbox>, contents: Arc<[<$name NodeStorage>]>) ->
                    ConcreteNodeArc<[<$name NodeStorage>]> {
                        let common = Arc::new_cyclic(|construction_weak| NodeCommon {
                            node_graph: NodeGraphStorage::new(AnyNodeWeak {
                                contents: (&contents).into(),
                                common: construction_weak.clone(),
                            }),
                            context,
                        });

                        ConcreteNodeArc { contents, common }
                    }
                }

                impl Buildable for ConcreteNodeArc<[<$name NodeStorage>]> {
                    type Storage = [<$name NodeStorage>];
                }

                impl SandboxMemberBehavior for ConcreteNodeArc<[<$name NodeStorage>]> {
                    fn get_context(&self) -> Weak<Sandbox> {
                        self.common.context.clone()
                    }
                }

                impl TryFrom<AnyNodeArc> for ConcreteNodeArc<[<$name NodeStorage>]> {
                    type Error = AnyNodeArc;

                    fn try_from(value: AnyNodeArc) -> Result<Self, Self::Error> {
                        match value.contents {
                            NodeContentsArc::$name(element) => {
                                return Ok(ConcreteNodeArc {
                                    contents: element,
                                    common: value.common,
                                })
                            },
                            _ => Err(value),
                        }
                    }
                }

                impl TryFrom<AnyNodeWeak> for ConcreteNodeWeak<[<$name NodeStorage>]> {
                    type Error = AnyNodeWeak;

                    fn try_from(value: AnyNodeWeak) -> Result<Self, Self::Error> {
                        match value.contents {
                            NodeContentsWeak::$name(element) => {
                                return Ok(ConcreteNodeWeak {
                                    contents: element,
                                    common: value.common,
                                })
                            },
                            _ => Err(value),
                        }
                    }
                }

                impl From<ConcreteNodeArc<[<$name NodeStorage>]>> for AnyNodeArc {
                    fn from(concrete: ConcreteNodeArc<[<$name NodeStorage>]>) -> Self {
                        AnyNodeArc {
                            common: concrete.common,
                            contents: NodeContentsArc::$name(concrete.contents),
                        }
                    }
                }

                impl From<ConcreteNodeWeak<[<$name NodeStorage>]>> for AnyNodeWeak {
                    fn from(concrete: ConcreteNodeWeak<[<$name NodeStorage>]>) -> Self {
                        AnyNodeWeak {
                            common: concrete.common,
                            contents: NodeContentsWeak::$name(concrete.contents),
                        }
                    }
                }

                impl NodeBehavior for ConcreteNodeArc<[<$name NodeStorage>]> {
                    fn first_child(&self) -> Option<AnyNodeArc> {
                        self.common.node_graph.first_child()
                    }

                    fn last_child(&self) -> Option<AnyNodeArc> {
                        self.common.node_graph.last_child()
                    }

                    fn append_child(&self, other: AnyNodeArc) {
                        self.common.node_graph.append_child(other)
                    }

                    fn child_nodes(&self) -> Arc<NodeList> {
                        self.common.node_graph.child_nodes()
                    }

                    fn clone_node(&self) -> AnyNodeArc {
                        AnyNodeArc::from(self.clone()).clone_node()
                    }

                    fn get_node_type(&self) -> isize {
                        $ti
                    }
                }
            )*
        }
    }
}

impl_concrete! {
    1 => Element,
    2 => Attribute,
    3 => Text,
    4 => CDataSection,
    5 => ProcessingInstruction,
    6 => Comment,
    7 => Document,
    8 => DocumentType,
    9 => DocumentFragment
}

impl DocumentNodeArc {
    /// Creates a new text node with the given text contents
    pub fn create_text_node(&self, text: String) -> TextNodeArc {
        TextNodeArc::new(self.get_context(), Arc::new(TextNodeStorage { data: text }))
    }
}