xso: add support for base64 text codec
This commit is contained in:
parent
4ec12fab16
commit
7c7f6d1f23
3 changed files with 78 additions and 2 deletions
|
@ -24,7 +24,7 @@ chrono = { version = "0.4.5", default-features = false, features = ["std"] }
|
||||||
# same repository dependencies
|
# same repository dependencies
|
||||||
jid = { version = "0.10", features = ["minidom"], path = "../jid" }
|
jid = { version = "0.10", features = ["minidom"], path = "../jid" }
|
||||||
minidom = { version = "0.15", path = "../minidom" }
|
minidom = { version = "0.15", path = "../minidom" }
|
||||||
xso = { version = "0.0.2", features = ["macros", "minidom", "panicking-into-impl", "jid"] }
|
xso = { version = "0.0.2", features = ["macros", "minidom", "panicking-into-impl", "jid", "base64"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# Build xmpp-parsers to make components instead of clients.
|
# Build xmpp-parsers to make components instead of clients.
|
||||||
|
|
|
@ -14,13 +14,15 @@ rxml = { version = "0.11.0", default-features = false }
|
||||||
minidom = { version = "^0.15" }
|
minidom = { version = "^0.15" }
|
||||||
xso_proc = { version = "0.0.2", optional = true }
|
xso_proc = { version = "0.0.2", optional = true }
|
||||||
|
|
||||||
# optional dependencies to provide text conversion to/from types from these crates
|
# optional dependencies to provide text conversion to/from types from/using
|
||||||
|
# these crates
|
||||||
# NOTE: because we don't have public/private dependencies yet and cargo
|
# NOTE: because we don't have public/private dependencies yet and cargo
|
||||||
# defaults to picking the highest matching version by default, the only
|
# defaults to picking the highest matching version by default, the only
|
||||||
# sensible thing we can do here is to depend on the least version of the most
|
# sensible thing we can do here is to depend on the least version of the most
|
||||||
# recent semver of each crate.
|
# recent semver of each crate.
|
||||||
jid = { version = "^0.10", optional = true }
|
jid = { version = "^0.10", optional = true }
|
||||||
uuid = { version = "^1", optional = true }
|
uuid = { version = "^1", optional = true }
|
||||||
|
base64 = { version = "^0.22", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
macros = [ "dep:xso_proc" ]
|
macros = [ "dep:xso_proc" ]
|
||||||
|
|
|
@ -6,8 +6,13 @@
|
||||||
|
|
||||||
//! Module containing implementations for conversions to/from XML text.
|
//! Module containing implementations for conversions to/from XML text.
|
||||||
|
|
||||||
|
#[cfg(feature = "base64")]
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{error::Error, FromXmlText, IntoXmlText};
|
use crate::{error::Error, FromXmlText, IntoXmlText};
|
||||||
|
|
||||||
|
#[cfg(feature = "base64")]
|
||||||
|
use base64::engine::{general_purpose::STANDARD as StandardBase64Engine, Engine as _};
|
||||||
#[cfg(feature = "jid")]
|
#[cfg(feature = "jid")]
|
||||||
use jid;
|
use jid;
|
||||||
#[cfg(feature = "uuid")]
|
#[cfg(feature = "uuid")]
|
||||||
|
@ -160,3 +165,72 @@ impl TextCodec<Option<String>> for EmptyAsNone {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait for preprocessing text data from XML.
|
||||||
|
///
|
||||||
|
/// This may be used by codecs to allow to customize some of their behaviour.
|
||||||
|
pub trait TextFilter {
|
||||||
|
/// Process the incoming string and return the result of the processing.
|
||||||
|
fn preprocess(s: String) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Text preprocessor which returns the input unchanged.
|
||||||
|
pub struct NoFilter;
|
||||||
|
|
||||||
|
impl TextFilter for NoFilter {
|
||||||
|
fn preprocess(s: String) -> String {
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Text preprocessor to remove all whitespace.
|
||||||
|
pub struct StripWhitespace;
|
||||||
|
|
||||||
|
impl TextFilter for StripWhitespace {
|
||||||
|
fn preprocess(s: String) -> String {
|
||||||
|
let s: String = s
|
||||||
|
.chars()
|
||||||
|
.filter(|ch| *ch != ' ' && *ch != '\n' && *ch != '\t')
|
||||||
|
.collect();
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Text codec transforming text to binary using standard base64.
|
||||||
|
///
|
||||||
|
/// The `Filter` type argument can be used to employ additional preprocessing
|
||||||
|
/// of incoming text data. Most interestingly, passing [`StripWhitespace`]
|
||||||
|
/// will make the implementation ignore any whitespace within the text.
|
||||||
|
#[cfg(feature = "base64")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
|
||||||
|
pub struct Base64<Filter: TextFilter = NoFilter>(PhantomData<Filter>);
|
||||||
|
|
||||||
|
#[cfg(feature = "base64")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
|
||||||
|
impl<Filter: TextFilter> TextCodec<Vec<u8>> for Base64<Filter> {
|
||||||
|
fn decode(s: String) -> Result<Vec<u8>, Error> {
|
||||||
|
let value = Filter::preprocess(s);
|
||||||
|
Ok(StandardBase64Engine
|
||||||
|
.decode(value.as_str().as_bytes())
|
||||||
|
.map_err(Error::text_parse_error)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode(value: Vec<u8>) -> Result<Option<String>, Error> {
|
||||||
|
Ok(Some(StandardBase64Engine.encode(&value)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "base64")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
|
||||||
|
impl<Filter: TextFilter> TextCodec<Option<Vec<u8>>> for Base64<Filter> {
|
||||||
|
fn decode(s: String) -> Result<Option<Vec<u8>>, Error> {
|
||||||
|
if s.len() == 0 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
Ok(Some(Self::decode(s)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode(decoded: Option<Vec<u8>>) -> Result<Option<String>, Error> {
|
||||||
|
decoded.map(Self::encode).transpose().map(Option::flatten)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue