diff --git a/parsers/src/util/macros.rs b/parsers/src/util/macros.rs index 5a084ba1..39cc6cb6 100644 --- a/parsers/src/util/macros.rs +++ b/parsers/src/util/macros.rs @@ -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() } diff --git a/parsers/src/util/mod.rs b/parsers/src/util/mod.rs index 2f7deecf..20591702 100644 --- a/parsers/src/util/mod.rs +++ b/parsers/src/util/mod.rs @@ -4,9 +4,6 @@ // 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/. -/// Various helpers. -pub(crate) mod text_node_codecs; - /// Helper macros to parse and serialise more easily. #[macro_use] mod macros; diff --git a/parsers/src/util/text_node_codecs.rs b/parsers/src/util/text_node_codecs.rs deleted file mode 100644 index cabdae3b..00000000 --- a/parsers/src/util/text_node_codecs.rs +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright (c) 2017 Emmanuel Gil Peyrot -// -// 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; - - /// Encode the given value; return None to not produce a text node at all. - fn encode(decoded: &Self::Decoded) -> Option; -} - -/// Codec for text content. -pub struct Text; - -impl Codec for Text { - type Decoded = String; - - fn decode(s: &str) -> Result { - Ok(s.to_owned()) - } - - fn encode(decoded: &String) -> Option { - Some(decoded.to_owned()) - } -} - -/// Codec transformer that makes the text optional; a "" string is decoded as None. -pub struct OptionalCodec(std::marker::PhantomData); - -impl Codec for OptionalCodec -where - T: Codec, -{ - type Decoded = Option; - - fn decode(s: &str) -> Result, Error> { - if s.is_empty() { - return Ok(None); - } - - Ok(Some(T::decode(s)?)) - } - - fn encode(decoded: &Option) -> Option { - decoded.as_ref().and_then(T::encode) - } -} - -/// Codec that trims whitespace around the text. -pub struct Trimmed(std::marker::PhantomData); - -impl Codec for Trimmed -where - T: Codec, -{ - type Decoded = T::Decoded; - - fn decode(s: &str) -> Result { - 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 { - T::encode(decoded) - } -} - -/// Codec wrapping that encodes/decodes a string as base64. -pub struct Base64; - -impl Codec for Base64 { - type Decoded = Vec; - - fn decode(s: &str) -> Result, Error> { - Base64Engine.decode(s).map_err(Error::text_parse_error) - } - - fn encode(decoded: &Vec) -> Option { - Some(Base64Engine.encode(decoded)) - } -} - -/// Codec wrapping base64 encode/decode, while ignoring whitespace characters. -pub struct WhitespaceAwareBase64; - -impl Codec for WhitespaceAwareBase64 { - type Decoded = Vec; - - fn decode(s: &str) -> Result { - 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 { - Some(Base64Engine.encode(decoded)) - } -} - -/// Codec for bytes of lowercase hexadecimal, with a fixed length `N` (in bytes). -pub struct FixedHex; - -impl Codec for FixedHex { - type Decoded = [u8; N]; - - fn decode(s: &str) -> Result { - 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 { - 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; - - fn decode(s: &str) -> Result { - 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 { - 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" - ); - } -}