diff --git a/parsers/src/attention.rs b/parsers/src/attention.rs index 66933778..c94bd54c 100644 --- a/parsers/src/attention.rs +++ b/parsers/src/attention.rs @@ -3,13 +3,13 @@ // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::message::MessagePayload; use crate::ns; /// Requests the attention of the recipient. -#[derive(FromXml, IntoXml, Debug, Clone, PartialEq)] +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] #[xml(namespace = ns::ATTENTION, name = "attention")] pub struct Attention; diff --git a/parsers/src/avatar.rs b/parsers/src/avatar.rs index 4fd873e2..b4af78a3 100644 --- a/parsers/src/avatar.rs +++ b/parsers/src/avatar.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::hashes::Sha1HexAttribute; use crate::ns; @@ -23,7 +23,7 @@ generate_element!( impl PubSubPayload for Metadata {} /// Communicates avatar metadata. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::AVATAR_METADATA, name = "info")] pub struct Info { /// The size of the image data in bytes. diff --git a/parsers/src/blocking.rs b/parsers/src/blocking.rs index 5f0aa9c7..223426a7 100644 --- a/parsers/src/blocking.rs +++ b/parsers/src/blocking.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload}; use crate::ns; @@ -14,7 +14,7 @@ use xso::error::FromElementError; /// The element requesting the blocklist, the result iq will contain a /// [BlocklistResult]. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::BLOCKING, name = "blocklist")] pub struct BlocklistRequest; @@ -88,7 +88,7 @@ generate_blocking_element!( impl IqSetPayload for Unblock {} /// The application-specific error condition when a message is blocked. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::BLOCKING_ERRORS, name = "blocked")] pub struct Blocked; diff --git a/parsers/src/bob.rs b/parsers/src/bob.rs index b2317df5..b2221e2c 100644 --- a/parsers/src/bob.rs +++ b/parsers/src/bob.rs @@ -4,12 +4,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{error::Error, text::Base64, FromXml, FromXmlText, IntoXml, IntoXmlText}; +use std::borrow::Cow; +use std::str::FromStr; + +use xso::{error::Error, text::Base64, AsXml, AsXmlText, FromXml, FromXmlText}; use crate::hashes::{Algo, Hash}; use crate::ns; use minidom::IntoAttributeValue; -use std::str::FromStr; /// A Content-ID, as defined in RFC2111. /// @@ -56,14 +58,18 @@ impl FromXmlText for ContentId { } } -impl IntoXmlText for ContentId { - fn into_xml_text(self) -> Result { +impl AsXmlText for ContentId { + fn as_xml_text(&self) -> Result, Error> { let algo = match self.hash.algo { Algo::Sha_1 => "sha1", Algo::Sha_256 => "sha256", _ => unimplemented!(), }; - Ok(format!("{}+{}@bob.xmpp.org", algo, self.hash.to_hex())) + Ok(Cow::Owned(format!( + "{}+{}@bob.xmpp.org", + algo, + self.hash.to_hex() + ))) } } @@ -79,7 +85,7 @@ impl IntoAttributeValue for ContentId { } /// Request for an uncached cid file. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::BOB, name = "data")] pub struct Data { /// The cid in question. diff --git a/parsers/src/bookmarks.rs b/parsers/src/bookmarks.rs index a814e574..aa924442 100644 --- a/parsers/src/bookmarks.rs +++ b/parsers/src/bookmarks.rs @@ -16,7 +16,7 @@ //! //! The [`Conference`][crate::bookmarks::Conference] struct used in [`private::Query`][`crate::private::Query`] is the one from this module. Only the querying mechanism changes from a legacy PubSub implementation here, to a legacy Private XML Query implementation in that other module. The [`Conference`][crate::bookmarks2::Conference] element from the [`bookmarks2`][crate::bookmarks2] module is a different structure, but conversion is possible from [`bookmarks::Conference`][crate::bookmarks::Conference] to [`bookmarks2::Conference`][crate::bookmarks2::Conference] via the [`Conference::into_bookmarks2`][crate::bookmarks::Conference::into_bookmarks2] method. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use jid::BareJid; @@ -63,7 +63,7 @@ impl Conference { } /// An URL bookmark. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::BOOKMARKS, name = "url")] pub struct Url { /// A user-defined name for this URL. diff --git a/parsers/src/carbons.rs b/parsers/src/carbons.rs index a3e5a3f6..9fdcc88f 100644 --- a/parsers/src/carbons.rs +++ b/parsers/src/carbons.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::forwarding::Forwarded; use crate::iq::IqSetPayload; @@ -12,14 +12,14 @@ use crate::message::MessagePayload; use crate::ns; /// Enable carbons for this session. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::CARBONS, name = "enable")] pub struct Enable; impl IqSetPayload for Enable {} /// Disable a previously-enabled carbons. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::CARBONS, name = "disable")] pub struct Disable; @@ -27,7 +27,7 @@ impl IqSetPayload for Disable {} /// Request the enclosing message to not be copied to other carbons-enabled /// resources of the user. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::CARBONS, name = "private")] pub struct Private; diff --git a/parsers/src/cert_management.rs b/parsers/src/cert_management.rs index f40d450e..4e3fb87a 100644 --- a/parsers/src/cert_management.rs +++ b/parsers/src/cert_management.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{text::Base64, FromXml, IntoXml}; +use xso::{text::Base64, AsXml, FromXml}; use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload}; use crate::ns; @@ -17,7 +17,7 @@ generate_elem_id!( ); /// An X.509 certificate. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SASL_CERT, name = "x509cert")] pub struct Cert { /// The BER X.509 data. @@ -43,7 +43,7 @@ generate_element!( impl IqSetPayload for Append {} /// Client requests the current list of X.509 certificates. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SASL_CERT, name = "items")] pub struct ListCertsQuery; diff --git a/parsers/src/csi.rs b/parsers/src/csi.rs index 6693bd2e..56cb76af 100644 --- a/parsers/src/csi.rs +++ b/parsers/src/csi.rs @@ -4,22 +4,22 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::ns; /// Stream:feature sent by the server to advertise it supports CSI. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::CSI, name = "csi")] pub struct Feature; /// Client indicates it is inactive. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::CSI, name = "inactive")] pub struct Inactive; /// Client indicates it is active again. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::CSI, name = "active")] pub struct Active; diff --git a/parsers/src/data_forms_validate.rs b/parsers/src/data_forms_validate.rs index d2fa42f5..f9aad49f 100644 --- a/parsers/src/data_forms_validate.rs +++ b/parsers/src/data_forms_validate.rs @@ -8,7 +8,7 @@ use std::fmt::{Display, Formatter}; use std::str::FromStr; use minidom::{Element, IntoAttributeValue}; -use xso::{error::FromElementError, FromXml, IntoXml}; +use xso::{error::FromElementError, AsXml, FromXml}; use crate::ns::{self, XDATA_VALIDATE}; use crate::Error; @@ -67,7 +67,7 @@ pub enum Method { } /// Selection Ranges in "list-multi" -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::XDATA_VALIDATE, name = "list-range")] pub struct ListRange { /// The 'min' attribute specifies the minimum allowable number of selected/entered values. diff --git a/parsers/src/date.rs b/parsers/src/date.rs index 277fc0d9..8ac24994 100644 --- a/parsers/src/date.rs +++ b/parsers/src/date.rs @@ -4,9 +4,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use std::borrow::Cow; use std::str::FromStr; -use xso::{error::Error, FromXmlText, IntoXmlText}; +use xso::{error::Error, AsXmlText, FromXmlText}; use chrono::{DateTime as ChronoDateTime, FixedOffset}; use minidom::{IntoAttributeValue, Node}; @@ -48,9 +49,9 @@ impl FromXmlText for DateTime { } } -impl IntoXmlText for DateTime { - fn into_xml_text(self) -> Result { - Ok(self.0.to_rfc3339()) +impl AsXmlText for DateTime { + fn as_xml_text(&self) -> Result, Error> { + Ok(Cow::Owned(self.0.to_rfc3339())) } } diff --git a/parsers/src/delay.rs b/parsers/src/delay.rs index 869b181a..da946dec 100644 --- a/parsers/src/delay.rs +++ b/parsers/src/delay.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{text::EmptyAsNone, FromXml, IntoXml}; +use xso::{text::EmptyAsNone, AsXml, FromXml}; use crate::date::DateTime; use crate::message::MessagePayload; @@ -13,7 +13,7 @@ use crate::presence::PresencePayload; use jid::Jid; /// Notes when and by whom a message got stored for later delivery. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::DELAY, name = "delay")] pub struct Delay { /// The entity which delayed this message. diff --git a/parsers/src/disco.rs b/parsers/src/disco.rs index 45455f97..c9734208 100644 --- a/parsers/src/disco.rs +++ b/parsers/src/disco.rs @@ -6,7 +6,7 @@ use xso::{ error::{Error, FromElementError}, - FromXml, IntoXml, + AsXml, FromXml, }; use crate::data_forms::{DataForm, DataFormType}; @@ -20,7 +20,7 @@ use jid::Jid; /// /// It should only be used in an ``, as it can only represent /// the request, and not a result. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::DISCO_INFO, name = "query")] pub struct DiscoInfoQuery { /// Node on which we are doing the discovery. @@ -31,7 +31,7 @@ pub struct DiscoInfoQuery { impl IqGetPayload for DiscoInfoQuery {} /// Structure representing a `` element. -#[derive(FromXml, IntoXml, Debug, Clone, PartialEq, Eq, Hash)] +#[derive(FromXml, AsXml, Debug, Clone, PartialEq, Eq, Hash)] #[xml(namespace = ns::DISCO_INFO, name = "feature")] pub struct Feature { /// Namespace of the feature we want to represent. @@ -203,7 +203,7 @@ children: [ impl IqGetPayload for DiscoItemsQuery {} /// Structure representing an `` element. -#[derive(FromXml, IntoXml, Debug, Clone, PartialEq)] +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] #[xml(namespace = ns::DISCO_ITEMS, name = "item")] pub struct Item { /// JID of the entity pointed by this item. diff --git a/parsers/src/eme.rs b/parsers/src/eme.rs index 9dbea40c..e9c5319e 100644 --- a/parsers/src/eme.rs +++ b/parsers/src/eme.rs @@ -4,13 +4,13 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::message::MessagePayload; use crate::ns; /// Structure representing an `` element. -#[derive(FromXml, IntoXml, Debug, Clone, PartialEq)] +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] #[xml(namespace = ns::EME, name = "encryption")] pub struct ExplicitMessageEncryption { /// Namespace of the encryption scheme used. diff --git a/parsers/src/extdisco.rs b/parsers/src/extdisco.rs index 264812df..48532a49 100644 --- a/parsers/src/extdisco.rs +++ b/parsers/src/extdisco.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::data_forms::DataForm; use crate::date::DateTime; @@ -101,7 +101,7 @@ generate_element!( impl IqGetPayload for Service {} /// Structure representing a `` element. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::EXT_DISCO, name = "services")] pub struct ServicesQuery { /// TODO diff --git a/parsers/src/fast.rs b/parsers/src/fast.rs index e287cf98..a96843f9 100644 --- a/parsers/src/fast.rs +++ b/parsers/src/fast.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::date::DateTime; use crate::ns; @@ -14,7 +14,7 @@ generate_elem_id!( Mechanism, "mechanism", FAST ); -// TODO: Replace this with a proper bool once we can derive FromXml and IntoXml on FastQuery. +// TODO: Replace this with a proper bool once we can derive FromXml and AsXml on FastQuery. generate_attribute!( /// Whether TLS zero-roundtrip is possible. Tls0Rtt, "tls-0rtt", bool @@ -34,7 +34,7 @@ children: [ ); /// This is the `` element the client MUST include within its SASL2 authentication request. -#[derive(FromXml, IntoXml, Debug, Clone, PartialEq)] +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] #[xml(namespace = ns::FAST, name = "fast")] pub struct FastResponse { /// Servers MUST reject any authentication requests received via TLS 0-RTT payloads that do not @@ -51,7 +51,7 @@ pub struct FastResponse { } /// This is the `` element sent by the client in the SASL2 authenticate step. -#[derive(FromXml, IntoXml, Debug, Clone, PartialEq)] +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] #[xml(namespace = ns::FAST, name = "request-token")] pub struct RequestToken { /// This element MUST contain a 'mechanism' attribute, the value of which MUST be one of the @@ -62,7 +62,7 @@ pub struct RequestToken { /// This is the `` element sent by the server on successful SASL2 authentication containing /// a `` element. -#[derive(FromXml, IntoXml, Debug, Clone, PartialEq)] +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] #[xml(namespace = ns::FAST, name = "token")] pub struct Token { /// The secret token to be used for subsequent authentications, as generated by the server. diff --git a/parsers/src/hashes.rs b/parsers/src/hashes.rs index 7585af71..d4ce6d8a 100644 --- a/parsers/src/hashes.rs +++ b/parsers/src/hashes.rs @@ -4,14 +4,16 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{error::Error, text::Base64, FromXml, FromXmlText, IntoXml, IntoXmlText}; - -use base64::{engine::general_purpose::STANDARD as Base64Engine, Engine}; -use minidom::IntoAttributeValue; +use std::borrow::Cow; use std::num::ParseIntError; use std::ops::{Deref, DerefMut}; use std::str::FromStr; +use xso::{error::Error, text::Base64, AsXml, AsXmlText, FromXml, FromXmlText}; + +use base64::{engine::general_purpose::STANDARD as Base64Engine, Engine}; +use minidom::IntoAttributeValue; + use crate::ns; /// List of the algorithms we support, or Unknown. @@ -97,9 +99,9 @@ impl FromXmlText for Algo { } } -impl IntoXmlText for Algo { - fn into_xml_text(self) -> Result { - Ok(String::from(match self { +impl AsXmlText for Algo { + fn as_xml_text(&self) -> Result, Error> { + Ok(Cow::Borrowed(match self { Algo::Sha_1 => "sha-1", Algo::Sha_256 => "sha-256", Algo::Sha_512 => "sha-512", @@ -107,7 +109,7 @@ impl IntoXmlText for Algo { Algo::Sha3_512 => "sha3-512", Algo::Blake2b_256 => "blake2b-256", Algo::Blake2b_512 => "blake2b-512", - Algo::Unknown(text) => return Ok(text), + Algo::Unknown(text) => text.as_str(), })) } } @@ -120,7 +122,7 @@ impl IntoAttributeValue for Algo { /// This element represents a hash of some data, defined by the hash /// algorithm used and the computed value. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::HASHES, name = "hash")] pub struct Hash { /// The algorithm used to create this hash. @@ -213,9 +215,9 @@ impl FromXmlText for Sha1HexAttribute { } } -impl IntoXmlText for Sha1HexAttribute { - fn into_xml_text(self) -> Result { - Ok(self.to_hex()) +impl AsXmlText for Sha1HexAttribute { + fn as_xml_text(&self) -> Result, xso::error::Error> { + Ok(Cow::Owned(self.to_hex())) } } diff --git a/parsers/src/http_upload.rs b/parsers/src/http_upload.rs index 6e0d3d95..4856e058 100644 --- a/parsers/src/http_upload.rs +++ b/parsers/src/http_upload.rs @@ -6,7 +6,7 @@ use xso::{ error::{Error, FromElementError}, - FromXml, IntoXml, + AsXml, FromXml, }; use crate::iq::{IqGetPayload, IqResultPayload}; @@ -14,7 +14,7 @@ use crate::ns; use crate::Element; /// Requesting a slot -#[derive(FromXml, IntoXml, Debug, Clone, PartialEq)] +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] #[xml(namespace = ns::HTTP_UPLOAD, name = "request")] pub struct SlotRequest { /// The filename to be uploaded. @@ -97,7 +97,7 @@ generate_element!( ); /// Get URL -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::HTTP_UPLOAD, name = "get")] pub struct Get { /// URL diff --git a/parsers/src/ibb.rs b/parsers/src/ibb.rs index 7e937f6e..fe5f6dd6 100644 --- a/parsers/src/ibb.rs +++ b/parsers/src/ibb.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{text::Base64, FromXml, IntoXml}; +use xso::{text::Base64, AsXml, FromXml}; use crate::iq::IqSetPayload; use crate::ns; @@ -44,7 +44,7 @@ attributes: [ impl IqSetPayload for Open {} /// Exchange a chunk of data in an open stream. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::IBB, name = "data")] pub struct Data { /// Sequence number of this chunk, must wraparound after 65535. @@ -63,7 +63,7 @@ pub struct Data { impl IqSetPayload for Data {} /// Close an open stream. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::IBB, name = "close")] pub struct Close { /// The identifier of the stream to be closed. diff --git a/parsers/src/idle.rs b/parsers/src/idle.rs index 866e3e35..dfee8ec3 100644 --- a/parsers/src/idle.rs +++ b/parsers/src/idle.rs @@ -4,14 +4,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::date::DateTime; use crate::ns; use crate::presence::PresencePayload; /// Represents the last time the user interacted with their system. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::IDLE, name = "idle")] pub struct Idle { /// The time at which the user stopped interacting. diff --git a/parsers/src/jid_prep.rs b/parsers/src/jid_prep.rs index 97a66dc0..82e1d8bf 100644 --- a/parsers/src/jid_prep.rs +++ b/parsers/src/jid_prep.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use jid::Jid; @@ -12,7 +12,7 @@ use crate::iq::{IqGetPayload, IqResultPayload}; use crate::ns; /// Request from a client to stringprep/PRECIS a string into a JID. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::JID_PREP, name = "jid")] pub struct JidPrepQuery { /// The potential JID. @@ -30,7 +30,7 @@ impl JidPrepQuery { } /// Response from the server with the stringprep’d/PRECIS’d JID. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::JID_PREP, name = "jid")] pub struct JidPrepResponse { /// The JID. diff --git a/parsers/src/jingle_ft.rs b/parsers/src/jingle_ft.rs index 64dcca06..bedca4da 100644 --- a/parsers/src/jingle_ft.rs +++ b/parsers/src/jingle_ft.rs @@ -13,7 +13,7 @@ use std::collections::BTreeMap; use std::str::FromStr; use xso::{ error::{Error, FromElementError}, - FromXml, IntoXml, + AsXml, FromXml, }; generate_element!( @@ -323,7 +323,7 @@ impl From for Element { } /// A notice that the file transfer has been completed. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::JINGLE_FT, name = "received")] pub struct Received { /// The content identifier of this Jingle session. diff --git a/parsers/src/jingle_grouping.rs b/parsers/src/jingle_grouping.rs index 082ab211..a01d3f5f 100644 --- a/parsers/src/jingle_grouping.rs +++ b/parsers/src/jingle_grouping.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::jingle::ContentId; use crate::ns; @@ -21,7 +21,7 @@ generate_attribute!( ); /// Describes a content that should be grouped with other ones. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::JINGLE_GROUPING, name = "content")] pub struct Content { /// The name of the matching [`Content`](crate::jingle::Content). diff --git a/parsers/src/jingle_ice_udp.rs b/parsers/src/jingle_ice_udp.rs index bc1182bf..32efac69 100644 --- a/parsers/src/jingle_ice_udp.rs +++ b/parsers/src/jingle_ice_udp.rs @@ -6,7 +6,7 @@ use std::net::IpAddr; -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::jingle_dtls_srtp::Fingerprint; use crate::ns; @@ -68,7 +68,7 @@ generate_attribute!( ); /// A candidate for an ICE-UDP session. -#[derive(FromXml, IntoXml, Debug, PartialEq, Clone)] +#[derive(FromXml, AsXml, Debug, PartialEq, Clone)] #[xml(namespace = ns::JINGLE_ICE_UDP, name = "candidate")] pub struct Candidate { /// A Component ID as defined in ICE-CORE. diff --git a/parsers/src/jingle_raw_udp.rs b/parsers/src/jingle_raw_udp.rs index c7e36a30..78e0bc04 100644 --- a/parsers/src/jingle_raw_udp.rs +++ b/parsers/src/jingle_raw_udp.rs @@ -6,7 +6,7 @@ use std::net::IpAddr; -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::jingle_ice_udp::Type; use crate::ns; @@ -35,7 +35,7 @@ impl Transport { } /// A candidate for an ICE-UDP session. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::JINGLE_RAW_UDP, name = "candidate")] pub struct Candidate { /// A Component ID as defined in ICE-CORE. diff --git a/parsers/src/jingle_rtcp_fb.rs b/parsers/src/jingle_rtcp_fb.rs index 052fc345..1ff9f822 100644 --- a/parsers/src/jingle_rtcp_fb.rs +++ b/parsers/src/jingle_rtcp_fb.rs @@ -4,12 +4,12 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::ns; /// Wrapper element for a rtcp-fb. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::JINGLE_RTCP_FB, name = "rtcp-fb")] pub struct RtcpFb { /// Type of this rtcp-fb. diff --git a/parsers/src/jingle_rtp.rs b/parsers/src/jingle_rtp.rs index b35d91f8..0442a164 100644 --- a/parsers/src/jingle_rtp.rs +++ b/parsers/src/jingle_rtp.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::jingle_rtcp_fb::RtcpFb; use crate::jingle_rtp_hdrext::RtpHdrext; @@ -13,7 +13,7 @@ use crate::ns; /// Specifies the ability to multiplex RTP Data and Control Packets on a single port as /// described in RFC 5761. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::JINGLE_RTP, name = "rtcp-mux")] pub struct RtcpMux; @@ -138,7 +138,7 @@ impl PayloadType { } /// Parameter related to a payload. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::JINGLE_RTP, name = "parameter")] pub struct Parameter { /// The name of the parameter, from the list at diff --git a/parsers/src/jingle_ssma.rs b/parsers/src/jingle_ssma.rs index f221f6b1..df43f550 100644 --- a/parsers/src/jingle_ssma.rs +++ b/parsers/src/jingle_ssma.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::ns; @@ -32,7 +32,7 @@ impl Source { } /// Parameter associated with a ssrc. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::JINGLE_SSMA, name = "parameter")] pub struct Parameter { /// The name of the parameter. diff --git a/parsers/src/jingle_thumnails.rs b/parsers/src/jingle_thumnails.rs index 59b5770e..59de078a 100644 --- a/parsers/src/jingle_thumnails.rs +++ b/parsers/src/jingle_thumnails.rs @@ -6,12 +6,12 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, you can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::ns; /// A Jingle thumbnail. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::JINGLE_THUMBNAILS, name = "thumbnail")] pub struct Thumbnail { /// The URI of the thumbnail. diff --git a/parsers/src/legacy_omemo.rs b/parsers/src/legacy_omemo.rs index 4260c0c1..2fe46bf3 100644 --- a/parsers/src/legacy_omemo.rs +++ b/parsers/src/legacy_omemo.rs @@ -4,14 +4,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{text::Base64, FromXml, IntoXml}; +use xso::{text::Base64, AsXml, FromXml}; use crate::message::MessagePayload; use crate::ns; use crate::pubsub::PubSubPayload; /// Element of the device list -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::LEGACY_OMEMO, name = "device")] pub struct Device { /// Device id @@ -33,7 +33,7 @@ impl PubSubPayload for DeviceList {} /// SignedPreKey public key /// Part of a device's bundle -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::LEGACY_OMEMO, name = "signedPreKeyPublic")] pub struct SignedPreKeyPublic { /// SignedPreKey id @@ -47,7 +47,7 @@ pub struct SignedPreKeyPublic { /// SignedPreKey signature /// Part of a device's bundle -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::LEGACY_OMEMO, name = "signedPreKeySignature")] pub struct SignedPreKeySignature { /// Signature bytes @@ -56,7 +56,7 @@ pub struct SignedPreKeySignature { } /// Part of a device's bundle -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::LEGACY_OMEMO, name = "identityKey")] pub struct IdentityKey { /// Serialized PublicKey @@ -76,7 +76,7 @@ generate_element!( /// PreKey public key /// Part of a device's bundle -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::LEGACY_OMEMO, name = "preKeyPublic")] pub struct PreKeyPublic { /// PreKey id @@ -123,7 +123,7 @@ generate_element!( ); /// IV used for payload encryption -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::LEGACY_OMEMO, name = "iv")] pub struct IV { /// IV bytes @@ -139,7 +139,7 @@ generate_attribute!( ); /// Part of the OMEMO element header -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::LEGACY_OMEMO, name = "key")] pub struct Key { /// The device id this key is encrypted for. @@ -159,7 +159,7 @@ pub struct Key { } /// The encrypted message body -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::LEGACY_OMEMO, name = "payload")] pub struct Payload { /// Encrypted with AES-128 in Galois/Counter Mode (GCM) diff --git a/parsers/src/mam.rs b/parsers/src/mam.rs index 9946ce91..9482b92a 100644 --- a/parsers/src/mam.rs +++ b/parsers/src/mam.rs @@ -6,7 +6,7 @@ use xso::{ error::{Error, FromElementError}, - FromXml, IntoXml, + AsXml, FromXml, }; use crate::data_forms::DataForm; @@ -165,7 +165,7 @@ generate_element!( impl IqResultPayload for Fin {} /// Metadata of the first message in the archive. -#[derive(FromXml, IntoXml, Debug, Clone, PartialEq)] +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] #[xml(namespace = ns::MAM, name = "start")] pub struct Start { /// The id of the first message in the archive. @@ -178,7 +178,7 @@ pub struct Start { } /// Metadata of the last message in the archive. -#[derive(FromXml, IntoXml, Debug, Clone, PartialEq)] +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] #[xml(namespace = ns::MAM, name = "end")] pub struct End { /// The id of the last message in the archive. @@ -191,7 +191,7 @@ pub struct End { } /// Request an archive for its metadata. -#[derive(FromXml, IntoXml, Debug, Clone, PartialEq)] +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] #[xml(namespace = ns::MAM, name = "metadata")] pub struct MetadataQuery; diff --git a/parsers/src/message_correct.rs b/parsers/src/message_correct.rs index 20d0dd3a..1516053a 100644 --- a/parsers/src/message_correct.rs +++ b/parsers/src/message_correct.rs @@ -4,14 +4,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::message::MessagePayload; use crate::ns; /// Defines that the message containing this payload should replace a /// previous message, identified by the id. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::MESSAGE_CORRECT, name = "replace")] pub struct Replace { /// The 'id' attribute of the message getting corrected. diff --git a/parsers/src/mix.rs b/parsers/src/mix.rs index 06453245..87758a60 100644 --- a/parsers/src/mix.rs +++ b/parsers/src/mix.rs @@ -7,7 +7,7 @@ // TODO: validate nicks by applying the “nickname” profile of the PRECIS OpaqueString class, as // defined in RFC 7700. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::iq::{IqResultPayload, IqSetPayload}; use crate::message::MessagePayload; @@ -59,7 +59,7 @@ impl Participant { } /// A node to subscribe to. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::MIX_CORE, name = "subscribe")] pub struct Subscribe { /// The PubSub node to subscribe to. @@ -151,7 +151,7 @@ impl UpdateSubscription { /// Request to leave a given MIX channel. It will automatically unsubscribe the user from all /// nodes on this channel. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::MIX_CORE, name = "leave")] pub struct Leave; @@ -204,7 +204,7 @@ impl Mix { } /// Create a new MIX channel. -#[derive(FromXml, IntoXml, PartialEq, Clone, Debug, Default)] +#[derive(FromXml, AsXml, PartialEq, Clone, Debug, Default)] #[xml(namespace = ns::MIX_CORE, name = "create")] pub struct Create { /// The requested channel identifier. @@ -230,7 +230,7 @@ impl Create { } /// Destroy a given MIX channel. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::MIX_CORE, name = "destroy")] pub struct Destroy { /// The channel identifier to be destroyed. diff --git a/parsers/src/muc/muc.rs b/parsers/src/muc/muc.rs index c5bde638..38fa8a00 100644 --- a/parsers/src/muc/muc.rs +++ b/parsers/src/muc/muc.rs @@ -5,14 +5,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::date::DateTime; use crate::ns; use crate::presence::PresencePayload; /// Represents the query for messages before our join. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone, Default)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone, Default)] #[xml(namespace = ns::MUC, name = "history")] pub struct History { /// How many characters of history to send, in XML characters. diff --git a/parsers/src/muc/user.rs b/parsers/src/muc/user.rs index 22a77e36..1cc35335 100644 --- a/parsers/src/muc/user.rs +++ b/parsers/src/muc/user.rs @@ -7,7 +7,7 @@ use xso::{ error::{Error, FromElementError}, - FromXml, IntoXml, + AsXml, FromXml, }; use crate::message::MessagePayload; @@ -131,7 +131,7 @@ impl From for Element { /// Used to continue a one-to-one discussion in a room, with more than one /// participant. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::MUC_USER, name = "continue")] pub struct Continue { /// The thread to continue in this room. diff --git a/parsers/src/occupant_id.rs b/parsers/src/occupant_id.rs index 44780fc6..95d9a844 100644 --- a/parsers/src/occupant_id.rs +++ b/parsers/src/occupant_id.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::message::MessagePayload; use crate::ns; @@ -14,7 +14,7 @@ use crate::presence::PresencePayload; /// /// It allows clients to identify a MUC participant across reconnects and /// renames. It thus prevents impersonification of anonymous users. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::OID, name = "occupant-id")] pub struct OccupantId { /// The id associated to the sending user by the MUC service. diff --git a/parsers/src/openpgp.rs b/parsers/src/openpgp.rs index d6c521bc..fecb97e8 100644 --- a/parsers/src/openpgp.rs +++ b/parsers/src/openpgp.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{text::Base64, FromXml, IntoXml}; +use xso::{text::Base64, AsXml, FromXml}; use crate::date::DateTime; use crate::ns; @@ -12,7 +12,7 @@ use crate::pubsub::PubSubPayload; /// Data contained in the PubKey element // TODO: Merge this container with the PubKey struct -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::OX, name = "data")] pub struct PubKeyData { /// Base64 data @@ -36,7 +36,7 @@ generate_element!( impl PubSubPayload for PubKey {} /// Public key metadata -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::OX, name = "pubkey-metadata")] pub struct PubKeyMeta { /// OpenPGP v4 fingerprint diff --git a/parsers/src/ping.rs b/parsers/src/ping.rs index d71514d6..2d505cc8 100644 --- a/parsers/src/ping.rs +++ b/parsers/src/ping.rs @@ -5,14 +5,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::iq::IqGetPayload; use crate::ns; /// Represents a ping to the recipient, which must be answered with an /// empty `` or with an error. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::PING, name = "ping")] pub struct Ping; diff --git a/parsers/src/pubsub/owner.rs b/parsers/src/pubsub/owner.rs index a144ff09..430bae81 100644 --- a/parsers/src/pubsub/owner.rs +++ b/parsers/src/pubsub/owner.rs @@ -5,7 +5,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::data_forms::DataForm; use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload}; @@ -29,7 +29,7 @@ generate_element!( ); /// An affiliation element. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::PUBSUB_OWNER, name = "affiliation")] pub struct Affiliation { /// The node this affiliation pertains to. @@ -77,7 +77,7 @@ generate_element!( ); /// A redirect element. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::PUBSUB_OWNER, name = "redirect")] pub struct Redirect { /// The node this node will be redirected to. @@ -86,7 +86,7 @@ pub struct Redirect { } /// Request to clear a node. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::PUBSUB_OWNER, name = "purge")] pub struct Purge { /// The node to be cleared. @@ -108,7 +108,7 @@ generate_element!( ); /// A subscription element, describing the state of a subscription. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::PUBSUB_OWNER, name = "subscription")] pub struct SubscriptionElem { /// The JID affected by this subscription. diff --git a/parsers/src/pubsub/pubsub.rs b/parsers/src/pubsub/pubsub.rs index 9d32cab0..b6cc74e6 100644 --- a/parsers/src/pubsub/pubsub.rs +++ b/parsers/src/pubsub/pubsub.rs @@ -6,7 +6,7 @@ use xso::{ error::{Error, FromElementError}, - FromXml, IntoXml, + AsXml, FromXml, }; use crate::data_forms::DataForm; @@ -34,7 +34,7 @@ generate_element!( ); /// An affiliation element. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::PUBSUB, name = "affiliation")] pub struct Affiliation { /// The node this affiliation pertains to. @@ -56,7 +56,7 @@ generate_element!( ); /// Request to create a new node. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::PUBSUB, name = "create")] pub struct Create { /// The node name to create, if `None` the service will generate one. @@ -222,7 +222,7 @@ impl From for Element { } /// A request to subscribe a JID to a node. -#[derive(FromXml, IntoXml, Debug, PartialEq, Clone)] +#[derive(FromXml, AsXml, Debug, PartialEq, Clone)] #[xml(namespace = ns::PUBSUB, name = "subscribe")] pub struct Subscribe { /// The JID being subscribed. @@ -270,7 +270,7 @@ generate_element!( ); /// An unsubscribe request. -#[derive(FromXml, IntoXml, Debug, PartialEq, Clone)] +#[derive(FromXml, AsXml, Debug, PartialEq, Clone)] #[xml(namespace = ns::PUBSUB, name = "unsubscribe")] pub struct Unsubscribe { /// The JID affected by this request. diff --git a/parsers/src/reactions.rs b/parsers/src/reactions.rs index 90806014..967b01f6 100644 --- a/parsers/src/reactions.rs +++ b/parsers/src/reactions.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::message::MessagePayload; use crate::ns; @@ -25,7 +25,7 @@ generate_element!( impl MessagePayload for Reactions {} /// One emoji reaction. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::REACTIONS, name = "reaction")] pub struct Reaction { /// The text of this reaction. diff --git a/parsers/src/receipts.rs b/parsers/src/receipts.rs index 83512b9d..1e3fc225 100644 --- a/parsers/src/receipts.rs +++ b/parsers/src/receipts.rs @@ -4,14 +4,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::message::MessagePayload; use crate::ns; /// Requests that this message is acked by the final recipient once /// received. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::RECEIPTS, name = "request")] pub struct Request; @@ -19,7 +19,7 @@ impl MessagePayload for Request {} /// Notes that a previous message has correctly been received, it is /// referenced by its 'id' attribute. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::RECEIPTS, name = "received")] pub struct Received { /// The 'id' attribute of the received message. diff --git a/parsers/src/rtt.rs b/parsers/src/rtt.rs index 91b5f08a..a8032912 100644 --- a/parsers/src/rtt.rs +++ b/parsers/src/rtt.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{text::EmptyAsNone, FromXml, IntoXml}; +use xso::{text::EmptyAsNone, AsXml, FromXml}; use crate::ns; use crate::Element; @@ -31,7 +31,7 @@ generate_attribute!( ); /// Supports the transmission of text, including key presses, and text block inserts. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::RTT, name = "t")] pub struct Insert { /// Position in the message to start inserting from. If None, this means to start from the @@ -113,7 +113,7 @@ impl TryFrom for Erase { /// Allow for the transmission of intervals, between real-time text actions, to recreate the /// pauses between key presses. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::RTT, name = "w")] pub struct Wait { /// Amount of milliseconds to wait before the next action. diff --git a/parsers/src/sasl.rs b/parsers/src/sasl.rs index f27e3d8c..59f20b5e 100644 --- a/parsers/src/sasl.rs +++ b/parsers/src/sasl.rs @@ -7,7 +7,7 @@ use xso::{ error::{Error, FromElementError}, text::Base64, - FromXml, IntoXml, + AsXml, FromXml, }; use crate::ns; @@ -48,7 +48,7 @@ generate_attribute!( /// The first step of the SASL process, selecting the mechanism and sending /// the first part of the handshake. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SASL, name = "auth")] pub struct Auth { /// The mechanism used. @@ -63,7 +63,7 @@ pub struct Auth { /// In case the mechanism selected at the [auth](struct.Auth.html) step /// requires a second step, the server sends this element with additional /// data. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SASL, name = "challenge")] pub struct Challenge { /// The challenge data. @@ -74,7 +74,7 @@ pub struct Challenge { /// In case the mechanism selected at the [auth](struct.Auth.html) step /// requires a second step, this contains the client’s response to the /// server’s [challenge](struct.Challenge.html). -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SASL, name = "response")] pub struct Response { /// The response data. @@ -84,12 +84,12 @@ pub struct Response { /// Sent by the client at any point after [auth](struct.Auth.html) if it /// wants to cancel the current authentication process. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SASL, name = "abort")] pub struct Abort; /// Sent by the server on SASL success. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SASL, name = "success")] pub struct Success { /// Possible data sent on success. diff --git a/parsers/src/sm.rs b/parsers/src/sm.rs index d7b3f25f..c62bb66a 100644 --- a/parsers/src/sm.rs +++ b/parsers/src/sm.rs @@ -4,13 +4,13 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::ns; use crate::stanza_error::DefinedCondition; /// Acknowledgement of the currently received stanzas. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SM, name = "a")] pub struct A { /// The last handled stanza. @@ -105,12 +105,12 @@ generate_element!( ); /// Requests the currently received stanzas by the other party. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SM, name = "r")] pub struct R; /// Requests a stream resumption. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SM, name = "resume")] pub struct Resume { /// The last handled stanza. @@ -124,7 +124,7 @@ pub struct Resume { } /// The response by the server for a successfully resumed stream. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SM, name = "resumed")] pub struct Resumed { /// The last handled stanza. @@ -139,7 +139,7 @@ pub struct Resumed { // TODO: add support for optional and required. /// Represents availability of Stream Management in ``. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SM, name = "sm")] pub struct StreamManagement; diff --git a/parsers/src/stanza_id.rs b/parsers/src/stanza_id.rs index 3f304132..f9f34622 100644 --- a/parsers/src/stanza_id.rs +++ b/parsers/src/stanza_id.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::message::MessagePayload; use crate::ns; @@ -12,7 +12,7 @@ use jid::Jid; /// Gives the identifier a service has stamped on this stanza, often in /// order to identify it inside of [an archive](../mam/index.html). -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SID, name = "stanza-id")] pub struct StanzaId { /// The id associated to this stanza by another entity. @@ -28,7 +28,7 @@ impl MessagePayload for StanzaId {} /// A hack for MUC before version 1.31 to track a message which may have /// its 'id' attribute changed. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::SID, name = "origin-id")] pub struct OriginId { /// The id this client set for this stanza. diff --git a/parsers/src/stream.rs b/parsers/src/stream.rs index 0b790305..594ce4d6 100644 --- a/parsers/src/stream.rs +++ b/parsers/src/stream.rs @@ -4,14 +4,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use jid::BareJid; use crate::ns; /// The stream opening for client-server communications. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::STREAM, name = "stream")] pub struct Stream { /// The JID of the entity opening this stream. diff --git a/parsers/src/time.rs b/parsers/src/time.rs index 17041a4a..86a31949 100644 --- a/parsers/src/time.rs +++ b/parsers/src/time.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::date::DateTime; use crate::iq::{IqGetPayload, IqResultPayload}; @@ -15,7 +15,7 @@ use std::str::FromStr; use xso::error::{Error, FromElementError}; /// An entity time query. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::TIME, name = "time")] pub struct TimeQuery; diff --git a/parsers/src/util/macro_tests.rs b/parsers/src/util/macro_tests.rs index c7b5f9e1..8cd42a2d 100644 --- a/parsers/src/util/macro_tests.rs +++ b/parsers/src/util/macro_tests.rs @@ -19,9 +19,9 @@ mod helpers { // this is to ensure that the macros do not have hidden dependencies on // any specific names being imported. use minidom::Element; - use xso::{error::FromElementError, transform, try_from_element, FromXml, IntoXml}; + use xso::{error::FromElementError, transform, try_from_element, AsXml, FromXml}; - pub(super) fn roundtrip_full( + pub(super) fn roundtrip_full( s: &str, ) { let initial: Element = s.parse().unwrap(); @@ -47,7 +47,7 @@ mod helpers { use self::helpers::{parse_str, roundtrip_full}; -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; // these are adverserial local names in order to trigger any issues with // unqualified names in the macro expansions. @@ -81,7 +81,7 @@ static BAR_NAME: &::xso::exports::rxml::strings::NcNameStr = { } }; -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = "foo")] struct Empty; @@ -164,7 +164,7 @@ fn empty_qname_check_has_precedence_over_attr_check() { } } -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = BAR_NAME)] struct NamePath; @@ -178,7 +178,7 @@ fn name_path_roundtrip() { roundtrip_full::(""); } -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = "urn:example:ns2", name = "baz")] struct NamespaceLit; @@ -192,7 +192,7 @@ fn namespace_lit_roundtrip() { roundtrip_full::(""); } -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = "attr")] struct RequiredAttribute { #[xml(attribute)] @@ -237,7 +237,7 @@ fn required_attribute_missing() { } } -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = "attr")] struct RenamedAttribute { #[xml(attribute = "a1")] @@ -256,7 +256,7 @@ fn renamed_attribute_roundtrip() { roundtrip_full::(""); } -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = "attr")] struct NamespacedAttribute { #[xml(attribute(namespace = "urn:example:ns1", name = FOO_NAME))] @@ -297,7 +297,7 @@ fn namespaced_attribute_roundtrip_b() { ); } -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = "attr")] struct PrefixedAttribute { #[xml(attribute = "xml:lang")] @@ -314,7 +314,7 @@ fn prefixed_attribute_roundtrip() { roundtrip_full::(""); } -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = "attr")] struct RequiredNonStringAttribute { #[xml(attribute)] @@ -331,7 +331,7 @@ fn required_non_string_attribute_roundtrip() { roundtrip_full::(""); } -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = "attr")] struct DefaultAttribute { #[xml(attribute(default))] @@ -381,7 +381,7 @@ fn default_attribute_roundtrip_pp() { roundtrip_full::(""); } -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = "text")] struct TextString { #[xml(text)] @@ -409,7 +409,7 @@ fn text_string_positive_preserves_whitespace() { assert_eq!(el.text, " \t\n"); } -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = "text")] struct TextNonString { #[xml(text)] @@ -426,7 +426,7 @@ fn text_non_string_roundtrip() { roundtrip_full::("123456"); } -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = "elem")] struct IgnoresWhitespaceWithoutTextConsumer; @@ -443,7 +443,7 @@ fn ignores_whitespace_without_text_consumer_positive() { .unwrap(); } -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = "elem")] struct FailsTextWithoutTextConsumer; @@ -465,7 +465,7 @@ fn fails_text_without_text_consumer_positive() { } } -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = "text")] struct TextWithCodec { #[xml(text(codec = xso::text::EmptyAsNone))] diff --git a/parsers/src/util/macros.rs b/parsers/src/util/macros.rs index 8f33acbb..54503e27 100644 --- a/parsers/src/util/macros.rs +++ b/parsers/src/util/macros.rs @@ -94,9 +94,13 @@ macro_rules! generate_attribute { }) } } - impl ::xso::IntoXmlText for $elem { - fn into_xml_text(self) -> Result { - Ok(self.to_string()) + impl ::xso::AsXmlText for $elem { + fn as_xml_text(&self) -> Result<::std::borrow::Cow<'_, str>, xso::error::Error> { + match self { + $( + $elem::$a => Ok(::std::borrow::Cow::Borrowed($b)) + ),+ + } } } impl ::minidom::IntoAttributeValue for $elem { @@ -130,16 +134,16 @@ macro_rules! generate_attribute { s.parse().map_err(xso::error::Error::text_parse_error) } } - impl ::xso::IntoXmlText for $elem { - fn into_xml_text(self) -> Result { - Ok(String::from(match self { + impl ::xso::AsXmlText for $elem { + fn as_xml_text(&self) -> Result, xso::error::Error> { + Ok(std::borrow::Cow::Borrowed(match self { $($elem::$a => $b),+ })) } #[allow(unreachable_patterns)] - fn into_optional_xml_text(self) -> Result, xso::error::Error> { - Ok(Some(String::from(match self { + fn as_optional_xml_text(&self) -> Result>, xso::error::Error> { + Ok(Some(std::borrow::Cow::Borrowed(match self { $elem::$default => return Ok(None), $($elem::$a => $b),+ }))) @@ -219,17 +223,17 @@ macro_rules! generate_attribute { } } } - impl ::xso::IntoXmlText for $elem { - fn into_xml_text(self) -> Result { + impl ::xso::AsXmlText for $elem { + fn as_xml_text(&self) -> Result<::std::borrow::Cow<'_, str>, xso::error::Error> { match self { - Self::True => Ok("true".to_owned()), - Self::False => Ok("false".to_owned()), + Self::True => Ok(::std::borrow::Cow::Borrowed("true")), + Self::False => Ok(::std::borrow::Cow::Borrowed("false")), } } - fn into_optional_xml_text(self) -> Result, xso::error::Error> { + fn as_optional_xml_text(&self) -> Result>, xso::error::Error> { match self { - Self::True => Ok(Some("true".to_owned())), + Self::True => Ok(Some(::std::borrow::Cow::Borrowed("true"))), Self::False => Ok(None), } } @@ -435,9 +439,9 @@ macro_rules! generate_id { Ok(Self(s)) } } - impl ::xso::IntoXmlText for $elem { - fn into_xml_text(self) ->Result { - Ok(self.0) + impl ::xso::AsXmlText for $elem { + fn as_xml_text(&self) ->Result<::std::borrow::Cow<'_, str>, xso::error::Error> { + Ok(::std::borrow::Cow::Borrowed(self.0.as_str())) } } impl ::minidom::IntoAttributeValue for $elem { @@ -803,11 +807,11 @@ macro_rules! generate_element { } } - impl ::xso::IntoXml for $elem { - type EventIter = ::xso::minidom_compat::IntoEventsViaElement; + impl ::xso::AsXml for $elem { + type ItemIter<'x> = ::xso::minidom_compat::AsItemsViaElement<'x>; - fn into_event_iter(self) -> Result { - Self::EventIter::new(self) + fn as_xml_iter(&self) -> Result, ::xso::error::Error> { + ::xso::minidom_compat::AsItemsViaElement::new(self.clone()) } } ); diff --git a/parsers/src/vcard.rs b/parsers/src/vcard.rs index 867f1a28..2a2ea6db 100644 --- a/parsers/src/vcard.rs +++ b/parsers/src/vcard.rs @@ -13,7 +13,7 @@ //! For vCard updates defined in [XEP-0153](https://xmpp.org/extensions/xep-0153.html), //! see [`vcard_update`][crate::vcard_update] module. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload}; use crate::util::text_node_codecs::{Codec, WhitespaceAwareBase64}; @@ -33,7 +33,7 @@ generate_element!( ); /// The type of the photo. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::VCARD, name = "TYPE")] pub struct Type { /// The type as a plain text string; at least "image/jpeg", "image/gif" and "image/png" SHOULD be supported. diff --git a/parsers/src/version.rs b/parsers/src/version.rs index 98ff9b44..cf51f5fc 100644 --- a/parsers/src/version.rs +++ b/parsers/src/version.rs @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use crate::iq::{IqGetPayload, IqResultPayload}; use crate::ns; @@ -13,7 +13,7 @@ use crate::ns; /// /// It should only be used in an ``, as it can only /// represent the request, and not a result. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::VERSION, name = "query")] pub struct VersionQuery; diff --git a/parsers/src/websocket.rs b/parsers/src/websocket.rs index b2b84e1d..ebf829f7 100644 --- a/parsers/src/websocket.rs +++ b/parsers/src/websocket.rs @@ -4,14 +4,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use xso::{FromXml, IntoXml}; +use xso::{AsXml, FromXml}; use jid::BareJid; use crate::ns; /// The stream opening for WebSocket. -#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::WEBSOCKET, name = "open")] pub struct Open { /// The JID of the entity opening this stream. diff --git a/xso-proc/Cargo.toml b/xso-proc/Cargo.toml index 5f8ef5d0..8d9a6fa4 100644 --- a/xso-proc/Cargo.toml +++ b/xso-proc/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.2" authors = [ "Jonas Schäfer ", ] -description = "Macro implementation of #[derive(FromXml, IntoXml)]" +description = "Macro implementation of #[derive(FromXml, AsXml)]" homepage = "https://xmpp.rs" repository = "https://gitlab.com/xmpp-rs/xmpp-rs" keywords = ["xso", "derive", "serialization"] diff --git a/xso-proc/src/compound.rs b/xso-proc/src/compound.rs index 41c12fe9..cfec95a1 100644 --- a/xso-proc/src/compound.rs +++ b/xso-proc/src/compound.rs @@ -12,9 +12,9 @@ use syn::{spanned::Spanned, *}; use crate::error_message::ParentRef; use crate::field::{FieldBuilderPart, FieldDef, FieldIteratorPart, FieldTempInit}; -use crate::scope::{mangle_member, FromEventsScope, IntoEventsScope}; -use crate::state::{FromEventsSubmachine, IntoEventsSubmachine, State}; -use crate::types::qname_ty; +use crate::scope::{mangle_member, AsItemsScope, FromEventsScope}; +use crate::state::{AsItemsSubmachine, FromEventsSubmachine, State}; +use crate::types::{namespace_ty, ncnamestr_cow_ty, phantom_lifetime_ty}; /// A struct or enum variant's contents. pub(crate) struct Compound { @@ -230,58 +230,86 @@ impl Compound { /// **Important:** The returned submachine is not in functional state! /// It's `init` must be modified so that a variable called `name` of type /// `rxml::QName` is in scope. - pub(crate) fn make_into_event_iter_statemachine( + pub(crate) fn make_as_item_iter_statemachine( &self, input_name: &Path, state_prefix: &str, - ) -> Result { - let scope = IntoEventsScope::new(); - let IntoEventsScope { ref attrs, .. } = scope; + lifetime: &Lifetime, + ) -> Result { + let scope = AsItemsScope::new(lifetime); - let start_element_state_ident = quote::format_ident!("{}StartElement", state_prefix); - let end_element_state_ident = quote::format_ident!("{}EndElement", state_prefix); + let element_head_start_state_ident = + quote::format_ident!("{}ElementHeadStart", state_prefix); + let element_head_end_state_ident = quote::format_ident!("{}ElementHeadEnd", state_prefix); + let element_foot_state_ident = quote::format_ident!("{}ElementFoot", state_prefix); let name_ident = quote::format_ident!("name"); + let ns_ident = quote::format_ident!("ns"); + let dummy_ident = quote::format_ident!("dummy"); let mut states = Vec::new(); - let mut init_body = TokenStream::default(); let mut destructure = TokenStream::default(); let mut start_init = TokenStream::default(); states.push( - State::new(start_element_state_ident.clone()) - .with_field(&name_ident, &qname_ty(Span::call_site())), + State::new(element_head_start_state_ident.clone()) + .with_field(&dummy_ident, &phantom_lifetime_ty(lifetime.clone())) + .with_field(&ns_ident, &namespace_ty(Span::call_site())) + .with_field( + &name_ident, + &ncnamestr_cow_ty(Span::call_site(), lifetime.clone()), + ), + ); + + let mut element_head_end_idx = states.len(); + states.push( + State::new(element_head_end_state_ident.clone()).with_impl(quote! { + ::core::option::Option::Some(::xso::Item::ElementHeadEnd) + }), ); for (i, field) in self.fields.iter().enumerate() { let member = field.member(); let bound_name = mangle_member(member); - let part = field.make_iterator_part(&scope, &bound_name)?; + let part = field.make_iterator_part(&bound_name)?; let state_name = quote::format_ident!("{}Field{}", state_prefix, i); + let ty = scope.borrow(field.ty().clone()); match part { - FieldIteratorPart::Header { setter } => { + FieldIteratorPart::Header { generator } => { + // we have to make sure that we carry our data around in + // all the previous states. + for state in &mut states[..element_head_end_idx] { + state.add_field(&bound_name, &ty); + } + states.insert( + element_head_end_idx, + State::new(state_name) + .with_field(&bound_name, &ty) + .with_impl(quote! { + #generator + }), + ); + element_head_end_idx += 1; + destructure.extend(quote! { - #member: #bound_name, + #member: ref #bound_name, }); - init_body.extend(setter); start_init.extend(quote! { #bound_name, }); - states[0].add_field(&bound_name, field.ty()); } FieldIteratorPart::Text { generator } => { // we have to make sure that we carry our data around in // all the previous states. for state in states.iter_mut() { - state.add_field(&bound_name, field.ty()); + state.add_field(&bound_name, &ty); } states.push( State::new(state_name) - .with_field(&bound_name, field.ty()) + .with_field(&bound_name, &ty) .with_impl(quote! { - #generator.map(|value| ::xso::exports::rxml::Event::Text( - ::xso::exports::rxml::parser::EventMetrics::zero(), + #generator.map(|value| ::xso::Item::Text( value, )) }), @@ -298,32 +326,27 @@ impl Compound { states[0].set_impl(quote! { { - let mut #attrs = ::xso::exports::rxml::AttrMap::new(); - #init_body - ::core::option::Option::Some(::xso::exports::rxml::Event::StartElement( - ::xso::exports::rxml::parser::EventMetrics::zero(), + ::core::option::Option::Some(::xso::Item::ElementHeadStart( + #ns_ident, #name_ident, - #attrs, )) } }); states.push( - State::new(end_element_state_ident.clone()).with_impl(quote! { - ::core::option::Option::Some(::xso::exports::rxml::Event::EndElement( - ::xso::exports::rxml::parser::EventMetrics::zero(), - )) + State::new(element_foot_state_ident.clone()).with_impl(quote! { + ::core::option::Option::Some(::xso::Item::ElementFoot) }), ); - Ok(IntoEventsSubmachine { + Ok(AsItemsSubmachine { defs: TokenStream::default(), states, destructure: quote! { #input_name { #destructure } }, init: quote! { - Self::#start_element_state_ident { #name_ident, #start_init } + Self::#element_head_start_state_ident { #dummy_ident: ::std::marker::PhantomData, #name_ident: name.1, #ns_ident: name.0, #start_init } }, }) } diff --git a/xso-proc/src/field.rs b/xso-proc/src/field.rs index 04a03586..de7c48c7 100644 --- a/xso-proc/src/field.rs +++ b/xso-proc/src/field.rs @@ -14,9 +14,9 @@ use rxml_validation::NcName; use crate::error_message::{self, ParentRef}; use crate::meta::{Flag, NameRef, NamespaceRef, XmlFieldMeta}; -use crate::scope::{FromEventsScope, IntoEventsScope}; +use crate::scope::FromEventsScope; use crate::types::{ - default_fn, from_xml_text_fn, into_optional_xml_text_fn, into_xml_text_fn, string_ty, + as_optional_xml_text_fn, as_xml_text_fn, default_fn, from_xml_text_fn, string_ty, text_codec_decode_fn, text_codec_encode_fn, }; @@ -69,13 +69,12 @@ pub(crate) enum FieldBuilderPart { pub(crate) enum FieldIteratorPart { /// The field is emitted as part of StartElement. Header { - /// A sequence of statements which updates the temporary variables - /// during the StartElement event's construction, consuming the - /// field's value. - setter: TokenStream, + /// An expression which consumes the field's value and returns a + /// `Item`. + generator: TokenStream, }, - /// The field is emitted as text event. + /// The field is emitted as text item. Text { /// An expression which consumes the field's value and returns a /// String, which is then emitted as text data. @@ -295,19 +294,13 @@ impl FieldDef { /// /// `bound_name` must be the name to which the field's value is bound in /// the iterator code. - pub(crate) fn make_iterator_part( - &self, - scope: &IntoEventsScope, - bound_name: &Ident, - ) -> Result { + pub(crate) fn make_iterator_part(&self, bound_name: &Ident) -> Result { match self.kind { FieldKind::Attribute { ref xml_name, ref xml_namespace, .. } => { - let IntoEventsScope { ref attrs, .. } = scope; - let xml_namespace = match xml_namespace { Some(v) => quote! { ::xso::exports::rxml::Namespace::from(#v) }, None => quote! { @@ -315,16 +308,13 @@ impl FieldDef { }, }; - let into_optional_xml_text = into_optional_xml_text_fn(self.ty.clone()); + let as_optional_xml_text = as_optional_xml_text_fn(self.ty.clone()); Ok(FieldIteratorPart::Header { - // This is a neat little trick: - // Option::from(x) converts x to an Option *unless* it - // already is an Option<_>. - setter: quote! { - #into_optional_xml_text(#bound_name)?.and_then(|#bound_name| #attrs.insert( + generator: quote! { + #as_optional_xml_text(#bound_name)?.map(|#bound_name| ::xso::Item::Attribute( #xml_namespace, - #xml_name.to_owned(), + ::std::borrow::Cow::Borrowed(#xml_name), #bound_name, )); }, @@ -338,8 +328,8 @@ impl FieldDef { quote! { #encode(#bound_name)? } } None => { - let into_xml_text = into_xml_text_fn(self.ty.clone()); - quote! { ::core::option::Option::Some(#into_xml_text(#bound_name)?) } + let as_xml_text = as_xml_text_fn(self.ty.clone()); + quote! { ::core::option::Option::Some(#as_xml_text(#bound_name)?) } } }; diff --git a/xso-proc/src/lib.rs b/xso-proc/src/lib.rs index c5b60597..0e357a43 100644 --- a/xso-proc/src/lib.rs +++ b/xso-proc/src/lib.rs @@ -111,26 +111,27 @@ pub fn from_xml(input: RawTokenStream) -> RawTokenStream { } } -/// Generate a `xso::IntoXml` implementation for the given item, or fail with +/// Generate a `xso::AsXml` implementation for the given item, or fail with /// a proper compiler error. -fn into_xml_impl(input: Item) -> Result { +fn as_xml_impl(input: Item) -> Result { let (vis, ident, def) = parse_struct(input)?; - let structs::IntoXmlParts { + let structs::AsXmlParts { defs, - into_event_iter_body, - event_iter_ty_ident, - } = def.make_into_event_iter(&vis)?; + as_xml_iter_body, + item_iter_ty_lifetime, + item_iter_ty, + } = def.make_as_xml_iter(&vis)?; #[cfg_attr(not(feature = "minidom"), allow(unused_mut))] let mut result = quote! { #defs - impl ::xso::IntoXml for #ident { - type EventIter = #event_iter_ty_ident; + impl ::xso::AsXml for #ident { + type ItemIter<#item_iter_ty_lifetime> = #item_iter_ty; - fn into_event_iter(self) -> ::core::result::Result { - #into_event_iter_body + fn as_xml_iter(&self) -> ::core::result::Result, ::xso::error::Error> { + #as_xml_iter_body } } }; @@ -162,15 +163,15 @@ fn into_xml_impl(input: Item) -> Result { Ok(result) } -/// Macro to derive a `xso::IntoXml` implementation on a type. +/// Macro to derive a `xso::AsXml` implementation on a type. /// /// The user-facing documentation for this macro lives in the `xso` crate. -#[proc_macro_derive(IntoXml, attributes(xml))] -pub fn into_xml(input: RawTokenStream) -> RawTokenStream { - // Shim wrapper around `into_xml_impl` which converts any errors into +#[proc_macro_derive(AsXml, attributes(xml))] +pub fn as_xml(input: RawTokenStream) -> RawTokenStream { + // Shim wrapper around `as_xml_impl` which converts any errors into // actual compiler errors within the resulting token stream. let item = syn::parse_macro_input!(input as Item); - match into_xml_impl(item) { + match as_xml_impl(item) { Ok(v) => v.into(), Err(e) => e.into_compile_error().into(), } diff --git a/xso-proc/src/scope.rs b/xso-proc/src/scope.rs index 1a4fbdc9..bfe4c594 100644 --- a/xso-proc/src/scope.rs +++ b/xso-proc/src/scope.rs @@ -9,6 +9,8 @@ use proc_macro2::Span; use syn::*; +use crate::types::ref_ty; + /// Container struct for various identifiers used throughout the parser code. /// /// This struct is passed around from the [`crate::compound::Compound`] @@ -80,19 +82,24 @@ impl FromEventsScope { /// same page about which identifiers are used for what. /// /// See [`FromEventsScope`] for recommendations on the usage. -pub(crate) struct IntoEventsScope { - /// Accesses the `AttrMap` from code in - /// [`crate::field::FieldIteratorPart::Header`]. - pub(crate) attrs: Ident, +pub(crate) struct AsItemsScope { + /// Lifetime for data borrowed by the implementation. + pub(crate) lifetime: Lifetime, } -impl IntoEventsScope { +impl AsItemsScope { /// Create a fresh scope with all necessary identifiers. - pub(crate) fn new() -> Self { + pub(crate) fn new(lifetime: &Lifetime) -> Self { Self { - attrs: Ident::new("attrs", Span::call_site()), + lifetime: lifetime.clone(), } } + + /// Create a reference to `ty`, borrowed for the lifetime of the AsXml + /// impl. + pub(crate) fn borrow(&self, ty: Type) -> Type { + ref_ty(ty, self.lifetime.clone()) + } } pub(crate) fn mangle_member(member: &Member) -> Ident { diff --git a/xso-proc/src/state.rs b/xso-proc/src/state.rs index 0e35d5fe..b7899a07 100644 --- a/xso-proc/src/state.rs +++ b/xso-proc/src/state.rs @@ -82,7 +82,7 @@ impl State { /// the `advance` implementation of the state machine. /// /// See [`FromEventsStateMachine::advance_match_arms`] and - /// [`IntoEventsSubmachine::compile`] for the respective + /// [`AsItemsSubmachine::compile`] for the respective /// requirements on the implementations. pub(crate) fn with_impl(mut self, body: TokenStream) -> Self { self.advance_body = body; @@ -171,12 +171,12 @@ impl FromEventsSubmachine { } } -/// A partial [`IntoEventsStateMachine`] which only covers the builder for a +/// A partial [`AsItemsStateMachine`] which only covers the builder for a /// single compound. /// -/// See [`IntoEventsStateMachine`] for more information on the state machines +/// See [`AsItemsStateMachine`] for more information on the state machines /// in general. -pub(crate) struct IntoEventsSubmachine { +pub(crate) struct AsItemsSubmachine { /// Additional items necessary for the statemachine. pub(crate) defs: TokenStream, @@ -194,7 +194,7 @@ pub(crate) struct IntoEventsSubmachine { pub(crate) init: TokenStream, } -impl IntoEventsSubmachine { +impl AsItemsSubmachine { /// Convert a partial state machine into a full state machine. /// /// This converts the abstract [`State`] items into token @@ -202,13 +202,13 @@ impl IntoEventsSubmachine { /// definitions and the match arms), rendering them effectively immutable. /// /// This requires that the [`State::advance_body`] token streams evaluate - /// to an `Option`. If it evaluates to `Some(.)`, that is + /// to an `Option`. If it evaluates to `Some(.)`, that is /// emitted from the iterator. If it evaluates to `None`, the `advance` /// implementation is called again. /// /// Each state implementation is augmented to also enter the next state, /// causing the iterator to terminate eventually. - pub(crate) fn compile(self) -> IntoEventsStateMachine { + pub(crate) fn compile(self) -> AsItemsStateMachine { let mut state_defs = TokenStream::default(); let mut advance_match_arms = TokenStream::default(); @@ -227,13 +227,13 @@ impl IntoEventsSubmachine { .. }) => { quote! { - ::core::result::Result::Ok((::core::option::Option::Some(Self::#next_name { #construct_next }), event)) + ::core::result::Result::Ok((::core::option::Option::Some(Self::#next_name { #construct_next }), item)) } } // final state -> exit the state machine None => { quote! { - ::core::result::Result::Ok((::core::option::Option::None, event)) + ::core::result::Result::Ok((::core::option::Option::None, item)) } } }; @@ -244,17 +244,17 @@ impl IntoEventsSubmachine { advance_match_arms.extend(quote! { Self::#name { #destructure } => { - let event = #advance_body; + let item = #advance_body; #footer } }); } - IntoEventsStateMachine { + AsItemsStateMachine { defs: self.defs, state_defs, advance_match_arms, - variants: vec![IntoEventsEntryPoint { + variants: vec![AsItemsEntryPoint { init: self.init, destructure: self.destructure, }], @@ -281,7 +281,7 @@ pub(crate) struct FromEventsEntryPoint { } /// A single variant's entrypoint into the event iterator. -pub(crate) struct IntoEventsEntryPoint { +pub(crate) struct AsItemsEntryPoint { /// A pattern match which destructures the target type into its parts, for /// use by `init`. destructure: TokenStream, @@ -468,7 +468,7 @@ impl FromEventsStateMachine { /// method. That method consumes the enum value and returns either a new enum /// value, an error, or the output type of the state machine. #[derive(Default)] -pub(crate) struct IntoEventsStateMachine { +pub(crate) struct AsItemsStateMachine { /// Extra items which are needed for the state machine implementation. defs: TokenStream, @@ -480,7 +480,7 @@ pub(crate) struct IntoEventsStateMachine { /// enumeration type. /// /// Each match arm must either diverge or evaluate to a - /// `Result<(Option, Option), xso::error::Error>`, where + /// `Result<(Option, Option), xso::error::Error>`, where /// where `State` is the state enumeration. /// /// If `Some(.)` is returned for the event, that event is emitted. If @@ -489,7 +489,7 @@ pub(crate) struct IntoEventsStateMachine { /// field. /// /// If `None` is returned for the `Option`, the iterator - /// terminates yielding the `Option` value directly (even if it is + /// terminates yielding the `Option` value directly (even if it is /// `None`). After the iterator has terminated, it yields `None` /// indefinitely. advance_match_arms: TokenStream, @@ -498,10 +498,10 @@ pub(crate) struct IntoEventsStateMachine { /// /// This may only contain more than one element if an enumeration is being /// serialised by the resulting state machine. - variants: Vec, + variants: Vec, } -impl IntoEventsStateMachine { +impl AsItemsStateMachine { /// Render the state machine as a token stream. /// /// The token stream contains the following pieces: @@ -515,7 +515,8 @@ impl IntoEventsStateMachine { vis: &Visibility, input_ty: &Type, state_ty_ident: &Ident, - event_iter_ty_ident: &Ident, + item_iter_ty_lifetime: &Lifetime, + item_iter_ty: &Type, ) -> Result { let Self { defs, @@ -525,10 +526,10 @@ impl IntoEventsStateMachine { } = self; let input_ty_ref = make_ty_ref(input_ty); - let docstr = format!("Convert a {0} into XML events.\n\nThis type is generated using the [`macro@xso::IntoXml`] derive macro and implements [`std::iter:Iterator`] for {0}.", input_ty_ref); + let docstr = format!("Convert a {0} into XML events.\n\nThis type is generated using the [`macro@xso::AsXml`] derive macro and implements [`std::iter:Iterator`] for {0}.", input_ty_ref); let init_body = if variants.len() == 1 { - let IntoEventsEntryPoint { destructure, init } = variants.remove(0); + let AsItemsEntryPoint { destructure, init } = variants.remove(0); quote! { { let #destructure = value; @@ -537,7 +538,7 @@ impl IntoEventsStateMachine { } } else { let mut match_arms = TokenStream::default(); - for IntoEventsEntryPoint { destructure, init } in variants { + for AsItemsEntryPoint { destructure, init } in variants { match_arms.extend(quote! { #destructure => #init, }); @@ -553,40 +554,40 @@ impl IntoEventsStateMachine { Ok(quote! { #defs - enum #state_ty_ident { + enum #state_ty_ident<#item_iter_ty_lifetime> { #state_defs } - impl #state_ty_ident { - fn advance(mut self) -> ::core::result::Result<(::core::option::Option, ::core::option::Option<::xso::exports::rxml::Event>), ::xso::error::Error> { + impl<#item_iter_ty_lifetime> #state_ty_ident<#item_iter_ty_lifetime> { + fn advance(mut self) -> ::core::result::Result<(::core::option::Option, ::core::option::Option<::xso::Item<#item_iter_ty_lifetime>>), ::xso::error::Error> { match self { #advance_match_arms } } fn new( - value: #input_ty, + value: &#item_iter_ty_lifetime #input_ty, ) -> ::core::result::Result { ::core::result::Result::Ok(#init_body) } } #[doc = #docstr] - #vis struct #event_iter_ty_ident(::core::option::Option<#state_ty_ident>); + #vis struct #item_iter_ty(::core::option::Option<#state_ty_ident<#item_iter_ty_lifetime>>); - impl ::std::iter::Iterator for #event_iter_ty_ident { - type Item = ::core::result::Result<::xso::exports::rxml::Event, ::xso::error::Error>; + impl<#item_iter_ty_lifetime> ::std::iter::Iterator for #item_iter_ty { + type Item = ::core::result::Result<::xso::Item<#item_iter_ty_lifetime>, ::xso::error::Error>; fn next(&mut self) -> ::core::option::Option { let mut state = self.0.take()?; loop { - let (next_state, ev) = match state.advance() { + let (next_state, item) = match state.advance() { ::core::result::Result::Ok(v) => v, ::core::result::Result::Err(e) => return ::core::option::Option::Some(::core::result::Result::Err(e)), }; - if let ::core::option::Option::Some(ev) = ev { + if let ::core::option::Option::Some(item) = item { self.0 = next_state; - return ::core::option::Option::Some(::core::result::Result::Ok(ev)); + return ::core::option::Option::Some(::core::result::Result::Ok(item)); } // no event, do we have a state? if let ::core::option::Option::Some(st) = next_state { @@ -602,8 +603,8 @@ impl IntoEventsStateMachine { } } - impl #event_iter_ty_ident { - fn new(value: #input_ty) -> ::core::result::Result { + impl<#item_iter_ty_lifetime> #item_iter_ty { + fn new(value: &#item_iter_ty_lifetime #input_ty) -> ::core::result::Result { #state_ty_ident::new(value).map(|ok| Self(::core::option::Option::Some(ok))) } } diff --git a/xso-proc/src/structs.rs b/xso-proc/src/structs.rs index 5242cefb..9106ffee 100644 --- a/xso-proc/src/structs.rs +++ b/xso-proc/src/structs.rs @@ -6,7 +6,7 @@ //! Handling of structs -use proc_macro2::TokenStream; +use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::*; @@ -25,16 +25,19 @@ pub(crate) struct FromXmlParts { pub(crate) builder_ty_ident: Ident, } -/// Parts necessary to construct a `::xso::IntoXml` implementation. -pub(crate) struct IntoXmlParts { +/// Parts necessary to construct a `::xso::AsXml` implementation. +pub(crate) struct AsXmlParts { /// Additional items necessary for the implementation. pub(crate) defs: TokenStream, - /// The body of the `::xso::IntoXml::into_event_iter` function. - pub(crate) into_event_iter_body: TokenStream, + /// The body of the `::xso::AsXml::as_xml_iter` function. + pub(crate) as_xml_iter_body: TokenStream, - /// The name of the type which is the `::xso::IntoXml::EventIter`. - pub(crate) event_iter_ty_ident: Ident, + /// The type which is the `::xso::AsXml::ItemIter`. + pub(crate) item_iter_ty: Type, + + /// The lifetime name used in `item_iter_ty`. + pub(crate) item_iter_ty_lifetime: Lifetime, } /// Definition of a struct and how to parse it. @@ -55,7 +58,7 @@ pub(crate) struct StructDef { builder_ty_ident: Ident, /// Name of the iterator type. - event_iter_ty_ident: Ident, + item_iter_ty_ident: Ident, /// Flag whether debug mode is enabled. debug: bool, @@ -78,7 +81,7 @@ impl StructDef { inner: Compound::from_fields(fields)?, target_ty_ident: ident.clone(), builder_ty_ident: quote::format_ident!("{}FromXmlBuilder", ident), - event_iter_ty_ident: quote::format_ident!("{}IntoXmlIterator", ident), + item_iter_ty_ident: quote::format_ident!("{}AsXmlIterator", ident), debug: meta.debug.is_set(), }) } @@ -136,22 +139,53 @@ impl StructDef { }) } - pub(crate) fn make_into_event_iter(&self, vis: &Visibility) -> Result { + pub(crate) fn make_as_xml_iter(&self, vis: &Visibility) -> Result { let xml_namespace = &self.namespace; let xml_name = &self.name; let target_ty_ident = &self.target_ty_ident; - let event_iter_ty_ident = &self.event_iter_ty_ident; - let state_ty_ident = quote::format_ident!("{}State", event_iter_ty_ident); + let item_iter_ty_ident = &self.item_iter_ty_ident; + let item_iter_ty_lifetime = Lifetime { + apostrophe: Span::call_site(), + ident: Ident::new("xso_proc_as_xml_iter_lifetime", Span::call_site()), + }; + let item_iter_ty = Type::Path(TypePath { + qself: None, + path: Path { + leading_colon: None, + segments: [PathSegment { + ident: item_iter_ty_ident.clone(), + arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { + colon2_token: None, + lt_token: token::Lt { + spans: [Span::call_site()], + }, + args: [GenericArgument::Lifetime(item_iter_ty_lifetime.clone())] + .into_iter() + .collect(), + gt_token: token::Gt { + spans: [Span::call_site()], + }, + }), + }] + .into_iter() + .collect(), + }, + }); + let state_ty_ident = quote::format_ident!("{}State", item_iter_ty_ident); let defs = self .inner - .make_into_event_iter_statemachine(&target_ty_ident.clone().into(), "Struct")? + .make_as_item_iter_statemachine( + &target_ty_ident.clone().into(), + "Struct", + &item_iter_ty_lifetime, + )? .with_augmented_init(|init| { quote! { let name = ( ::xso::exports::rxml::Namespace::from(#xml_namespace), - #xml_name.into(), + ::std::borrow::Cow::Borrowed(#xml_name), ); #init } @@ -165,15 +199,17 @@ impl StructDef { } .into(), &state_ty_ident, - event_iter_ty_ident, + &item_iter_ty_lifetime, + &item_iter_ty, )?; - Ok(IntoXmlParts { + Ok(AsXmlParts { defs, - into_event_iter_body: quote! { - #event_iter_ty_ident::new(self) + as_xml_iter_body: quote! { + #item_iter_ty_ident::new(self) }, - event_iter_ty_ident: event_iter_ty_ident.clone(), + item_iter_ty, + item_iter_ty_lifetime, }) } diff --git a/xso-proc/src/types.rs b/xso-proc/src/types.rs index db438024..70b9f93b 100644 --- a/xso-proc/src/types.rs +++ b/xso-proc/src/types.rs @@ -9,8 +9,8 @@ use proc_macro2::Span; use syn::{spanned::Spanned, *}; -/// Construct a [`syn::Type`] referring to `::xso::exports::rxml::QName`. -pub(crate) fn qname_ty(span: Span) -> Type { +/// Construct a [`syn::Type`] referring to `::xso::exports::rxml::Namespace`. +pub(crate) fn namespace_ty(span: Span) -> Type { Type::Path(TypePath { qself: None, path: Path { @@ -31,7 +31,7 @@ pub(crate) fn qname_ty(span: Span) -> Type { arguments: PathArguments::None, }, PathSegment { - ident: Ident::new("QName", span), + ident: Ident::new("Namespace", span), arguments: PathArguments::None, }, ] @@ -41,6 +41,83 @@ pub(crate) fn qname_ty(span: Span) -> Type { }) } +/// Construct a [`syn::Type`] referring to `::xso::exports::rxml::NcNameStr`. +pub(crate) fn ncnamestr_ty(span: Span) -> Type { + Type::Path(TypePath { + qself: None, + path: Path { + leading_colon: Some(syn::token::PathSep { + spans: [span, span], + }), + segments: [ + PathSegment { + ident: Ident::new("xso", span), + arguments: PathArguments::None, + }, + PathSegment { + ident: Ident::new("exports", span), + arguments: PathArguments::None, + }, + PathSegment { + ident: Ident::new("rxml", span), + arguments: PathArguments::None, + }, + PathSegment { + ident: Ident::new("NcNameStr", span), + arguments: PathArguments::None, + }, + ] + .into_iter() + .collect(), + }, + }) +} + +/// Construct a [`syn::Type`] referring to `Cow<#lifetime, #ty>`. +pub(crate) fn cow_ty(ty: Type, lifetime: Lifetime) -> Type { + let span = ty.span(); + Type::Path(TypePath { + qself: None, + path: Path { + leading_colon: Some(syn::token::PathSep { + spans: [span, span], + }), + segments: [ + PathSegment { + ident: Ident::new("std", span), + arguments: PathArguments::None, + }, + PathSegment { + ident: Ident::new("borrow", span), + arguments: PathArguments::None, + }, + PathSegment { + ident: Ident::new("Cow", span), + arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { + colon2_token: None, + lt_token: token::Lt { spans: [span] }, + args: [ + GenericArgument::Lifetime(lifetime), + GenericArgument::Type(ty), + ] + .into_iter() + .collect(), + gt_token: token::Gt { spans: [span] }, + }), + }, + ] + .into_iter() + .collect(), + }, + }) +} + +/// Construct a [`syn::Type`] referring to +/// `Cow<#lifetime, ::rxml::NcNameStr>`. +pub(crate) fn ncnamestr_cow_ty(ty_span: Span, lifetime: Lifetime) -> Type { + cow_ty(ncnamestr_ty(ty_span), lifetime) +} + /// Construct a [`syn::Expr`] referring to /// `<#ty as ::xso::FromXmlText>::from_xml_text`. pub(crate) fn from_xml_text_fn(ty: Type) -> Expr { @@ -79,8 +156,8 @@ pub(crate) fn from_xml_text_fn(ty: Type) -> Expr { } /// Construct a [`syn::Expr`] referring to -/// `<#ty as ::xso::IntoOptionalXmlText>::into_optional_xml_text`. -pub(crate) fn into_optional_xml_text_fn(ty: Type) -> Expr { +/// `<#ty as ::xso::AsOptionalXmlText>::as_optional_xml_text`. +pub(crate) fn as_optional_xml_text_fn(ty: Type) -> Expr { let span = ty.span(); Expr::Path(ExprPath { attrs: Vec::new(), @@ -101,11 +178,11 @@ pub(crate) fn into_optional_xml_text_fn(ty: Type) -> Expr { arguments: PathArguments::None, }, PathSegment { - ident: Ident::new("IntoOptionalXmlText", span), + ident: Ident::new("AsOptionalXmlText", span), arguments: PathArguments::None, }, PathSegment { - ident: Ident::new("into_optional_xml_text", span), + ident: Ident::new("as_optional_xml_text", span), arguments: PathArguments::None, }, ] @@ -185,8 +262,8 @@ pub(crate) fn string_ty(span: Span) -> Type { } /// Construct a [`syn::Expr`] referring to -/// `<#ty as ::xso::IntoXmlText>::into_xml_text`. -pub(crate) fn into_xml_text_fn(ty: Type) -> Expr { +/// `<#ty as ::xso::AsXmlText>::as_xml_text`. +pub(crate) fn as_xml_text_fn(ty: Type) -> Expr { let span = ty.span(); Expr::Path(ExprPath { attrs: Vec::new(), @@ -207,11 +284,11 @@ pub(crate) fn into_xml_text_fn(ty: Type) -> Expr { arguments: PathArguments::None, }, PathSegment { - ident: Ident::new("IntoXmlText", span), + ident: Ident::new("AsXmlText", span), arguments: PathArguments::None, }, PathSegment { - ident: Ident::new("into_xml_text", span), + ident: Ident::new("as_xml_text", span), arguments: PathArguments::None, }, ] @@ -293,3 +370,55 @@ pub(crate) fn text_codec_decode_fn(codec_ty: Type, for_ty: Type) -> Expr { path: ty.path, }) } + +/// Construct a [`syn::Type`] for `&#lifetime #ty`. +pub(crate) fn ref_ty(ty: Type, lifetime: Lifetime) -> Type { + let span = ty.span(); + Type::Reference(TypeReference { + and_token: token::And { spans: [span] }, + lifetime: Some(lifetime), + mutability: None, + elem: Box::new(ty), + }) +} + +/// Construct a [`syn::Type`] referring to +/// `::std::marker::PhantomData<&#lifetime ()>`. +pub(crate) fn phantom_lifetime_ty(lifetime: Lifetime) -> Type { + let span = lifetime.span(); + let dummy = Type::Tuple(TypeTuple { + paren_token: token::Paren::default(), + elems: punctuated::Punctuated::default(), + }); + Type::Path(TypePath { + qself: None, + path: Path { + leading_colon: Some(syn::token::PathSep { + spans: [span, span], + }), + segments: [ + PathSegment { + ident: Ident::new("std", span), + arguments: PathArguments::None, + }, + PathSegment { + ident: Ident::new("marker", span), + arguments: PathArguments::None, + }, + PathSegment { + ident: Ident::new("PhantomData", span), + arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { + colon2_token: None, + lt_token: token::Lt { spans: [span] }, + args: [GenericArgument::Type(ref_ty(dummy, lifetime))] + .into_iter() + .collect(), + gt_token: token::Gt { spans: [span] }, + }), + }, + ] + .into_iter() + .collect(), + }, + }) +} diff --git a/xso/src/from_xml_doc.md b/xso/src/from_xml_doc.md index 90073ba6..7ff83bd0 100644 --- a/xso/src/from_xml_doc.md +++ b/xso/src/from_xml_doc.md @@ -1,7 +1,7 @@ # Make a struct or enum parseable from XML This derives the [`FromXml`] trait on a struct or enum. It is the counterpart -to [`macro@IntoXml`]. +to [`macro@AsXml`]. ## Example @@ -75,7 +75,7 @@ The following mapping types are defined: The `attribute` meta causes the field to be mapped to an XML attribute of the same name. For `FromXml`, the field's type must implement [`FromXmlText`] and -for `IntoXml`, the field's type must implement [`IntoOptionalXmlText`]. +for `AsXml`, the field's type must implement [`AsOptionalXmlText`]. The following keys can be used inside the `#[xml(attribute(..))]` meta: @@ -99,7 +99,7 @@ otherwise). If `default` is specified and the attribute is absent in the source, the value is generated using [`std::default::Default`], requiring the field type to implement the `Default` trait for a `FromXml` derivation. `default` has no -influence on `IntoXml`. +influence on `AsXml`. ##### Example @@ -148,14 +148,14 @@ If `codec` is given, the given `codec` must implement [`TextCodec`][`TextCodec`] where `T` is the type of the field. If `codec` is *not* given, the field's type must implement [`FromXmlText`] for -`FromXml` and for `IntoXml`, the field's type must implement [`IntoXmlText`]. +`FromXml` and for `AsXml`, the field's type must implement [`AsXmlText`]. The `text` meta also supports a shorthand syntax, `#[xml(text = ..)]`, where the value is treated as the value for the `codec` key (with optional prefix as described above, and unnamespaced otherwise). Only a single field per struct may be annotated with `#[xml(text)]` at a time, -to avoid parsing ambiguities. This is also true if only `IntoXml` is derived on +to avoid parsing ambiguities. This is also true if only `AsXml` is derived on a field, for consistency. ##### Example without codec diff --git a/xso/src/lib.rs b/xso/src/lib.rs index 6a66d1c3..9d540748 100644 --- a/xso/src/lib.rs +++ b/xso/src/lib.rs @@ -49,14 +49,14 @@ pub use xso_proc::FromXml; /// # Make a struct or enum serialisable to XML /// -/// This derives the [`IntoXml`] trait on a struct or enum. It is the +/// This derives the [`AsXml`] trait on a struct or enum. It is the /// counterpart to [`macro@FromXml`]. /// /// The attributes necessary and available for the derivation to work are /// documented on [`macro@FromXml`]. #[doc(inline)] #[cfg(feature = "macros")] -pub use xso_proc::IntoXml; +pub use xso_proc::AsXml; /// Trait allowing to consume a struct and iterate its contents as /// serialisable [`rxml::Event`] items. @@ -369,10 +369,10 @@ impl AsOptionalXmlText for Option { } } -/// Attempt to transform a type implementing [`IntoXml`] into another +/// Attempt to transform a type implementing [`AsXml`] into another /// type which implements [`FromXml`]. -pub fn transform(from: F) -> Result { - let mut iter = from.into_event_iter()?; +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), Some(Err(e)) => return Err(e), @@ -418,8 +418,24 @@ pub fn try_from_element( } }; - let mut iter = from.into_event_iter()?; - iter.next().expect("first event from minidom::Element")?; + let mut iter = from.as_xml_iter()?; + // consume the element header + for item in &mut iter { + let item = item?; + match item { + // discard the element header + Item::XmlDeclaration(..) => (), + Item::ElementHeadStart(..) => (), + Item::Attribute(..) => (), + Item::ElementHeadEnd => { + // now that the element header is over, we break out + break; + } + Item::Text(..) => panic!("text before end of element header"), + Item::ElementFoot => panic!("element foot before end of element header"), + } + } + let iter = self::rxml_util::ItemToEvent::new(iter); for event in iter { let event = event?; if let Some(v) = sink.feed(event)? { diff --git a/xso/src/rxml_util.rs b/xso/src/rxml_util.rs index 36f95646..7f5fcd60 100644 --- a/xso/src/rxml_util.rs +++ b/xso/src/rxml_util.rs @@ -8,9 +8,7 @@ use std::borrow::Cow; -use rxml::{Namespace, NcNameStr, XmlVersion}; -#[cfg(feature = "minidom")] -use rxml::Event; +use rxml::{parser::EventMetrics, AttrMap, Event, Namespace, NcName, NcNameStr, XmlVersion}; /// An encodable item. /// @@ -164,12 +162,130 @@ impl>> Iterator for EventT } } +/// Iterator adapter which converts an iterator over [`Item`] to +/// an iterator over [`Event`][`crate::Event`]. +/// +/// As `Event` does not support borrowing data, this iterator copies the data +/// from the items on the fly. +pub(crate) struct ItemToEvent { + inner: I, + event_buffer: Option, + elem_buffer: Option<(Namespace, NcName, AttrMap)>, +} + +impl<'x, I: Iterator, crate::error::Error>>> ItemToEvent { + /// Create a new adapter with `inner` as the source iterator. + pub(crate) fn new(inner: I) -> Self { + Self { + inner, + event_buffer: None, + elem_buffer: None, + } + } +} + +impl ItemToEvent { + fn update<'x>(&mut self, item: Item<'x>) -> Result, crate::error::Error> { + assert!(self.event_buffer.is_none()); + match item { + Item::XmlDeclaration(v) => { + assert!(self.elem_buffer.is_none()); + Ok(Some(Event::XmlDeclaration(EventMetrics::zero(), v))) + } + Item::ElementHeadStart(ns, name) => { + if self.elem_buffer.is_some() { + // this is only used with AsXml implementations, so + // triggering this is always a coding failure instead of a + // runtime error. + panic!("got a second ElementHeadStart items without ElementHeadEnd inbetween: ns={:?} name={:?} (state={:?})", ns, name, self.elem_buffer); + } + self.elem_buffer = Some((ns.to_owned(), name.into_owned(), AttrMap::new())); + Ok(None) + } + Item::Attribute(ns, name, value) => { + let Some((_, _, attrs)) = self.elem_buffer.as_mut() else { + // this is only used with AsXml implementations, so + // triggering this is always a coding failure instead of a + // runtime error. + panic!( + "got a second Attribute item without ElementHeadStart: ns={:?}, name={:?}", + ns, name + ); + }; + attrs.insert(ns, name.into_owned(), value.into_owned()); + Ok(None) + } + Item::ElementHeadEnd => { + let Some((ns, name, attrs)) = self.elem_buffer.take() else { + // this is only used with AsXml implementations, so + // triggering this is always a coding failure instead of a + // runtime error. + panic!( + "got ElementHeadEnd item without ElementHeadStart: {:?}", + item + ); + }; + Ok(Some(Event::StartElement( + EventMetrics::zero(), + (ns, name), + attrs, + ))) + } + Item::Text(value) => { + if let Some(elem_buffer) = self.elem_buffer.as_ref() { + // this is only used with AsXml implementations, so + // triggering this is always a coding failure instead of a + // runtime error. + panic!("got Text after ElementHeadStart but before ElementHeadEnd: Text({:?}) (state = {:?})", value, elem_buffer); + } + Ok(Some(Event::Text(EventMetrics::zero(), value.into_owned()))) + } + Item::ElementFoot => { + let end_ev = Event::EndElement(EventMetrics::zero()); + let result = if let Some((ns, name, attrs)) = self.elem_buffer.take() { + // content-less element + self.event_buffer = Some(end_ev); + Event::StartElement(EventMetrics::zero(), (ns, name), attrs) + } else { + end_ev + }; + Ok(Some(result)) + } + } + } +} + +impl<'x, I: Iterator, crate::error::Error>>> Iterator for ItemToEvent { + type Item = Result; + + fn next(&mut self) -> Option { + if let Some(event) = self.event_buffer.take() { + return Some(Ok(event)); + } + loop { + let item = match self.inner.next() { + Some(Ok(v)) => v, + Some(Err(e)) => return Some(Err(e)), + None => return None, + }; + match self.update(item).transpose() { + Some(v) => return Some(v), + None => (), + } + } + } + + fn size_hint(&self) -> (usize, Option) { + // we may create an indefinte amount of items for a single event, + // so we cannot provide a reasonable upper bound. + (self.inner.size_hint().0, None) + } +} + #[cfg(all(test, feature = "minidom"))] mod tests_minidom { use std::convert::TryInto; - use rxml::{parser::EventMetrics, AttrMap}; - use super::*; fn events_to_items>(events: I) -> Vec> { @@ -307,3 +423,144 @@ mod tests_minidom { }; } } + +#[cfg(test)] +mod tests { + use std::convert::TryInto; + + use super::*; + + fn items_to_events<'x, I: IntoIterator>>( + items: I, + ) -> Result, crate::error::Error> { + let iter = ItemToEvent { + inner: items.into_iter().map(|x| Ok(x)), + event_buffer: None, + elem_buffer: None, + }; + let mut result = Vec::new(); + for ev in iter { + let ev = ev?; + result.push(ev); + } + Ok(result) + } + + #[test] + fn item_to_event_xml_decl() { + let items = vec![Item::XmlDeclaration(XmlVersion::V1_0)]; + let events = items_to_events(items).expect("item conversion"); + assert_eq!(events.len(), 1); + match events[0] { + Event::XmlDeclaration(_, XmlVersion::V1_0) => (), + ref other => panic!("unexected event in position 0: {:?}", other), + }; + } + + #[test] + fn item_to_event_simple_empty_element() { + let items = vec![ + Item::ElementHeadStart(Namespace::NONE, Cow::Borrowed("elem".try_into().unwrap())), + Item::ElementHeadEnd, + Item::ElementFoot, + ]; + let events = items_to_events(items).expect("item conversion"); + assert_eq!(events.len(), 2); + match events[0] { + Event::StartElement(_, (ref ns, ref name), ref attrs) => { + assert_eq!(attrs.len(), 0); + assert_eq!(ns, Namespace::none()); + assert_eq!(name, "elem"); + } + ref other => panic!("unexected event in position 0: {:?}", other), + }; + match events[1] { + Event::EndElement(_) => (), + ref other => panic!("unexected event in position 1: {:?}", other), + }; + } + + #[test] + fn item_to_event_short_empty_element() { + let items = vec![ + Item::ElementHeadStart(Namespace::NONE, Cow::Borrowed("elem".try_into().unwrap())), + Item::ElementFoot, + ]; + let events = items_to_events(items).expect("item conversion"); + assert_eq!(events.len(), 2); + match events[0] { + Event::StartElement(_, (ref ns, ref name), ref attrs) => { + assert_eq!(attrs.len(), 0); + assert_eq!(ns, Namespace::none()); + assert_eq!(name, "elem"); + } + ref other => panic!("unexected event in position 0: {:?}", other), + }; + match events[1] { + Event::EndElement(_) => (), + ref other => panic!("unexected event in position 1: {:?}", other), + }; + } + + #[test] + fn item_to_event_element_with_text_content() { + let items = vec![ + Item::ElementHeadStart(Namespace::NONE, Cow::Borrowed("elem".try_into().unwrap())), + Item::ElementHeadEnd, + Item::Text(Cow::Borrowed("Hello World!")), + Item::ElementFoot, + ]; + let events = items_to_events(items).expect("item conversion"); + assert_eq!(events.len(), 3); + match events[0] { + Event::StartElement(_, (ref ns, ref name), ref attrs) => { + assert_eq!(attrs.len(), 0); + assert_eq!(ns, Namespace::none()); + assert_eq!(name, "elem"); + } + ref other => panic!("unexected event in position 0: {:?}", other), + }; + match events[1] { + Event::Text(_, ref value) => { + assert_eq!(value, "Hello World!"); + } + ref other => panic!("unexected event in position 1: {:?}", other), + }; + match events[2] { + Event::EndElement(_) => (), + ref other => panic!("unexected event in position 2: {:?}", other), + }; + } + + #[test] + fn item_to_event_element_with_attributes() { + let items = vec![ + Item::ElementHeadStart(Namespace::NONE, Cow::Borrowed("elem".try_into().unwrap())), + Item::Attribute( + Namespace::NONE, + Cow::Borrowed("attr".try_into().unwrap()), + Cow::Borrowed("value"), + ), + Item::ElementHeadEnd, + Item::ElementFoot, + ]; + let events = items_to_events(items).expect("item conversion"); + assert_eq!(events.len(), 2); + match events[0] { + Event::StartElement(_, (ref ns, ref name), ref attrs) => { + assert_eq!(ns, Namespace::none()); + assert_eq!(name, "elem"); + assert_eq!(attrs.len(), 1); + assert_eq!( + attrs.get(Namespace::none(), "attr").map(|x| x.as_str()), + Some("value") + ); + } + ref other => panic!("unexected event in position 0: {:?}", other), + }; + match events[1] { + Event::EndElement(_) => (), + ref other => panic!("unexected event in position 2: {:?}", other), + }; + } +} diff --git a/xso/src/text.rs b/xso/src/text.rs index 40664e2c..767062e5 100644 --- a/xso/src/text.rs +++ b/xso/src/text.rs @@ -134,7 +134,7 @@ convert_via_fromstr_and_display! { /// Represent a way to encode/decode text data into a Rust type. /// /// This trait can be used in scenarios where implementing [`FromXmlText`] -/// and/or [`IntoXmlText`] on a type is not feasible or sensible, such as the +/// and/or [`AsXmlText`] on a type is not feasible or sensible, such as the /// following: /// /// 1. The type originates in a foreign crate, preventing the implementation @@ -143,7 +143,7 @@ convert_via_fromstr_and_display! { /// 2. There is more than one way to convert a value to/from XML. /// /// The codec to use for a text can be specified in the attributes understood -/// by `FromXml` and `IntoXml` derive macros. See the documentation of the +/// by `FromXml` and `AsXml` derive macros. See the documentation of the /// [`FromXml`][`macro@crate::FromXml`] derive macro for details. pub trait TextCodec { /// Decode a string value into the type. @@ -152,7 +152,7 @@ pub trait TextCodec { /// Encode the type as string value. /// /// If this returns `None`, the string value is not emitted at all. - fn encode(value: T) -> Result, Error>; + fn encode(value: &T) -> Result>, Error>; } /// Text codec which does no transform. @@ -163,8 +163,8 @@ impl TextCodec for Plain { Ok(s) } - fn encode(value: String) -> Result, Error> { - Ok(Some(value)) + fn encode(value: &String) -> Result>, Error> { + Ok(Some(Cow::Borrowed(value.as_str()))) } } @@ -180,9 +180,9 @@ impl TextCodec> for EmptyAsNone { } } - fn encode(value: Option) -> Result, Error> { - Ok(match value { - Some(v) if !v.is_empty() => Some(v), + fn encode(value: &Option) -> Result>, Error> { + Ok(match value.as_ref() { + Some(v) if !v.is_empty() => Some(Cow::Borrowed(v.as_str())), Some(_) | None => None, }) } @@ -237,8 +237,8 @@ impl TextCodec> for Base64 { .map_err(Error::text_parse_error) } - fn encode(value: Vec) -> Result, Error> { - Ok(Some(StandardBase64Engine.encode(&value))) + fn encode(value: &Vec) -> Result>, Error> { + Ok(Some(Cow::Owned(StandardBase64Engine.encode(&value)))) } } @@ -252,7 +252,11 @@ impl TextCodec>> for Base64 { Ok(Some(Self::decode(s)?)) } - fn encode(decoded: Option>) -> Result, Error> { - decoded.map(Self::encode).transpose().map(Option::flatten) + fn encode(decoded: &Option>) -> Result>, Error> { + decoded + .as_ref() + .map(Self::encode) + .transpose() + .map(Option::flatten) } }