From 9951f5a6dc85491f7868ee32b1f07850cd126909 Mon Sep 17 00:00:00 2001 From: Lukas Friman Date: Fri, 9 May 2025 12:20:49 +0200 Subject: [PATCH] Started work on `from_value_owned`. --- xmlity/src/value/deserializer_owned.rs | 622 +++++++++++++++++++++++++ xmlity/src/value/mod.rs | 8 + 2 files changed, 630 insertions(+) create mode 100644 xmlity/src/value/deserializer_owned.rs diff --git a/xmlity/src/value/deserializer_owned.rs b/xmlity/src/value/deserializer_owned.rs new file mode 100644 index 0000000..d80320a --- /dev/null +++ b/xmlity/src/value/deserializer_owned.rs @@ -0,0 +1,622 @@ +use std::mem; + +use crate::{ + de::{self, AttributesAccess, ElementAccess, Visitor}, + Deserialize, Deserializer, ExpandedName, +}; + +use super::*; + +impl<'de> Deserializer<'de> for XmlValue { + type Error = XmlValueDeserializerError; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + XmlValue::Text(xml_text) => xml_text.deserialize_any(visitor), + XmlValue::CData(xml_cdata) => xml_cdata.deserialize_any(visitor), + XmlValue::Element(xml_element) => xml_element.deserialize_any(visitor), + XmlValue::Seq(xml_seq) => XmlSeqAccess::new(xml_seq).deserialize_any(visitor), + XmlValue::PI(xml_pi) => xml_pi.deserialize_any(visitor), + XmlValue::Decl(xml_decl) => xml_decl.deserialize_any(visitor), + XmlValue::Comment(xml_comment) => xml_comment.deserialize_any(visitor), + XmlValue::Doctype(xml_doctype) => xml_doctype.deserialize_any(visitor), + XmlValue::None => visitor.visit_none(), + } + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + XmlValue::Text(xml_text) => xml_text.deserialize_seq(visitor), + XmlValue::CData(xml_cdata) => xml_cdata.deserialize_seq(visitor), + XmlValue::Element(xml_element) => xml_element.deserialize_seq(visitor), + XmlValue::Seq(xml_seq) => XmlSeqAccess::new(xml_seq).deserialize_seq(visitor), + XmlValue::PI(xml_pi) => xml_pi.deserialize_seq(visitor), + XmlValue::Decl(xml_decl) => xml_decl.deserialize_seq(visitor), + XmlValue::Comment(xml_comment) => xml_comment.deserialize_seq(visitor), + XmlValue::Doctype(xml_doctype) => xml_doctype.deserialize_seq(visitor), + XmlValue::None => visitor.visit_none(), + } + } +} + +impl<'de> Deserializer<'de> for XmlText { + type Error = XmlValueDeserializerError; + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_text(self) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_seq(&mut Some(self)) + } +} + +impl<'de> Deserializer<'de> for XmlCData { + type Error = XmlValueDeserializerError; + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_cdata(self) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_any(visitor) + } +} + +impl<'de> de::XmlCData<'de> for XmlCData { + type NamespaceContext<'a> + = () + where + Self: 'a; + + fn into_bytes(self) -> Cow<'de, [u8]> { + Cow::Owned(self.0) + } + + fn as_bytes(&self) -> &[u8] { + &self.0 + } + + fn into_string(self) -> Cow<'de, str> { + Cow::Owned(String::from_utf8(self.0).unwrap()) + } + + fn as_str(&self) -> &str { + std::str::from_utf8(&self.0).unwrap() + } + + fn namespace_context(&self) -> Self::NamespaceContext<'_> {} +} + +impl<'de> Deserializer<'de> for XmlChild { + type Error = XmlValueDeserializerError; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + XmlChild::Text(xml_text) => xml_text.deserialize_any(visitor), + XmlChild::CData(xml_cdata) => xml_cdata.deserialize_any(visitor), + XmlChild::Element(xml_element) => xml_element.deserialize_any(visitor), + XmlChild::PI(xml_pi) => xml_pi.deserialize_any(visitor), + XmlChild::Comment(xml_comment) => xml_comment.deserialize_any(visitor), + XmlChild::None => visitor.visit_none(), + } + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + XmlChild::Text(xml_text) => xml_text.deserialize_seq(visitor), + XmlChild::CData(xml_cdata) => xml_cdata.deserialize_seq(visitor), + XmlChild::Element(xml_element) => xml_element.deserialize_seq(visitor), + XmlChild::PI(xml_pi) => xml_pi.deserialize_seq(visitor), + XmlChild::Comment(xml_comment) => xml_comment.deserialize_seq(visitor), + XmlChild::None => visitor.visit_none(), + } + } +} + +impl<'de> Deserializer<'de> for XmlElement { + type Error = XmlValueDeserializerError; + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_element(XmlElementAccess { + element: self, + attribute_index: 0, + write_attribute_index_to: None, + }) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_any(visitor) + } +} + +impl<'de> crate::de::Deserializer<'de> for XmlAttribute { + type Error = XmlValueDeserializerError; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_attribute(self) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_attribute(self) + } +} + +impl<'de> Deserializer<'de> for &mut XmlSeqAccess<'_, XmlValue> { + type Error = XmlValueDeserializerError; + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_seq(self) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_any(visitor) + } +} + +impl<'de> Deserializer<'de> for &mut XmlSeqAccess<'_, XmlChild> { + type Error = XmlValueDeserializerError; + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_seq(self) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_any(visitor) + } +} + +impl<'de> Deserializer<'de> for XmlSeq { + type Error = XmlValueDeserializerError; + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_seq(XmlSeqAccess::new(self)) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_any(visitor) + } +} + +impl<'de> Deserializer<'de> for XmlSeq { + type Error = XmlValueDeserializerError; + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_seq(XmlSeqAccess::new(self)) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_any(visitor) + } +} + +impl<'de> Deserializer<'de> for XmlProcessingInstruction { + type Error = XmlValueDeserializerError; + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_pi(self) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_any(visitor) + } +} + +impl<'de> Deserializer<'de> for XmlDecl { + type Error = XmlValueDeserializerError; + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_decl(self) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_any(visitor) + } +} + +impl<'de> Deserializer<'de> for XmlComment { + type Error = XmlValueDeserializerError; + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_comment(self) + } + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_any(visitor) + } +} + +impl<'de> Deserializer<'de> for XmlDoctype { + type Error = XmlValueDeserializerError; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_doctype(self) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_any(visitor) + } +} + +// Element access + +struct XmlElementAccess<'i> { + element: XmlElement, + attribute_index: usize, + write_attribute_index_to: Option<&'i mut usize>, +} + +impl Drop for XmlElementAccess<'_> { + fn drop(&mut self) { + if let Some(write_to) = self.write_attribute_index_to.as_mut() { + **write_to = self.attribute_index; + } + } +} + +impl<'de> AttributesAccess<'de> for XmlElementAccess<'_> { + type Error = XmlValueDeserializerError; + + type SubAccess<'a> + = XmlElementAccess<'a> + where + Self: 'a; + + fn next_attribute(&mut self) -> Result, Self::Error> + where + T: Deserialize<'de>, + { + let Some(attribute) = self.element.attributes.get(self.attribute_index) else { + return Ok(None); + }; + let attribute = T::deserialize(attribute)?; + self.attribute_index += 1; + Ok(Some(attribute)) + } + + fn sub_access(&mut self) -> Result, Self::Error> { + Ok(XmlElementAccess { + attribute_index: self.attribute_index, + element: self.element, + write_attribute_index_to: Some(&mut self.attribute_index), + }) + } +} + +impl<'de> ElementAccess<'de> for XmlElementAccess<'_> { + type ChildrenAccess = XmlSeqAccess<'static, XmlChild>; + type NamespaceContext<'a> + = () + where + Self: 'a; + + fn name(&self) -> ExpandedName<'_> { + self.element.name.clone() + } + + fn children(mut self) -> Result { + let seq = mem::replace(&mut self.element.children, XmlSeq::new()); + Ok(XmlSeqAccess { + seq, + index: 0, + write_index_to: None, + }) + } + + fn namespace_context(&self) -> Self::NamespaceContext<'_> {} +} + +// Seq + +struct XmlSeqAccess<'i, T> { + seq: XmlSeq, + index: usize, + write_index_to: Option<&'i mut usize>, +} + +impl XmlSeqAccess<'_, T> { + pub fn new(seq: XmlSeq) -> Self { + Self { + seq, + index: 0, + write_index_to: None, + } + } +} + +impl Drop for XmlSeqAccess<'_, T> { + fn drop(&mut self) { + if let Some(write_index_to) = self.write_index_to.as_mut() { + **write_index_to = self.index; + } + } +} + +// One would think that these impls for XmlSeqAccess that take XmlValue and XmlChild should be unified using a generic impl, but this does not appear to be possible due to an error mentioning limits in the borrow checker. +// I've fought the borrow checker for a long time and lost, so for now, these are separate impls. +// If you want to take a stab at unifying these, be my guest. +impl<'de> de::SeqAccess<'de> for XmlSeqAccess<'_, XmlChild> { + type Error = XmlValueDeserializerError; + type SubAccess<'g> + = XmlSeqAccess<'g, XmlChild> + where + Self: 'g; + fn next_element(&mut self) -> Result, Self::Error> + where + T: Deserialize<'de>, + { + let Some(value) = self.seq.values.get(self.index) else { + return Ok(None); + }; + let value = T::deserialize(value)?; + self.index += 1; + Ok(Some(value)) + } + + fn next_element_seq(&mut self) -> Result, Self::Error> + where + T: Deserialize<'de>, + { + T::deserialize_seq(self).map(Some) + } + + fn sub_access(&mut self) -> Result, Self::Error> { + let seq = mem::replace(&mut self.seq, XmlSeq::new()); + + Ok(XmlSeqAccess { + seq, + index: self.index, + write_index_to: Some(&mut self.index), + }) + } +} + +impl<'de> de::SeqAccess<'de> for XmlSeqAccess<'_, XmlValue> { + type Error = XmlValueDeserializerError; + type SubAccess<'g> + = XmlSeqAccess<'g, XmlValue> + where + Self: 'g; + fn next_element(&mut self) -> Result, Self::Error> + where + T: Deserialize<'de>, + { + let Some(value) = self.seq.values.get(self.index) else { + return Ok(None); + }; + let value = T::deserialize(value)?; + self.index += 1; + Ok(Some(value)) + } + + fn next_element_seq(&mut self) -> Result, Self::Error> + where + T: Deserialize<'de>, + { + T::deserialize_seq(self).map(Some) + } + + fn sub_access(&mut self) -> Result, Self::Error> { + Ok(XmlSeqAccess { + seq: self.seq, + index: self.index, + write_index_to: Some(&mut self.index), + }) + } +} + +impl de::XmlProcessingInstruction for XmlProcessingInstruction { + type NamespaceContext<'a> + = () + where + Self: 'a; + + fn content(&self) -> &[u8] { + self.content.as_slice() + } + + fn target(&self) -> &[u8] { + self.target.as_slice() + } + fn namespace_context(&self) -> Self::NamespaceContext<'_> {} +} + +impl de::XmlDeclaration for XmlDecl { + type NamespaceContext<'a> + = () + where + Self: 'a; + + fn version(&self) -> &[u8] { + self.version.as_bytes() + } + + fn encoding(&self) -> Option<&[u8]> { + self.encoding.as_deref().map(|e| e.as_bytes()) + } + + fn standalone(&self) -> Option<&[u8]> { + self.standalone.as_deref().map(|s| s.as_bytes()) + } + + fn namespace_context(&self) -> Self::NamespaceContext<'_> {} +} + +impl<'de> de::XmlComment<'de> for XmlComment { + type NamespaceContext<'a> + = () + where + Self: 'a; + + fn into_bytes(self) -> Cow<'de, [u8]> { + Cow::Owned(self.0) + } + + fn as_bytes(&self) -> &[u8] { + &self.0 + } + + fn namespace_context(&self) -> Self::NamespaceContext<'_> {} +} + +impl<'de> de::XmlDoctype<'de> for XmlDoctype { + type NamespaceContext<'a> + = () + where + Self: 'a; + + fn into_bytes(self) -> Cow<'de, [u8]> { + Cow::Owned(self.0) + } + + fn as_bytes(&self) -> &[u8] { + &self.0 + } + + fn namespace_context(&self) -> Self::NamespaceContext<'_> {} +} + +impl<'de> de::XmlText<'de> for XmlText { + type NamespaceContext<'a> + = () + where + Self: 'a; + + fn into_bytes(self) -> Cow<'de, [u8]> { + Cow::Owned(self.0) + } + + fn as_bytes(&self) -> &[u8] { + &self.0 + } + + fn into_string(self) -> Cow<'de, str> { + Cow::Owned(String::from_utf8(self.0).unwrap()) + } + + fn as_str(&self) -> &str { + std::str::from_utf8(&self.0).unwrap() + } + + fn namespace_context(&self) -> Self::NamespaceContext<'_> {} +} + +impl<'de> de::SeqAccess<'de> for &mut Option { + type Error = XmlValueDeserializerError; + + type SubAccess<'g> + = Self + where + Self: 'g; + + fn next_element(&mut self) -> Result, Self::Error> + where + T: Deserialize<'de>, + { + let Some(text) = self.take() else { + return Ok(None); + }; + + match T::deserialize(text) { + Ok(value) => Ok(Some(value)), + Err(_) => { + *self = Some(text); + Ok(None) + } + } + } + + fn next_element_seq(&mut self) -> Result, Self::Error> + where + T: Deserialize<'de>, + { + let Some(text) = self.take() else { + return Ok(None); + }; + + match T::deserialize_seq(text) { + Ok(value) => Ok(Some(value)), + Err(_) => { + *self = Some(text); + Ok(None) + } + } + } + + fn sub_access(&mut self) -> Result, Self::Error> { + Ok(*self) + } +} diff --git a/xmlity/src/value/mod.rs b/xmlity/src/value/mod.rs index 40d6bcf..3996084 100644 --- a/xmlity/src/value/mod.rs +++ b/xmlity/src/value/mod.rs @@ -20,6 +20,7 @@ use crate::{ mod deserialize; mod deserializer; +mod deserializer_owned; mod serialize; mod serializer; @@ -30,6 +31,13 @@ pub fn from_value<'de, T: crate::Deserialize<'de>>( T::deserialize_seq(value) } +/// Creates any `T` implementing [`Deserialize`] from an owned [`XmlValue`] +pub fn from_value_owned( + value: XmlValue, +) -> Result { + T::deserialize_seq(value) +} + /// Creates an [`XmlValue`] from any `T` implementing [`Serialize`]. pub fn to_value(input: &T) -> Result { let mut value = XmlValue::None;