From 58698f633f91e1c0db97cab2f55da099829c1689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Sch=C3=A4fer?= Date: Fri, 20 Dec 2024 12:43:23 +0100 Subject: [PATCH] xso: only take reference in transform This avoids the need for an expensive clone. Since we switched to AsXml instead of IntoXml, we don't necessarily have to clone the data when building new elements, only when it's absolutely necessary. The clones then happen implicitly in the ItemToEvent iterator used internally. This mostly fixes #86, with the caveat that there's no absolutely cheap test: On success, the entire element will be copied, while on failure, you learn about it rather quickly. --- parsers/src/util/macro_tests.rs | 3 +-- xso-proc/src/lib.rs | 13 +++++++++++++ xso/src/lib.rs | 2 +- xso/src/minidom_compat.rs | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/parsers/src/util/macro_tests.rs b/parsers/src/util/macro_tests.rs index 397bdd89d8a5c80700a06dbb537d2faded5cb1a0..0da7e6d2a837fa08364dc174d8641a05b4927148 100644 --- a/parsers/src/util/macro_tests.rs +++ b/parsers/src/util/macro_tests.rs @@ -29,8 +29,7 @@ mod helpers { Ok(v) => v, Err(e) => panic!("failed to parse from {:?}: {}", s, e), }; - let recovered = - transform(structural.clone()).expect("roundtrip did not produce an element"); + let recovered = transform(&structural).expect("roundtrip did not produce an element"); assert_eq!(initial, recovered); let structural2: T = match try_from_element(recovered) { Ok(v) => v, diff --git a/xso-proc/src/lib.rs b/xso-proc/src/lib.rs index e2fc530cadeda79fa7f98bab27aead5bf9b3d9ab..28d3ce942dcb030b42e75fccb6770b1153ed3918 100644 --- a/xso-proc/src/lib.rs +++ b/xso-proc/src/lib.rs @@ -152,6 +152,12 @@ fn as_xml_impl(input: Item) -> Result { result.extend(quote! { impl ::core::convert::From<#ident> for ::xso::exports::minidom::Element { fn from(other: #ident) -> Self { + ::xso::transform(&other).expect("seamless conversion into minidom::Element") + } + } + + impl ::core::convert::From<&#ident> for ::xso::exports::minidom::Element { + fn from(other: &#ident) -> Self { ::xso::transform(other).expect("seamless conversion into minidom::Element") } } @@ -163,6 +169,13 @@ fn as_xml_impl(input: Item) -> Result { type Error = ::xso::error::Error; fn try_from(other: #ident) -> ::core::result::Result { + ::xso::transform(&other) + } + } + impl ::core::convert::TryFrom<&#ident> for ::xso::exports::minidom::Element { + type Error = ::xso::error::Error; + + fn try_from(other: &#ident) -> ::core::result::Result { ::xso::transform(other) } } diff --git a/xso/src/lib.rs b/xso/src/lib.rs index 808435e699d9ca6f54eae3a8539b4eded1817b8c..568e1cd1ab3c7a1984ee5068c7f20e644ed5ba7b 100644 --- a/xso/src/lib.rs +++ b/xso/src/lib.rs @@ -381,7 +381,7 @@ impl UnknownChildPolicy { /// Attempt to transform a type implementing [`AsXml`] into another /// type which implements [`FromXml`]. -pub fn transform(from: F) -> Result { +pub fn transform(from: &F) -> Result { let mut iter = self::rxml_util::ItemToEvent::new(from.as_xml_iter()?); let (qname, attrs) = match iter.next() { Some(Ok(rxml::Event::StartElement(_, qname, attrs))) => (qname, attrs), diff --git a/xso/src/minidom_compat.rs b/xso/src/minidom_compat.rs index e2148fd6ea301fb1915268a7adec0a06f6d970e3..3e998de7e48604214f7a6ee5bf2b3a53000132ad 100644 --- a/xso/src/minidom_compat.rs +++ b/xso/src/minidom_compat.rs @@ -475,7 +475,7 @@ mod tests { #[test] fn transform_element_is_equivalent() { let el: Element = "some text".parse().unwrap(); - let transformed: Element = crate::transform(el.clone()).unwrap(); + let transformed: Element = crate::transform(&el).unwrap(); assert_eq!(el, transformed); } }