1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! Wrapped representation of a DOM Element. See [node](../index.html) module for distinction from
//! raw representation.

use downcast_rs::DowncastSync;
use paste::paste;

use std::convert::TryFrom;
use std::result::Result;
use std::sync::{Arc, Weak};

use element::Element;

use crate::error::DomError;
use crate::node::raw::{self as raw_node, element as raw_element, AnyRawNode};
use crate::sandbox::Sandbox;

mod element;

/// A base trait for all wrapped node types
pub trait AnyWrappedNode {
    /// Gives a weak reference to the sandbox the node was created in.
    fn get_context(&self) -> Weak<Sandbox>;
}

#[macro_export]
/// Provides the trait implementations for all wrapped node types
macro_rules! node_base {
    ($ty: ty, impl { $($rest:tt)* }) => {
        impl AnyWrappedNode for $ty {
            fn get_context(&self) -> Weak<$crate::sandbox::Sandbox> {
                self.0.clone().get_context()
            }
        }

        impl $ty {
            $($rest)*
        }
    }
}

macro_rules! impl_wrapped_nodes {
    ($((
        $ty: ty,
        $raw_ty: ty,
        $blurb: literal,
        $link: literal,
        impl { $( $rest:tt )* }
        $(, $postlude: literal)?
    ))*) => {
        $(
            paste! {
                #[doc =
                    "A wrapped ["
                    $blurb
                    "](https://developer.mozilla.org/en-US/docs/Web/API/"
                    $link
                    ") node"
                    $(" " $postlude)?
                ]
                pub struct $ty(pub Arc<$raw_ty>);

                node_base!($ty, impl {
                    pub(crate) fn new(context: Weak<$crate::sandbox::Sandbox>) -> Self {
                        Self(<$raw_ty>::new(context))
                    }
                    $($rest)*
                });

                impl From<$ty> for Node {
                    fn from(source: $ty) -> Node {
                        Node(source.0)
                    }
                }

                impl TryFrom<Node> for $ty {
                    type Error = Node;

                    fn try_from(elem: Node) -> Result<$ty, Node> {
                        elem.0
                            .downcast_arc::<$raw_ty>()
                            .map($ty)
                            .map_err(Node)
                    }
                }
            }
        )*
    }
}

impl_wrapped_nodes! {
    (
        TextNode,
        raw_node::TextNode,
        "text",
        "Text",
        impl {}
    )
    (
        Document,
        raw_node::Document,
        "document",
        "Document",
        impl {
            fn query_selector(&self, selectors: &str) -> Result<Option<Element>, DomError> {
                let sandbox = self.get_context().upgrade().ok_or_else(|| DomError::SandboxDropped)?;
                match selectors {
                    //"html" => {
                    //    Ok(Some(self.document_element.into()))
                    //},
                    //"body" => Ok(Some((&*self.body).into())),
                    _ => Err(DomError::InvalidQuerySelector),
                }
            }
        }
    )
}

/// Any wrapped Node
pub struct Node(pub Arc<dyn AnyRawNode>);
node_base!(Node, impl {});