use std::{
any::type_name,
borrow::Cow,
ops::{Deref, DerefMut},
os::raw::c_void,
ptr::{NonNull, null_mut},
};
use super::{
InvalidNodePointerCastError, NodeCommon, XML_LOCAL_NAMESPACE, XML_XML_NAMESPACE, XmlDocPtr,
XmlElementType, XmlGenericNodePtr, XmlNodePtr, XmlNsType, xml_tree_err_memory,
};
#[repr(C)]
pub struct XmlNs {
pub next: Option<XmlNsPtr>,
pub(crate) typ: XmlNsType,
pub href: Option<Box<str>>,
pub prefix: Option<Box<str>>,
pub _private: *mut c_void,
pub(crate) context: Option<XmlDocPtr>,
pub node: Option<XmlGenericNodePtr>,
}
impl XmlNs {
pub fn prefix(&self) -> Option<Cow<'_, str>> {
self.prefix.as_deref().map(Cow::Borrowed)
}
pub fn href(&self) -> Option<Cow<'_, str>> {
self.href.as_deref().map(Cow::Borrowed)
}
#[doc(alias = "xmlNodeGetContent")]
pub fn get_content(&self) -> Option<String> {
assert!(matches!(
self.element_type(),
XmlElementType::XmlNamespaceDecl
));
self.href().map(|href| href.into_owned())
}
#[doc(alias = "xmlBufGetNodeContent")]
pub fn get_content_to(&self, buf: &mut String) -> i32 {
assert!(matches!(
self.element_type(),
XmlElementType::XmlNamespaceDecl
));
buf.push_str(self.href().unwrap().as_ref());
0
}
}
impl Default for XmlNs {
fn default() -> Self {
Self {
next: None,
typ: XmlNsType::XmlNamespaceDecl,
href: None,
prefix: None,
_private: null_mut(),
context: None,
node: None,
}
}
}
impl NodeCommon for XmlNs {
fn document(&self) -> Option<XmlDocPtr> {
self.context
}
fn set_document(&mut self, doc: Option<XmlDocPtr>) {
self.context = doc;
}
fn element_type(&self) -> XmlElementType {
self.typ
}
fn name(&self) -> Option<Cow<'_, str>> {
self.href()
}
fn children(&self) -> Option<XmlGenericNodePtr> {
None
}
fn set_children(&mut self, _children: Option<XmlGenericNodePtr>) {}
fn last(&self) -> Option<XmlGenericNodePtr> {
None
}
fn set_last(&mut self, _last: Option<XmlGenericNodePtr>) {}
fn next(&self) -> Option<XmlGenericNodePtr> {
self.next.map(|ns| ns.into())
}
fn set_next(&mut self, next: Option<XmlGenericNodePtr>) {
self.next = next.map(|p| XmlNsPtr::try_from(p).unwrap());
}
fn prev(&self) -> Option<XmlGenericNodePtr> {
None
}
fn set_prev(&mut self, _prev: Option<XmlGenericNodePtr>) {}
fn parent(&self) -> Option<XmlGenericNodePtr> {
None
}
fn set_parent(&mut self, _parent: Option<XmlGenericNodePtr>) {}
fn unlink(&mut self) {}
}
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct XmlNsPtr(NonNull<XmlNs>);
impl XmlNsPtr {
pub(crate) fn new(node: XmlNs) -> Option<Self> {
let boxed = Box::new(node);
NonNull::new(Box::leak(boxed)).map(Self)
}
pub unsafe fn from_raw(ptr: *mut XmlNs) -> Result<Option<Self>, InvalidNodePointerCastError> {
unsafe {
if ptr.is_null() {
return Ok(None);
}
match (*ptr).element_type() {
XmlElementType::XmlNamespaceDecl => Ok(Some(Self(NonNull::new_unchecked(ptr)))),
_ => Err(InvalidNodePointerCastError {
from: (*ptr).element_type(),
to: type_name::<Self>(),
}),
}
}
}
pub(crate) unsafe fn free(self) {
unsafe {
let _ = *Box::from_raw(self.0.as_ptr());
}
}
}
impl Clone for XmlNsPtr {
fn clone(&self) -> Self {
*self
}
}
impl Copy for XmlNsPtr {}
impl Deref for XmlNsPtr {
type Target = XmlNs;
fn deref(&self) -> &Self::Target {
unsafe { self.0.as_ref() }
}
}
impl DerefMut for XmlNsPtr {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.0.as_mut() }
}
}
impl TryFrom<XmlGenericNodePtr> for XmlNsPtr {
type Error = InvalidNodePointerCastError;
fn try_from(value: XmlGenericNodePtr) -> Result<Self, Self::Error> {
match value.element_type() {
XmlElementType::XmlNamespaceDecl => Ok(Self(value.0.cast())),
_ => Err(InvalidNodePointerCastError {
from: value.element_type(),
to: type_name::<Self>(),
}),
}
}
}
impl From<XmlNsPtr> for XmlGenericNodePtr {
fn from(value: XmlNsPtr) -> Self {
Self(value.0 as NonNull<dyn NodeCommon>)
}
}
impl From<XmlNsPtr> for *mut XmlNs {
fn from(value: XmlNsPtr) -> Self {
value.0.as_ptr()
}
}
#[doc(alias = "xmlNewNs")]
pub fn xml_new_ns(
node: Option<XmlNodePtr>,
href: Option<&str>,
prefix: Option<&str>,
) -> Option<XmlNsPtr> {
if node.is_some_and(|node| node.element_type() != XmlElementType::XmlElementNode) {
return None;
}
if prefix == Some("xml") {
if href == Some(XML_XML_NAMESPACE) {
return None;
}
}
let Some(mut cur) = XmlNsPtr::new(XmlNs {
typ: XML_LOCAL_NAMESPACE,
..Default::default()
}) else {
xml_tree_err_memory("building namespace");
return None;
};
cur.href = href.map(|href| href.into());
cur.prefix = prefix.map(|prefix| prefix.into());
if let Some(mut node) = node {
if let Some(ns_def) = node.ns_def {
let mut prev = ns_def;
if prev.prefix == cur.prefix {
unsafe {
xml_free_ns(cur);
}
return None;
}
while let Some(next) = prev.next {
prev = next;
if prev.prefix == cur.prefix {
unsafe {
xml_free_ns(cur);
}
return None;
}
}
prev.next = Some(cur);
} else {
node.ns_def = Some(cur);
}
}
Some(cur)
}
#[doc(alias = "xmlFreeNs")]
pub unsafe fn xml_free_ns(cur: XmlNsPtr) {
unsafe {
cur.free();
}
}
#[doc(alias = "xmlFreeNsList")]
pub unsafe fn xml_free_ns_list(cur: XmlNsPtr) {
unsafe {
let mut next = cur.next;
xml_free_ns(cur);
while let Some(now) = next {
next = now.next;
xml_free_ns(now);
}
}
}