1use std::fmt;
6use std::iter::Enumerate;
7use std::rc::Rc;
8use std::vec::IntoIter;
9
10use script_bindings::error::Fallible;
11use script_bindings::script_runtime::CanGc;
12use script_bindings::str::DOMString;
13
14use super::Node;
15use crate::dom::bindings::callback::ExceptionHandling;
16use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
17use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
18use crate::dom::bindings::root::DomRoot;
19
20pub(crate) struct EvaluationCtx {
22 pub(crate) starting_node: DomRoot<Node>,
24 pub(crate) context_node: DomRoot<Node>,
26 pub(crate) predicate_ctx: Option<PredicateCtx>,
28 pub(crate) predicate_nodes: Option<Vec<DomRoot<Node>>>,
30 pub(crate) resolver: Option<Rc<XPathNSResolver>>,
32}
33
34#[derive(Clone, Copy, Debug)]
35pub(crate) struct PredicateCtx {
36 pub(crate) index: usize,
37 pub(crate) size: usize,
38}
39
40impl EvaluationCtx {
41 pub(crate) fn new(context_node: &Node, resolver: Option<Rc<XPathNSResolver>>) -> EvaluationCtx {
43 EvaluationCtx {
44 starting_node: DomRoot::from_ref(context_node),
45 context_node: DomRoot::from_ref(context_node),
46 predicate_ctx: None,
47 predicate_nodes: None,
48 resolver,
49 }
50 }
51
52 pub(crate) fn subcontext_for_node(&self, node: &Node) -> EvaluationCtx {
54 EvaluationCtx {
55 starting_node: self.starting_node.clone(),
56 context_node: DomRoot::from_ref(node),
57 predicate_ctx: self.predicate_ctx,
58 predicate_nodes: self.predicate_nodes.clone(),
59 resolver: self.resolver.clone(),
60 }
61 }
62
63 pub(crate) fn update_predicate_nodes(&self, nodes: Vec<&Node>) -> EvaluationCtx {
64 EvaluationCtx {
65 starting_node: self.starting_node.clone(),
66 context_node: self.context_node.clone(),
67 predicate_ctx: None,
68 predicate_nodes: Some(nodes.into_iter().map(DomRoot::from_ref).collect()),
69 resolver: self.resolver.clone(),
70 }
71 }
72
73 pub(crate) fn subcontext_iter_for_nodes(&self) -> EvalNodesetIter<'_> {
74 let size = self.predicate_nodes.as_ref().map_or(0, |v| v.len());
75 EvalNodesetIter {
76 ctx: self,
77 nodes_iter: self
78 .predicate_nodes
79 .as_ref()
80 .map_or_else(|| Vec::new().into_iter(), |v| v.clone().into_iter())
81 .enumerate(),
82 size,
83 }
84 }
85
86 pub(crate) fn resolve_namespace(
88 &self,
89 prefix: Option<&str>,
90 can_gc: CanGc,
91 ) -> Fallible<Option<DOMString>> {
92 if let Some(resolver) = self.resolver.as_ref() {
94 if let Some(namespace_uri) = resolver.LookupNamespaceURI__(
95 prefix.map(DOMString::from),
96 ExceptionHandling::Rethrow,
97 can_gc,
98 )? {
99 return Ok(Some(namespace_uri));
100 }
101 }
102
103 Ok(self
105 .context_node
106 .LookupNamespaceURI(prefix.map(DOMString::from)))
107 }
108}
109
110pub(crate) struct EvalNodesetIter<'a> {
113 ctx: &'a EvaluationCtx,
114 nodes_iter: Enumerate<IntoIter<DomRoot<Node>>>,
115 size: usize,
116}
117
118impl Iterator for EvalNodesetIter<'_> {
119 type Item = EvaluationCtx;
120
121 fn next(&mut self) -> Option<EvaluationCtx> {
122 self.nodes_iter.next().map(|(idx, node)| EvaluationCtx {
123 starting_node: self.ctx.starting_node.clone(),
124 context_node: node.clone(),
125 predicate_nodes: self.ctx.predicate_nodes.clone(),
126 predicate_ctx: Some(PredicateCtx {
127 index: idx + 1,
128 size: self.size,
129 }),
130 resolver: self.ctx.resolver.clone(),
131 })
132 }
133}
134
135impl fmt::Debug for EvaluationCtx {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 f.debug_struct("EvaluationCtx")
138 .field("starting_node", &self.starting_node)
139 .field("context_node", &self.context_node)
140 .field("predicate_ctx", &self.predicate_ctx)
141 .field("predicate_nodes", &self.predicate_nodes)
142 .field("resolver", &"<callback function>")
143 .finish()
144 }
145}