@@ -693,13 +693,7 @@ macro_rules! generate_element {
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, children: [$($(#[$child_meta:meta])* $child_ident:ident: $coucou:tt<$child_type:ty> = ($child_name:tt, $child_ns:tt) => $child_constructor:ident),+$(,)?]) => (
generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [], children: [$($(#[$child_meta])* $child_ident: $coucou<$child_type> = ($child_name, $child_ns) => $child_constructor),*]);
);
- ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, text: ($(#[$text_meta:meta])* $text_ident:ident: $codec:ty )) => (
- generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [], children: [], text: ($(#[$text_meta])* $text_ident: $codec));
- );
- ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),+$(,)?], text: ($(#[$text_meta:meta])* $text_ident:ident: $codec:ty )) => (
- generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_action<$attr_type> = $attr_name),*], children: [], text: ($(#[$text_meta])* $text_ident: $codec));
- );
- ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),*$(,)?], children: [$($(#[$child_meta:meta])* $child_ident:ident: $coucou:tt<$child_type:ty> = ($child_name:tt, $child_ns:tt) => $child_constructor:ident),*$(,)?] $(, text: ($(#[$text_meta:meta])* $text_ident:ident: $codec:ty ))*) => (
+ ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),*$(,)?], children: [$($(#[$child_meta:meta])* $child_ident:ident: $coucou:tt<$child_type:ty> = ($child_name:tt, $child_ns:tt) => $child_constructor:ident),*$(,)?]) => (
$(#[$meta])*
#[derive(Debug, Clone, PartialEq)]
pub struct $elem {
@@ -711,10 +705,6 @@ macro_rules! generate_element {
$(#[$child_meta])*
pub $child_ident: start_decl!($coucou, $child_type),
)*
- $(
- $(#[$text_meta])*
- pub $text_ident: <$codec as Codec>::Decoded,
- )*
}
impl ::xso::FromXml for $elem {
@@ -743,22 +733,6 @@ macro_rules! generate_element {
$(
start_parse_elem!($child_ident: $coucou);
)*
- // We must pull the texts out of the Element before we pull
- // the children, because take_elements_as_children drains
- // *all* child nodes, including texts.
- // To deal with the genericity of this macro, we need a local
- // struct decl to carry the identifier around.
- struct Texts {
- $(
- $text_ident: <$codec as Codec>::Decoded,
- )*
- }
- #[allow(unused_variables)]
- let texts = Texts {
- $(
- $text_ident: <$codec>::decode(&elem.text())?,
- )*
- };
for _child in elem.take_contents_as_children() {
let residual = _child;
$(
@@ -783,9 +757,6 @@ macro_rules! generate_element {
$(
$child_ident: finish_parse_elem!($child_ident: $coucou = $child_name, $name),
)*
- $(
- $text_ident: texts.$text_ident,
- )*
})
}
}
@@ -799,9 +770,6 @@ macro_rules! generate_element {
$(
builder = generate_serialiser!(builder, elem, $child_ident, $coucou, $child_constructor, ($child_name, $child_ns));
)*
- $(
- builder = builder.append_all(<$codec>::encode(&elem.$text_ident).map(::minidom::Node::Text).into_iter());
- )*
builder.build()
}
@@ -1,217 +0,0 @@
-// Copyright (c) 2017 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
-//
-// 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 base64::{engine::general_purpose::STANDARD as Base64Engine, Engine};
-use xso::error::Error;
-
-/// A trait for codecs that can decode and encode text nodes.
-pub trait Codec {
- type Decoded;
-
- /// Decode the given string into the codecβs output.
- fn decode(s: &str) -> Result<Self::Decoded, Error>;
-
- /// Encode the given value; return None to not produce a text node at all.
- fn encode(decoded: &Self::Decoded) -> Option<String>;
-}
-
-/// Codec for text content.
-pub struct Text;
-
-impl Codec for Text {
- type Decoded = String;
-
- fn decode(s: &str) -> Result<String, Error> {
- Ok(s.to_owned())
- }
-
- fn encode(decoded: &String) -> Option<String> {
- Some(decoded.to_owned())
- }
-}
-
-/// Codec transformer that makes the text optional; a "" string is decoded as None.
-pub struct OptionalCodec<T: Codec>(std::marker::PhantomData<T>);
-
-impl<T> Codec for OptionalCodec<T>
-where
- T: Codec,
-{
- type Decoded = Option<T::Decoded>;
-
- fn decode(s: &str) -> Result<Option<T::Decoded>, Error> {
- if s.is_empty() {
- return Ok(None);
- }
-
- Ok(Some(T::decode(s)?))
- }
-
- fn encode(decoded: &Option<T::Decoded>) -> Option<String> {
- decoded.as_ref().and_then(T::encode)
- }
-}
-
-/// Codec that trims whitespace around the text.
-pub struct Trimmed<T: Codec>(std::marker::PhantomData<T>);
-
-impl<T> Codec for Trimmed<T>
-where
- T: Codec,
-{
- type Decoded = T::Decoded;
-
- fn decode(s: &str) -> Result<T::Decoded, Error> {
- match s.trim() {
- // TODO: This error message can be a bit opaque when used
- // in-context; ideally it'd be configurable.
- "" => Err(Error::Other(
- "The text in the element's text node was empty after trimming.",
- )),
- trimmed => T::decode(trimmed),
- }
- }
-
- fn encode(decoded: &T::Decoded) -> Option<String> {
- T::encode(decoded)
- }
-}
-
-/// Codec wrapping that encodes/decodes a string as base64.
-pub struct Base64;
-
-impl Codec for Base64 {
- type Decoded = Vec<u8>;
-
- fn decode(s: &str) -> Result<Vec<u8>, Error> {
- Base64Engine.decode(s).map_err(Error::text_parse_error)
- }
-
- fn encode(decoded: &Vec<u8>) -> Option<String> {
- Some(Base64Engine.encode(decoded))
- }
-}
-
-/// Codec wrapping base64 encode/decode, while ignoring whitespace characters.
-pub struct WhitespaceAwareBase64;
-
-impl Codec for WhitespaceAwareBase64 {
- type Decoded = Vec<u8>;
-
- fn decode(s: &str) -> Result<Self::Decoded, Error> {
- let s: String = s
- .chars()
- .filter(|ch| *ch != ' ' && *ch != '\n' && *ch != '\t')
- .collect();
-
- Base64Engine.decode(s).map_err(Error::text_parse_error)
- }
-
- fn encode(decoded: &Self::Decoded) -> Option<String> {
- Some(Base64Engine.encode(decoded))
- }
-}
-
-/// Codec for bytes of lowercase hexadecimal, with a fixed length `N` (in bytes).
-pub struct FixedHex<const N: usize>;
-
-impl<const N: usize> Codec for FixedHex<N> {
- type Decoded = [u8; N];
-
- fn decode(s: &str) -> Result<Self::Decoded, Error> {
- if s.len() != 2 * N {
- return Err(Error::Other("Invalid length"));
- }
-
- let mut bytes = [0u8; N];
- for i in 0..N {
- bytes[i] =
- u8::from_str_radix(&s[2 * i..2 * i + 2], 16).map_err(Error::text_parse_error)?;
- }
-
- Ok(bytes)
- }
-
- fn encode(decoded: &Self::Decoded) -> Option<String> {
- let mut bytes = String::with_capacity(N * 2);
- for byte in decoded {
- bytes.extend(format!("{:02x}", byte).chars());
- }
- Some(bytes)
- }
-}
-
-/// Codec for colon-separated bytes of uppercase hexadecimal.
-pub struct ColonSeparatedHex;
-
-impl Codec for ColonSeparatedHex {
- type Decoded = Vec<u8>;
-
- fn decode(s: &str) -> Result<Self::Decoded, Error> {
- let mut bytes = vec![];
- for i in 0..(1 + s.len()) / 3 {
- let byte =
- u8::from_str_radix(&s[3 * i..3 * i + 2], 16).map_err(Error::text_parse_error)?;
- if 3 * i + 2 < s.len() {
- assert_eq!(&s[3 * i + 2..3 * i + 3], ":");
- }
- bytes.push(byte);
- }
- Ok(bytes)
- }
-
- fn encode(decoded: &Self::Decoded) -> Option<String> {
- let mut bytes = vec![];
- for byte in decoded {
- bytes.push(format!("{:02X}", byte));
- }
- Some(bytes.join(":"))
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn fixed_hex() {
- let value = [0x01, 0xfe, 0xef];
-
- // Test that we support both lowercase and uppercase as input.
- let hex = FixedHex::<3>::decode("01feEF").unwrap();
- assert_eq!(&hex, &value);
-
- // Test that we do output lowercase.
- let hex = FixedHex::<3>::encode(&value).unwrap();
- assert_eq!(hex, "01feef");
-
- // What if we give it a string that's too long?
- let err = FixedHex::<3>::decode("01feEF01").unwrap_err();
- assert_eq!(err.to_string(), "Invalid length");
-
- // Too short?
- let err = FixedHex::<3>::decode("01fe").unwrap_err();
- assert_eq!(err.to_string(), "Invalid length");
-
- // Not-even numbers?
- let err = FixedHex::<3>::decode("01feE").unwrap_err();
- assert_eq!(err.to_string(), "Invalid length");
-
- // No colon supported.
- let err = FixedHex::<3>::decode("0:f:EF").unwrap_err();
- assert_eq!(
- err.to_string(),
- "text parse error: invalid digit found in string"
- );
-
- // No non-hex character allowed.
- let err = FixedHex::<3>::decode("01defg").unwrap_err();
- assert_eq!(
- err.to_string(),
- "text parse error: invalid digit found in string"
- );
- }
-}