xrust/transform/
logic.rs

1//! These functions are for features defined in XPath Functions 1.0 and 2.0.
2
3use std::rc::Rc;
4use url::Url;
5
6use crate::item::{Item, Node, Sequence, SequenceTrait};
7use crate::transform::context::{Context, StaticContext};
8use crate::transform::Transform;
9use crate::value::{Operator, Value};
10use crate::xdmerror::{Error, ErrorKind};
11
12/// Return the disjunction of all of the given functions.
13pub(crate) fn tr_or<
14    N: Node,
15    F: FnMut(&str) -> Result<(), Error>,
16    G: FnMut(&str) -> Result<N, Error>,
17    H: FnMut(&Url) -> Result<String, Error>,
18>(
19    ctxt: &Context<N>,
20    stctxt: &mut StaticContext<N, F, G, H>,
21    v: &Vec<Transform<N>>,
22) -> Result<Sequence<N>, Error> {
23    // Future: Evaluate every operand to check for dynamic errors
24    let mut b = false;
25    let mut i = 0;
26    loop {
27        match v.get(i) {
28            Some(a) => {
29                if ctxt.dispatch(stctxt, a)?.to_bool() {
30                    b = true;
31                    break;
32                }
33                i += 1;
34            }
35            None => break,
36        }
37    }
38    Ok(vec![Item::Value(Rc::new(Value::from(b)))])
39}
40
41/// Return the conjunction of all of the given functions.
42pub(crate) fn tr_and<
43    N: Node,
44    F: FnMut(&str) -> Result<(), Error>,
45    G: FnMut(&str) -> Result<N, Error>,
46    H: FnMut(&Url) -> Result<String, Error>,
47>(
48    ctxt: &Context<N>,
49    stctxt: &mut StaticContext<N, F, G, H>,
50    v: &Vec<Transform<N>>,
51) -> Result<Sequence<N>, Error> {
52    // Future: Evaluate every operand to check for dynamic errors
53    let mut b = true;
54    let mut i = 0;
55    loop {
56        match v.get(i) {
57            Some(a) => {
58                if !ctxt.dispatch(stctxt, a)?.to_bool() {
59                    b = false;
60                    break;
61                }
62                i += 1;
63            }
64            None => break,
65        }
66    }
67    Ok(vec![Item::Value(Rc::new(Value::from(b)))])
68}
69
70/// General comparison of two sequences.
71pub(crate) fn general_comparison<
72    N: Node,
73    F: FnMut(&str) -> Result<(), Error>,
74    G: FnMut(&str) -> Result<N, Error>,
75    H: FnMut(&Url) -> Result<String, Error>,
76>(
77    ctxt: &Context<N>,
78    stctxt: &mut StaticContext<N, F, G, H>,
79    o: &Operator,
80    l: &Transform<N>,
81    r: &Transform<N>,
82) -> Result<Sequence<N>, Error> {
83    let left = ctxt.dispatch(stctxt, l)?;
84    let right = ctxt.dispatch(stctxt, r)?;
85
86    let mut b = false;
87    for i in left {
88        for j in &right {
89            b = i.compare(j, *o).unwrap();
90            if b {
91                break;
92            }
93        }
94        if b {
95            break;
96        }
97    }
98
99    Ok(vec![Item::Value(Rc::new(Value::from(b)))])
100}
101
102/// Value comparison of two singleton sequences.
103pub(crate) fn value_comparison<
104    N: Node,
105    F: FnMut(&str) -> Result<(), Error>,
106    G: FnMut(&str) -> Result<N, Error>,
107    H: FnMut(&Url) -> Result<String, Error>,
108>(
109    ctxt: &Context<N>,
110    stctxt: &mut StaticContext<N, F, G, H>,
111    o: &Operator,
112    l: &Transform<N>,
113    r: &Transform<N>,
114) -> Result<Sequence<N>, Error> {
115    let left = ctxt.dispatch(stctxt, l)?;
116    if left.len() != 1 {
117        return Err(Error::new(
118            ErrorKind::TypeError,
119            String::from("left-hand sequence is not a singleton sequence"),
120        ));
121    }
122    let right = ctxt.dispatch(stctxt, r)?;
123    if right.len() != 1 {
124        return Err(Error::new(
125            ErrorKind::TypeError,
126            String::from("right-hand sequence is not a singleton sequence"),
127        ));
128    }
129
130    Ok(vec![Item::Value(Rc::new(Value::from(
131        left[0].compare(&right[0], *o)?,
132    )))])
133}
134
135/// Each function in the supplied vector is evaluated, and the resulting sequences are combined into a single sequence.
136/// All items must be nodes.
137/// TODO: eliminate duplicates, sort by document order (XPath 3.1 3.4.2).
138pub(crate) fn union<
139    N: Node,
140    F: FnMut(&str) -> Result<(), Error>,
141    G: FnMut(&str) -> Result<N, Error>,
142    H: FnMut(&Url) -> Result<String, Error>,
143>(
144    ctxt: &Context<N>,
145    stctxt: &mut StaticContext<N, F, G, H>,
146    branches: &Vec<Transform<N>>,
147) -> Result<Sequence<N>, Error> {
148    let mut result = vec![];
149    for b in branches {
150        let mut c = ctxt.dispatch(stctxt, b)?;
151        if c.iter().any(|f| !f.is_node()) {
152            return Err(Error::new(
153                ErrorKind::TypeError,
154                "all operands must be nodes",
155            ));
156        }
157        result.append(&mut c)
158    }
159    // TODO: eliminate duplicates and sort into document order
160    Ok(result)
161}