1use std::cmp::Ordering;
8
9use chrono::Local;
10use num_bigint::BigInt;
11use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
12use rust_decimal::Decimal;
13
14use crate::ids::{SimpleTypeKey, TypeKey};
15use crate::namespace::qname::QualifiedName;
16use crate::schema::model::SchemaSet;
17use crate::types::validators::VALIDATOR_REGISTRY;
18use crate::types::value::{
19 DateTimeValue, DateValue, DayTimeDurationValue, DurationValue, TimeValue, TimezoneOffset,
20 XmlAtomicValue, XmlValue, XmlValueKind, YearMonthDurationValue,
21};
22use crate::types::XmlTypeCode;
23use crate::xpath::ast::{BinaryOpKind, UnaryOpKind};
24use crate::xpath::cast::cast_to;
25use crate::xpath::context::XPathContext;
26use crate::xpath::error::XPathError;
27use crate::xpath::iterator::{BufferedNodeIterator, XmlItemRef, XmlNodeIterator};
28use crate::xpath::type_info::type_code_to_name;
29use crate::xpath::DomNavigator;
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32enum NumericClass {
33 Byte,
34 UnsignedByte,
35 Short,
36 UnsignedShort,
37 Int,
38 UnsignedInt,
39 Long,
40 UnsignedLong,
41 Integer,
42 Decimal,
43 Float,
44 Double,
45}
46
47#[derive(Debug, Clone)]
48enum NumericValue {
49 Integer(BigInt),
50 Decimal(Decimal),
51 Float(f32),
52 Double(f64),
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56enum Promote {
57 Left,
58 Right,
59 None,
60}
61
62const XPATH_DECIMAL_DIV_SCALE: u32 = 18;
68
69pub fn eval_unary(op: UnaryOpKind, value: &XmlValue) -> Result<XmlValue, XPathError> {
71 match op {
72 UnaryOpKind::Identity => Ok(value.clone()),
73 UnaryOpKind::Negate => eval_numeric_unary(value),
74 }
75}
76
77pub fn eval_binary(
79 op: BinaryOpKind,
80 left: &XmlValue,
81 right: &XmlValue,
82) -> Result<XmlValue, XPathError> {
83 match op {
84 BinaryOpKind::Add | BinaryOpKind::Sub | BinaryOpKind::Mul | BinaryOpKind::Div => {
85 if let Some(result) = eval_temporal_binary(op, left, right)? {
86 return Ok(result);
87 }
88 eval_numeric_binary(op, left, right)
89 }
90 BinaryOpKind::IDiv | BinaryOpKind::Mod => eval_numeric_binary(op, left, right),
91 BinaryOpKind::GeneralEq | BinaryOpKind::ValueEq => {
92 Ok(XmlValue::boolean(compare_eq(left, right)?))
93 }
94 BinaryOpKind::GeneralNe | BinaryOpKind::ValueNe => {
95 Ok(XmlValue::boolean(!compare_eq(left, right)?))
96 }
97 BinaryOpKind::GeneralGt | BinaryOpKind::ValueGt => {
98 Ok(XmlValue::boolean(compare_gt(left, right)?))
99 }
100 BinaryOpKind::GeneralGe | BinaryOpKind::ValueGe => {
101 Ok(XmlValue::boolean(compare_ge(left, right)?))
102 }
103 BinaryOpKind::GeneralLt | BinaryOpKind::ValueLt => {
104 Ok(XmlValue::boolean(compare_lt(left, right)?))
105 }
106 BinaryOpKind::GeneralLe | BinaryOpKind::ValueLe => {
107 Ok(XmlValue::boolean(compare_le(left, right)?))
108 }
109 BinaryOpKind::And | BinaryOpKind::Or => eval_boolean_logic(op, left, right),
110 BinaryOpKind::Is | BinaryOpKind::Before | BinaryOpKind::After => {
111 Err(unsupported_operator(op, left, right))
112 }
113 BinaryOpKind::Union | BinaryOpKind::Intersect | BinaryOpKind::Except => {
114 Err(unsupported_operator(op, left, right))
115 }
116 }
117}
118
119pub fn eval_range(start: &XmlValue, end: &XmlValue) -> Result<Vec<XmlValue>, XPathError> {
124 let start_class = numeric_class(start.type_code).ok_or_else(|| {
125 XPathError::type_mismatch("xs:integer", type_code_to_name(start.type_code))
126 })?;
127 let end_class = numeric_class(end.type_code)
128 .ok_or_else(|| XPathError::type_mismatch("xs:integer", type_code_to_name(end.type_code)))?;
129
130 if !is_integer_class(start_class) {
131 return Err(XPathError::type_mismatch(
132 "xs:integer",
133 type_code_to_name(start.type_code),
134 ));
135 }
136 if !is_integer_class(end_class) {
137 return Err(XPathError::type_mismatch(
138 "xs:integer",
139 type_code_to_name(end.type_code),
140 ));
141 }
142
143 let start_val = to_integer_value(start)?;
144 let end_val = to_integer_value(end)?;
145
146 if start_val > end_val {
147 return Ok(Vec::new());
148 }
149
150 let mut result = Vec::new();
151 let mut current = start_val;
152 let one = BigInt::from(1);
153 while current <= end_val {
154 result.push(XmlValue {
155 type_code: XmlTypeCode::Integer,
156 schema_type: None,
157 value: XmlValueKind::Atomic(XmlAtomicValue::Integer(current.clone())),
158 });
159 current += &one;
160 }
161
162 Ok(result)
163}
164
165pub fn is_numeric(code: XmlTypeCode) -> bool {
167 code.is_numeric()
168}
169
170fn eval_boolean_logic(
171 op: BinaryOpKind,
172 left: &XmlValue,
173 right: &XmlValue,
174) -> Result<XmlValue, XPathError> {
175 let left_bool = left
176 .as_boolean()
177 .ok_or_else(|| XPathError::internal("Boolean operator requires boolean operands"))?;
178 let right_bool = right
179 .as_boolean()
180 .ok_or_else(|| XPathError::internal("Boolean operator requires boolean operands"))?;
181
182 let result = match op {
183 BinaryOpKind::And => left_bool && right_bool,
184 BinaryOpKind::Or => left_bool || right_bool,
185 _ => return Err(XPathError::internal("Unexpected boolean operator")),
186 };
187
188 Ok(XmlValue::boolean(result))
189}
190
191fn compare_eq(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
192 let left = unwrap_union_value(left);
193 let right = unwrap_union_value(right);
194
195 if let Some(result) = compare_temporal_eq(left, right)? {
196 return Ok(result);
197 }
198
199 if left.type_code.is_list() || right.type_code.is_list() {
200 if left.type_code != right.type_code {
201 return Err(operator_not_defined("op:eq", left, right));
202 }
203 return Ok(list_values_equal(left, right));
204 }
205
206 if left.type_code.is_numeric() && right.type_code.is_numeric() {
207 return numeric_eq(left, right);
208 }
209
210 if left.type_code == XmlTypeCode::Boolean && right.type_code == XmlTypeCode::Boolean {
211 return Ok(left.as_boolean() == right.as_boolean());
212 }
213
214 if is_string_like(left.type_code) && is_string_like(right.type_code) {
215 return Ok(left.to_string_value() == right.to_string_value());
216 }
217
218 if left.type_code == right.type_code {
219 if left.type_code == XmlTypeCode::QName {
221 if let (Some(lq), Some(rq)) = (left.as_qname(), right.as_qname()) {
222 return Ok(lq.namespace_uri == rq.namespace_uri && lq.local_name == rq.local_name);
223 }
224 }
225 return Ok(left.value == right.value);
226 }
227
228 Err(operator_not_defined("op:eq", left, right))
229}
230
231fn compare_gt(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
232 let left = unwrap_union_value(left);
233 let right = unwrap_union_value(right);
234
235 if let Some(result) = compare_temporal_gt(left, right)? {
236 return Ok(result);
237 }
238
239 if left.type_code.is_numeric() && right.type_code.is_numeric() {
240 return numeric_gt(left, right);
241 }
242
243 if left.type_code == XmlTypeCode::Boolean && right.type_code == XmlTypeCode::Boolean {
244 let l = left.as_boolean().unwrap_or(false);
245 let r = right.as_boolean().unwrap_or(false);
246 return Ok(l && !r);
247 }
248
249 if is_string_like(left.type_code) && is_string_like(right.type_code) {
250 let left_value = left.to_string_value();
251 let right_value = right.to_string_value();
252 return Ok(compare_string_values(&left_value, &right_value) == Ordering::Greater);
253 }
254
255 Err(operator_not_defined("op:gt", left, right))
256}
257
258fn compare_ge(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
259 match compare_eq(left, right) {
260 Ok(true) => Ok(true),
261 Ok(false) => compare_gt(left, right),
262 Err(err) if is_operator_not_defined(&err) => compare_gt(left, right),
263 Err(err) => Err(err),
264 }
265}
266
267fn compare_lt(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
268 compare_gt(right, left)
269}
270
271fn compare_le(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
272 match compare_eq(left, right) {
273 Ok(true) => Ok(true),
274 Ok(false) => compare_lt(left, right),
275 Err(err) if is_operator_not_defined(&err) => compare_lt(left, right),
276 Err(err) => Err(err),
277 }
278}
279
280fn eval_temporal_binary(
281 op: BinaryOpKind,
282 left: &XmlValue,
283 right: &XmlValue,
284) -> Result<Option<XmlValue>, XPathError> {
285 if !is_temporal_type(left.type_code) && !is_temporal_type(right.type_code) {
286 return Ok(None);
287 }
288
289 let result = match op {
290 BinaryOpKind::Add => eval_temporal_add(left, right),
291 BinaryOpKind::Sub => eval_temporal_sub(left, right),
292 BinaryOpKind::Mul => eval_temporal_mul(left, right),
293 BinaryOpKind::Div => eval_temporal_div(left, right),
294 _ => return Ok(None),
295 }?;
296
297 Ok(Some(result))
298}
299
300fn compare_temporal_eq(left: &XmlValue, right: &XmlValue) -> Result<Option<bool>, XPathError> {
301 if !is_temporal_type(left.type_code) && !is_temporal_type(right.type_code) {
302 return Ok(None);
303 }
304
305 if is_date_time_code(left.type_code) || is_date_time_code(right.type_code) {
306 if !(is_date_time_code(left.type_code) && is_date_time_code(right.type_code)) {
307 return Err(operator_not_defined("op:eq", left, right));
308 }
309 let left_dt =
310 as_datetime(left).ok_or_else(|| XPathError::internal("Expected dateTime value"))?;
311 let right_dt =
312 as_datetime(right).ok_or_else(|| XPathError::internal("Expected dateTime value"))?;
313 return Ok(Some(compare_datetime_eq(left_dt, right_dt)?));
314 }
315
316 if left.type_code == XmlTypeCode::Date || right.type_code == XmlTypeCode::Date {
317 if left.type_code != XmlTypeCode::Date || right.type_code != XmlTypeCode::Date {
318 return Err(operator_not_defined("op:eq", left, right));
319 }
320 let left_date = as_date(left).ok_or_else(|| XPathError::internal("Expected date value"))?;
321 let right_date =
322 as_date(right).ok_or_else(|| XPathError::internal("Expected date value"))?;
323 return Ok(Some(compare_date_eq(left_date, right_date)?));
324 }
325
326 if left.type_code == XmlTypeCode::Time || right.type_code == XmlTypeCode::Time {
327 if left.type_code != XmlTypeCode::Time || right.type_code != XmlTypeCode::Time {
328 return Err(operator_not_defined("op:eq", left, right));
329 }
330 let left_time = as_time(left).ok_or_else(|| XPathError::internal("Expected time value"))?;
331 let right_time =
332 as_time(right).ok_or_else(|| XPathError::internal("Expected time value"))?;
333 return Ok(Some(compare_time_eq(left_time, right_time)?));
334 }
335
336 if is_duration_code(left.type_code) || is_duration_code(right.type_code) {
337 if !(is_duration_code(left.type_code) && is_duration_code(right.type_code)) {
338 return Err(operator_not_defined("op:eq", left, right));
339 }
340 let left_parts =
341 duration_parts(left)?.ok_or_else(|| XPathError::internal("Expected duration value"))?;
342 let right_parts = duration_parts(right)?
343 .ok_or_else(|| XPathError::internal("Expected duration value"))?;
344 return Ok(Some(left_parts == right_parts));
345 }
346
347 Err(operator_not_defined("op:eq", left, right))
348}
349
350fn compare_temporal_gt(left: &XmlValue, right: &XmlValue) -> Result<Option<bool>, XPathError> {
351 if !is_temporal_type(left.type_code) && !is_temporal_type(right.type_code) {
352 return Ok(None);
353 }
354
355 if is_date_time_code(left.type_code) || is_date_time_code(right.type_code) {
356 if !(is_date_time_code(left.type_code) && is_date_time_code(right.type_code)) {
357 return Err(operator_not_defined("op:gt", left, right));
358 }
359 let left_dt =
360 as_datetime(left).ok_or_else(|| XPathError::internal("Expected dateTime value"))?;
361 let right_dt =
362 as_datetime(right).ok_or_else(|| XPathError::internal("Expected dateTime value"))?;
363 return Ok(Some(compare_datetime_gt(left_dt, right_dt)?));
364 }
365
366 if left.type_code == XmlTypeCode::Date || right.type_code == XmlTypeCode::Date {
367 if left.type_code != XmlTypeCode::Date || right.type_code != XmlTypeCode::Date {
368 return Err(operator_not_defined("op:gt", left, right));
369 }
370 let left_date = as_date(left).ok_or_else(|| XPathError::internal("Expected date value"))?;
371 let right_date =
372 as_date(right).ok_or_else(|| XPathError::internal("Expected date value"))?;
373 return Ok(Some(compare_date_gt(left_date, right_date)?));
374 }
375
376 if left.type_code == XmlTypeCode::Time || right.type_code == XmlTypeCode::Time {
377 if left.type_code != XmlTypeCode::Time || right.type_code != XmlTypeCode::Time {
378 return Err(operator_not_defined("op:gt", left, right));
379 }
380 let left_time = as_time(left).ok_or_else(|| XPathError::internal("Expected time value"))?;
381 let right_time =
382 as_time(right).ok_or_else(|| XPathError::internal("Expected time value"))?;
383 return Ok(Some(compare_time_gt(left_time, right_time)?));
384 }
385
386 if left.type_code == XmlTypeCode::YearMonthDuration
387 || right.type_code == XmlTypeCode::YearMonthDuration
388 {
389 if left.type_code != XmlTypeCode::YearMonthDuration
390 || right.type_code != XmlTypeCode::YearMonthDuration
391 {
392 return Err(operator_not_defined("op:gt", left, right));
393 }
394 let left_duration = as_year_month_duration(left)
395 .ok_or_else(|| XPathError::internal("Expected yearMonthDuration value"))?;
396 let right_duration = as_year_month_duration(right)
397 .ok_or_else(|| XPathError::internal("Expected yearMonthDuration value"))?;
398 return Ok(Some(
399 year_month_total_months(left_duration) > year_month_total_months(right_duration),
400 ));
401 }
402
403 if left.type_code == XmlTypeCode::DayTimeDuration
404 || right.type_code == XmlTypeCode::DayTimeDuration
405 {
406 if left.type_code != XmlTypeCode::DayTimeDuration
407 || right.type_code != XmlTypeCode::DayTimeDuration
408 {
409 return Err(operator_not_defined("op:gt", left, right));
410 }
411 let left_duration = as_day_time_duration(left)
412 .ok_or_else(|| XPathError::internal("Expected dayTimeDuration value"))?;
413 let right_duration = as_day_time_duration(right)
414 .ok_or_else(|| XPathError::internal("Expected dayTimeDuration value"))?;
415 return Ok(Some(
416 day_time_total_seconds(left_duration)? > day_time_total_seconds(right_duration)?,
417 ));
418 }
419
420 Err(operator_not_defined("op:gt", left, right))
421}
422
423fn operator_not_defined(op: &str, left: &XmlValue, right: &XmlValue) -> XPathError {
424 XPathError::BinaryOperatorNotDefined {
425 operator: op.to_string(),
426 left_type: type_code_to_name(left.type_code).to_string(),
427 right_type: type_code_to_name(right.type_code).to_string(),
428 }
429}
430
431fn is_operator_not_defined(err: &XPathError) -> bool {
432 matches!(err, XPathError::BinaryOperatorNotDefined { .. })
433}
434
435fn unwrap_union_value(value: &XmlValue) -> &XmlValue {
436 let mut current = value;
437 loop {
438 match ¤t.value {
439 XmlValueKind::Union(inner) => current = inner,
440 _ => return current,
441 }
442 }
443}
444
445fn list_values_equal(left: &XmlValue, right: &XmlValue) -> bool {
446 match (&left.value, &right.value) {
447 (
448 XmlValueKind::List {
449 item_type: left_item_type,
450 items: left_items,
451 },
452 XmlValueKind::List {
453 item_type: right_item_type,
454 items: right_items,
455 },
456 ) => left_item_type == right_item_type && left_items == right_items,
457 _ => false,
458 }
459}
460
461fn compare_string_values(left: &str, right: &str) -> Ordering {
462 left.cmp(right)
463}
464
465fn eval_temporal_add(left: &XmlValue, right: &XmlValue) -> Result<XmlValue, XPathError> {
466 if let Some(left_dt) = as_datetime(left) {
467 if let Some(duration) = as_year_month_duration(right) {
468 let result = add_datetime_year_month(left_dt, duration)?;
469 return Ok(xml_datetime_value(left.type_code, result));
470 }
471 if let Some(duration) = as_day_time_duration(right) {
472 let result = add_datetime_day_time(left_dt, duration)?;
473 return Ok(xml_datetime_value(left.type_code, result));
474 }
475 return Err(unsupported_operator(BinaryOpKind::Add, left, right));
476 }
477
478 if let Some(left_date) = as_date(left) {
479 if let Some(duration) = as_year_month_duration(right) {
480 let result = add_date_year_month(left_date, duration)?;
481 return Ok(xml_date_value(left.type_code, result));
482 }
483 if let Some(duration) = as_day_time_duration(right) {
484 let result = add_date_day_time(left_date, duration)?;
485 return Ok(xml_date_value(left.type_code, result));
486 }
487 return Err(unsupported_operator(BinaryOpKind::Add, left, right));
488 }
489
490 if let Some(left_time) = as_time(left) {
491 if let Some(duration) = as_day_time_duration(right) {
492 let result = add_time_day_time(left_time, duration)?;
493 return Ok(xml_time_value(left.type_code, result));
494 }
495 return Err(unsupported_operator(BinaryOpKind::Add, left, right));
496 }
497
498 if let Some(left_duration) = as_year_month_duration(left) {
499 if let Some(right_duration) = as_year_month_duration(right) {
500 let total =
501 year_month_total_months(left_duration) + year_month_total_months(right_duration);
502 return Ok(xml_year_month_duration_value(year_month_from_months(
503 total,
504 )?));
505 }
506 if let Some(right_dt) = as_datetime(right) {
507 let result = add_datetime_year_month(right_dt, left_duration)?;
508 return Ok(xml_datetime_value(right.type_code, result));
509 }
510 if let Some(right_date) = as_date(right) {
511 let result = add_date_year_month(right_date, left_duration)?;
512 return Ok(xml_date_value(right.type_code, result));
513 }
514 return Err(unsupported_operator(BinaryOpKind::Add, left, right));
515 }
516
517 if let Some(left_duration) = as_day_time_duration(left) {
518 if let Some(right_duration) = as_day_time_duration(right) {
519 let total =
520 day_time_total_seconds(left_duration)? + day_time_total_seconds(right_duration)?;
521 return Ok(xml_day_time_duration_value(day_time_from_seconds(total)?));
522 }
523 if let Some(right_dt) = as_datetime(right) {
524 let result = add_datetime_day_time(right_dt, left_duration)?;
525 return Ok(xml_datetime_value(right.type_code, result));
526 }
527 if let Some(right_date) = as_date(right) {
528 let result = add_date_day_time(right_date, left_duration)?;
529 return Ok(xml_date_value(right.type_code, result));
530 }
531 if let Some(right_time) = as_time(right) {
532 let result = add_time_day_time(right_time, left_duration)?;
533 return Ok(xml_time_value(right.type_code, result));
534 }
535 return Err(unsupported_operator(BinaryOpKind::Add, left, right));
536 }
537
538 Err(unsupported_operator(BinaryOpKind::Add, left, right))
539}
540
541fn eval_temporal_sub(left: &XmlValue, right: &XmlValue) -> Result<XmlValue, XPathError> {
542 if let Some(left_dt) = as_datetime(left) {
543 if let Some(right_dt) = as_datetime(right) {
544 let result = diff_datetime(left_dt, right_dt)?;
545 return Ok(xml_day_time_duration_value(result));
546 }
547 if let Some(duration) = as_year_month_duration(right) {
548 let result = add_datetime_year_month(left_dt, &negate_year_month_duration(duration))?;
549 return Ok(xml_datetime_value(left.type_code, result));
550 }
551 if let Some(duration) = as_day_time_duration(right) {
552 let result = add_datetime_day_time(left_dt, &negate_day_time_duration(duration))?;
553 return Ok(xml_datetime_value(left.type_code, result));
554 }
555 return Err(unsupported_operator(BinaryOpKind::Sub, left, right));
556 }
557
558 if let Some(left_date) = as_date(left) {
559 if let Some(right_date) = as_date(right) {
560 let result = diff_date(left_date, right_date)?;
561 return Ok(xml_day_time_duration_value(result));
562 }
563 if let Some(duration) = as_year_month_duration(right) {
564 let result = add_date_year_month(left_date, &negate_year_month_duration(duration))?;
565 return Ok(xml_date_value(left.type_code, result));
566 }
567 if let Some(duration) = as_day_time_duration(right) {
568 let result = add_date_day_time(left_date, &negate_day_time_duration(duration))?;
569 return Ok(xml_date_value(left.type_code, result));
570 }
571 return Err(unsupported_operator(BinaryOpKind::Sub, left, right));
572 }
573
574 if let Some(left_time) = as_time(left) {
575 if let Some(right_time) = as_time(right) {
576 let result = diff_time(left_time, right_time)?;
577 return Ok(xml_day_time_duration_value(result));
578 }
579 if let Some(duration) = as_day_time_duration(right) {
580 let result = add_time_day_time(left_time, &negate_day_time_duration(duration))?;
581 return Ok(xml_time_value(left.type_code, result));
582 }
583 return Err(unsupported_operator(BinaryOpKind::Sub, left, right));
584 }
585
586 if let Some(left_duration) = as_year_month_duration(left) {
587 if let Some(right_duration) = as_year_month_duration(right) {
588 let total =
589 year_month_total_months(left_duration) - year_month_total_months(right_duration);
590 return Ok(xml_year_month_duration_value(year_month_from_months(
591 total,
592 )?));
593 }
594 return Err(unsupported_operator(BinaryOpKind::Sub, left, right));
595 }
596
597 if let Some(left_duration) = as_day_time_duration(left) {
598 if let Some(right_duration) = as_day_time_duration(right) {
599 let total =
600 day_time_total_seconds(left_duration)? - day_time_total_seconds(right_duration)?;
601 return Ok(xml_day_time_duration_value(day_time_from_seconds(total)?));
602 }
603 return Err(unsupported_operator(BinaryOpKind::Sub, left, right));
604 }
605
606 Err(unsupported_operator(BinaryOpKind::Sub, left, right))
607}
608
609fn eval_temporal_mul(left: &XmlValue, right: &XmlValue) -> Result<XmlValue, XPathError> {
610 if let Some(duration) = as_year_month_duration(left) {
611 if right.type_code.is_numeric() {
612 let factor = numeric_to_f64(right)?;
613 return Ok(xml_year_month_duration_value(year_month_mul_numeric(
614 duration, factor,
615 )?));
616 }
617 return Err(unsupported_operator(BinaryOpKind::Mul, left, right));
618 }
619
620 if let Some(duration) = as_day_time_duration(left) {
621 if right.type_code.is_numeric() {
622 return Ok(xml_day_time_duration_value(day_time_mul_numeric_value(
623 duration, right,
624 )?));
625 }
626 return Err(unsupported_operator(BinaryOpKind::Mul, left, right));
627 }
628
629 if left.type_code.is_numeric() {
630 if let Some(duration) = as_year_month_duration(right) {
631 let factor = numeric_to_f64(left)?;
632 return Ok(xml_year_month_duration_value(year_month_mul_numeric(
633 duration, factor,
634 )?));
635 }
636 if let Some(duration) = as_day_time_duration(right) {
637 return Ok(xml_day_time_duration_value(day_time_mul_numeric_value(
638 duration, left,
639 )?));
640 }
641 }
642
643 Err(unsupported_operator(BinaryOpKind::Mul, left, right))
644}
645
646fn eval_temporal_div(left: &XmlValue, right: &XmlValue) -> Result<XmlValue, XPathError> {
647 if let Some(duration) = as_year_month_duration(left) {
648 if right.type_code.is_numeric() {
649 let divisor = numeric_to_f64(right)?;
650 return Ok(xml_year_month_duration_value(year_month_div_numeric(
651 duration, divisor,
652 )?));
653 }
654 if let Some(right_duration) = as_year_month_duration(right) {
655 let ratio = year_month_div_duration(duration, right_duration)?;
656 return Ok(XmlValue::decimal(ratio));
657 }
658 return Err(unsupported_operator(BinaryOpKind::Div, left, right));
659 }
660
661 if let Some(duration) = as_day_time_duration(left) {
662 if right.type_code.is_numeric() {
663 return Ok(xml_day_time_duration_value(day_time_div_numeric_value(
664 duration, right,
665 )?));
666 }
667 if let Some(right_duration) = as_day_time_duration(right) {
668 let ratio = day_time_div_duration(duration, right_duration)?;
669 return Ok(XmlValue::decimal(ratio));
670 }
671 return Err(unsupported_operator(BinaryOpKind::Div, left, right));
672 }
673
674 Err(unsupported_operator(BinaryOpKind::Div, left, right))
675}
676
677fn numeric_eq(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
678 let (left_val, right_val, class) = promote_numeric(left, right)?;
679 Ok(match class {
680 NumericClass::Float => {
681 let (l, r) = float_pair(left_val, right_val)?;
682 l == r
683 }
684 NumericClass::Double => {
685 let (l, r) = double_pair(left_val, right_val)?;
686 l == r
687 }
688 NumericClass::Decimal => {
689 let (l, r) = decimal_pair(left_val, right_val)?;
690 l == r
691 }
692 _ => {
693 let (l, r) = integer_pair(left_val, right_val)?;
694 l == r
695 }
696 })
697}
698
699fn numeric_gt(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
700 let (left_val, right_val, class) = promote_numeric(left, right)?;
701 Ok(match class {
702 NumericClass::Float => {
703 let (l, r) = float_pair(left_val, right_val)?;
704 l > r
705 }
706 NumericClass::Double => {
707 let (l, r) = double_pair(left_val, right_val)?;
708 l > r
709 }
710 NumericClass::Decimal => {
711 let (l, r) = decimal_pair(left_val, right_val)?;
712 l > r
713 }
714 _ => {
715 let (l, r) = integer_pair(left_val, right_val)?;
716 l > r
717 }
718 })
719}
720
721fn eval_numeric_unary(value: &XmlValue) -> Result<XmlValue, XPathError> {
722 let promoted;
724 let value = if value.type_code == XmlTypeCode::UntypedAtomic {
725 promoted = cast_untyped_to_double(value)?;
726 &promoted
727 } else {
728 value
729 };
730 let class = numeric_class(value.type_code)
731 .ok_or_else(|| XPathError::internal("Unary operator requires numeric operand"))?;
732
733 let result_type = unary_result_type(class);
734 let value = to_numeric_value(value, class)?;
735
736 let result = match value {
737 NumericValue::Integer(v) => NumericValue::Integer(-v),
738 NumericValue::Decimal(v) => NumericValue::Decimal(-v),
739 NumericValue::Float(v) => NumericValue::Float(-v),
740 NumericValue::Double(v) => NumericValue::Double(-v),
741 };
742
743 Ok(numeric_to_xml_value(result, result_type))
744}
745
746fn eval_numeric_binary(
747 op: BinaryOpKind,
748 left: &XmlValue,
749 right: &XmlValue,
750) -> Result<XmlValue, XPathError> {
751 let (left_val, right_val, class) = promote_numeric(left, right)?;
752 let result_type = binary_result_type(op, class);
753
754 match op {
755 BinaryOpKind::Add => Ok(numeric_add(left_val, right_val, result_type)?),
756 BinaryOpKind::Sub => Ok(numeric_sub(left_val, right_val, result_type)?),
757 BinaryOpKind::Mul => Ok(numeric_mul(left_val, right_val, result_type)?),
758 BinaryOpKind::Div => Ok(numeric_div(left_val, right_val, class, result_type)?),
759 BinaryOpKind::IDiv => Ok(numeric_idiv(left_val, right_val)?),
760 BinaryOpKind::Mod => Ok(numeric_mod(left_val, right_val, result_type)?),
761 _ => Err(XPathError::internal("Unsupported numeric operator")),
762 }
763}
764
765fn numeric_add(
766 left: NumericValue,
767 right: NumericValue,
768 result_type: XmlTypeCode,
769) -> Result<XmlValue, XPathError> {
770 let result = match (left, right) {
771 (NumericValue::Integer(l), NumericValue::Integer(r)) => NumericValue::Integer(l + r),
772 (NumericValue::Decimal(l), NumericValue::Decimal(r)) => NumericValue::Decimal(l + r),
773 (NumericValue::Float(l), NumericValue::Float(r)) => NumericValue::Float(l + r),
774 (NumericValue::Double(l), NumericValue::Double(r)) => NumericValue::Double(l + r),
775 _ => return Err(XPathError::internal("Numeric add type mismatch")),
776 };
777 Ok(numeric_to_xml_value(result, result_type))
778}
779
780fn numeric_sub(
781 left: NumericValue,
782 right: NumericValue,
783 result_type: XmlTypeCode,
784) -> Result<XmlValue, XPathError> {
785 let result = match (left, right) {
786 (NumericValue::Integer(l), NumericValue::Integer(r)) => NumericValue::Integer(l - r),
787 (NumericValue::Decimal(l), NumericValue::Decimal(r)) => NumericValue::Decimal(l - r),
788 (NumericValue::Float(l), NumericValue::Float(r)) => NumericValue::Float(l - r),
789 (NumericValue::Double(l), NumericValue::Double(r)) => NumericValue::Double(l - r),
790 _ => return Err(XPathError::internal("Numeric sub type mismatch")),
791 };
792 Ok(numeric_to_xml_value(result, result_type))
793}
794
795fn numeric_mul(
796 left: NumericValue,
797 right: NumericValue,
798 result_type: XmlTypeCode,
799) -> Result<XmlValue, XPathError> {
800 let result = match (left, right) {
801 (NumericValue::Integer(l), NumericValue::Integer(r)) => NumericValue::Integer(l * r),
802 (NumericValue::Decimal(l), NumericValue::Decimal(r)) => NumericValue::Decimal(l * r),
803 (NumericValue::Float(l), NumericValue::Float(r)) => NumericValue::Float(l * r),
804 (NumericValue::Double(l), NumericValue::Double(r)) => NumericValue::Double(l * r),
805 _ => return Err(XPathError::internal("Numeric mul type mismatch")),
806 };
807 Ok(numeric_to_xml_value(result, result_type))
808}
809
810fn numeric_div(
811 left: NumericValue,
812 right: NumericValue,
813 class: NumericClass,
814 result_type: XmlTypeCode,
815) -> Result<XmlValue, XPathError> {
816 let result = match (left, right) {
817 (NumericValue::Integer(l), NumericValue::Integer(r)) => {
818 if r == BigInt::from(0) {
819 return Err(XPathError::FOAR0001);
820 }
821 let left_dec = decimal_from_bigint(&l)?;
822 let right_dec = decimal_from_bigint(&r)?;
823 NumericValue::Decimal((left_dec / right_dec).round_dp(XPATH_DECIMAL_DIV_SCALE))
824 }
825 (NumericValue::Decimal(l), NumericValue::Decimal(r)) => {
826 if r.is_zero() {
827 return Err(XPathError::FOAR0001);
828 }
829 NumericValue::Decimal((l / r).round_dp(XPATH_DECIMAL_DIV_SCALE))
830 }
831 (NumericValue::Float(l), NumericValue::Float(r)) => NumericValue::Float(l / r),
832 (NumericValue::Double(l), NumericValue::Double(r)) => NumericValue::Double(l / r),
833 _ => return Err(XPathError::internal("Numeric div type mismatch")),
834 };
835
836 let result_type = match class {
837 NumericClass::Decimal | NumericClass::Float | NumericClass::Double => result_type,
838 _ => XmlTypeCode::Decimal,
839 };
840
841 Ok(numeric_to_xml_value(result, result_type))
842}
843
844fn numeric_idiv(left: NumericValue, right: NumericValue) -> Result<XmlValue, XPathError> {
845 let result = match (left, right) {
846 (NumericValue::Integer(l), NumericValue::Integer(r)) => {
847 if r == BigInt::from(0) {
848 return Err(XPathError::FOAR0001);
849 }
850 NumericValue::Integer(l / r)
851 }
852 (NumericValue::Decimal(l), NumericValue::Decimal(r)) => {
853 if r.is_zero() {
854 return Err(XPathError::FOAR0001);
855 }
856 let q = (l / r).trunc();
857 NumericValue::Integer(decimal_to_bigint(&q)?)
858 }
859 (NumericValue::Float(l), NumericValue::Float(r)) => {
860 let q = l / r;
861 if q.is_nan() || q.is_infinite() {
862 return Err(XPathError::FOAR0001);
863 }
864 NumericValue::Integer(BigInt::from(q.trunc() as i64))
865 }
866 (NumericValue::Double(l), NumericValue::Double(r)) => {
867 let q = l / r;
868 if q.is_nan() || q.is_infinite() {
869 return Err(XPathError::FOAR0001);
870 }
871 NumericValue::Integer(BigInt::from(q.trunc() as i64))
872 }
873 _ => return Err(XPathError::internal("Numeric idiv type mismatch")),
874 };
875
876 Ok(numeric_to_xml_value(result, XmlTypeCode::Integer))
877}
878
879fn numeric_mod(
880 left: NumericValue,
881 right: NumericValue,
882 result_type: XmlTypeCode,
883) -> Result<XmlValue, XPathError> {
884 let result = match (left, right) {
885 (NumericValue::Integer(l), NumericValue::Integer(r)) => {
886 if r == BigInt::from(0) {
887 return Err(XPathError::FOAR0001);
888 }
889 NumericValue::Integer(l % r)
890 }
891 (NumericValue::Decimal(l), NumericValue::Decimal(r)) => {
892 if r.is_zero() {
893 return Err(XPathError::FOAR0001);
894 }
895 NumericValue::Decimal(l % r)
896 }
897 (NumericValue::Float(l), NumericValue::Float(r)) => NumericValue::Float(l % r),
898 (NumericValue::Double(l), NumericValue::Double(r)) => NumericValue::Double(l % r),
899 _ => return Err(XPathError::internal("Numeric mod type mismatch")),
900 };
901 Ok(numeric_to_xml_value(result, result_type))
902}
903
904fn cast_untyped_to_double(value: &XmlValue) -> Result<XmlValue, XPathError> {
909 let s = value.to_string_value();
910 let d: f64 = s
911 .trim()
912 .parse()
913 .map_err(|_| XPathError::invalid_cast_value(&s, "xs:double"))?;
914 Ok(XmlValue::double(d))
915}
916
917fn promote_numeric(
918 left: &XmlValue,
919 right: &XmlValue,
920) -> Result<(NumericValue, NumericValue, NumericClass), XPathError> {
921 let left_promoted;
923 let left_ref = if left.type_code == XmlTypeCode::UntypedAtomic {
924 left_promoted = cast_untyped_to_double(left)?;
925 &left_promoted
926 } else {
927 left
928 };
929 let right_promoted;
930 let right_ref = if right.type_code == XmlTypeCode::UntypedAtomic {
931 right_promoted = cast_untyped_to_double(right)?;
932 &right_promoted
933 } else {
934 right
935 };
936
937 let left_class = numeric_class(left_ref.type_code)
938 .ok_or_else(|| XPathError::internal("Left operand not numeric"))?;
939 let right_class = numeric_class(right_ref.type_code)
940 .ok_or_else(|| XPathError::internal("Right operand not numeric"))?;
941
942 let promotion = numeric_promotion(left_class, right_class);
943 let target_class = match promotion {
944 Promote::Left => left_class,
945 Promote::Right => right_class,
946 Promote::None => left_class,
947 };
948
949 let left_val = to_numeric_value(left_ref, target_class)?;
950 let right_val = to_numeric_value(right_ref, target_class)?;
951
952 Ok((left_val, right_val, target_class))
953}
954
955fn numeric_class(code: XmlTypeCode) -> Option<NumericClass> {
956 match code {
957 XmlTypeCode::Byte => Some(NumericClass::Byte),
958 XmlTypeCode::UnsignedByte => Some(NumericClass::UnsignedByte),
959 XmlTypeCode::Short => Some(NumericClass::Short),
960 XmlTypeCode::UnsignedShort => Some(NumericClass::UnsignedShort),
961 XmlTypeCode::Int => Some(NumericClass::Int),
962 XmlTypeCode::UnsignedInt => Some(NumericClass::UnsignedInt),
963 XmlTypeCode::Long => Some(NumericClass::Long),
964 XmlTypeCode::UnsignedLong => Some(NumericClass::UnsignedLong),
965 XmlTypeCode::Integer
966 | XmlTypeCode::NonPositiveInteger
967 | XmlTypeCode::NegativeInteger
968 | XmlTypeCode::NonNegativeInteger
969 | XmlTypeCode::PositiveInteger => Some(NumericClass::Integer),
970 XmlTypeCode::Decimal => Some(NumericClass::Decimal),
971 XmlTypeCode::Float => Some(NumericClass::Float),
972 XmlTypeCode::Double => Some(NumericClass::Double),
973 _ => None,
974 }
975}
976
977fn numeric_precedence(class: NumericClass) -> u8 {
978 match class {
979 NumericClass::Byte => 0,
980 NumericClass::UnsignedByte => 1,
981 NumericClass::Short => 2,
982 NumericClass::UnsignedShort => 3,
983 NumericClass::Int => 4,
984 NumericClass::UnsignedInt => 5,
985 NumericClass::Long => 6,
986 NumericClass::UnsignedLong => 7,
987 NumericClass::Integer => 8,
988 NumericClass::Decimal => 9,
989 NumericClass::Float => 10,
990 NumericClass::Double => 11,
991 }
992}
993
994fn numeric_promotion(left: NumericClass, right: NumericClass) -> Promote {
995 let left_rank = numeric_precedence(left);
996 let right_rank = numeric_precedence(right);
997
998 match left_rank.cmp(&right_rank) {
999 Ordering::Less => Promote::Right,
1000 Ordering::Greater => Promote::Left,
1001 Ordering::Equal => Promote::None,
1002 }
1003}
1004
1005fn binary_result_type(op: BinaryOpKind, class: NumericClass) -> XmlTypeCode {
1006 match op {
1007 BinaryOpKind::Div => div_result_type(class),
1008 BinaryOpKind::IDiv => XmlTypeCode::Integer,
1009 BinaryOpKind::Add | BinaryOpKind::Sub | BinaryOpKind::Mul | BinaryOpKind::Mod => {
1010 arithmetic_result_type(class)
1011 }
1012 _ => arithmetic_result_type(class),
1013 }
1014}
1015
1016fn unary_result_type(class: NumericClass) -> XmlTypeCode {
1017 match class {
1018 NumericClass::Byte
1019 | NumericClass::UnsignedByte
1020 | NumericClass::Short
1021 | NumericClass::UnsignedShort => XmlTypeCode::Int,
1022 NumericClass::UnsignedInt => XmlTypeCode::Long,
1023 NumericClass::UnsignedLong => XmlTypeCode::Integer,
1024 NumericClass::Int => XmlTypeCode::Int,
1025 NumericClass::Long => XmlTypeCode::Long,
1026 NumericClass::Integer => XmlTypeCode::Integer,
1027 NumericClass::Decimal => XmlTypeCode::Decimal,
1028 NumericClass::Float => XmlTypeCode::Float,
1029 NumericClass::Double => XmlTypeCode::Double,
1030 }
1031}
1032
1033fn arithmetic_result_type(class: NumericClass) -> XmlTypeCode {
1034 match class {
1035 NumericClass::Byte
1036 | NumericClass::UnsignedByte
1037 | NumericClass::Short
1038 | NumericClass::UnsignedShort => XmlTypeCode::Int,
1039 NumericClass::UnsignedInt => XmlTypeCode::UnsignedInt,
1040 NumericClass::Int => XmlTypeCode::Int,
1041 NumericClass::Long => XmlTypeCode::Long,
1042 NumericClass::UnsignedLong => XmlTypeCode::Integer,
1043 NumericClass::Integer => XmlTypeCode::Integer,
1044 NumericClass::Decimal => XmlTypeCode::Decimal,
1045 NumericClass::Float => XmlTypeCode::Float,
1046 NumericClass::Double => XmlTypeCode::Double,
1047 }
1048}
1049
1050fn div_result_type(class: NumericClass) -> XmlTypeCode {
1051 match class {
1052 NumericClass::Decimal => XmlTypeCode::Decimal,
1053 NumericClass::Float => XmlTypeCode::Float,
1054 NumericClass::Double => XmlTypeCode::Double,
1055 _ => XmlTypeCode::Decimal,
1056 }
1057}
1058
1059fn is_integer_class(class: NumericClass) -> bool {
1060 matches!(
1061 class,
1062 NumericClass::Byte
1063 | NumericClass::UnsignedByte
1064 | NumericClass::Short
1065 | NumericClass::UnsignedShort
1066 | NumericClass::Int
1067 | NumericClass::UnsignedInt
1068 | NumericClass::Long
1069 | NumericClass::UnsignedLong
1070 | NumericClass::Integer
1071 )
1072}
1073
1074fn to_integer_value(value: &XmlValue) -> Result<BigInt, XPathError> {
1075 match &value.value {
1076 XmlValueKind::Atomic(XmlAtomicValue::Integer(v)) => Ok(v.clone()),
1077 _ => Err(XPathError::internal("Expected integer value")),
1078 }
1079}
1080
1081fn to_numeric_value(value: &XmlValue, class: NumericClass) -> Result<NumericValue, XPathError> {
1082 match class {
1083 NumericClass::Decimal => {
1084 let decimal = value
1085 .as_decimal()
1086 .ok_or_else(|| XPathError::internal("Expected decimal value"))?;
1087 Ok(NumericValue::Decimal(decimal))
1088 }
1089 NumericClass::Float => {
1090 let val = value
1091 .as_double()
1092 .ok_or_else(|| XPathError::internal("Expected numeric value"))?;
1093 Ok(NumericValue::Float(val as f32))
1094 }
1095 NumericClass::Double => {
1096 let val = value
1097 .as_double()
1098 .ok_or_else(|| XPathError::internal("Expected numeric value"))?;
1099 Ok(NumericValue::Double(val))
1100 }
1101 _ => Ok(NumericValue::Integer(to_integer_value(value)?)),
1102 }
1103}
1104
1105fn decimal_from_bigint(value: &BigInt) -> Result<Decimal, XPathError> {
1106 value
1107 .to_string()
1108 .parse::<Decimal>()
1109 .map_err(|_| XPathError::internal("Failed to convert integer to decimal"))
1110}
1111
1112fn decimal_to_bigint(value: &Decimal) -> Result<BigInt, XPathError> {
1113 value
1114 .trunc()
1115 .to_string()
1116 .parse::<BigInt>()
1117 .map_err(|_| XPathError::internal("Failed to convert decimal to integer"))
1118}
1119
1120fn numeric_to_xml_value(value: NumericValue, type_code: XmlTypeCode) -> XmlValue {
1121 let value = match value {
1122 NumericValue::Integer(v) => XmlValueKind::Atomic(XmlAtomicValue::Integer(v)),
1123 NumericValue::Decimal(v) => XmlValueKind::Atomic(XmlAtomicValue::Decimal(v)),
1124 NumericValue::Float(v) => XmlValueKind::Atomic(XmlAtomicValue::Float(v)),
1125 NumericValue::Double(v) => XmlValueKind::Atomic(XmlAtomicValue::Double(v)),
1126 };
1127
1128 XmlValue {
1129 type_code,
1130 schema_type: None,
1131 value,
1132 }
1133}
1134
1135fn integer_pair(left: NumericValue, right: NumericValue) -> Result<(BigInt, BigInt), XPathError> {
1136 match (left, right) {
1137 (NumericValue::Integer(l), NumericValue::Integer(r)) => Ok((l, r)),
1138 _ => Err(XPathError::internal("Expected integer values")),
1139 }
1140}
1141
1142fn decimal_pair(left: NumericValue, right: NumericValue) -> Result<(Decimal, Decimal), XPathError> {
1143 match (left, right) {
1144 (NumericValue::Decimal(l), NumericValue::Decimal(r)) => Ok((l, r)),
1145 _ => Err(XPathError::internal("Expected decimal values")),
1146 }
1147}
1148
1149fn float_pair(left: NumericValue, right: NumericValue) -> Result<(f32, f32), XPathError> {
1150 match (left, right) {
1151 (NumericValue::Float(l), NumericValue::Float(r)) => Ok((l, r)),
1152 _ => Err(XPathError::internal("Expected float values")),
1153 }
1154}
1155
1156fn double_pair(left: NumericValue, right: NumericValue) -> Result<(f64, f64), XPathError> {
1157 match (left, right) {
1158 (NumericValue::Double(l), NumericValue::Double(r)) => Ok((l, r)),
1159 _ => Err(XPathError::internal("Expected double values")),
1160 }
1161}
1162
1163fn xml_datetime_value(type_code: XmlTypeCode, value: DateTimeValue) -> XmlValue {
1164 XmlValue {
1165 type_code,
1166 schema_type: None,
1167 value: XmlValueKind::Atomic(XmlAtomicValue::DateTime(value)),
1168 }
1169}
1170
1171fn xml_date_value(type_code: XmlTypeCode, value: DateValue) -> XmlValue {
1172 XmlValue {
1173 type_code,
1174 schema_type: None,
1175 value: XmlValueKind::Atomic(XmlAtomicValue::Date(value)),
1176 }
1177}
1178
1179fn xml_time_value(type_code: XmlTypeCode, value: TimeValue) -> XmlValue {
1180 XmlValue {
1181 type_code,
1182 schema_type: None,
1183 value: XmlValueKind::Atomic(XmlAtomicValue::Time(value)),
1184 }
1185}
1186
1187fn xml_year_month_duration_value(value: YearMonthDurationValue) -> XmlValue {
1188 XmlValue {
1189 type_code: XmlTypeCode::YearMonthDuration,
1190 schema_type: None,
1191 value: XmlValueKind::Atomic(XmlAtomicValue::YearMonthDuration(value)),
1192 }
1193}
1194
1195fn xml_day_time_duration_value(value: DayTimeDurationValue) -> XmlValue {
1196 XmlValue {
1197 type_code: XmlTypeCode::DayTimeDuration,
1198 schema_type: None,
1199 value: XmlValueKind::Atomic(XmlAtomicValue::DayTimeDuration(value)),
1200 }
1201}
1202
1203fn is_temporal_type(code: XmlTypeCode) -> bool {
1204 matches!(
1205 code,
1206 XmlTypeCode::DateTime
1207 | XmlTypeCode::DateTimeStamp
1208 | XmlTypeCode::Date
1209 | XmlTypeCode::Time
1210 | XmlTypeCode::Duration
1211 | XmlTypeCode::YearMonthDuration
1212 | XmlTypeCode::DayTimeDuration
1213 )
1214}
1215
1216fn is_date_time_code(code: XmlTypeCode) -> bool {
1217 matches!(code, XmlTypeCode::DateTime | XmlTypeCode::DateTimeStamp)
1218}
1219
1220fn is_duration_code(code: XmlTypeCode) -> bool {
1221 matches!(
1222 code,
1223 XmlTypeCode::Duration | XmlTypeCode::YearMonthDuration | XmlTypeCode::DayTimeDuration
1224 )
1225}
1226
1227fn as_datetime(value: &XmlValue) -> Option<&DateTimeValue> {
1228 match &value.value {
1229 XmlValueKind::Atomic(XmlAtomicValue::DateTime(v)) => Some(v),
1230 _ => None,
1231 }
1232}
1233
1234fn as_date(value: &XmlValue) -> Option<&DateValue> {
1235 match &value.value {
1236 XmlValueKind::Atomic(XmlAtomicValue::Date(v)) => Some(v),
1237 _ => None,
1238 }
1239}
1240
1241fn as_time(value: &XmlValue) -> Option<&TimeValue> {
1242 match &value.value {
1243 XmlValueKind::Atomic(XmlAtomicValue::Time(v)) => Some(v),
1244 _ => None,
1245 }
1246}
1247
1248fn as_duration(value: &XmlValue) -> Option<&DurationValue> {
1249 match &value.value {
1250 XmlValueKind::Atomic(XmlAtomicValue::Duration(v)) => Some(v),
1251 _ => None,
1252 }
1253}
1254
1255fn as_year_month_duration(value: &XmlValue) -> Option<&YearMonthDurationValue> {
1256 match &value.value {
1257 XmlValueKind::Atomic(XmlAtomicValue::YearMonthDuration(v)) => Some(v),
1258 _ => None,
1259 }
1260}
1261
1262fn as_day_time_duration(value: &XmlValue) -> Option<&DayTimeDurationValue> {
1263 match &value.value {
1264 XmlValueKind::Atomic(XmlAtomicValue::DayTimeDuration(v)) => Some(v),
1265 _ => None,
1266 }
1267}
1268
1269fn duration_parts(value: &XmlValue) -> Result<Option<(i64, Decimal)>, XPathError> {
1270 if let Some(duration) = as_duration(value) {
1271 let months = duration_total_months(duration);
1272 let seconds = duration_total_seconds(duration)?;
1273 return Ok(Some((months, seconds)));
1274 }
1275 if let Some(duration) = as_year_month_duration(value) {
1276 return Ok(Some((year_month_total_months(duration), Decimal::ZERO)));
1277 }
1278 if let Some(duration) = as_day_time_duration(value) {
1279 let seconds = day_time_total_seconds(duration)?;
1280 return Ok(Some((0, seconds)));
1281 }
1282 Ok(None)
1283}
1284
1285fn numeric_to_f64(value: &XmlValue) -> Result<f64, XPathError> {
1286 let val = value
1287 .as_double()
1288 .ok_or_else(|| XPathError::internal("Expected numeric value"))?;
1289 if !val.is_finite() {
1290 return Err(XPathError::internal("Numeric value is not finite"));
1291 }
1292 Ok(val)
1293}
1294
1295fn numeric_to_decimal(value: &XmlValue) -> Result<Decimal, XPathError> {
1296 match value.type_code {
1297 XmlTypeCode::Float | XmlTypeCode::Double => {
1298 let val = numeric_to_f64(value)?;
1299 Decimal::from_f64(val)
1300 .ok_or_else(|| XPathError::internal("Failed to convert float to decimal"))
1301 }
1302 _ => value
1303 .as_decimal()
1304 .ok_or_else(|| XPathError::internal("Expected decimal value")),
1305 }
1306}
1307
1308fn compare_datetime_eq(left: &DateTimeValue, right: &DateTimeValue) -> Result<bool, XPathError> {
1309 let left_inst = datetime_instant_for_compare(left)?;
1310 let right_inst = datetime_instant_for_compare(right)?;
1311 Ok(left_inst == right_inst)
1312}
1313
1314fn compare_datetime_gt(left: &DateTimeValue, right: &DateTimeValue) -> Result<bool, XPathError> {
1315 let left_inst = datetime_instant_for_compare(left)?;
1316 let right_inst = datetime_instant_for_compare(right)?;
1317 Ok(left_inst > right_inst)
1318}
1319
1320fn compare_date_eq(left: &DateValue, right: &DateValue) -> Result<bool, XPathError> {
1321 let left_inst = date_instant_for_compare(left)?;
1322 let right_inst = date_instant_for_compare(right)?;
1323 Ok(left_inst == right_inst)
1324}
1325
1326fn compare_date_gt(left: &DateValue, right: &DateValue) -> Result<bool, XPathError> {
1327 let left_inst = date_instant_for_compare(left)?;
1328 let right_inst = date_instant_for_compare(right)?;
1329 Ok(left_inst > right_inst)
1330}
1331
1332fn compare_time_eq(left: &TimeValue, right: &TimeValue) -> Result<bool, XPathError> {
1333 let left_inst = time_seconds_for_compare(left)?;
1334 let right_inst = time_seconds_for_compare(right)?;
1335 Ok(left_inst == right_inst)
1336}
1337
1338fn compare_time_gt(left: &TimeValue, right: &TimeValue) -> Result<bool, XPathError> {
1339 let left_inst = time_seconds_for_compare(left)?;
1340 let right_inst = time_seconds_for_compare(right)?;
1341 Ok(left_inst > right_inst)
1342}
1343
1344fn datetime_instant_for_compare(value: &DateTimeValue) -> Result<Decimal, XPathError> {
1345 let instant = datetime_to_instant(value)?;
1346 apply_timezone_offset(instant, value.timezone)
1347}
1348
1349fn date_instant_for_compare(value: &DateValue) -> Result<Decimal, XPathError> {
1350 let instant = date_to_instant(value)?;
1351 apply_timezone_offset(instant, value.timezone)
1352}
1353
1354fn time_seconds_for_compare(value: &TimeValue) -> Result<Decimal, XPathError> {
1355 let seconds = time_to_seconds(value)?;
1356 apply_timezone_offset(seconds, value.timezone)
1357}
1358
1359fn apply_timezone_offset(
1360 instant: Decimal,
1361 timezone: Option<TimezoneOffset>,
1362) -> Result<Decimal, XPathError> {
1363 let offset = timezone.unwrap_or_else(implicit_timezone_offset);
1364 let offset_minutes = decimal_from_i64(offset.0 as i64)?;
1365 Ok(instant - offset_minutes * Decimal::from(60))
1366}
1367
1368fn implicit_timezone_offset() -> TimezoneOffset {
1369 let seconds = Local::now().offset().local_minus_utc();
1370 TimezoneOffset((seconds / 60) as i16)
1371}
1372
1373fn add_datetime_year_month(
1374 value: &DateTimeValue,
1375 duration: &YearMonthDurationValue,
1376) -> Result<DateTimeValue, XPathError> {
1377 let delta = year_month_total_months(duration);
1378 let (year, month, day) = add_months_to_date(value.year, value.month, value.day, delta)?;
1379 Ok(DateTimeValue {
1380 year,
1381 month,
1382 day,
1383 hour: value.hour,
1384 minute: value.minute,
1385 second: value.second,
1386 timezone: value.timezone,
1387 })
1388}
1389
1390fn add_date_year_month(
1391 value: &DateValue,
1392 duration: &YearMonthDurationValue,
1393) -> Result<DateValue, XPathError> {
1394 let delta = year_month_total_months(duration);
1395 let (year, month, day) = add_months_to_date(value.year, value.month, value.day, delta)?;
1396 Ok(DateValue {
1397 year,
1398 month,
1399 day,
1400 timezone: value.timezone,
1401 })
1402}
1403
1404fn add_datetime_day_time(
1405 value: &DateTimeValue,
1406 duration: &DayTimeDurationValue,
1407) -> Result<DateTimeValue, XPathError> {
1408 let instant = datetime_to_instant(value)?;
1409 let delta = day_time_total_seconds(duration)?;
1410 instant_to_datetime(instant + delta, value.timezone)
1411}
1412
1413fn add_date_day_time(
1414 value: &DateValue,
1415 duration: &DayTimeDurationValue,
1416) -> Result<DateValue, XPathError> {
1417 let instant = date_to_instant(value)?;
1418 let delta = day_time_total_seconds(duration)?;
1419 instant_to_date(instant + delta, value.timezone)
1420}
1421
1422fn add_time_day_time(
1423 value: &TimeValue,
1424 duration: &DayTimeDurationValue,
1425) -> Result<TimeValue, XPathError> {
1426 let seconds = time_to_seconds(value)?;
1427 let delta = day_time_total_seconds(duration)?;
1428 let normalized = normalize_seconds_in_day(seconds + delta)?;
1429 let (hour, minute, second) = time_components_from_seconds(normalized)?;
1430 Ok(TimeValue {
1431 hour,
1432 minute,
1433 second,
1434 timezone: value.timezone,
1435 })
1436}
1437
1438fn diff_datetime(
1439 left: &DateTimeValue,
1440 right: &DateTimeValue,
1441) -> Result<DayTimeDurationValue, XPathError> {
1442 let left_inst = datetime_instant_for_compare(left)?;
1443 let right_inst = datetime_instant_for_compare(right)?;
1444 day_time_from_seconds(left_inst - right_inst)
1445}
1446
1447fn diff_date(left: &DateValue, right: &DateValue) -> Result<DayTimeDurationValue, XPathError> {
1448 let left_inst = date_instant_for_compare(left)?;
1449 let right_inst = date_instant_for_compare(right)?;
1450 day_time_from_seconds(left_inst - right_inst)
1451}
1452
1453fn diff_time(left: &TimeValue, right: &TimeValue) -> Result<DayTimeDurationValue, XPathError> {
1454 let left_inst = time_seconds_for_compare(left)?;
1455 let right_inst = time_seconds_for_compare(right)?;
1456 day_time_from_seconds(left_inst - right_inst)
1457}
1458
1459fn year_month_total_months(value: &YearMonthDurationValue) -> i64 {
1460 let total = value.years as i64 * 12 + value.months as i64;
1461 if value.negative {
1462 -total
1463 } else {
1464 total
1465 }
1466}
1467
1468fn duration_total_months(value: &DurationValue) -> i64 {
1469 let total = value.years as i64 * 12 + value.months as i64;
1470 if value.negative {
1471 -total
1472 } else {
1473 total
1474 }
1475}
1476
1477fn day_time_total_seconds(value: &DayTimeDurationValue) -> Result<Decimal, XPathError> {
1478 let days = decimal_from_i64(value.days as i64)?;
1479 let hours = decimal_from_i64(value.hours as i64)?;
1480 let minutes = decimal_from_i64(value.minutes as i64)?;
1481 let total = days * Decimal::from(86_400)
1482 + hours * Decimal::from(3_600)
1483 + minutes * Decimal::from(60)
1484 + value.seconds;
1485 Ok(if value.negative { -total } else { total })
1486}
1487
1488fn duration_total_seconds(value: &DurationValue) -> Result<Decimal, XPathError> {
1489 let days = decimal_from_i64(value.days as i64)?;
1490 let hours = decimal_from_i64(value.hours as i64)?;
1491 let minutes = decimal_from_i64(value.minutes as i64)?;
1492 let total = days * Decimal::from(86_400)
1493 + hours * Decimal::from(3_600)
1494 + minutes * Decimal::from(60)
1495 + value.seconds;
1496 Ok(if value.negative { -total } else { total })
1497}
1498
1499fn negate_year_month_duration(value: &YearMonthDurationValue) -> YearMonthDurationValue {
1500 let negative = if value.years == 0 && value.months == 0 {
1501 false
1502 } else {
1503 !value.negative
1504 };
1505 YearMonthDurationValue {
1506 negative,
1507 years: value.years,
1508 months: value.months,
1509 }
1510}
1511
1512fn negate_day_time_duration(value: &DayTimeDurationValue) -> DayTimeDurationValue {
1513 let negative =
1514 if value.days == 0 && value.hours == 0 && value.minutes == 0 && value.seconds.is_zero() {
1515 false
1516 } else {
1517 !value.negative
1518 };
1519 DayTimeDurationValue {
1520 negative,
1521 days: value.days,
1522 hours: value.hours,
1523 minutes: value.minutes,
1524 seconds: value.seconds,
1525 }
1526}
1527
1528fn year_month_from_months(months: i64) -> Result<YearMonthDurationValue, XPathError> {
1529 let negative = months < 0;
1530 let abs_months = months.abs();
1531 let years = abs_months / 12;
1532 let months = abs_months % 12;
1533 let years = u32::try_from(years)
1534 .map_err(|_| XPathError::internal("yearMonthDuration years out of range"))?;
1535 let months = u32::try_from(months)
1536 .map_err(|_| XPathError::internal("yearMonthDuration months out of range"))?;
1537 Ok(YearMonthDurationValue {
1538 negative,
1539 years,
1540 months,
1541 })
1542}
1543
1544fn day_time_from_seconds(seconds: Decimal) -> Result<DayTimeDurationValue, XPathError> {
1545 let negative = seconds.is_sign_negative();
1546 let abs = if negative { -seconds } else { seconds };
1547 let seconds_per_day = decimal_from_i64(86_400)?;
1548 let days = (abs / seconds_per_day).floor();
1549 let mut remainder = abs - days * seconds_per_day;
1550 let hours = (remainder / Decimal::from(3_600)).floor();
1551 remainder -= hours * Decimal::from(3_600);
1552 let minutes = (remainder / Decimal::from(60)).floor();
1553 let seconds = remainder - minutes * Decimal::from(60);
1554 let days = decimal_to_u32(days, "days")?;
1555 let hours = decimal_to_u32(hours, "hours")?;
1556 let minutes = decimal_to_u32(minutes, "minutes")?;
1557 Ok(DayTimeDurationValue {
1558 negative,
1559 days,
1560 hours,
1561 minutes,
1562 seconds,
1563 })
1564}
1565
1566fn year_month_mul_numeric(
1567 value: &YearMonthDurationValue,
1568 factor: f64,
1569) -> Result<YearMonthDurationValue, XPathError> {
1570 if !factor.is_finite() {
1571 return Err(XPathError::internal("Numeric value is not finite"));
1572 }
1573 let months = year_month_total_months(value) as f64 * factor;
1574 let rounded = (months + 0.5).floor();
1575 year_month_from_months(rounded as i64)
1576}
1577
1578fn year_month_div_numeric(
1579 value: &YearMonthDurationValue,
1580 divisor: f64,
1581) -> Result<YearMonthDurationValue, XPathError> {
1582 if divisor == 0.0 {
1583 return Err(XPathError::internal("Division by zero"));
1584 }
1585 if !divisor.is_finite() {
1586 return Err(XPathError::internal("Numeric value is not finite"));
1587 }
1588 let months = year_month_total_months(value) as f64 / divisor;
1589 let rounded = (months + 0.5).floor();
1590 year_month_from_months(rounded as i64)
1591}
1592
1593fn year_month_div_duration(
1594 left: &YearMonthDurationValue,
1595 right: &YearMonthDurationValue,
1596) -> Result<Decimal, XPathError> {
1597 let left_months = year_month_total_months(left);
1598 let right_months = year_month_total_months(right);
1599 if right_months == 0 {
1600 return Err(XPathError::internal("Division by zero"));
1601 }
1602 let left = decimal_from_i64(left_months)?;
1603 let right = decimal_from_i64(right_months)?;
1604 Ok(left / right)
1605}
1606
1607fn day_time_mul_numeric(
1608 value: &DayTimeDurationValue,
1609 factor: Decimal,
1610) -> Result<DayTimeDurationValue, XPathError> {
1611 let total = day_time_total_seconds(value)? * factor;
1612 day_time_from_seconds(total)
1613}
1614
1615fn day_time_div_numeric(
1616 value: &DayTimeDurationValue,
1617 divisor: Decimal,
1618) -> Result<DayTimeDurationValue, XPathError> {
1619 if divisor.is_zero() {
1620 return Err(XPathError::internal("Division by zero"));
1621 }
1622 let total = day_time_total_seconds(value)? / divisor;
1623 day_time_from_seconds(total)
1624}
1625
1626fn day_time_mul_numeric_value(
1629 value: &DayTimeDurationValue,
1630 factor: &XmlValue,
1631) -> Result<DayTimeDurationValue, XPathError> {
1632 match numeric_to_decimal(factor) {
1633 Ok(d) => day_time_mul_numeric(value, d),
1634 Err(_) => {
1635 let f = numeric_to_f64(factor)?;
1636 let total = day_time_total_seconds(value)?
1637 .to_f64()
1638 .ok_or_else(|| XPathError::internal("Failed to convert seconds to f64"))?;
1639 let result = Decimal::from_f64(total * f).ok_or(XPathError::FODT0002)?;
1640 day_time_from_seconds(result)
1641 }
1642 }
1643}
1644
1645fn day_time_div_numeric_value(
1648 value: &DayTimeDurationValue,
1649 divisor: &XmlValue,
1650) -> Result<DayTimeDurationValue, XPathError> {
1651 match numeric_to_decimal(divisor) {
1652 Ok(d) => day_time_div_numeric(value, d),
1653 Err(_) => {
1654 let f = numeric_to_f64(divisor)?;
1655 if f == 0.0 {
1656 return Err(XPathError::FODT0002);
1657 }
1658 let total = day_time_total_seconds(value)?
1659 .to_f64()
1660 .ok_or_else(|| XPathError::internal("Failed to convert seconds to f64"))?;
1661 let result = Decimal::from_f64(total / f).ok_or(XPathError::FODT0002)?;
1662 day_time_from_seconds(result)
1663 }
1664 }
1665}
1666
1667fn day_time_div_duration(
1668 left: &DayTimeDurationValue,
1669 right: &DayTimeDurationValue,
1670) -> Result<Decimal, XPathError> {
1671 let left_seconds = day_time_total_seconds(left)?;
1672 let right_seconds = day_time_total_seconds(right)?;
1673 if right_seconds.is_zero() {
1674 return Err(XPathError::internal("Division by zero"));
1675 }
1676 Ok(left_seconds / right_seconds)
1677}
1678
1679fn add_months_to_date(
1680 year: i32,
1681 month: u8,
1682 day: u8,
1683 delta_months: i64,
1684) -> Result<(i32, u8, u8), XPathError> {
1685 let astro_year = if year <= 0 {
1688 year as i64 + 1
1689 } else {
1690 year as i64
1691 };
1692 let month_index = month as i64 - 1;
1693 let total = astro_year * 12 + month_index + delta_months;
1694 let new_astro_year = total.div_euclid(12);
1695 let new_month = total.rem_euclid(12) + 1;
1696 let new_year = if new_astro_year <= 0 {
1698 new_astro_year - 1
1699 } else {
1700 new_astro_year
1701 };
1702 let year = i32::try_from(new_year).map_err(|_| XPathError::internal("Year out of range"))?;
1703 let month = u8::try_from(new_month).map_err(|_| XPathError::internal("Month out of range"))?;
1704 let max_day = days_in_month(year, month)?;
1705 let day = day.min(max_day);
1706 Ok((year, month, day))
1707}
1708
1709fn days_in_month(year: i32, month: u8) -> Result<u8, XPathError> {
1710 let days = match month {
1711 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
1712 4 | 6 | 9 | 11 => 30,
1713 2 => {
1714 if is_leap_year(year) {
1715 29
1716 } else {
1717 28
1718 }
1719 }
1720 _ => return Err(XPathError::internal("Invalid month value")),
1721 };
1722 Ok(days)
1723}
1724
1725fn is_leap_year(xsd_year: i32) -> bool {
1726 let year = if xsd_year <= 0 {
1728 xsd_year as i64 + 1
1729 } else {
1730 xsd_year as i64
1731 };
1732 year.rem_euclid(4) == 0 && (year.rem_euclid(100) != 0 || year.rem_euclid(400) == 0)
1733}
1734
1735fn datetime_to_instant(value: &DateTimeValue) -> Result<Decimal, XPathError> {
1736 let astro_year = if value.year <= 0 {
1738 value.year + 1
1739 } else {
1740 value.year
1741 };
1742 let days = days_from_civil(astro_year, value.month, value.day);
1743 let seconds = time_to_seconds_components(value.hour, value.minute, value.second)?;
1744 Ok(decimal_from_i64(days)? * Decimal::from(86_400) + seconds)
1745}
1746
1747fn date_to_instant(value: &DateValue) -> Result<Decimal, XPathError> {
1748 let astro_year = if value.year <= 0 {
1750 value.year + 1
1751 } else {
1752 value.year
1753 };
1754 let days = days_from_civil(astro_year, value.month, value.day);
1755 Ok(decimal_from_i64(days)? * Decimal::from(86_400))
1756}
1757
1758fn time_to_seconds(value: &TimeValue) -> Result<Decimal, XPathError> {
1759 time_to_seconds_components(value.hour, value.minute, value.second)
1760}
1761
1762fn time_to_seconds_components(
1763 hour: u8,
1764 minute: u8,
1765 second: Decimal,
1766) -> Result<Decimal, XPathError> {
1767 let hours = decimal_from_i64(hour as i64)?;
1768 let minutes = decimal_from_i64(minute as i64)?;
1769 Ok(hours * Decimal::from(3_600) + minutes * Decimal::from(60) + second)
1770}
1771
1772fn instant_to_datetime(
1773 instant: Decimal,
1774 timezone: Option<TimezoneOffset>,
1775) -> Result<DateTimeValue, XPathError> {
1776 let day_seconds = decimal_from_i64(86_400)?;
1777 let days = (instant / day_seconds).floor();
1778 let mut seconds_in_day = instant - days * day_seconds;
1779 if seconds_in_day < Decimal::ZERO {
1780 seconds_in_day += day_seconds;
1781 }
1782 let days = decimal_to_i64(days, "day count")?;
1783 let (astro_year, month, day) = civil_from_days(days);
1784 let year = if astro_year <= 0 {
1786 astro_year - 1
1787 } else {
1788 astro_year
1789 };
1790 let (hour, minute, second) = time_components_from_seconds(seconds_in_day)?;
1791 Ok(DateTimeValue {
1792 year,
1793 month,
1794 day,
1795 hour,
1796 minute,
1797 second,
1798 timezone,
1799 })
1800}
1801
1802fn instant_to_date(
1803 instant: Decimal,
1804 timezone: Option<TimezoneOffset>,
1805) -> Result<DateValue, XPathError> {
1806 let day_seconds = decimal_from_i64(86_400)?;
1807 let days = (instant / day_seconds).floor();
1808 let days = decimal_to_i64(days, "day count")?;
1809 let (astro_year, month, day) = civil_from_days(days);
1810 let year = if astro_year <= 0 {
1812 astro_year - 1
1813 } else {
1814 astro_year
1815 };
1816 Ok(DateValue {
1817 year,
1818 month,
1819 day,
1820 timezone,
1821 })
1822}
1823
1824fn normalize_seconds_in_day(seconds: Decimal) -> Result<Decimal, XPathError> {
1825 let day_seconds = decimal_from_i64(86_400)?;
1826 let days = (seconds / day_seconds).floor();
1827 let mut remainder = seconds - days * day_seconds;
1828 if remainder < Decimal::ZERO {
1829 remainder += day_seconds;
1830 }
1831 Ok(remainder)
1832}
1833
1834fn time_components_from_seconds(seconds: Decimal) -> Result<(u8, u8, Decimal), XPathError> {
1835 let hours = (seconds / Decimal::from(3_600)).floor();
1836 let mut remainder = seconds - hours * Decimal::from(3_600);
1837 let minutes = (remainder / Decimal::from(60)).floor();
1838 remainder -= minutes * Decimal::from(60);
1839 let hour = decimal_to_u8(hours, "hours")?;
1840 let minute = decimal_to_u8(minutes, "minutes")?;
1841 Ok((hour, minute, remainder))
1842}
1843
1844fn days_from_civil(year: i32, month: u8, day: u8) -> i64 {
1845 let y = year as i64 - if month <= 2 { 1 } else { 0 };
1846 let m = month as i64;
1847 let d = day as i64;
1848 let era = if y >= 0 { y } else { y - 399 } / 400;
1849 let yoe = y - era * 400;
1850 let mp = m + if m > 2 { -3 } else { 9 };
1851 let doy = (153 * mp + 2) / 5 + d - 1;
1852 let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
1853 era * 146_097 + doe - 719_468
1854}
1855
1856fn civil_from_days(days: i64) -> (i32, u8, u8) {
1857 let z = days + 719_468;
1858 let era = if z >= 0 { z } else { z - 146_096 } / 146_097;
1859 let doe = z - era * 146_097;
1860 let yoe = (doe - doe / 1_460 + doe / 36_524 - doe / 146_096) / 365;
1861 let y = yoe + era * 400;
1862 let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
1863 let mp = (5 * doy + 2) / 153;
1864 let d = doy - (153 * mp + 2) / 5 + 1;
1865 let m = mp + if mp < 10 { 3 } else { -9 };
1866 let year = y + if m <= 2 { 1 } else { 0 };
1867 (year as i32, m as u8, d as u8)
1868}
1869
1870fn decimal_from_i64(value: i64) -> Result<Decimal, XPathError> {
1871 Decimal::from_i64(value)
1872 .ok_or_else(|| XPathError::internal("Failed to convert integer to decimal"))
1873}
1874
1875fn decimal_to_i64(value: Decimal, label: &str) -> Result<i64, XPathError> {
1876 value
1877 .to_i64()
1878 .ok_or_else(|| XPathError::internal(format!("Failed to convert {} to integer", label)))
1879}
1880
1881fn decimal_to_u32(value: Decimal, label: &str) -> Result<u32, XPathError> {
1882 let val = decimal_to_i64(value, label)?;
1883 u32::try_from(val).map_err(|_| XPathError::internal(format!("{} out of range", label)))
1884}
1885
1886fn decimal_to_u8(value: Decimal, label: &str) -> Result<u8, XPathError> {
1887 let val = decimal_to_i64(value, label)?;
1888 u8::try_from(val).map_err(|_| XPathError::internal(format!("{} out of range", label)))
1889}
1890
1891fn is_string_like(code: XmlTypeCode) -> bool {
1892 code.is_string_derived() || matches!(code, XmlTypeCode::AnyUri | XmlTypeCode::UntypedAtomic)
1893}
1894
1895pub fn magnitude_relationship(
1917 left: &XmlValue,
1918 right: &XmlValue,
1919) -> Result<(XmlValue, XmlValue), XPathError> {
1920 let mut left_result = left.clone();
1921 let mut right_result = right.clone();
1922
1923 if left.type_code == XmlTypeCode::UntypedAtomic {
1925 if right.type_code.is_numeric() {
1926 let s = left.to_string_value();
1928 let d: f64 = s
1929 .trim()
1930 .parse()
1931 .map_err(|_| XPathError::invalid_cast_value(&s, "xs:double"))?;
1932 left_result = XmlValue::double(d);
1933 } else if is_string_like(right.type_code) {
1934 left_result = XmlValue::string(left.to_string_value());
1936 }
1937 }
1939
1940 if right.type_code == XmlTypeCode::UntypedAtomic {
1942 if left_result.type_code.is_numeric() {
1943 let s = right.to_string_value();
1945 let d: f64 = s
1946 .trim()
1947 .parse()
1948 .map_err(|_| XPathError::invalid_cast_value(&s, "xs:double"))?;
1949 right_result = XmlValue::double(d);
1950 } else if is_string_like(left_result.type_code) {
1951 right_result = XmlValue::string(right.to_string_value());
1953 }
1954 }
1956
1957 Ok((left_result, right_result))
1958}
1959
1960fn get_primitive_base_type(
1973 schema_set: Option<&SchemaSet>,
1974 schema_type: Option<SimpleTypeKey>,
1975 type_code: XmlTypeCode,
1976) -> XmlTypeCode {
1977 if let (Some(schema_set), Some(type_key)) = (schema_set, schema_type) {
1979 let builtin_types = schema_set.builtin_types();
1980
1981 if let Some(code) = builtin_types.get_type_code(type_key) {
1983 return get_xsd_primitive_type(code);
1984 }
1985
1986 if let Some(type_def) = schema_set.arenas.simple_types.get(type_key) {
1988 let mut current_def = type_def;
1989 loop {
1990 if let Some(TypeKey::Simple(base_key)) = current_def.resolved_base_type {
1991 if let Some(code) = builtin_types.get_type_code(base_key) {
1992 return get_xsd_primitive_type(code);
1993 }
1994 if let Some(base_def) = schema_set.arenas.simple_types.get(base_key) {
1995 current_def = base_def;
1996 continue;
1997 }
1998 }
1999 break;
2000 }
2001 }
2002 }
2003
2004 get_xsd_primitive_type(type_code)
2006}
2007
2008fn get_xsd_primitive_type(code: XmlTypeCode) -> XmlTypeCode {
2013 match code {
2014 XmlTypeCode::String
2016 | XmlTypeCode::Boolean
2017 | XmlTypeCode::Decimal
2018 | XmlTypeCode::Float
2019 | XmlTypeCode::Double
2020 | XmlTypeCode::Duration
2021 | XmlTypeCode::DateTime
2022 | XmlTypeCode::Time
2023 | XmlTypeCode::Date
2024 | XmlTypeCode::GYearMonth
2025 | XmlTypeCode::GYear
2026 | XmlTypeCode::GMonthDay
2027 | XmlTypeCode::GDay
2028 | XmlTypeCode::GMonth
2029 | XmlTypeCode::HexBinary
2030 | XmlTypeCode::Base64Binary
2031 | XmlTypeCode::AnyUri
2032 | XmlTypeCode::QName
2033 | XmlTypeCode::Notation => code,
2034
2035 XmlTypeCode::DayTimeDuration => XmlTypeCode::DayTimeDuration,
2038 XmlTypeCode::YearMonthDuration => XmlTypeCode::YearMonthDuration,
2039
2040 XmlTypeCode::NormalizedString
2042 | XmlTypeCode::Token
2043 | XmlTypeCode::Language
2044 | XmlTypeCode::NmToken
2045 | XmlTypeCode::Name
2046 | XmlTypeCode::NCName
2047 | XmlTypeCode::Id
2048 | XmlTypeCode::IdRef
2049 | XmlTypeCode::Entity => XmlTypeCode::String,
2050
2051 XmlTypeCode::Integer
2053 | XmlTypeCode::NonPositiveInteger
2054 | XmlTypeCode::NegativeInteger
2055 | XmlTypeCode::Long
2056 | XmlTypeCode::Int
2057 | XmlTypeCode::Short
2058 | XmlTypeCode::Byte
2059 | XmlTypeCode::NonNegativeInteger
2060 | XmlTypeCode::UnsignedLong
2061 | XmlTypeCode::UnsignedInt
2062 | XmlTypeCode::UnsignedShort
2063 | XmlTypeCode::UnsignedByte
2064 | XmlTypeCode::PositiveInteger => XmlTypeCode::Decimal,
2065
2066 XmlTypeCode::DateTimeStamp => XmlTypeCode::DateTime,
2068
2069 XmlTypeCode::NmTokens | XmlTypeCode::IdRefs | XmlTypeCode::Entities => XmlTypeCode::String,
2071
2072 _ => XmlTypeCode::String,
2074 }
2075}
2076
2077fn cast_to_primitive(value: &XmlValue, target_type: XmlTypeCode) -> Result<XmlValue, XPathError> {
2082 match cast_to(value, target_type) {
2084 Ok(result) => Ok(result),
2085 Err(_) => {
2086 let string_val = value.to_string_value();
2088 VALIDATOR_REGISTRY
2089 .validate(target_type, &string_val)
2090 .map_err(|e| XPathError::FORG0001 {
2091 value: string_val,
2092 target_type: format!("{:?}: {}", target_type, e),
2093 })
2094 }
2095 }
2096}
2097
2098fn cast_to_primitive_ctx(
2103 context: &XPathContext,
2104 value: &XmlValue,
2105 target_type: XmlTypeCode,
2106) -> Result<XmlValue, XPathError> {
2107 match target_type {
2108 XmlTypeCode::QName | XmlTypeCode::Notation => {
2109 cast_to_qname_with_context(context, value, target_type)
2111 }
2112 _ => cast_to_primitive(value, target_type),
2113 }
2114}
2115
2116pub(crate) fn cast_to_qname_with_context(
2120 context: &XPathContext,
2121 value: &XmlValue,
2122 type_code: XmlTypeCode,
2123) -> Result<XmlValue, XPathError> {
2124 use crate::xpath::functions::qname::parse_lexical_qname;
2125
2126 let lexical = value.to_string_value();
2127
2128 let (prefix, local_name) = parse_lexical_qname(&lexical)?;
2130
2131 let namespace_uri = if let Some(ref pfx) = prefix {
2133 let prefix_id = context
2134 .names
2135 .get(pfx)
2136 .ok_or_else(|| XPathError::undefined_prefix(pfx))?;
2137 let ns_id = context
2138 .namespaces
2139 .resolve_prefix(prefix_id)
2140 .ok_or_else(|| XPathError::undefined_prefix(pfx))?;
2141 Some(ns_id)
2142 } else {
2143 None
2145 };
2146
2147 let local_id = context.names.add(&local_name);
2149 let prefix_id = prefix.as_ref().map(|p| context.names.add(p));
2150 let qn = QualifiedName::new(namespace_uri, local_id, prefix_id);
2151
2152 Ok(XmlValue::new(
2153 type_code,
2154 XmlValueKind::Atomic(XmlAtomicValue::QName(qn)),
2155 ))
2156}
2157
2158pub fn magnitude_relationship_ctx(
2172 context: &XPathContext,
2173 left: &XmlValue,
2174 right: &XmlValue,
2175) -> Result<(XmlValue, XmlValue), XPathError> {
2176 let mut left_result = left.clone();
2177 let mut right_result = right.clone();
2178
2179 if left_result.type_code == XmlTypeCode::UntypedAtomic {
2180 if right.type_code.is_numeric() {
2181 let s = left_result.to_string_value();
2183 let d: f64 = s
2184 .trim()
2185 .parse()
2186 .map_err(|_| XPathError::invalid_cast_value(&s, "xs:double"))?;
2187 left_result = XmlValue::double(d);
2188 } else if is_string_like(right.type_code) {
2189 left_result = XmlValue::string(left_result.to_string_value());
2191 } else if right.type_code != XmlTypeCode::UntypedAtomic {
2192 let primitive_type =
2194 get_primitive_base_type(context.schema_set, right.schema_type, right.type_code);
2195 left_result = cast_to_primitive_ctx(context, &left_result, primitive_type)?;
2196 }
2197 }
2198
2199 if right_result.type_code == XmlTypeCode::UntypedAtomic {
2200 if left_result.type_code.is_numeric() {
2201 let s = right_result.to_string_value();
2203 let d: f64 = s
2204 .trim()
2205 .parse()
2206 .map_err(|_| XPathError::invalid_cast_value(&s, "xs:double"))?;
2207 right_result = XmlValue::double(d);
2208 } else if is_string_like(left_result.type_code) {
2209 right_result = XmlValue::string(right_result.to_string_value());
2211 } else if left_result.type_code != XmlTypeCode::UntypedAtomic {
2212 let primitive_type = get_primitive_base_type(
2214 context.schema_set,
2215 left_result.schema_type,
2216 left_result.type_code,
2217 );
2218 right_result = cast_to_primitive_ctx(context, &right_result, primitive_type)?;
2219 }
2220 }
2221
2222 Ok((left_result, right_result))
2223}
2224
2225fn atomize_item<N: DomNavigator>(item: XmlItemRef<'_, N>) -> Result<Option<XmlValue>, XPathError> {
2226 match item {
2227 XmlItemRef::Atomic(value) => Ok(Some(value.clone())),
2228 XmlItemRef::Node(node) => crate::xpath::atomize::atomize_node(node),
2229 }
2230}
2231
2232pub fn value_eq(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
2237 compare_eq(left, right)
2238}
2239
2240pub fn value_gt(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
2242 compare_gt(left, right)
2243}
2244
2245pub fn value_ge(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
2247 compare_ge(left, right)
2248}
2249
2250pub fn value_lt(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
2252 compare_lt(left, right)
2253}
2254
2255pub fn value_le(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
2257 compare_le(left, right)
2258}
2259
2260pub fn general_eq(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
2269 let (l, r) = magnitude_relationship(left, right)?;
2270 compare_eq(&l, &r)
2271}
2272
2273pub fn general_gt(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
2275 let (l, r) = magnitude_relationship(left, right)?;
2276 compare_gt(&l, &r)
2277}
2278
2279pub fn general_ne(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
2281 general_eq(left, right).map(|eq| !eq)
2282}
2283
2284pub fn general_ge(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
2286 let (l, r) = magnitude_relationship(left, right)?;
2287 compare_ge(&l, &r)
2288}
2289
2290pub fn general_lt(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
2292 let (l, r) = magnitude_relationship(left, right)?;
2293 compare_lt(&l, &r)
2294}
2295
2296pub fn general_le(left: &XmlValue, right: &XmlValue) -> Result<bool, XPathError> {
2298 let (l, r) = magnitude_relationship(left, right)?;
2299 compare_le(&l, &r)
2300}
2301
2302pub fn general_eq_iter<I1, I2>(
2307 context: &XPathContext,
2308 left: &I1,
2309 right: &I2,
2310) -> Result<bool, XPathError>
2311where
2312 I1: XmlNodeIterator,
2313 I2: XmlNodeIterator,
2314{
2315 let right_buf = BufferedNodeIterator::preload(right.clone())?;
2316 let mut left_iter = left.clone();
2317
2318 while left_iter.move_next()? {
2319 let left_item = left_iter
2320 .current()
2321 .ok_or_else(|| XPathError::internal("Iterator current missing"))?;
2322 let left_value = match atomize_item(left_item)? {
2323 Some(v) => v,
2324 None => continue, };
2326 let mut right_iter = right_buf.clone();
2327
2328 while right_iter.move_next()? {
2329 let right_item = right_iter
2330 .current()
2331 .ok_or_else(|| XPathError::internal("Iterator current missing"))?;
2332 let right_value = match atomize_item(right_item)? {
2333 Some(v) => v,
2334 None => continue, };
2336 let (l, r) = magnitude_relationship_ctx(context, &left_value, &right_value)?;
2337
2338 match value_eq(&l, &r) {
2339 Ok(true) => return Ok(true),
2340 Ok(false) => continue,
2341 Err(err) if is_operator_not_defined(&err) => continue,
2342 Err(err) => return Err(err),
2343 }
2344 }
2345 }
2346
2347 Ok(false)
2348}
2349
2350pub fn general_ne_iter<I1, I2>(
2351 context: &XPathContext,
2352 left: &I1,
2353 right: &I2,
2354) -> Result<bool, XPathError>
2355where
2356 I1: XmlNodeIterator,
2357 I2: XmlNodeIterator,
2358{
2359 let right_buf = BufferedNodeIterator::preload(right.clone())?;
2360 let mut left_iter = left.clone();
2361
2362 while left_iter.move_next()? {
2363 let left_item = left_iter
2364 .current()
2365 .ok_or_else(|| XPathError::internal("Iterator current missing"))?;
2366 let left_value = match atomize_item(left_item)? {
2367 Some(v) => v,
2368 None => continue, };
2370 let mut right_iter = right_buf.clone();
2371
2372 while right_iter.move_next()? {
2373 let right_item = right_iter
2374 .current()
2375 .ok_or_else(|| XPathError::internal("Iterator current missing"))?;
2376 let right_value = match atomize_item(right_item)? {
2377 Some(v) => v,
2378 None => continue, };
2380 let (l, r) = magnitude_relationship_ctx(context, &left_value, &right_value)?;
2381
2382 match value_eq(&l, &r) {
2383 Ok(true) => continue,
2384 Ok(false) => return Ok(true),
2385 Err(err) if is_operator_not_defined(&err) => return Ok(true),
2386 Err(err) => return Err(err),
2387 }
2388 }
2389 }
2390
2391 Ok(false)
2392}
2393
2394pub fn general_lt_iter<I1, I2>(
2395 context: &XPathContext,
2396 left: &I1,
2397 right: &I2,
2398) -> Result<bool, XPathError>
2399where
2400 I1: XmlNodeIterator,
2401 I2: XmlNodeIterator,
2402{
2403 let right_buf = BufferedNodeIterator::preload(right.clone())?;
2404 let mut left_iter = left.clone();
2405
2406 while left_iter.move_next()? {
2407 let left_item = left_iter
2408 .current()
2409 .ok_or_else(|| XPathError::internal("Iterator current missing"))?;
2410 let left_value = match atomize_item(left_item)? {
2411 Some(v) => v,
2412 None => continue, };
2414 let mut right_iter = right_buf.clone();
2415
2416 while right_iter.move_next()? {
2417 let right_item = right_iter
2418 .current()
2419 .ok_or_else(|| XPathError::internal("Iterator current missing"))?;
2420 let right_value = match atomize_item(right_item)? {
2421 Some(v) => v,
2422 None => continue, };
2424 let (l, r) = magnitude_relationship_ctx(context, &left_value, &right_value)?;
2425
2426 match value_lt(&l, &r) {
2427 Ok(true) => return Ok(true),
2428 Ok(false) => continue,
2429 Err(err) => return Err(err),
2430 }
2431 }
2432 }
2433
2434 Ok(false)
2435}
2436
2437pub fn general_le_iter<I1, I2>(
2438 context: &XPathContext,
2439 left: &I1,
2440 right: &I2,
2441) -> Result<bool, XPathError>
2442where
2443 I1: XmlNodeIterator,
2444 I2: XmlNodeIterator,
2445{
2446 let right_buf = BufferedNodeIterator::preload(right.clone())?;
2447 let mut left_iter = left.clone();
2448
2449 while left_iter.move_next()? {
2450 let left_item = left_iter
2451 .current()
2452 .ok_or_else(|| XPathError::internal("Iterator current missing"))?;
2453 let left_value = match atomize_item(left_item)? {
2454 Some(v) => v,
2455 None => continue, };
2457 let mut right_iter = right_buf.clone();
2458
2459 while right_iter.move_next()? {
2460 let right_item = right_iter
2461 .current()
2462 .ok_or_else(|| XPathError::internal("Iterator current missing"))?;
2463 let right_value = match atomize_item(right_item)? {
2464 Some(v) => v,
2465 None => continue, };
2467 let (l, r) = magnitude_relationship_ctx(context, &left_value, &right_value)?;
2468
2469 match value_eq(&l, &r) {
2470 Ok(true) => return Ok(true),
2471 Ok(false) => {}
2472 Err(err) if is_operator_not_defined(&err) => {}
2473 Err(err) => return Err(err),
2474 }
2475
2476 match value_lt(&l, &r) {
2477 Ok(true) => return Ok(true),
2478 Ok(false) => continue,
2479 Err(err) => return Err(err),
2480 }
2481 }
2482 }
2483
2484 Ok(false)
2485}
2486
2487pub fn general_gt_iter<I1, I2>(
2488 context: &XPathContext,
2489 left: &I1,
2490 right: &I2,
2491) -> Result<bool, XPathError>
2492where
2493 I1: XmlNodeIterator,
2494 I2: XmlNodeIterator,
2495{
2496 let right_buf = BufferedNodeIterator::preload(right.clone())?;
2497 let mut left_iter = left.clone();
2498
2499 while left_iter.move_next()? {
2500 let left_item = left_iter
2501 .current()
2502 .ok_or_else(|| XPathError::internal("Iterator current missing"))?;
2503 let left_value = match atomize_item(left_item)? {
2504 Some(v) => v,
2505 None => continue, };
2507 let mut right_iter = right_buf.clone();
2508
2509 while right_iter.move_next()? {
2510 let right_item = right_iter
2511 .current()
2512 .ok_or_else(|| XPathError::internal("Iterator current missing"))?;
2513 let right_value = match atomize_item(right_item)? {
2514 Some(v) => v,
2515 None => continue, };
2517 let (l, r) = magnitude_relationship_ctx(context, &left_value, &right_value)?;
2518
2519 match value_gt(&l, &r) {
2520 Ok(true) => return Ok(true),
2521 Ok(false) => continue,
2522 Err(err) => return Err(err),
2523 }
2524 }
2525 }
2526
2527 Ok(false)
2528}
2529
2530pub fn general_ge_iter<I1, I2>(
2531 context: &XPathContext,
2532 left: &I1,
2533 right: &I2,
2534) -> Result<bool, XPathError>
2535where
2536 I1: XmlNodeIterator,
2537 I2: XmlNodeIterator,
2538{
2539 let right_buf = BufferedNodeIterator::preload(right.clone())?;
2540 let mut left_iter = left.clone();
2541
2542 while left_iter.move_next()? {
2543 let left_item = left_iter
2544 .current()
2545 .ok_or_else(|| XPathError::internal("Iterator current missing"))?;
2546 let left_value = match atomize_item(left_item)? {
2547 Some(v) => v,
2548 None => continue, };
2550 let mut right_iter = right_buf.clone();
2551
2552 while right_iter.move_next()? {
2553 let right_item = right_iter
2554 .current()
2555 .ok_or_else(|| XPathError::internal("Iterator current missing"))?;
2556 let right_value = match atomize_item(right_item)? {
2557 Some(v) => v,
2558 None => continue, };
2560 let (l, r) = magnitude_relationship_ctx(context, &left_value, &right_value)?;
2561
2562 match value_eq(&l, &r) {
2563 Ok(true) => return Ok(true),
2564 Ok(false) => {}
2565 Err(err) if is_operator_not_defined(&err) => {}
2566 Err(err) => return Err(err),
2567 }
2568
2569 match value_gt(&l, &r) {
2570 Ok(true) => return Ok(true),
2571 Ok(false) => continue,
2572 Err(err) => return Err(err),
2573 }
2574 }
2575 }
2576
2577 Ok(false)
2578}
2579
2580fn coerce_for_comparison_10(
2594 op: BinaryOpKind,
2595 left: &XmlValue,
2596 right: &XmlValue,
2597) -> (XmlValue, XmlValue) {
2598 let is_equality = matches!(op, BinaryOpKind::GeneralEq | BinaryOpKind::GeneralNe);
2599
2600 if is_equality {
2601 if left.type_code == XmlTypeCode::Boolean || right.type_code == XmlTypeCode::Boolean {
2603 let l_bool = ebv_atomic(left);
2604 let r_bool = ebv_atomic(right);
2605 return (XmlValue::boolean(l_bool), XmlValue::boolean(r_bool));
2606 }
2607
2608 if left.type_code.is_numeric() || right.type_code.is_numeric() {
2610 let l_num = crate::xpath::atomize::to_number(left);
2611 let r_num = crate::xpath::atomize::to_number(right);
2612 return (XmlValue::double(l_num), XmlValue::double(r_num));
2613 }
2614
2615 let l_str = left.to_string_value();
2617 let r_str = right.to_string_value();
2618 return (XmlValue::string(l_str), XmlValue::string(r_str));
2619 }
2620
2621 let l_num = crate::xpath::atomize::to_number(left);
2623 let r_num = crate::xpath::atomize::to_number(right);
2624 (XmlValue::double(l_num), XmlValue::double(r_num))
2625}
2626
2627fn ebv_atomic(value: &XmlValue) -> bool {
2629 if let Some(b) = value.as_boolean() {
2630 return b;
2631 }
2632 if let Some(s) = value.as_string() {
2633 return !s.is_empty();
2634 }
2635 if let Some(d) = value.as_double() {
2636 return !d.is_nan() && d != 0.0;
2637 }
2638 if value.type_code.is_numeric() {
2639 let d = crate::xpath::atomize::to_number(value);
2640 return !d.is_nan() && d != 0.0;
2641 }
2642 let s = value.to_string_value();
2643 !s.is_empty()
2644}
2645
2646pub fn general_eq_iter_10<I1, I2>(left: &I1, right: &I2) -> Result<bool, XPathError>
2648where
2649 I1: XmlNodeIterator,
2650 I2: XmlNodeIterator,
2651{
2652 general_compare_iter_10(BinaryOpKind::GeneralEq, left, right)
2653}
2654
2655pub fn general_ne_iter_10<I1, I2>(left: &I1, right: &I2) -> Result<bool, XPathError>
2657where
2658 I1: XmlNodeIterator,
2659 I2: XmlNodeIterator,
2660{
2661 general_compare_iter_10(BinaryOpKind::GeneralNe, left, right)
2662}
2663
2664pub fn general_lt_iter_10<I1, I2>(left: &I1, right: &I2) -> Result<bool, XPathError>
2666where
2667 I1: XmlNodeIterator,
2668 I2: XmlNodeIterator,
2669{
2670 general_compare_iter_10(BinaryOpKind::GeneralLt, left, right)
2671}
2672
2673pub fn general_le_iter_10<I1, I2>(left: &I1, right: &I2) -> Result<bool, XPathError>
2675where
2676 I1: XmlNodeIterator,
2677 I2: XmlNodeIterator,
2678{
2679 general_compare_iter_10(BinaryOpKind::GeneralLe, left, right)
2680}
2681
2682pub fn general_gt_iter_10<I1, I2>(left: &I1, right: &I2) -> Result<bool, XPathError>
2684where
2685 I1: XmlNodeIterator,
2686 I2: XmlNodeIterator,
2687{
2688 general_compare_iter_10(BinaryOpKind::GeneralGt, left, right)
2689}
2690
2691pub fn general_ge_iter_10<I1, I2>(left: &I1, right: &I2) -> Result<bool, XPathError>
2693where
2694 I1: XmlNodeIterator,
2695 I2: XmlNodeIterator,
2696{
2697 general_compare_iter_10(BinaryOpKind::GeneralGe, left, right)
2698}
2699
2700fn general_compare_iter_10<I1, I2>(
2702 op: BinaryOpKind,
2703 left: &I1,
2704 right: &I2,
2705) -> Result<bool, XPathError>
2706where
2707 I1: XmlNodeIterator,
2708 I2: XmlNodeIterator,
2709{
2710 let right_buf = BufferedNodeIterator::preload(right.clone())?;
2711 let mut left_iter = left.clone();
2712
2713 while left_iter.move_next()? {
2714 let left_item = left_iter
2715 .current()
2716 .ok_or_else(|| XPathError::internal("Iterator current missing"))?;
2717 let left_value = match atomize_item(left_item)? {
2718 Some(v) => v,
2719 None => continue, };
2721 let mut right_iter = right_buf.clone();
2722
2723 while right_iter.move_next()? {
2724 let right_item = right_iter
2725 .current()
2726 .ok_or_else(|| XPathError::internal("Iterator current missing"))?;
2727 let right_value = match atomize_item(right_item)? {
2728 Some(v) => v,
2729 None => continue, };
2731 let (l, r) = coerce_for_comparison_10(op, &left_value, &right_value);
2732
2733 let satisfied = match op {
2734 BinaryOpKind::GeneralEq => compare_eq(&l, &r).unwrap_or(false),
2735 BinaryOpKind::GeneralNe => !compare_eq(&l, &r).unwrap_or(true),
2736 BinaryOpKind::GeneralLt => compare_lt(&l, &r).unwrap_or(false),
2737 BinaryOpKind::GeneralLe => compare_le(&l, &r).unwrap_or(false),
2738 BinaryOpKind::GeneralGt => compare_gt(&l, &r).unwrap_or(false),
2739 BinaryOpKind::GeneralGe => compare_ge(&l, &r).unwrap_or(false),
2740 _ => unreachable!(),
2741 };
2742
2743 if satisfied {
2744 return Ok(true);
2745 }
2746 }
2747 }
2748
2749 Ok(false)
2750}
2751
2752pub fn eval_numeric_binary_10(
2756 op: BinaryOpKind,
2757 left: &XmlValue,
2758 right: &XmlValue,
2759) -> Result<XmlValue, XPathError> {
2760 let l = crate::xpath::atomize::to_number(left);
2761 let r = crate::xpath::atomize::to_number(right);
2762
2763 let result = match op {
2764 BinaryOpKind::Add => l + r,
2765 BinaryOpKind::Sub => l - r,
2766 BinaryOpKind::Mul => l * r,
2767 BinaryOpKind::Div => {
2768 if r == 0.0 {
2769 if l == 0.0 || l.is_nan() {
2770 f64::NAN
2771 } else if l > 0.0 {
2772 f64::INFINITY
2773 } else {
2774 f64::NEG_INFINITY
2775 }
2776 } else {
2777 l / r
2778 }
2779 }
2780 BinaryOpKind::Mod => {
2781 if r == 0.0 {
2782 f64::NAN
2783 } else {
2784 l % r
2785 }
2786 }
2787 _ => return Err(XPathError::internal("Unsupported arithmetic operator")),
2788 };
2789
2790 Ok(XmlValue::double(result))
2791}
2792
2793pub fn general_eq_seq(left: &[XmlValue], right: &[XmlValue]) -> Result<bool, XPathError> {
2819 if left.is_empty() || right.is_empty() {
2821 return Ok(false);
2822 }
2823
2824 for l in left {
2826 for r in right {
2827 match general_eq(l, r) {
2828 Ok(true) => return Ok(true),
2829 Ok(false) => continue,
2830 Err(_) => continue, }
2832 }
2833 }
2834
2835 Ok(false)
2836}
2837
2838pub fn general_ne_seq(left: &[XmlValue], right: &[XmlValue]) -> Result<bool, XPathError> {
2842 if left.is_empty() || right.is_empty() {
2843 return Ok(false);
2844 }
2845
2846 for l in left {
2847 for r in right {
2848 match general_ne(l, r) {
2849 Ok(true) => return Ok(true),
2850 Ok(false) => continue,
2851 Err(_) => continue,
2852 }
2853 }
2854 }
2855
2856 Ok(false)
2857}
2858
2859pub fn general_lt_seq(left: &[XmlValue], right: &[XmlValue]) -> Result<bool, XPathError> {
2863 if left.is_empty() || right.is_empty() {
2864 return Ok(false);
2865 }
2866
2867 for l in left {
2868 for r in right {
2869 match general_lt(l, r) {
2870 Ok(true) => return Ok(true),
2871 Ok(false) => continue,
2872 Err(_) => continue,
2873 }
2874 }
2875 }
2876
2877 Ok(false)
2878}
2879
2880pub fn general_le_seq(left: &[XmlValue], right: &[XmlValue]) -> Result<bool, XPathError> {
2884 if left.is_empty() || right.is_empty() {
2885 return Ok(false);
2886 }
2887
2888 for l in left {
2889 for r in right {
2890 match general_le(l, r) {
2891 Ok(true) => return Ok(true),
2892 Ok(false) => continue,
2893 Err(_) => continue,
2894 }
2895 }
2896 }
2897
2898 Ok(false)
2899}
2900
2901pub fn general_gt_seq(left: &[XmlValue], right: &[XmlValue]) -> Result<bool, XPathError> {
2905 if left.is_empty() || right.is_empty() {
2906 return Ok(false);
2907 }
2908
2909 for l in left {
2910 for r in right {
2911 match general_gt(l, r) {
2912 Ok(true) => return Ok(true),
2913 Ok(false) => continue,
2914 Err(_) => continue,
2915 }
2916 }
2917 }
2918
2919 Ok(false)
2920}
2921
2922pub fn general_ge_seq(left: &[XmlValue], right: &[XmlValue]) -> Result<bool, XPathError> {
2926 if left.is_empty() || right.is_empty() {
2927 return Ok(false);
2928 }
2929
2930 for l in left {
2931 for r in right {
2932 match general_ge(l, r) {
2933 Ok(true) => return Ok(true),
2934 Ok(false) => continue,
2935 Err(_) => continue,
2936 }
2937 }
2938 }
2939
2940 Ok(false)
2941}
2942
2943fn unsupported_operator(op: BinaryOpKind, left: &XmlValue, right: &XmlValue) -> XPathError {
2944 XPathError::internal(format!(
2945 "Operator {:?} not defined for types {:?} and {:?}",
2946 op, left.type_code, right.type_code
2947 ))
2948}
2949
2950#[cfg(test)]
2951mod tests {
2952 use super::*;
2953 use crate::namespace::qname::QualifiedName;
2954 use crate::namespace::NameTable;
2955 use crate::navigator::RoXmlNavigator;
2956 use crate::xpath::context::XPathContext;
2957 use crate::xpath::iterator::{VecNodeIterator, XmlItem};
2958
2959 fn int_value(type_code: XmlTypeCode, value: i64) -> XmlValue {
2960 XmlValue {
2961 type_code,
2962 schema_type: None,
2963 value: XmlValueKind::Atomic(XmlAtomicValue::Integer(BigInt::from(value))),
2964 }
2965 }
2966
2967 fn decimal_value(value: &str) -> XmlValue {
2968 XmlValue {
2969 type_code: XmlTypeCode::Decimal,
2970 schema_type: None,
2971 value: XmlValueKind::Atomic(XmlAtomicValue::Decimal(value.parse::<Decimal>().unwrap())),
2972 }
2973 }
2974
2975 fn datetime_value(
2976 type_code: XmlTypeCode,
2977 year: i32,
2978 month: u8,
2979 day: u8,
2980 hour: u8,
2981 minute: u8,
2982 second: Decimal,
2983 ) -> XmlValue {
2984 XmlValue {
2985 type_code,
2986 schema_type: None,
2987 value: XmlValueKind::Atomic(XmlAtomicValue::DateTime(DateTimeValue {
2988 year,
2989 month,
2990 day,
2991 hour,
2992 minute,
2993 second,
2994 timezone: None,
2995 })),
2996 }
2997 }
2998
2999 fn date_value(year: i32, month: u8, day: u8) -> XmlValue {
3000 XmlValue {
3001 type_code: XmlTypeCode::Date,
3002 schema_type: None,
3003 value: XmlValueKind::Atomic(XmlAtomicValue::Date(DateValue {
3004 year,
3005 month,
3006 day,
3007 timezone: None,
3008 })),
3009 }
3010 }
3011
3012 fn time_value(hour: u8, minute: u8, second: Decimal) -> XmlValue {
3013 XmlValue {
3014 type_code: XmlTypeCode::Time,
3015 schema_type: None,
3016 value: XmlValueKind::Atomic(XmlAtomicValue::Time(TimeValue {
3017 hour,
3018 minute,
3019 second,
3020 timezone: None,
3021 })),
3022 }
3023 }
3024
3025 fn time_value_with_tz(
3026 hour: u8,
3027 minute: u8,
3028 second: Decimal,
3029 timezone: TimezoneOffset,
3030 ) -> XmlValue {
3031 XmlValue {
3032 type_code: XmlTypeCode::Time,
3033 schema_type: None,
3034 value: XmlValueKind::Atomic(XmlAtomicValue::Time(TimeValue {
3035 hour,
3036 minute,
3037 second,
3038 timezone: Some(timezone),
3039 })),
3040 }
3041 }
3042
3043 fn year_month_duration_value(years: u32, months: u32) -> XmlValue {
3044 XmlValue {
3045 type_code: XmlTypeCode::YearMonthDuration,
3046 schema_type: None,
3047 value: XmlValueKind::Atomic(XmlAtomicValue::YearMonthDuration(
3048 YearMonthDurationValue {
3049 negative: false,
3050 years,
3051 months,
3052 },
3053 )),
3054 }
3055 }
3056
3057 fn day_time_duration_value(days: u32, hours: u32, minutes: u32, seconds: Decimal) -> XmlValue {
3058 XmlValue {
3059 type_code: XmlTypeCode::DayTimeDuration,
3060 schema_type: None,
3061 value: XmlValueKind::Atomic(XmlAtomicValue::DayTimeDuration(DayTimeDurationValue {
3062 negative: false,
3063 days,
3064 hours,
3065 minutes,
3066 seconds,
3067 })),
3068 }
3069 }
3070
3071 fn duration_value(
3072 negative: bool,
3073 years: u32,
3074 months: u32,
3075 days: u32,
3076 hours: u32,
3077 minutes: u32,
3078 seconds: Decimal,
3079 ) -> XmlValue {
3080 XmlValue {
3081 type_code: XmlTypeCode::Duration,
3082 schema_type: None,
3083 value: XmlValueKind::Atomic(XmlAtomicValue::Duration(DurationValue {
3084 negative,
3085 years,
3086 months,
3087 days,
3088 hours,
3089 minutes,
3090 seconds,
3091 })),
3092 }
3093 }
3094
3095 #[test]
3096 fn test_add_byte_unsigned_byte_returns_int() {
3097 let left = int_value(XmlTypeCode::Byte, 1);
3098 let right = int_value(XmlTypeCode::UnsignedByte, 2);
3099 let result = eval_binary(BinaryOpKind::Add, &left, &right).unwrap();
3100 assert_eq!(result.type_code, XmlTypeCode::Int);
3101 assert_eq!(result.as_integer().unwrap(), &BigInt::from(3));
3102 }
3103
3104 #[test]
3105 fn test_add_int_unsigned_int_returns_unsigned_int() {
3106 let left = int_value(XmlTypeCode::Int, 3);
3107 let right = int_value(XmlTypeCode::UnsignedInt, 4);
3108 let result = eval_binary(BinaryOpKind::Add, &left, &right).unwrap();
3109 assert_eq!(result.type_code, XmlTypeCode::UnsignedInt);
3110 assert_eq!(result.as_integer().unwrap(), &BigInt::from(7));
3111 }
3112
3113 #[test]
3114 fn test_div_int_int_returns_decimal() {
3115 let left = int_value(XmlTypeCode::Int, 3);
3116 let right = int_value(XmlTypeCode::Int, 2);
3117 let result = eval_binary(BinaryOpKind::Div, &left, &right).unwrap();
3118 assert_eq!(result.type_code, XmlTypeCode::Decimal);
3119 assert_eq!(result.as_decimal().unwrap(), Decimal::new(15, 1));
3120 }
3121
3122 #[test]
3123 fn test_div_short_bounds_rounds_to_xpath_precision() {
3124 let left = int_value(XmlTypeCode::Short, -32768);
3125 let right = int_value(XmlTypeCode::Short, 32767);
3126 let result = eval_binary(BinaryOpKind::Div, &left, &right).unwrap();
3127 assert_eq!(result.type_code, XmlTypeCode::Decimal);
3128 assert_eq!(
3129 result.as_decimal().unwrap().to_string(),
3130 "-1.000030518509475997"
3131 );
3132 }
3133
3134 #[test]
3135 fn test_idiv_double_truncates() {
3136 let left = XmlValue::double(5.9);
3137 let right = XmlValue::double(2.0);
3138 let result = eval_binary(BinaryOpKind::IDiv, &left, &right).unwrap();
3139 assert_eq!(result.type_code, XmlTypeCode::Integer);
3140 assert_eq!(result.as_integer().unwrap(), &BigInt::from(2));
3141 }
3142
3143 #[test]
3144 fn test_unary_minus_unsigned_int_returns_long() {
3145 let value = int_value(XmlTypeCode::UnsignedInt, 5);
3146 let result = eval_unary(UnaryOpKind::Negate, &value).unwrap();
3147 assert_eq!(result.type_code, XmlTypeCode::Long);
3148 assert_eq!(result.as_integer().unwrap(), &BigInt::from(-5));
3149 }
3150
3151 #[test]
3152 fn test_string_comparison() {
3153 let left = XmlValue::string("alpha");
3154 let right = XmlValue::string("beta");
3155 let result = eval_binary(BinaryOpKind::GeneralLt, &left, &right).unwrap();
3156 assert_eq!(result.as_boolean(), Some(true));
3157 }
3158
3159 #[test]
3160 fn test_boolean_eq() {
3161 let left = XmlValue::boolean(true);
3162 let right = XmlValue::boolean(false);
3163 let result = eval_binary(BinaryOpKind::GeneralEq, &left, &right).unwrap();
3164 assert_eq!(result.as_boolean(), Some(false));
3165 }
3166
3167 #[test]
3168 fn test_range_integer_sequence() {
3169 let start = int_value(XmlTypeCode::Integer, 1);
3170 let end = int_value(XmlTypeCode::Integer, 3);
3171 let result = eval_range(&start, &end).unwrap();
3172 let values: Vec<_> = result
3173 .iter()
3174 .map(|v| v.as_integer().unwrap().clone())
3175 .collect();
3176 assert_eq!(
3177 values,
3178 vec![BigInt::from(1), BigInt::from(2), BigInt::from(3)]
3179 );
3180 }
3181
3182 #[test]
3183 fn test_decimal_eq() {
3184 let left = decimal_value("2.5");
3185 let right = decimal_value("2.5");
3186 let result = eval_binary(BinaryOpKind::GeneralEq, &left, &right).unwrap();
3187 assert_eq!(result.as_boolean(), Some(true));
3188 }
3189
3190 #[test]
3191 fn test_datetime_add_year_month_clamps_day() {
3192 let left = datetime_value(XmlTypeCode::DateTime, 2023, 1, 31, 10, 0, Decimal::ZERO);
3193 let right = year_month_duration_value(0, 1);
3194 let result = eval_binary(BinaryOpKind::Add, &left, &right).unwrap();
3195 assert_eq!(result.type_code, XmlTypeCode::DateTime);
3196 match result.value {
3197 XmlValueKind::Atomic(XmlAtomicValue::DateTime(dt)) => {
3198 assert_eq!((dt.year, dt.month, dt.day), (2023, 2, 28));
3199 assert_eq!((dt.hour, dt.minute), (10, 0));
3200 }
3201 _ => panic!("Expected dateTime result"),
3202 }
3203 }
3204
3205 #[test]
3206 fn test_date_sub_date_returns_day_time_duration() {
3207 let left = date_value(2024, 3, 15);
3208 let right = date_value(2024, 3, 14);
3209 let result = eval_binary(BinaryOpKind::Sub, &left, &right).unwrap();
3210 assert_eq!(result.type_code, XmlTypeCode::DayTimeDuration);
3211 match result.value {
3212 XmlValueKind::Atomic(XmlAtomicValue::DayTimeDuration(duration)) => {
3213 assert!(!duration.negative);
3214 assert_eq!(duration.days, 1);
3215 assert_eq!(duration.hours, 0);
3216 assert_eq!(duration.minutes, 0);
3217 assert!(duration.seconds.is_zero());
3218 }
3219 _ => panic!("Expected dayTimeDuration result"),
3220 }
3221 }
3222
3223 #[test]
3224 fn test_time_add_day_time_wraps() {
3225 let left = time_value(23, 0, Decimal::ZERO);
3226 let right = day_time_duration_value(0, 2, 0, Decimal::ZERO);
3227 let result = eval_binary(BinaryOpKind::Add, &left, &right).unwrap();
3228 assert_eq!(result.type_code, XmlTypeCode::Time);
3229 match result.value {
3230 XmlValueKind::Atomic(XmlAtomicValue::Time(time)) => {
3231 assert_eq!((time.hour, time.minute), (1, 0));
3232 }
3233 _ => panic!("Expected time result"),
3234 }
3235 }
3236
3237 #[test]
3238 fn test_time_compare_uses_implicit_timezone() {
3239 let implicit = implicit_timezone_offset();
3240 let left = time_value(10, 0, Decimal::ZERO);
3241 let right = time_value_with_tz(10, 0, Decimal::ZERO, implicit);
3242 let result = eval_binary(BinaryOpKind::GeneralEq, &left, &right).unwrap();
3243 assert_eq!(result.as_boolean(), Some(true));
3244 }
3245
3246 #[test]
3247 fn test_numeric_mul_year_month_duration() {
3248 let left = int_value(XmlTypeCode::Int, 2);
3249 let right = year_month_duration_value(1, 2);
3250 let result = eval_binary(BinaryOpKind::Mul, &left, &right).unwrap();
3251 assert_eq!(result.type_code, XmlTypeCode::YearMonthDuration);
3252 match result.value {
3253 XmlValueKind::Atomic(XmlAtomicValue::YearMonthDuration(duration)) => {
3254 assert_eq!((duration.years, duration.months), (2, 4));
3255 }
3256 _ => panic!("Expected yearMonthDuration result"),
3257 }
3258 }
3259
3260 #[test]
3261 fn test_day_time_duration_div_duration_returns_decimal() {
3262 let left = day_time_duration_value(0, 3, 0, Decimal::ZERO);
3263 let right = day_time_duration_value(0, 1, 0, Decimal::ZERO);
3264 let result = eval_binary(BinaryOpKind::Div, &left, &right).unwrap();
3265 assert_eq!(result.type_code, XmlTypeCode::Decimal);
3266 assert_eq!(result.as_decimal(), Some(Decimal::from(3)));
3267 }
3268
3269 #[test]
3270 fn test_duration_eq_across_subtypes() {
3271 let left = duration_value(false, 1, 2, 0, 0, 0, Decimal::ZERO);
3272 let right = year_month_duration_value(1, 2);
3273 let result = eval_binary(BinaryOpKind::GeneralEq, &left, &right).unwrap();
3274 assert_eq!(result.as_boolean(), Some(true));
3275 }
3276
3277 #[test]
3278 fn test_datetime_sub_datetime_returns_day_time_duration() {
3279 let left = datetime_value(XmlTypeCode::DateTime, 2024, 3, 15, 12, 0, Decimal::ZERO);
3280 let right = datetime_value(XmlTypeCode::DateTime, 2024, 3, 15, 11, 0, Decimal::ZERO);
3281 let result = eval_binary(BinaryOpKind::Sub, &left, &right).unwrap();
3282 assert_eq!(result.type_code, XmlTypeCode::DayTimeDuration);
3283 match result.value {
3284 XmlValueKind::Atomic(XmlAtomicValue::DayTimeDuration(duration)) => {
3285 assert!(!duration.negative);
3286 assert_eq!((duration.days, duration.hours, duration.minutes), (0, 1, 0));
3287 }
3288 _ => panic!("Expected dayTimeDuration result"),
3289 }
3290 }
3291
3292 #[test]
3297 fn test_magnitude_relationship_untyped_to_numeric() {
3298 let left = XmlValue::untyped("42");
3300 let right = int_value(XmlTypeCode::Integer, 42);
3301 let (promoted_left, promoted_right) = magnitude_relationship(&left, &right).unwrap();
3302 assert_eq!(promoted_left.type_code, XmlTypeCode::Double);
3303 assert_eq!(promoted_right.type_code, XmlTypeCode::Integer);
3304 }
3305
3306 #[test]
3307 fn test_magnitude_relationship_untyped_to_string() {
3308 let left = XmlValue::untyped("hello");
3310 let right = XmlValue::string("world");
3311 let (promoted_left, promoted_right) = magnitude_relationship(&left, &right).unwrap();
3312 assert_eq!(promoted_left.type_code, XmlTypeCode::String);
3313 assert_eq!(promoted_right.type_code, XmlTypeCode::String);
3314 }
3315
3316 #[test]
3317 fn test_magnitude_relationship_both_untyped() {
3318 let left = XmlValue::untyped("abc");
3320 let right = XmlValue::untyped("def");
3321 let (promoted_left, promoted_right) = magnitude_relationship(&left, &right).unwrap();
3322 assert!(is_string_like(promoted_left.type_code));
3324 assert!(is_string_like(promoted_right.type_code));
3325 }
3326
3327 #[test]
3328 fn test_general_eq_with_untyped() {
3329 let left = XmlValue::untyped("42");
3331 let right = int_value(XmlTypeCode::Integer, 42);
3332 assert!(general_eq(&left, &right).unwrap());
3333 }
3334
3335 #[test]
3336 fn test_general_eq_strings() {
3337 let left = XmlValue::string("hello");
3338 let right = XmlValue::string("hello");
3339 assert!(general_eq(&left, &right).unwrap());
3340
3341 let right2 = XmlValue::string("world");
3342 assert!(!general_eq(&left, &right2).unwrap());
3343 }
3344
3345 #[test]
3346 fn test_general_gt_with_untyped() {
3347 let left = XmlValue::untyped("50");
3349 let right = int_value(XmlTypeCode::Integer, 42);
3350 assert!(general_gt(&left, &right).unwrap());
3351 }
3352
3353 #[test]
3354 fn test_general_ne() {
3355 let left = XmlValue::string("a");
3356 let right = XmlValue::string("b");
3357 assert!(general_ne(&left, &right).unwrap());
3358
3359 let same = XmlValue::string("a");
3360 assert!(!general_ne(&left, &same).unwrap());
3361 }
3362
3363 #[test]
3364 fn test_general_comparisons_numeric() {
3365 let five = int_value(XmlTypeCode::Integer, 5);
3366 let ten = int_value(XmlTypeCode::Integer, 10);
3367
3368 assert!(general_lt(&five, &ten).unwrap());
3369 assert!(general_le(&five, &ten).unwrap());
3370 assert!(!general_gt(&five, &ten).unwrap());
3371 assert!(!general_ge(&five, &ten).unwrap());
3372
3373 assert!(general_ge(&five, &five).unwrap());
3374 assert!(general_le(&five, &five).unwrap());
3375 }
3376
3377 #[test]
3378 fn test_value_comparisons() {
3379 let a = XmlValue::string("abc");
3380 let b = XmlValue::string("xyz");
3381
3382 assert!(value_lt(&a, &b).unwrap());
3383 assert!(value_le(&a, &b).unwrap());
3384 assert!(!value_gt(&a, &b).unwrap());
3385 assert!(!value_ge(&a, &b).unwrap());
3386 assert!(!value_eq(&a, &b).unwrap());
3387 }
3388
3389 #[test]
3394 fn test_general_eq_seq_finds_match() {
3395 let left = vec![
3397 int_value(XmlTypeCode::Integer, 1),
3398 int_value(XmlTypeCode::Integer, 2),
3399 int_value(XmlTypeCode::Integer, 3),
3400 ];
3401 let right = vec![
3402 int_value(XmlTypeCode::Integer, 3),
3403 int_value(XmlTypeCode::Integer, 4),
3404 int_value(XmlTypeCode::Integer, 5),
3405 ];
3406 assert!(general_eq_seq(&left, &right).unwrap());
3407 }
3408
3409 #[test]
3410 fn test_general_eq_seq_no_match() {
3411 let left = vec![
3413 int_value(XmlTypeCode::Integer, 1),
3414 int_value(XmlTypeCode::Integer, 2),
3415 ];
3416 let right = vec![
3417 int_value(XmlTypeCode::Integer, 3),
3418 int_value(XmlTypeCode::Integer, 4),
3419 ];
3420 assert!(!general_eq_seq(&left, &right).unwrap());
3421 }
3422
3423 #[test]
3424 fn test_general_eq_seq_empty_is_false() {
3425 let left: Vec<XmlValue> = vec![];
3427 let right = vec![int_value(XmlTypeCode::Integer, 1)];
3428 assert!(!general_eq_seq(&left, &right).unwrap());
3429 assert!(!general_eq_seq(&right, &left).unwrap());
3430 assert!(!general_eq_seq(&left, &left).unwrap());
3431 }
3432
3433 #[test]
3434 fn test_general_ne_seq() {
3435 let left = vec![
3437 int_value(XmlTypeCode::Integer, 1),
3438 int_value(XmlTypeCode::Integer, 2),
3439 ];
3440 let right = vec![
3441 int_value(XmlTypeCode::Integer, 2),
3442 int_value(XmlTypeCode::Integer, 3),
3443 ];
3444 assert!(general_ne_seq(&left, &right).unwrap());
3445
3446 let same = vec![int_value(XmlTypeCode::Integer, 1)];
3448 assert!(!general_ne_seq(&same, &same).unwrap());
3449 }
3450
3451 #[test]
3452 fn test_general_lt_seq() {
3453 let left = vec![
3455 int_value(XmlTypeCode::Integer, 1),
3456 int_value(XmlTypeCode::Integer, 2),
3457 ];
3458 let right = vec![
3459 int_value(XmlTypeCode::Integer, 3),
3460 int_value(XmlTypeCode::Integer, 4),
3461 ];
3462 assert!(general_lt_seq(&left, &right).unwrap());
3463
3464 assert!(!general_lt_seq(&right, &left).unwrap());
3466
3467 let mixed = vec![
3469 int_value(XmlTypeCode::Integer, 1),
3470 int_value(XmlTypeCode::Integer, 5),
3471 ];
3472 assert!(general_lt_seq(&mixed, &right).unwrap());
3473 }
3474
3475 #[test]
3476 fn test_general_gt_seq() {
3477 let left = vec![
3479 int_value(XmlTypeCode::Integer, 3),
3480 int_value(XmlTypeCode::Integer, 4),
3481 ];
3482 let right = vec![
3483 int_value(XmlTypeCode::Integer, 1),
3484 int_value(XmlTypeCode::Integer, 2),
3485 ];
3486 assert!(general_gt_seq(&left, &right).unwrap());
3487 }
3488
3489 #[test]
3490 fn test_general_le_seq() {
3491 let left = vec![
3493 int_value(XmlTypeCode::Integer, 1),
3494 int_value(XmlTypeCode::Integer, 2),
3495 ];
3496 let right = vec![
3497 int_value(XmlTypeCode::Integer, 2),
3498 int_value(XmlTypeCode::Integer, 3),
3499 ];
3500 assert!(general_le_seq(&left, &right).unwrap());
3501 }
3502
3503 #[test]
3504 fn test_general_ge_seq() {
3505 let left = vec![
3507 int_value(XmlTypeCode::Integer, 2),
3508 int_value(XmlTypeCode::Integer, 3),
3509 ];
3510 let right = vec![
3511 int_value(XmlTypeCode::Integer, 1),
3512 int_value(XmlTypeCode::Integer, 2),
3513 ];
3514 assert!(general_ge_seq(&left, &right).unwrap());
3515 }
3516
3517 #[test]
3518 fn test_general_seq_with_type_promotion() {
3519 let left = vec![XmlValue::untyped("42")];
3521 let right = vec![int_value(XmlTypeCode::Integer, 42)];
3522 assert!(general_eq_seq(&left, &right).unwrap());
3523 }
3524
3525 #[test]
3526 fn test_general_seq_mixed_types() {
3527 let left = vec![
3530 int_value(XmlTypeCode::Integer, 1),
3531 XmlValue::string("hello"),
3532 ];
3533 let right = vec![
3534 XmlValue::string("hello"),
3535 int_value(XmlTypeCode::Integer, 2),
3536 ];
3537 assert!(general_eq_seq(&left, &right).unwrap());
3538 }
3539
3540 #[test]
3541 fn test_compare_ge_prefers_eq_over_ordering() {
3542 let names = NameTable::new();
3544 let local = names.add("a");
3545 let qname = QualifiedName::local(local);
3546 let left = XmlValue::new(
3547 XmlTypeCode::QName,
3548 XmlValueKind::Atomic(XmlAtomicValue::QName(qname)),
3549 );
3550 let right = left.clone();
3551
3552 assert!(compare_ge(&left, &right).unwrap());
3553 assert!(compare_le(&left, &right).unwrap());
3554 }
3555
3556 #[test]
3557 fn test_list_equality() {
3558 let left = XmlValue::new(
3559 XmlTypeCode::NmTokens,
3560 XmlValueKind::List {
3561 item_type: XmlTypeCode::NmToken,
3562 items: vec![
3563 XmlAtomicValue::String("a".to_string()),
3564 XmlAtomicValue::String("b".to_string()),
3565 ],
3566 },
3567 );
3568 let right = left.clone();
3569 let different = XmlValue::new(
3570 XmlTypeCode::NmTokens,
3571 XmlValueKind::List {
3572 item_type: XmlTypeCode::NmToken,
3573 items: vec![XmlAtomicValue::String("a".to_string())],
3574 },
3575 );
3576
3577 assert!(compare_eq(&left, &right).unwrap());
3578 assert!(!compare_eq(&left, &different).unwrap());
3579 }
3580
3581 #[test]
3582 fn test_union_unwrap_equality() {
3583 let inner = XmlValue::string("hello");
3584 let left = XmlValue::new(XmlTypeCode::String, XmlValueKind::Union(Box::new(inner)));
3585 let right = XmlValue::string("hello");
3586 assert!(compare_eq(&left, &right).unwrap());
3587 }
3588
3589 #[test]
3590 fn test_general_eq_iter_finds_match() {
3591 let names = NameTable::new();
3592 let context = XPathContext::new(&names);
3593 let left: VecNodeIterator<RoXmlNavigator<'static>> = VecNodeIterator::new(vec![
3594 XmlItem::Atomic(XmlValue::integer(BigInt::from(1))),
3595 XmlItem::Atomic(XmlValue::integer(BigInt::from(2))),
3596 ]);
3597 let right: VecNodeIterator<RoXmlNavigator<'static>> =
3598 VecNodeIterator::new(vec![XmlItem::Atomic(XmlValue::integer(BigInt::from(2)))]);
3599
3600 assert!(general_eq_iter(&context, &left, &right).unwrap());
3601 }
3602
3603 #[test]
3604 fn test_general_eq_iter_invalid_cast_errors() {
3605 let names = NameTable::new();
3606 let context = XPathContext::new(&names);
3607 let left: VecNodeIterator<RoXmlNavigator<'static>> =
3608 VecNodeIterator::new(vec![XmlItem::Atomic(XmlValue::untyped("not-a-number"))]);
3609 let right: VecNodeIterator<RoXmlNavigator<'static>> =
3610 VecNodeIterator::new(vec![XmlItem::Atomic(XmlValue::integer(BigInt::from(1)))]);
3611
3612 let result = general_eq_iter(&context, &left, &right);
3613 assert!(matches!(result, Err(XPathError::FORG0001 { .. })));
3614 }
3615
3616 #[test]
3617 fn test_general_eq_iter_type_mismatch_is_false() {
3618 let names = NameTable::new();
3619 let context = XPathContext::new(&names);
3620 let left: VecNodeIterator<RoXmlNavigator<'static>> =
3621 VecNodeIterator::new(vec![XmlItem::Atomic(XmlValue::boolean(true))]);
3622 let right: VecNodeIterator<RoXmlNavigator<'static>> =
3623 VecNodeIterator::new(vec![XmlItem::Atomic(date_value(2024, 1, 1))]);
3624
3625 assert!(!general_eq_iter(&context, &left, &right).unwrap());
3626 }
3627
3628 #[test]
3629 fn test_general_gt_iter_type_mismatch_errors() {
3630 let names = NameTable::new();
3631 let context = XPathContext::new(&names);
3632 let left: VecNodeIterator<RoXmlNavigator<'static>> =
3633 VecNodeIterator::new(vec![XmlItem::Atomic(XmlValue::boolean(true))]);
3634 let right: VecNodeIterator<RoXmlNavigator<'static>> =
3635 VecNodeIterator::new(vec![XmlItem::Atomic(XmlValue::string("false"))]);
3636
3637 let result = general_gt_iter(&context, &left, &right);
3638 assert!(matches!(
3639 result,
3640 Err(XPathError::BinaryOperatorNotDefined { .. })
3641 ));
3642 }
3643
3644 #[test]
3649 fn test_magnitude_relationship_ctx_numeric_to_double() {
3650 let names = NameTable::new();
3652 let context = XPathContext::new(&names);
3653
3654 let untyped = XmlValue::untyped("42");
3655 let typed = XmlValue::integer(BigInt::from(100));
3656
3657 let (left, _right) = magnitude_relationship_ctx(&context, &untyped, &typed).unwrap();
3658
3659 assert_eq!(left.type_code, XmlTypeCode::Double);
3660 assert!((left.as_double().unwrap() - 42.0).abs() < 0.001);
3661 }
3662
3663 #[test]
3664 fn test_magnitude_relationship_ctx_promotes_untyped() {
3665 let names = NameTable::new();
3666 let context = XPathContext::new(&names);
3667
3668 let untyped = XmlValue::untyped("2.5");
3670 let typed = XmlValue::double(1.5);
3671
3672 let (left, right) = magnitude_relationship_ctx(&context, &untyped, &typed).unwrap();
3673
3674 assert_eq!(left.type_code, XmlTypeCode::Double);
3675 assert!((left.as_double().unwrap() - 2.5).abs() < 0.001);
3676 assert_eq!(right.type_code, XmlTypeCode::Double);
3677 }
3678
3679 #[test]
3680 fn test_magnitude_relationship_ctx_string_like() {
3681 let names = NameTable::new();
3682 let context = XPathContext::new(&names);
3683
3684 let untyped = XmlValue::untyped("test");
3686 let typed = XmlValue::string("other");
3687
3688 let (left, right) = magnitude_relationship_ctx(&context, &untyped, &typed).unwrap();
3689
3690 assert_eq!(left.type_code, XmlTypeCode::String);
3691 assert_eq!(left.to_string_value(), "test");
3692 assert_eq!(right.type_code, XmlTypeCode::String);
3693 }
3694
3695 #[test]
3696 fn test_get_xsd_primitive_type_string_derived() {
3697 assert_eq!(
3699 get_xsd_primitive_type(XmlTypeCode::NormalizedString),
3700 XmlTypeCode::String
3701 );
3702 assert_eq!(
3703 get_xsd_primitive_type(XmlTypeCode::Token),
3704 XmlTypeCode::String
3705 );
3706 assert_eq!(
3707 get_xsd_primitive_type(XmlTypeCode::NCName),
3708 XmlTypeCode::String
3709 );
3710 assert_eq!(get_xsd_primitive_type(XmlTypeCode::Id), XmlTypeCode::String);
3711 }
3712
3713 #[test]
3714 fn test_get_xsd_primitive_type_integer_derived() {
3715 assert_eq!(
3717 get_xsd_primitive_type(XmlTypeCode::Integer),
3718 XmlTypeCode::Decimal
3719 );
3720 assert_eq!(
3721 get_xsd_primitive_type(XmlTypeCode::Long),
3722 XmlTypeCode::Decimal
3723 );
3724 assert_eq!(
3725 get_xsd_primitive_type(XmlTypeCode::Int),
3726 XmlTypeCode::Decimal
3727 );
3728 assert_eq!(
3729 get_xsd_primitive_type(XmlTypeCode::UnsignedInt),
3730 XmlTypeCode::Decimal
3731 );
3732 }
3733
3734 #[test]
3735 fn test_get_xsd_primitive_type_duration_special_cases() {
3736 assert_eq!(
3738 get_xsd_primitive_type(XmlTypeCode::DayTimeDuration),
3739 XmlTypeCode::DayTimeDuration
3740 );
3741 assert_eq!(
3742 get_xsd_primitive_type(XmlTypeCode::YearMonthDuration),
3743 XmlTypeCode::YearMonthDuration
3744 );
3745 assert_eq!(
3747 get_xsd_primitive_type(XmlTypeCode::Duration),
3748 XmlTypeCode::Duration
3749 );
3750 }
3751
3752 #[test]
3753 fn test_get_xsd_primitive_type_date_time() {
3754 assert_eq!(
3756 get_xsd_primitive_type(XmlTypeCode::DateTime),
3757 XmlTypeCode::DateTime
3758 );
3759 assert_eq!(get_xsd_primitive_type(XmlTypeCode::Date), XmlTypeCode::Date);
3760 assert_eq!(get_xsd_primitive_type(XmlTypeCode::Time), XmlTypeCode::Time);
3761 assert_eq!(
3763 get_xsd_primitive_type(XmlTypeCode::DateTimeStamp),
3764 XmlTypeCode::DateTime
3765 );
3766 }
3767
3768 #[test]
3769 fn test_get_primitive_base_type_without_schema() {
3770 let primitive = get_primitive_base_type(None, None, XmlTypeCode::Integer);
3772 assert_eq!(primitive, XmlTypeCode::Decimal);
3773
3774 let primitive = get_primitive_base_type(None, None, XmlTypeCode::NCName);
3775 assert_eq!(primitive, XmlTypeCode::String);
3776 }
3777
3778 #[test]
3779 fn test_get_primitive_base_type_with_schema() {
3780 let schema_set = SchemaSet::new();
3782 let builtin_types = schema_set.builtin_types();
3783
3784 let primitive = get_primitive_base_type(
3786 Some(&schema_set),
3787 Some(builtin_types.integer),
3788 XmlTypeCode::Integer,
3789 );
3790 assert_eq!(primitive, XmlTypeCode::Decimal);
3791
3792 let primitive = get_primitive_base_type(
3794 Some(&schema_set),
3795 Some(builtin_types.string),
3796 XmlTypeCode::String,
3797 );
3798 assert_eq!(primitive, XmlTypeCode::String);
3799 }
3800
3801 #[test]
3802 fn test_magnitude_relationship_ctx_to_date() {
3803 let names = NameTable::new();
3805 let context = XPathContext::new(&names);
3806
3807 let untyped = XmlValue::untyped("2024-01-15");
3808 let typed = date_value(2024, 6, 1);
3809
3810 let (left, right) = magnitude_relationship_ctx(&context, &untyped, &typed).unwrap();
3811
3812 assert_eq!(left.type_code, XmlTypeCode::Date);
3813 assert_eq!(right.type_code, XmlTypeCode::Date);
3814 }
3815
3816 #[test]
3817 fn test_magnitude_relationship_ctx_to_boolean() {
3818 let names = NameTable::new();
3820 let context = XPathContext::new(&names);
3821
3822 let untyped = XmlValue::untyped("true");
3823 let typed = XmlValue::boolean(false);
3824
3825 let (left, right) = magnitude_relationship_ctx(&context, &untyped, &typed).unwrap();
3826
3827 assert_eq!(left.type_code, XmlTypeCode::Boolean);
3828 assert_eq!(left.as_boolean(), Some(true));
3829 assert_eq!(right.type_code, XmlTypeCode::Boolean);
3830 }
3831
3832 #[test]
3837 fn test_xpath10_eq_boolean_priority() {
3838 let left = XmlValue::string("1".to_string());
3840 let right = XmlValue::boolean(true);
3841 let (l, r) = coerce_for_comparison_10(BinaryOpKind::GeneralEq, &left, &right);
3842 assert_eq!(l.type_code, XmlTypeCode::Boolean);
3843 assert_eq!(r.type_code, XmlTypeCode::Boolean);
3844 assert!(compare_eq(&l, &r).unwrap());
3845 }
3846
3847 #[test]
3848 fn test_xpath10_eq_boolean_priority_empty_string() {
3849 let left = XmlValue::string("".to_string());
3851 let right = XmlValue::boolean(true);
3852 let (l, r) = coerce_for_comparison_10(BinaryOpKind::GeneralEq, &left, &right);
3853 assert_eq!(l.as_boolean(), Some(false));
3854 assert_eq!(r.as_boolean(), Some(true));
3855 assert!(!compare_eq(&l, &r).unwrap());
3856 }
3857
3858 #[test]
3859 fn test_xpath10_relational_numeric() {
3860 let left = XmlValue::string("3".to_string());
3862 let right = XmlValue::string("10".to_string());
3863 let (l, r) = coerce_for_comparison_10(BinaryOpKind::GeneralLt, &left, &right);
3864 assert_eq!(l.type_code, XmlTypeCode::Double);
3865 assert_eq!(r.type_code, XmlTypeCode::Double);
3866 assert!(compare_lt(&l, &r).unwrap());
3867 }
3868
3869 #[test]
3870 fn test_xpath10_eq_string_comparison() {
3871 let left = XmlValue::string("3".to_string());
3873 let right = XmlValue::string("10".to_string());
3874 let (l, r) = coerce_for_comparison_10(BinaryOpKind::GeneralEq, &left, &right);
3875 assert_eq!(l.type_code, XmlTypeCode::String);
3876 assert_eq!(r.type_code, XmlTypeCode::String);
3877 assert!(!compare_eq(&l, &r).unwrap());
3878 }
3879
3880 #[test]
3881 fn test_xpath10_eq_numeric_priority() {
3882 let left = XmlValue::string("3".to_string());
3884 let right = XmlValue::double(3.0);
3885 let (l, r) = coerce_for_comparison_10(BinaryOpKind::GeneralEq, &left, &right);
3886 assert_eq!(l.type_code, XmlTypeCode::Double);
3887 assert_eq!(r.type_code, XmlTypeCode::Double);
3888 assert!(compare_eq(&l, &r).unwrap());
3889 }
3890
3891 #[test]
3892 fn test_xpath10_arithmetic_returns_double() {
3893 let left = XmlValue::integer(BigInt::from(1));
3895 let right = XmlValue::integer(BigInt::from(2));
3896 let result = eval_numeric_binary_10(BinaryOpKind::Add, &left, &right).unwrap();
3897 assert_eq!(result.type_code, XmlTypeCode::Double);
3898 assert_eq!(result.as_double(), Some(3.0));
3899 }
3900
3901 #[test]
3902 fn test_xpath10_arithmetic_div_by_zero() {
3903 let left = XmlValue::double(1.0);
3904 let right = XmlValue::double(0.0);
3905 let result = eval_numeric_binary_10(BinaryOpKind::Div, &left, &right).unwrap();
3906 assert_eq!(result.as_double(), Some(f64::INFINITY));
3907 }
3908
3909 #[test]
3910 fn test_xpath10_arithmetic_mod() {
3911 let left = XmlValue::integer(BigInt::from(5));
3912 let right = XmlValue::integer(BigInt::from(3));
3913 let result = eval_numeric_binary_10(BinaryOpKind::Mod, &left, &right).unwrap();
3914 assert_eq!(result.type_code, XmlTypeCode::Double);
3915 assert_eq!(result.as_double(), Some(2.0));
3916 }
3917
3918 #[test]
3919 fn test_xpath10_general_eq_iter() {
3920 type Item = XmlItem<RoXmlNavigator<'static>>;
3922 let left_items: Vec<Item> = vec![XmlItem::Atomic(XmlValue::string("hello".to_string()))];
3923 let right_items: Vec<Item> = vec![XmlItem::Atomic(XmlValue::string("hello".to_string()))];
3924 let left_iter = VecNodeIterator::new(left_items);
3925 let right_iter = VecNodeIterator::new(right_items);
3926 assert!(general_eq_iter_10(&left_iter, &right_iter).unwrap());
3927 }
3928
3929 #[test]
3930 fn test_xpath10_general_ne_iter() {
3931 type Item = XmlItem<RoXmlNavigator<'static>>;
3932 let left_items: Vec<Item> = vec![XmlItem::Atomic(XmlValue::string("a".to_string()))];
3933 let right_items: Vec<Item> = vec![XmlItem::Atomic(XmlValue::string("b".to_string()))];
3934 let left_iter = VecNodeIterator::new(left_items);
3935 let right_iter = VecNodeIterator::new(right_items);
3936 assert!(general_ne_iter_10(&left_iter, &right_iter).unwrap());
3937 }
3938
3939 #[test]
3940 fn test_xpath10_general_lt_iter_numeric_coercion() {
3941 type Item = XmlItem<RoXmlNavigator<'static>>;
3943 let left_items: Vec<Item> = vec![XmlItem::Atomic(XmlValue::string("3".to_string()))];
3944 let right_items: Vec<Item> = vec![XmlItem::Atomic(XmlValue::string("10".to_string()))];
3945 let left_iter = VecNodeIterator::new(left_items);
3946 let right_iter = VecNodeIterator::new(right_items);
3947 assert!(general_lt_iter_10(&left_iter, &right_iter).unwrap());
3948 }
3949
3950 #[test]
3955 fn test_untyped_atomic_add() {
3956 let left = XmlValue::untyped("40");
3958 let right = int_value(XmlTypeCode::Integer, 1);
3959 let result = eval_binary(BinaryOpKind::Add, &left, &right).unwrap();
3960 assert_eq!(result.type_code, XmlTypeCode::Double);
3961 assert_eq!(result.as_double().unwrap(), 41.0);
3962 }
3963
3964 #[test]
3965 fn test_untyped_atomic_both_sides() {
3966 let left = XmlValue::untyped("40");
3968 let right = XmlValue::untyped("40");
3969 let result = eval_binary(BinaryOpKind::Add, &left, &right).unwrap();
3970 assert_eq!(result.type_code, XmlTypeCode::Double);
3971 assert_eq!(result.as_double().unwrap(), 80.0);
3972 }
3973
3974 #[test]
3975 fn test_untyped_atomic_div() {
3976 let left = XmlValue::untyped("40");
3978 let right = int_value(XmlTypeCode::Integer, 2);
3979 let result = eval_binary(BinaryOpKind::Div, &left, &right).unwrap();
3980 assert_eq!(result.type_code, XmlTypeCode::Double);
3981 assert_eq!(result.as_double().unwrap(), 20.0);
3982 }
3983
3984 #[test]
3985 fn test_untyped_atomic_negate() {
3986 let value = XmlValue::untyped("42");
3988 let result = eval_unary(UnaryOpKind::Negate, &value).unwrap();
3989 assert_eq!(result.type_code, XmlTypeCode::Double);
3990 assert_eq!(result.as_double().unwrap(), -42.0);
3991 }
3992
3993 #[test]
3994 fn test_untyped_atomic_non_numeric_fails() {
3995 let left = XmlValue::untyped("abc");
3997 let right = int_value(XmlTypeCode::Integer, 1);
3998 assert!(eval_binary(BinaryOpKind::Add, &left, &right).is_err());
3999 }
4000}