use std::{
any::type_name,
borrow::Cow,
ops::{Deref, DerefMut},
os::raw::c_void,
ptr::{NonNull, null_mut},
rc::Rc,
};
#[cfg(feature = "libxml_regexp")]
use crate::libxml::xmlregexp::XmlRegexp;
use crate::{
dom::elementdecl::ElementContent,
tree::{
InvalidNodePointerCastError, NodeCommon, XmlDocPtr, XmlElementType, XmlElementTypeVal,
XmlGenericNodePtr,
},
};
use super::{XmlAttributePtr, XmlDtdPtr};
#[repr(C)]
pub struct XmlElement {
pub _private: *mut c_void,
pub(crate) typ: XmlElementType,
pub(crate) name: Option<String>,
pub(crate) children: Option<XmlGenericNodePtr>,
pub(crate) last: Option<XmlGenericNodePtr>,
pub(crate) parent: Option<XmlDtdPtr>,
pub(crate) next: Option<XmlGenericNodePtr>,
pub(crate) prev: Option<XmlGenericNodePtr>,
pub(crate) doc: Option<XmlDocPtr>,
pub(crate) etype: XmlElementTypeVal,
pub(crate) content: Option<Rc<ElementContent>>,
pub(crate) attributes: Option<XmlAttributePtr>,
pub(crate) prefix: Option<String>,
#[cfg(feature = "libxml_regexp")]
pub(crate) cont_model: Option<Rc<XmlRegexp>>,
#[cfg(not(feature = "libxml_regexp"))]
pub(crate) cont_model: *mut c_void,
}
impl Default for XmlElement {
fn default() -> Self {
Self {
_private: null_mut(),
typ: XmlElementType::XmlElementDecl,
name: None,
children: None,
last: None,
parent: None,
next: None,
prev: None,
doc: None,
etype: XmlElementTypeVal::XmlElementTypeUndefined,
content: None,
attributes: None,
prefix: None,
cont_model: None,
}
}
}
impl NodeCommon for XmlElement {
fn document(&self) -> Option<XmlDocPtr> {
self.doc
}
fn set_document(&mut self, doc: Option<XmlDocPtr>) {
self.doc = doc;
}
fn element_type(&self) -> XmlElementType {
self.typ
}
fn name(&self) -> Option<Cow<'_, str>> {
self.name.as_deref().map(Cow::Borrowed)
}
fn children(&self) -> Option<XmlGenericNodePtr> {
self.children
}
fn set_children(&mut self, children: Option<XmlGenericNodePtr>) {
self.children = children;
}
fn last(&self) -> Option<XmlGenericNodePtr> {
self.last
}
fn set_last(&mut self, last: Option<XmlGenericNodePtr>) {
self.last = last;
}
fn next(&self) -> Option<XmlGenericNodePtr> {
self.next
}
fn set_next(&mut self, next: Option<XmlGenericNodePtr>) {
self.next = next;
}
fn prev(&self) -> Option<XmlGenericNodePtr> {
self.prev
}
fn set_prev(&mut self, prev: Option<XmlGenericNodePtr>) {
self.prev = prev;
}
fn parent(&self) -> Option<XmlGenericNodePtr> {
self.parent.map(|node| node.into())
}
fn set_parent(&mut self, parent: Option<XmlGenericNodePtr>) {
self.parent = parent.map(|p| XmlDtdPtr::try_from(p).unwrap());
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct XmlElementPtr(NonNull<XmlElement>);
impl XmlElementPtr {
pub(crate) fn new(node: XmlElement) -> Option<Self> {
let boxed = Box::new(node);
NonNull::new(Box::leak(boxed)).map(Self)
}
pub(crate) unsafe fn free(self) {
unsafe {
let _ = *Box::from_raw(self.0.as_ptr());
}
}
}
impl Clone for XmlElementPtr {
fn clone(&self) -> Self {
*self
}
}
impl Copy for XmlElementPtr {}
impl Deref for XmlElementPtr {
type Target = XmlElement;
fn deref(&self) -> &Self::Target {
unsafe { self.0.as_ref() }
}
}
impl DerefMut for XmlElementPtr {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.0.as_mut() }
}
}
impl TryFrom<XmlGenericNodePtr> for XmlElementPtr {
type Error = InvalidNodePointerCastError;
fn try_from(value: XmlGenericNodePtr) -> Result<Self, Self::Error> {
match value.element_type() {
XmlElementType::XmlElementDecl => Ok(Self(value.0.cast())),
_ => Err(InvalidNodePointerCastError {
from: value.element_type(),
to: type_name::<Self>(),
}),
}
}
}
impl From<XmlElementPtr> for XmlGenericNodePtr {
fn from(value: XmlElementPtr) -> Self {
Self(value.0 as NonNull<dyn NodeCommon>)
}
}
impl From<XmlElementPtr> for *mut XmlElement {
fn from(value: XmlElementPtr) -> Self {
value.0.as_ptr()
}
}
#[doc(alias = "xmlCopyElement")]
#[cfg(feature = "libxml_tree")]
pub(crate) fn xml_copy_element(elem: XmlElementPtr) -> Option<XmlElementPtr> {
use std::rc::Weak;
use crate::{dom::elementdecl::deep_clone_element_content, valid::xml_verr_memory};
let res = XmlElementPtr::new(XmlElement {
typ: XmlElementType::XmlElementDecl,
etype: elem.etype,
name: elem.name.clone(),
prefix: elem.prefix.clone(),
content: deep_clone_element_content(elem.content.clone(), Weak::new()),
attributes: None,
..Default::default()
});
if res.is_none() {
xml_verr_memory(None, Some("malloc failed"));
}
res
}
#[doc(alias = "xmlFreeElement")]
pub(crate) unsafe fn xml_free_element(elem: Option<XmlElementPtr>) {
unsafe {
let Some(mut elem) = elem else {
return;
};
elem.unlink();
elem.free();
}
}