use std::{borrow::Cow, ffi::c_void};
use crate::{generic_error, tree::XmlGenericNodePtr, xpointer::XmlLocationSet};
use super::{
XML_XPATH_NAN, XmlNodeSet, xml_xpath_cast_boolean_to_number, xml_xpath_cast_boolean_to_string,
xml_xpath_cast_node_set_to_boolean, xml_xpath_cast_node_set_to_number,
xml_xpath_cast_node_set_to_string, xml_xpath_cast_number_to_boolean,
xml_xpath_cast_number_to_string, xml_xpath_cast_string_to_boolean,
xml_xpath_cast_string_to_number, xml_xpath_free_node_set, xml_xpath_free_value_tree,
xml_xpath_node_set_create, xml_xpath_node_set_merge,
};
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum XmlXPathObjectType {
#[default]
XPathUndefined = 0,
XPathNodeset = 1,
XPathBoolean = 2,
XPathNumber = 3,
XPathString = 4,
#[cfg(feature = "libxml_xptr_locs")]
XPathPoint = 5,
#[cfg(feature = "libxml_xptr_locs")]
XPathRange = 6,
#[cfg(feature = "libxml_xptr_locs")]
XPathLocationset = 7,
XPathUsers = 8,
XPathXSLTTree = 9,
}
#[repr(C)]
#[derive(Clone, PartialEq)]
pub struct XmlXPathObject {
pub typ: XmlXPathObjectType,
pub nodesetval: Option<Box<XmlNodeSet>>,
pub boolval: bool,
pub floatval: f64,
pub stringval: Option<String>,
pub(crate) user: Option<XmlXPathObjectUserData>,
pub(crate) index: i32,
pub(crate) user2: Option<XmlXPathObjectUserData>,
pub(crate) index2: i32,
}
impl Default for XmlXPathObject {
fn default() -> Self {
Self {
typ: XmlXPathObjectType::default(),
nodesetval: None,
boolval: false,
floatval: 0.0,
stringval: None,
user: None,
index: 0,
user2: None,
index2: 0,
}
}
}
impl Drop for XmlXPathObject {
#[doc(alias = "xmlXPathFreeObject")]
fn drop(&mut self) {
if matches!(
self.typ,
XmlXPathObjectType::XPathNodeset | XmlXPathObjectType::XPathXSLTTree
) {
if self.boolval {
self.typ = XmlXPathObjectType::XPathXSLTTree; xml_xpath_free_value_tree(self.nodesetval.take());
} else if let Some(set) = self.nodesetval.take() {
xml_xpath_free_node_set(Some(set));
}
} else if matches!(self.typ, XmlXPathObjectType::XPathString) && self.stringval.is_some() {
let _ = self.stringval.take();
} else {
#[cfg(feature = "libxml_xptr_locs")]
let _ = self.user.take();
}
}
}
impl From<&str> for XmlXPathObject {
fn from(value: &str) -> Self {
let mut ret = Self::default();
ret.typ = XmlXPathObjectType::XPathString;
ret.stringval = Some(value.to_owned());
ret
}
}
impl From<String> for XmlXPathObject {
fn from(value: String) -> Self {
let mut ret = Self::default();
ret.typ = XmlXPathObjectType::XPathString;
ret.stringval = Some(value);
ret
}
}
impl From<f64> for XmlXPathObject {
fn from(value: f64) -> Self {
let mut ret = Self::default();
ret.typ = XmlXPathObjectType::XPathNumber;
ret.floatval = value;
ret
}
}
impl From<bool> for XmlXPathObject {
fn from(value: bool) -> Self {
let mut ret = Self::default();
ret.typ = XmlXPathObjectType::XPathBoolean;
ret.boolval = value;
ret
}
}
#[derive(Clone, PartialEq)]
pub enum XmlXPathObjectUserData {
Node(XmlGenericNodePtr),
LocationSet(XmlLocationSet),
External(*mut c_void),
}
impl XmlXPathObjectUserData {
pub fn as_node(&self) -> Option<&XmlGenericNodePtr> {
match self {
Self::Node(node) => Some(node),
_ => None,
}
}
pub fn as_location_set(&self) -> Option<&XmlLocationSet> {
match self {
Self::LocationSet(loc) => Some(loc),
_ => None,
}
}
pub fn as_location_set_mut(&mut self) -> Option<&mut XmlLocationSet> {
match self {
Self::LocationSet(loc) => Some(loc),
_ => None,
}
}
pub fn as_external(&self) -> Option<&*mut c_void> {
match self {
Self::External(external) => Some(external),
_ => None,
}
}
}
#[doc(
alias = "xmlXPathNewCString",
alias = "xmlXPathNewString",
alias = "xmlXPathCacheNewString",
alias = "xmlXPathCacheNewCString"
)]
pub fn xml_xpath_new_string(val: Option<&str>) -> XmlXPathObject {
XmlXPathObject::from(val.unwrap_or(""))
}
#[doc(
alias = "xmlXPathWrapString",
alias = "xmlXPathWrapCString",
alias = "xmlXPathCacheWrapString"
)]
pub fn xml_xpath_wrap_string(val: Option<&str>) -> XmlXPathObject {
let mut ret = XmlXPathObject::default();
ret.typ = XmlXPathObjectType::XPathString;
ret.stringval = val.map(|s| s.to_owned());
ret
}
#[doc(alias = "xmlXPathNewFloat", alias = "xmlXPathCacheNewFloat")]
pub fn xml_xpath_new_float(val: f64) -> XmlXPathObject {
XmlXPathObject::from(val)
}
#[doc(alias = "xmlXPathNewBoolean", alias = "xmlXPathCacheNewBoolean")]
pub fn xml_xpath_new_boolean(val: bool) -> XmlXPathObject {
XmlXPathObject::from(val)
}
#[doc(alias = "xmlXPathNewNodeSet", alias = "xmlXPathCacheNewNodeSet")]
pub fn xml_xpath_new_node_set(val: Option<XmlGenericNodePtr>) -> XmlXPathObject {
let mut ret = XmlXPathObject::default();
ret.typ = XmlXPathObjectType::XPathNodeset;
ret.boolval = false;
ret.nodesetval = xml_xpath_node_set_create(val);
ret
}
#[doc(alias = "xmlXPathWrapNodeSet", alias = "xmlXPathCacheWrapNodeSet")]
pub fn xml_xpath_wrap_node_set(val: Option<Box<XmlNodeSet>>) -> XmlXPathObject {
let mut ret = XmlXPathObject::default();
ret.typ = XmlXPathObjectType::XPathNodeset;
ret.nodesetval = val;
ret
}
#[doc(alias = "xmlXPathNewValueTree")]
pub fn xml_xpath_new_value_tree(val: Option<XmlGenericNodePtr>) -> XmlXPathObject {
let mut ret = XmlXPathObject::default();
ret.typ = XmlXPathObjectType::XPathXSLTTree;
ret.boolval = true;
ret.user = val.map(XmlXPathObjectUserData::Node);
ret.nodesetval = xml_xpath_node_set_create(val);
ret
}
#[doc(alias = "xmlXPathWrapExternal")]
pub fn xml_xpath_wrap_external(val: *mut c_void) -> XmlXPathObject {
let mut ret = XmlXPathObject::default();
ret.typ = XmlXPathObjectType::XPathUsers;
ret.user = (!val.is_null()).then_some(XmlXPathObjectUserData::External(val));
ret
}
#[doc(alias = "xmlXPathObjectCopy", alias = "xmlXPathCacheObjectCopy")]
pub fn xml_xpath_object_copy(val: &XmlXPathObject) -> XmlXPathObject {
let mut ret = val.clone();
match val.typ {
XmlXPathObjectType::XPathBoolean | XmlXPathObjectType::XPathNumber => {}
#[cfg(feature = "libxml_xptr_locs")]
XmlXPathObjectType::XPathPoint | XmlXPathObjectType::XPathRange => {}
XmlXPathObjectType::XPathString => {}
XmlXPathObjectType::XPathXSLTTree | XmlXPathObjectType::XPathNodeset => {
ret.nodesetval = xml_xpath_node_set_merge(None, val.nodesetval.as_deref());
ret.boolval = false;
}
#[cfg(feature = "libxml_xptr_locs")]
XmlXPathObjectType::XPathLocationset => {
}
XmlXPathObjectType::XPathUsers => {
ret.user = val.user.clone();
}
XmlXPathObjectType::XPathUndefined => {
generic_error!("xmlXPathObjectCopy: unsupported type {}\n", val.typ as i32);
} }
ret
}
#[doc(alias = "xmlXPathCastToBoolean")]
pub fn xml_xpath_cast_to_boolean(val: &XmlXPathObject) -> bool {
match val.typ {
XmlXPathObjectType::XPathUndefined => false,
XmlXPathObjectType::XPathNodeset | XmlXPathObjectType::XPathXSLTTree => {
xml_xpath_cast_node_set_to_boolean(val.nodesetval.as_deref())
}
XmlXPathObjectType::XPathString => {
xml_xpath_cast_string_to_boolean(val.stringval.as_deref())
}
XmlXPathObjectType::XPathNumber => xml_xpath_cast_number_to_boolean(val.floatval),
XmlXPathObjectType::XPathBoolean => val.boolval,
XmlXPathObjectType::XPathUsers => {
false
}
#[cfg(feature = "libxml_xptr_locs")]
XmlXPathObjectType::XPathPoint
| XmlXPathObjectType::XPathRange
| XmlXPathObjectType::XPathLocationset => {
false
}
}
}
#[doc(alias = "xmlXPathCastToNumber")]
pub fn xml_xpath_cast_to_number(val: &mut XmlXPathObject) -> f64 {
match val.typ {
XmlXPathObjectType::XPathUndefined => XML_XPATH_NAN,
XmlXPathObjectType::XPathNodeset | XmlXPathObjectType::XPathXSLTTree => {
xml_xpath_cast_node_set_to_number(val.nodesetval.as_deref_mut())
}
XmlXPathObjectType::XPathString => {
let strval = val.stringval.as_deref();
xml_xpath_cast_string_to_number(strval)
}
XmlXPathObjectType::XPathNumber => val.floatval,
XmlXPathObjectType::XPathBoolean => xml_xpath_cast_boolean_to_number(val.boolval),
XmlXPathObjectType::XPathUsers => {
XML_XPATH_NAN
}
#[cfg(feature = "libxml_xptr_locs")]
XmlXPathObjectType::XPathPoint
| XmlXPathObjectType::XPathRange
| XmlXPathObjectType::XPathLocationset => {
XML_XPATH_NAN
}
}
}
#[doc(alias = "xmlXPathCastToString")]
pub fn xml_xpath_cast_to_string(val: &mut XmlXPathObject) -> Cow<'static, str> {
match val.typ {
XmlXPathObjectType::XPathUndefined => "".into(),
XmlXPathObjectType::XPathNodeset | XmlXPathObjectType::XPathXSLTTree => {
xml_xpath_cast_node_set_to_string(val.nodesetval.as_deref_mut())
}
XmlXPathObjectType::XPathString => val.stringval.clone().unwrap().into(),
XmlXPathObjectType::XPathBoolean => xml_xpath_cast_boolean_to_string(val.boolval).into(),
XmlXPathObjectType::XPathNumber => xml_xpath_cast_number_to_string(val.floatval),
XmlXPathObjectType::XPathUsers => {
"".into()
}
#[cfg(feature = "libxml_xptr_locs")]
XmlXPathObjectType::XPathPoint
| XmlXPathObjectType::XPathRange
| XmlXPathObjectType::XPathLocationset => {
"".into()
}
}
}
#[doc(
alias = "xmlXPathConvertBoolean",
alias = "xmlXPathCacheConvertBoolean"
)]
pub fn xml_xpath_convert_boolean(val: Option<XmlXPathObject>) -> XmlXPathObject {
let Some(val) = val else {
return xml_xpath_new_boolean(false);
};
if val.typ == XmlXPathObjectType::XPathBoolean {
return val;
}
xml_xpath_new_boolean(xml_xpath_cast_to_boolean(&val))
}
#[doc(alias = "xmlXPathConvertNumber", alias = "xmlXPathCacheConvertNumber")]
pub fn xml_xpath_convert_number(val: Option<XmlXPathObject>) -> XmlXPathObject {
let Some(mut val) = val else {
return xml_xpath_new_float(0.0);
};
if val.typ == XmlXPathObjectType::XPathNumber {
return val;
}
xml_xpath_new_float(xml_xpath_cast_to_number(&mut val))
}
#[doc(alias = "xmlXPathConvertString", alias = "xmlXPathCacheConvertString")]
pub fn xml_xpath_convert_string(val: Option<XmlXPathObject>) -> XmlXPathObject {
let Some(mut val) = val else {
return xml_xpath_new_string(Some(""));
};
let mut res = None::<Cow<'_, str>>;
match val.typ {
XmlXPathObjectType::XPathUndefined => {}
XmlXPathObjectType::XPathNodeset | XmlXPathObjectType::XPathXSLTTree => {
res = Some(xml_xpath_cast_node_set_to_string(
val.nodesetval.as_deref_mut(),
));
}
XmlXPathObjectType::XPathString => {
return val;
}
XmlXPathObjectType::XPathBoolean => {
res = Some(xml_xpath_cast_boolean_to_string(val.boolval).into());
}
XmlXPathObjectType::XPathNumber => {
res = Some(xml_xpath_cast_number_to_string(val.floatval));
}
XmlXPathObjectType::XPathUsers => {
}
#[cfg(feature = "libxml_xptr_locs")]
XmlXPathObjectType::XPathPoint
| XmlXPathObjectType::XPathRange
| XmlXPathObjectType::XPathLocationset => {
}
}
let Some(res) = res else {
return xml_xpath_new_string(Some(""));
};
xml_xpath_wrap_string(Some(&res))
}