use std::error::Error;
use std::fmt;
use std::f64;
use std::i64;
use std::ops::Neg;
use std::ops::Rem;
use std::str::FromStr;
use dom::*;
use xmlerror::*;
use xpath_impl::parser::*;
use xpath_impl::xsequence::*;
fn atof(s: &str) -> f64 {
return f64::from_str(s.trim()).unwrap_or(f64::NAN);
}
fn atoi(s: &str) -> i64 {
return i64::from_str(s.trim()).unwrap_or(0);
}
fn f64_to_i64(f: f64) -> i64 {
return f as i64;
}
fn i64_to_f64(n: i64) -> f64 {
return n as f64;
}
fn int_to_dec(n: i64) -> f64 { return atof(&format!("{}.0", n));
}
fn dec_to_dbl(n: f64) -> f64 { return n;
}
fn int_to_dbl(n: i64) -> f64 { return atof(&format!("{}.0", n));
}
#[derive(Debug, PartialEq, Clone)]
pub enum XItem {
XItemXNodePtr {
value: XNodePtr,
},
XIMap {
value: XSeqMap,
},
XIArray {
value: XSeqArray,
},
XINode {
value: NodePtr,
},
XIString {
value: String,
},
XIInteger {
value: i64,
},
XIDecimal {
value: f64,
},
XIDouble {
value: f64,
},
XIBoolean {
value: bool,
},
}
#[derive(Debug, PartialEq, Clone)]
pub struct XSeqMap {
v: Vec<(XItem, XSequence)>,
}
impl fmt::Display for XSeqMap {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut s = String::from("{");
for (i, v) in self.v.iter().enumerate() {
if i != 0 {
s += &", ";
}
s += &format!("{} => {}", v.0, v.1);
}
s += &"}";
return write!(f, "{}", s);
}
}
impl XSeqMap {
pub fn map_size(&self) -> usize {
return self.v.len();
}
pub fn map_keys(&self) -> Vec<XItem> {
let mut result: Vec<XItem> = vec!{};
for entry in self.v.iter() {
result.push(entry.0.clone());
}
return result;
}
pub fn map_contains(&self, key: &XItem) -> bool {
for entry in self.v.iter() {
if entry.0.op_same_key(key) {
return true;
}
}
return false;
}
pub fn map_get(&self, key: &XItem) -> Option<XSequence> {
for entry in self.v.iter() {
if entry.0.op_same_key(key) {
return Some(entry.1.clone());
}
}
return None;
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct XSeqArray {
v: Vec<XSequence>,
}
impl fmt::Display for XSeqArray {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut s = String::from("[");
for (i, v) in self.v.iter().enumerate() {
if i != 0 {
s += &", ";
}
s += &format!("{}", v);
}
s += &"]";
return write!(f, "{}", s);
}
}
impl XSeqArray {
pub fn array_size(&self) -> usize {
return self.v.len();
}
pub fn array_get(&self, index: &XItem) -> Option<XSequence> {
let i = index.get_as_raw_integer();
match i {
Ok(i) => {
if 1 <= i && i <= self.v.len() as i64 {
return Some(self.v[(i - 1) as usize].clone());
}
},
_ => {},
}
return None;
}
pub fn array_flatten(&self) -> XSequence {
let mut result = new_xsequence();
for xseq in self.v.iter() {
for xitem in xseq.iter() {
match xitem {
XItem::XIArray{value} => {
result.append(&value.array_flatten());
},
_ => {
result.push(xitem);
}
}
}
}
return result;
}
}
pub fn new_xitem_xnodeptr(xnode: &XNodePtr) -> XItem {
return XItem::XItemXNodePtr {
value: xnode.clone(),
}
}
pub fn new_xitem_node(node: &NodePtr) -> XItem {
return XItem::XINode {
value: node.rc_clone(),
};
}
pub fn new_xitem_map(value: &Vec<(XItem, XSequence)>) -> XItem {
return XItem::XIMap {
value: XSeqMap {
v: value.clone(),
},
};
}
pub fn new_xitem_array(value: &Vec<XSequence>) -> XItem {
return XItem::XIArray{
value: XSeqArray {
v: value.clone(),
},
};
}
pub fn new_xitem_string(value: &str) -> XItem {
return XItem::XIString{value: value.to_string()};
}
pub fn new_xitem_integer(value: i64) -> XItem {
return XItem::XIInteger{value};
}
pub fn new_xitem_decimal(value: f64) -> XItem {
return XItem::XIDecimal{value};
}
pub fn new_xitem_double(value: f64) -> XItem {
return XItem::XIDouble{value};
}
pub fn new_xitem_boolean(value: bool) -> XItem {
return XItem::XIBoolean{value};
}
impl NodePtr {
fn string_value(&self) -> String {
match self.node_type() {
NodeType::DocumentRoot | NodeType::Element => {
let mut s = String::new();
for ch in self.children().iter() {
s += &ch.string_value();
}
return s;
},
NodeType::Text | NodeType::Attribute | NodeType::Comment => {
return format!("{}", self.value());
},
NodeType::XMLDecl | NodeType::Instruction => {
return format!("{} {}", self.name(), self.value());
},
_ => return String::new(),
}
}
fn typed_value(&self) -> String {
match self.node_type() {
NodeType::Text => { return format!("{}", self.value());
},
NodeType::DocumentRoot => { let mut s = String::new();
for ch in self.children().iter() {
s += &ch.typed_value();
}
return s;
},
NodeType::Comment => { return format!("{}", self.value());
},
NodeType::Instruction => { return format!("{} {}", self.name(), self.value());
},
NodeType::Attribute => { return format!("{}", self.value());
},
NodeType::Element => { let mut s = String::new();
for ch in self.children().iter() {
s += &ch.typed_value();
}
return s;
},
_ => return String::new(),
}
}
}
impl fmt::Display for XItem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
XItem::XINode{value} => {
return write!(f, "{}", value);
},
XItem::XIString{value} => {
return write!(f, r#""{}""#, value);
},
XItem::XIInteger{value} => {
return write!(f, "{}", value);
},
XItem::XIDecimal{value} => {
let mut s = String::from(format!("{}", value));
if ! s.contains(".") {
s += &".0";
}
return write!(f, "{}", s);
},
XItem::XIDouble{value} => {
if value.is_nan() {
return write!(f, "NaN");
} else if value.is_infinite() {
if value.signum() == 1.0 {
return write!(f, "+Infinity");
} else {
return write!(f, "-Infinity");
}
} else if *value == 0.0 && value.signum() == -1.0 {
return write!(f, "-0e0");
} else {
return write!(f, "{:e}", value);
}
},
XItem::XIBoolean{value} => {
if *value == true {
return write!(f, "true");
} else {
return write!(f, "false");
}
},
XItem::XItemXNodePtr{value} => {
return write!(f, "{}", value);
},
XItem::XIMap{value} => {
return write!(f, "{}", value);
},
XItem::XIArray{value} => {
return write!(f, "{}", value);
},
}
}
}
impl XItem {
pub fn xs_type(&self) -> String {
match self {
XItem::XItemXNodePtr{value: _} => return String::from("function(*)"),
XItem::XIMap{value: _} => return String::from("map(*)"),
XItem::XIArray{value: _} => return String::from("array(*)"),
XItem::XINode{value: _} => return String::from("node"),
XItem::XIString{value: _} => return String::from("xs:string"),
XItem::XIInteger{value: _} => return String::from("xs:integer"),
XItem::XIDecimal{value: _} => return String::from("xs:decimal"),
XItem::XIDouble{value: _} => return String::from("xs:double"),
XItem::XIBoolean{value: _} => return String::from("xs:boolean"),
}
}
pub fn as_nodeptr(&self) -> Option<NodePtr> {
match self {
XItem::XINode{value} => return Some(value.rc_clone()),
_ => return None,
}
}
pub fn atomize(&self) -> XItem {
match self {
XItem::XINode{value} => {
return XItem::XIString {
value: value.typed_value(),
}
},
_ => return self.clone(),
}
}
pub fn is_item(&self) -> bool {
match self {
XItem::XItemXNodePtr{value: _} => return false,
_ => return true,
}
}
pub fn is_numeric(&self) -> bool {
match self {
XItem::XIInteger{value: _} => return true,
XItem::XIDecimal{value: _} => return true,
XItem::XIDouble{value: _} => return true,
_ => return false,
}
}
pub fn op_same_key(&self, other: &XItem) -> bool {
let k1 = self.get_as_raw_string();
if let Err(_) = k1 {
return false;
}
let k1 = k1.unwrap();
let k2 = other.get_as_raw_string();
if let Err(_) = k2 {
return false;
}
let k2 = k2.unwrap();
return k1 == k2;
}
pub fn castable_as(&self, type_name: &str) -> bool {
match self.cast_as(type_name) {
Ok(_) => return true,
Err(_) => return false,
}
}
pub fn cast_as(&self, type_name: &str) -> Result<XItem, Box<Error>> {
match type_name {
"string" | "xs:string" => {
if let Ok(s) = self.get_as_raw_string() {
return Ok(new_xitem_string(&s));
}
},
"double" | "xs:double" => {
if let Ok(d) = self.get_as_raw_double() {
return Ok(new_xitem_double(d));
}
},
"decimal" | "xs:decimal" => {
if let Ok(d) = self.get_as_raw_decimal() {
return Ok(new_xitem_decimal(d));
}
},
"integer" | "xs:integer" => {
if let Ok(i) = self.get_as_raw_integer() {
return Ok(new_xitem_integer(i));
}
},
"boolean" | "xs:boolean" => {
if let Ok(b) = self.get_as_raw_boolean() {
return Ok(new_xitem_boolean(b));
}
},
_ => {},
}
return Err(type_error!("Item {}: can't cast to {}",
self.to_string(), type_name));
}
pub fn get_as_raw_xnodeptr(&self) -> Result<XNodePtr, Box<Error>> {
match self {
XItem::XItemXNodePtr{value} => {
return Ok(value.clone());
},
_ => {
return Err(type_error!("Item is not XItemXNodePtr"));
},
}
}
pub fn get_as_raw_map(&self) -> Result<XSeqMap, Box<Error>> {
match self {
XItem::XIMap{value} => {
return Ok(value.clone());
},
_ => {
return Err(type_error!("Item is not XSeqMap"));
},
}
}
pub fn get_as_raw_array(&self) -> Result<XSeqArray, Box<Error>> {
match self {
XItem::XIArray{value} => {
return Ok(value.clone());
},
_ => {
return Err(type_error!("Item is not XSeqArray"));
},
}
}
pub fn get_as_raw_string(&self) -> Result<String, Box<Error>> {
match self {
XItem::XINode{value} => {
return Ok(value.string_value());
},
XItem::XIString{value} => {
return Ok(value.clone());
},
XItem::XIInteger{value} => {
return Ok(String::from(format!("{}", value)));
},
XItem::XIDecimal{value} => {
return Ok(String::from(format!("{}", value)));
},
XItem::XIDouble{value} => {
if value.is_nan() {
return Ok(String::from("NaN"));
} else if value.is_infinite() {
if value.signum() == 1.0 {
return Ok(String::from("+Infinity"));
} else {
return Ok(String::from("-Infinity"));
}
} else {
return Ok(String::from(format!("{}", value)));
}
},
XItem::XIBoolean{value} => {
if *value == true {
return Ok(String::from("true"));
} else {
return Ok(String::from("false"));
}
},
_ => {},
}
return Err(type_error!(
"Item {}: can't cast to string", self.to_string()));
}
pub fn get_as_raw_double(&self) -> Result<f64, Box<Error>> {
match self {
XItem::XINode{value} => {
return Ok(atof(&value.string_value()));
},
XItem::XIString{ref value} => {
return Ok(atof(value.as_str()));
},
XItem::XIInteger{ref value} => {
return Ok(i64_to_f64(*value));
},
XItem::XIDecimal{ref value} => {
return Ok(*value);
},
XItem::XIDouble{ref value} => {
return Ok(*value);
},
XItem::XIBoolean{value} => {
return Ok(if *value == true { 1.0 } else { 0.0 });
},
_ => {},
}
return Err(type_error!(
"Item {}: can't cast to double", self.to_string()));
}
pub fn get_as_raw_decimal(&self) -> Result<f64, Box<Error>> {
match self {
XItem::XINode{value} => {
return Ok(atof(&value.string_value()));
},
XItem::XIString{ref value} => {
return Ok(atof(value.as_str()));
},
XItem::XIInteger{ref value} => {
return Ok(i64_to_f64(*value));
},
XItem::XIDecimal{ref value} => {
return Ok(*value);
},
XItem::XIDouble{ref value} => {
return Ok(*value);
},
XItem::XIBoolean{value} => {
return Ok(if *value == true { 1.0 } else { 0.0 });
},
_ => {},
}
return Err(type_error!(
"Item {}: can't cast to decimal", self.to_string()));
}
pub fn get_as_raw_integer(&self) -> Result<i64, Box<Error>> {
match self {
XItem::XINode{value} => {
return Ok(atoi(&value.string_value()));
},
XItem::XIInteger{value} => return Ok(*value),
XItem::XIString{value} => {
return Ok(atoi(value));
},
XItem::XIDecimal{value} => return Ok(f64_to_i64(*value)),
XItem::XIDouble{value} => return Ok(f64_to_i64(*value)),
XItem::XIBoolean{value} => {
if *value == true {
return Ok(1);
} else {
return Ok(0);
}
},
_ => {},
}
return Err(type_error!(
"Item {}: can't cast to integer", self.to_string()));
}
pub fn get_as_raw_boolean(&self) -> Result<bool, Box<Error>> {
match self {
XItem::XINode{value} => {
match value.string_value().as_str() {
"true" | "1" => return Ok(true),
"false" | "0" => return Ok(false),
_ => {},
}
},
XItem::XIInteger{value} => return Ok(*value != 0),
XItem::XIString{value} => {
match value.as_str() {
"true" | "1" => return Ok(true),
"false" | "0" => return Ok(false),
_ => {},
}
},
XItem::XIDecimal{value} => {
if *value == 0.0 || value.is_nan() {
return Ok(false);
} else {
return Ok(true);
}
},
XItem::XIDouble{value} => {
if *value == 0.0 || value.is_nan() {
return Ok(false);
} else {
return Ok(true);
}
},
XItem::XIBoolean{value} => {
return Ok(*value);
},
_ => {},
}
return Err(type_error!(
"Item {}: can't cast to boolean", self.to_string()));
}
}
pub fn xitem_compare(lhs: &XItem, rhs: &XItem) -> Result<i64, Box<Error>> {
match lhs {
XItem::XIString{value: lhs} => {
match rhs {
XItem::XIString{value: rhs} => {
if lhs < rhs {
return Ok(-1);
} else if lhs == rhs {
return Ok(0);
} else {
return Ok(1);
}
},
_ => {},
}
},
_ => {},
}
return Err(type_error!("xitem_compare: Not string"));
}
pub fn xitem_numeric_add(lhs: &XItem, rhs: &XItem) -> Result<XItem, Box<Error>> {
return xitem_numeric_operation(lhs, rhs,
|a, b| { a + b },
|a, b| { a + b },
|a, b| { a + b });
}
pub fn xitem_numeric_subtract(lhs: &XItem, rhs: &XItem) -> Result<XItem, Box<Error>> {
return xitem_numeric_operation(lhs, rhs,
|a, b| { a - b },
|a, b| { a - b },
|a, b| { a - b });
}
pub fn xitem_numeric_multiply(lhs: &XItem, rhs: &XItem) -> Result<XItem, Box<Error>> {
return xitem_numeric_operation(lhs, rhs,
|a, b| { a * b },
|a, b| { a * b },
|a, b| { a * b });
}
pub fn xitem_numeric_divide(lhs: &XItem, rhs: &XItem) -> Result<XItem, Box<Error>> {
let rhs_a = match rhs {
XItem::XIInteger{value: rhs} => {
if *rhs == 0 {
return Err(dynamic_error!("Division by zero"));
}
new_xitem_decimal(i64_to_f64(*rhs))
},
XItem::XIDecimal{value: rhs} => {
if *rhs == 0.0 {
return Err(dynamic_error!("Division by zero"));
}
new_xitem_decimal(*rhs)
},
XItem::XIDouble{value: rhs} => new_xitem_double(*rhs),
_ => return Err(cant_occur!("xitem_numeric_divide: rhs_a")),
};
return xitem_numeric_operation(lhs, &rhs_a,
|a, b| { a / b },
|a, b| { a / b },
|a, b| { a / b });
}
pub fn xitem_numeric_integer_divide(lhs: &XItem, rhs: &XItem) -> Result<XItem, Box<Error>> {
match lhs {
XItem::XIDouble{value} => {
if value.is_nan() {
return Err(dynamic_error!("Numeric operation overflow/underflow."));
}
if ! value.is_finite() {
return Err(dynamic_error!("Numeric operation overflow/underflow."));
}
},
_ => {},
}
match rhs {
XItem::XIDouble{value} => {
if value.is_nan() {
return Err(dynamic_error!("Numeric operation overflow/underflow."));
}
},
_ => {},
}
let lhs = match lhs {
XItem::XIInteger{value} => *value,
XItem::XIDecimal{value} => f64_to_i64(*value),
XItem::XIDouble{value} => f64_to_i64(*value),
_ => 0,
};
let rhs = match rhs {
XItem::XIInteger{value} => *value,
XItem::XIDecimal{value} => f64_to_i64(*value),
XItem::XIDouble{value} => f64_to_i64(*value),
_ => 0,
};
if rhs != 0 {
return Ok(new_xitem_integer(lhs / rhs));
} else {
return Err(dynamic_error!("Division by zero"));
}
}
pub fn xitem_numeric_mod(lhs: &XItem, rhs: &XItem) -> Result<XItem, Box<Error>> {
match rhs {
XItem::XIInteger{value: rhs} => {
if *rhs == 0 {
return Err(dynamic_error!("Division by zero"));
}
},
XItem::XIDecimal{value: rhs} => {
if *rhs == 0.0 {
return Err(dynamic_error!("Division by zero"));
}
},
_ => {},
}
return xitem_numeric_operation(lhs, rhs,
|a, b| { a.rem(b) },
|a, b| { a.rem(b) },
|a, b| { a.rem(b) });
}
pub fn xitem_numeric_unary_plus(arg: &XItem) -> Result<XItem, Box<Error>> {
match arg {
XItem::XIInteger{value} => return Ok(new_xitem_integer(*value)),
XItem::XIDecimal{value} => return Ok(new_xitem_decimal(*value)),
XItem::XIDouble{value} => return Ok(new_xitem_double(*value)),
_ => return Err(type_error!("xitem_numeric_operation: Not numeric")),
}
}
pub fn xitem_numeric_unary_minus(arg: &XItem) -> Result<XItem, Box<Error>> {
match arg {
XItem::XIInteger{value} => return Ok(new_xitem_integer(value.neg())),
XItem::XIDecimal{value} => return Ok(new_xitem_decimal(value.neg())),
XItem::XIDouble{value} => return Ok(new_xitem_double(value.neg())),
_ => return Err(type_error!("xitem_numeric_operation: Not numeric")),
}
}
fn xitem_numeric_operation<FINT, FDEC, FDBL>(lhs: &XItem, rhs: &XItem,
mut int_op: FINT, mut dec_op: FDEC, mut dbl_op: FDBL) -> Result<XItem, Box<Error>>
where FINT: FnMut(i64, i64) -> i64,
FDEC: FnMut(f64, f64) -> f64,
FDBL: FnMut(f64, f64) -> f64 {
match lhs {
XItem::XIInteger{value: lhs} => {
match rhs {
XItem::XIInteger{value: rhs} => {
return Ok(new_xitem_integer(int_op(*lhs, *rhs)));
},
XItem::XIDecimal{value: rhs} => {
return Ok(new_xitem_decimal(dec_op(int_to_dec(*lhs), *rhs)));
},
XItem::XIDouble{value: rhs} => {
return Ok(new_xitem_double(dbl_op(int_to_dbl(*lhs), *rhs)));
},
_ => {},
}
},
XItem::XIDecimal{value: lhs} => {
match rhs {
XItem::XIInteger{value: rhs} => {
return Ok(new_xitem_decimal(dec_op(*lhs, int_to_dec(*rhs))));
},
XItem::XIDecimal{value: rhs} => {
return Ok(new_xitem_decimal(dec_op(*lhs, *rhs)));
},
XItem::XIDouble{value: rhs} => {
return Ok(new_xitem_double(dec_op(dec_to_dbl(*lhs), *rhs)));
},
_ => {},
}
},
XItem::XIDouble{value: lhs} => {
match rhs {
XItem::XIInteger{value: rhs} => {
return Ok(new_xitem_double(dbl_op(*lhs, int_to_dbl(*rhs))));
},
XItem::XIDecimal{value: rhs} => {
return Ok(new_xitem_double(dbl_op(*lhs, dec_to_dbl(*rhs))));
},
XItem::XIDouble{value: rhs} => {
return Ok(new_xitem_double(dbl_op(*lhs, *rhs)));
},
_ => {},
}
},
_ => {},
}
return Err(type_error!("xitem_numeric_operation: Not numeric"));
}
pub fn xitem_numeric_equal(lhs: &XItem, rhs: &XItem) -> Result<bool, Box<Error>> {
return xitem_numeric_comparison(lhs, rhs,
|a, b| { a == b },
|a, b| { a == b },
|a, b| { a == b });
}
pub fn xitem_numeric_less_than(lhs: &XItem, rhs: &XItem) -> Result<bool, Box<Error>> {
return xitem_numeric_comparison(lhs, rhs,
|a, b| { a < b },
|a, b| { a < b },
|a, b| { a < b });
}
pub fn xitem_numeric_greater_than(lhs: &XItem, rhs: &XItem) -> Result<bool, Box<Error>> {
return xitem_numeric_comparison(lhs, rhs,
|a, b| { a > b },
|a, b| { a > b },
|a, b| { a > b });
}
fn xitem_numeric_comparison<FINT, FDEC, FDBL>(lhs: &XItem, rhs: &XItem,
mut int_op: FINT, mut dec_op: FDEC, mut dbl_op: FDBL) -> Result<bool, Box<Error>>
where FINT: FnMut(i64, i64) -> bool,
FDEC: FnMut(f64, f64) -> bool,
FDBL: FnMut(f64, f64) -> bool {
match lhs {
XItem::XIInteger{value: lhs} => {
match rhs {
XItem::XIInteger{value: rhs} => {
return Ok(int_op(*lhs, *rhs));
},
XItem::XIDecimal{value: rhs} => {
return Ok(dec_op(int_to_dec(*lhs), *rhs));
},
XItem::XIDouble{value: rhs} => {
return Ok(dbl_op(int_to_dbl(*lhs), *rhs));
},
_ => {},
}
},
XItem::XIDecimal{value: lhs} => {
match rhs {
XItem::XIInteger{value: rhs} => {
return Ok(dec_op(*lhs, int_to_dec(*rhs)));
},
XItem::XIDecimal{value: rhs} => {
return Ok(dec_op(*lhs, *rhs));
},
XItem::XIDouble{value: rhs} => {
return Ok(dbl_op(dec_to_dbl(*lhs), *rhs));
},
_ => {},
}
},
XItem::XIDouble{value: lhs} => {
match rhs {
XItem::XIInteger{value: rhs} => {
return Ok(dbl_op(*lhs, int_to_dbl(*rhs)));
},
XItem::XIDecimal{value: rhs} => {
return Ok(dbl_op(*lhs, dec_to_dbl(*rhs)));
},
XItem::XIDouble{value: rhs} => {
return Ok(dbl_op(*lhs, *rhs));
},
_ => {},
}
},
_ => {},
}
return Err(type_error!("xitem_numeric_comparison: Not numeric"));
}
pub fn xitem_boolean_equal(lhs: &XItem, rhs: &XItem) -> Result<bool, Box<Error>> {
if let XItem::XIBoolean{value: lhs} = lhs {
if let XItem::XIBoolean{value: rhs} = rhs {
return Ok(*lhs == *rhs);
}
}
return Err(type_error!("xitem_boolean_equal: Not boolean"));
}
pub fn xitem_boolean_less_than(lhs: &XItem, rhs: &XItem) -> Result<bool, Box<Error>> {
if let XItem::XIBoolean{value: lhs} = lhs {
if let XItem::XIBoolean{value: rhs} = rhs {
return Ok(*lhs == false && *rhs == true);
}
}
return Err(type_error!("xitem_boolean_less_than: Not boolean"));
}
pub fn xitem_boolean_greater_than(lhs: &XItem, rhs: &XItem) -> Result<bool, Box<Error>> {
if let XItem::XIBoolean{value: lhs} = lhs {
if let XItem::XIBoolean{value: rhs} = rhs {
return Ok(*lhs == true && *rhs == false);
}
}
return Err(type_error!("xitem_boolean_greater_than: Not boolean"));
}