diff --git a/Cargo.lock b/Cargo.lock index 19ea784..72113ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,59 +1,61 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "base64" -version = "0.13.0" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "hex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "itoa" -version = "0.4.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "proc-macro2" -version = "1.0.18" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.7" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "serde" -version = "1.0.117" +version = "1.0.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" +checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" dependencies = [ "serde_derive", ] [[package]] name = "serde-bytes-repr" -version = "0.1.5" +version = "0.2.0" dependencies = [ "base64", "hex", @@ -64,18 +66,18 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.5" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.117" +version = "1.0.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e" +checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" dependencies = [ "proc-macro2", "quote", @@ -84,9 +86,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.59" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", @@ -95,17 +97,17 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.33" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] -name = "unicode-xid" -version = "0.2.0" +name = "unicode-ident" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/Cargo.toml b/Cargo.toml index ad0f9f5..6c21cd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde-bytes-repr" -version = "0.1.5" +version = "0.2.0" authors = ["cfsamson "] description = "Serde adapter for controlling the representation of bytes" repository = "https://github.com/cfsamson/rfi-serde-byte-repr" @@ -16,7 +16,7 @@ edition = "2018" [dependencies] serde = "1.0.117" -base64 = "0.13.0" +base64 = "0.21.4" hex = "0.4.2" [dev-dependencies] diff --git a/src/deserializer.rs b/src/deserializer.rs index db78351..ae94e80 100644 --- a/src/deserializer.rs +++ b/src/deserializer.rs @@ -1,4 +1,5 @@ use crate::{ByteFmtDeserializer, ByteFormat}; +use base64::Engine; use serde::de; use std::fmt; @@ -278,34 +279,43 @@ impl Visitor { } } - fn decode(&self, v: &[u8]) -> Result, E> where E: de::Error { + fn decode(&self, v: &[u8]) -> Result, E> + where + E: de::Error, + { match self.fmt { - ByteFormat::Base64(cfg) => match base64::decode_config(v, cfg) { - Ok(bytes) => Ok(bytes), - Err(base64::DecodeError::InvalidByte(index, b)) - => Err(E::invalid_value( - de::Unexpected::Char(b.into()), - &format!("valid base64 character at index {}", index).as_str() - )), - Err(base64::DecodeError::InvalidLength) - => Err(E::invalid_length(v.len(), &"valid base64 length")), - Err(base64::DecodeError::InvalidLastSymbol(_,b)) - => Err(E::invalid_value( - de::Unexpected::Char(b.into()), - &"valid character ending base64 string" - )), - }, + ByteFormat::Base64(ref alphabet, config) => { + match base64::engine::GeneralPurpose::new(alphabet, config).decode(v) { + Ok(bytes) => Ok(bytes), + Err(base64::DecodeError::InvalidByte(index, b)) => Err(E::invalid_value( + de::Unexpected::Char(b.into()), + &format!("valid base64 character at index {}", index).as_str(), + )), + Err(base64::DecodeError::InvalidLength) => { + Err(E::invalid_length(v.len(), &"valid base64 length")) + } + Err(base64::DecodeError::InvalidLastSymbol(_, b)) => Err(E::invalid_value( + de::Unexpected::Char(b.into()), + &"valid character ending base64 string", + )), + Err(base64::DecodeError::InvalidPadding) => Err(E::invalid_value( + de::Unexpected::Other("invalid padding"), + &"valid padding", + )), + } + } ByteFormat::Hex => match hex::decode(v) { Ok(bytes) => Ok(bytes), - Err(hex::FromHexError::OddLength) - => Err(E::invalid_length(v.len(), &"even length")), - Err(hex::FromHexError::InvalidHexCharacter{c, index}) - => Err(E::invalid_value( + Err(hex::FromHexError::OddLength) => { + Err(E::invalid_length(v.len(), &"even length")) + } + Err(hex::FromHexError::InvalidHexCharacter { c, index }) => Err(E::invalid_value( de::Unexpected::Char(c), - &format!("valid hex character at index {}", index).as_str() + &format!("valid hex character at index {}", index).as_str(), + )), + Err(hex::FromHexError::InvalidStringLength) => Err(E::custom( + "Imposible to reach due to unrestricted return length", )), - Err(hex::FromHexError::InvalidStringLength) - => Err(E::custom("Imposible to reach due to unrestricted return length")), }, } } diff --git a/src/lib.rs b/src/lib.rs index e218e17..6abb79a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,8 +34,8 @@ //! //! let mut out = vec![]; //! let mut ser = serde_json::Serializer::new(&mut out); -//! let base64_config = base64::Config::new(base64::CharacterSet::UrlSafe, true); -//! let ser = ByteFmtSerializer::base64(&mut ser, base64_config); +//! let base64_config = base64::engine::GeneralPurposeConfig::new(); +//! let ser = ByteFmtSerializer::base64(&mut ser, base64::alphabet::URL_SAFE, base64_config); //! demo.serialize(ser).unwrap(); //! //! let serialized = String::from_utf8(out).unwrap(); @@ -57,8 +57,8 @@ //! //! let json = br#"{"bytes":"dGVzdGluZw=="}"#; //! let mut json_de = serde_json::Deserializer::from_slice(json); -//! let base64_config = base64::Config::new(base64::CharacterSet::UrlSafe, true); -//! let bytefmt_json_de = ByteFmtDeserializer::new_base64(&mut json_de, base64_config); +//! let base64_config = base64::engine::GeneralPurposeConfig::new(); +//! let bytefmt_json_de = ByteFmtDeserializer::new_base64(&mut json_de, base64::alphabet::URL_SAFE, base64_config); //! let demo: Demo = Demo::deserialize(bytefmt_json_de).unwrap(); //! //! let deserialized = String::from_utf8(demo.bytes).unwrap(); @@ -66,12 +66,14 @@ //! # } //! ``` +use base64::{alphabet::Alphabet, engine::GeneralPurposeConfig, Engine}; + mod deserializer; mod serializer; #[derive(Clone)] enum ByteFormat { - Base64(base64::Config), + Base64(Alphabet, GeneralPurposeConfig), Hex, } @@ -85,10 +87,10 @@ impl ByteFmtSerializer { /// Crates an adapter which serializes to and from a Base64 representation. /// Provide a configuration from the `base64` crate specifying the specifics /// on how you want the bytes encoded. - pub fn base64(ser: S, cfg: base64::Config) -> Self { + pub fn base64(ser: S, alphabet: Alphabet, config: GeneralPurposeConfig) -> Self { Self { inner: ser, - encode_kind: ByteFormat::Base64(cfg), + encode_kind: ByteFormat::Base64(alphabet, config), } } @@ -102,8 +104,10 @@ impl ByteFmtSerializer { fn encode(&self, v: &[u8]) -> String { match self.encode_kind { - ByteFormat::Base64(cfg) => base64::encode_config(&v, cfg), - ByteFormat::Hex => hex::encode(&v), + ByteFormat::Base64(ref alphabet, config) => { + base64::engine::GeneralPurpose::new(alphabet, config).encode(v) + } + ByteFormat::Hex => hex::encode(v), } } } @@ -118,10 +122,11 @@ impl ByteFmtDeserializer { /// Crates an adapter which deserializes from a Base64 representation. Provide a /// configuration from the `base64` crate specifying the specifics on how you want the bytes /// encoded. - pub fn new_base64(deserializer: D, config: base64::Config) -> Self { + /// + pub fn new_base64(deserializer: D, alphabet: Alphabet, config: GeneralPurposeConfig) -> Self { ByteFmtDeserializer { inner: deserializer, - fmt: ByteFormat::Base64(config), + fmt: ByteFormat::Base64(alphabet, config), } } diff --git a/src/serializer.rs b/src/serializer.rs index 3e2df7c..0ec886f 100644 --- a/src/serializer.rs +++ b/src/serializer.rs @@ -264,7 +264,7 @@ pub struct BytesSerialize<'a, T: ?Sized> { impl<'a, T: ?Sized> BytesSerialize<'a, T> { fn new(value: &'a T, fmt: ByteFormat) -> Self { - BytesSerialize { value, fmt: fmt } + BytesSerialize { value, fmt } } } @@ -293,7 +293,7 @@ struct BytesSerializeSized { impl BytesSerializeSized { fn new(value: T, fmt: ByteFormat) -> Self { - BytesSerializeSized { value, fmt: fmt } + BytesSerializeSized { value, fmt } } } diff --git a/tests/deserialize.rs b/tests/deserialize.rs index 6fc89ae..9cf8828 100644 --- a/tests/deserialize.rs +++ b/tests/deserialize.rs @@ -11,8 +11,9 @@ fn deserialize_struct_base64() { let json = br#"{"bytes":"dGVzdGluZw=="}"#; let mut json_de = serde_json::Deserializer::from_slice(json); - let base64_config = base64::Config::new(base64::CharacterSet::UrlSafe, true); - let bytefmt_json_de = ByteFmtDeserializer::new_base64(&mut json_de, base64_config); + let base64_config = base64::engine::GeneralPurposeConfig::new(); + let bytefmt_json_de = + ByteFmtDeserializer::new_base64(&mut json_de, base64::alphabet::URL_SAFE, base64_config); let demo: Demo = Demo::deserialize(bytefmt_json_de).unwrap(); let deserialized = String::from_utf8(demo.bytes).unwrap(); @@ -23,8 +24,9 @@ fn deserialize_struct_base64() { fn deserialize_seq_base64() { let json = br#""dGVzdGluZw==""#; let mut json_de = serde_json::Deserializer::from_slice(json); - let base64_config = base64::Config::new(base64::CharacterSet::UrlSafe, true); - let bytefmt_json_de = ByteFmtDeserializer::new_base64(&mut json_de, base64_config); + let base64_config = base64::engine::GeneralPurposeConfig::new(); + let bytefmt_json_de = + ByteFmtDeserializer::new_base64(&mut json_de, base64::alphabet::URL_SAFE, base64_config); let bytes: serde_bytes::ByteBuf = Deserialize::deserialize(bytefmt_json_de).unwrap(); let deserialized = String::from_utf8(bytes.to_vec()).unwrap(); @@ -74,8 +76,9 @@ fn deserialize_option_base64() { let json = br#"{"demo":{"bytes":"dGVzdGluZw=="}}"#; let mut json_de = serde_json::Deserializer::from_slice(json); - let base64_config = base64::Config::new(base64::CharacterSet::UrlSafe, true); - let bytefmt_json_de = ByteFmtDeserializer::new_base64(&mut json_de, base64_config); + let base64_config = base64::engine::GeneralPurposeConfig::new(); + let bytefmt_json_de = + ByteFmtDeserializer::new_base64(&mut json_de, base64::alphabet::URL_SAFE, base64_config); let option_wrapper: OptionWrapper = OptionWrapper::deserialize(bytefmt_json_de).unwrap(); let deserialized = String::from_utf8(option_wrapper.demo.unwrap().bytes).unwrap(); @@ -104,7 +107,6 @@ fn deserialize_option_hex() { assert_eq!("testing", deserialized.as_str()); } - #[test] fn deserialize_invalid_struct_base64() { #[derive(Serialize, Deserialize, Debug)] @@ -115,17 +117,22 @@ fn deserialize_invalid_struct_base64() { let json = br#"{"bytes":"12345"}"#; let mut json_de = serde_json::Deserializer::from_slice(json); - let base64_config = base64::Config::new(base64::CharacterSet::UrlSafe, true); - let bytefmt_json_de = ByteFmtDeserializer::new_base64(&mut json_de, base64_config); + let base64_config = base64::engine::GeneralPurposeConfig::new(); + let bytefmt_json_de = + ByteFmtDeserializer::new_base64(&mut json_de, base64::alphabet::URL_SAFE, base64_config); let demo = Demo::deserialize(bytefmt_json_de); let msg = format!("{}", demo.unwrap_err()); - assert_eq!("invalid length 5, expected valid base64 length at line 1 column 16", msg); + assert_eq!( + "invalid length 5, expected valid base64 length at line 1 column 16", + msg + ); let json = br#"{"bytes":"12345%"}"#; let mut json_de = serde_json::Deserializer::from_slice(json); - let base64_config = base64::Config::new(base64::CharacterSet::UrlSafe, true); - let bytefmt_json_de = ByteFmtDeserializer::new_base64(&mut json_de, base64_config); + let base64_config = base64::engine::GeneralPurposeConfig::new(); + let bytefmt_json_de = + ByteFmtDeserializer::new_base64(&mut json_de, base64::alphabet::URL_SAFE, base64_config); let demo = Demo::deserialize(bytefmt_json_de); let msg = format!("{}", demo.unwrap_err()); @@ -133,8 +140,10 @@ fn deserialize_invalid_struct_base64() { let json = br#"{"bytes":"123456"}"#; let mut json_de = serde_json::Deserializer::from_slice(json); - let base64_config = base64::Config::new(base64::CharacterSet::UrlSafe, true); - let bytefmt_json_de = ByteFmtDeserializer::new_base64(&mut json_de, base64_config); + let base64_config = base64::engine::GeneralPurposeConfig::new() + .with_decode_padding_mode(base64::engine::DecodePaddingMode::Indifferent); + let bytefmt_json_de = + ByteFmtDeserializer::new_base64(&mut json_de, base64::alphabet::URL_SAFE, base64_config); let demo = Demo::deserialize(bytefmt_json_de); let msg = format!("{}", demo.unwrap_err()); @@ -155,7 +164,10 @@ fn deserialize_invalid_struct_hex() { let demo = Demo::deserialize(bytefmt_json_de); let msg = format!("{}", demo.unwrap_err()); - assert_eq!("invalid length 13, expected even length at line 1 column 24", msg); + assert_eq!( + "invalid length 13, expected even length at line 1 column 24", + msg + ); let json = br#"{"bytes":"746g7374696e67"}"#; let mut json_de = serde_json::Deserializer::from_slice(json); @@ -163,5 +175,8 @@ fn deserialize_invalid_struct_hex() { let demo = Demo::deserialize(bytefmt_json_de); let msg = format!("{}", demo.unwrap_err()); - assert_eq!("invalid value: character `g`, expected valid hex character at index 3 at line 1 column 25", msg); -} \ No newline at end of file + assert_eq!( + "invalid value: character `g`, expected valid hex character at index 3 at line 1 column 25", + msg + ); +} diff --git a/tests/serialize.rs b/tests/serialize.rs index 8e577ae..edad0f9 100644 --- a/tests/serialize.rs +++ b/tests/serialize.rs @@ -10,8 +10,8 @@ fn serialize_newtype_base64() { let mut out = vec![]; let mut ser = serde_json::Serializer::new(&mut out); - let base64_config = base64::Config::new(base64::CharacterSet::UrlSafe, true); - let ser = ByteFmtSerializer::base64(&mut ser, base64_config); + let base64_config = base64::engine::GeneralPurposeConfig::new(); + let ser = ByteFmtSerializer::base64(&mut ser, base64::alphabet::URL_SAFE, base64_config); demo.serialize(ser).unwrap(); let serialized = String::from_utf8(out).unwrap(); @@ -24,14 +24,15 @@ fn serialize_newtype_variant_base64() { enum Demo { #[serde(with = "serde_bytes")] N(Vec), - }; + } + let bytes = b"testing".to_vec(); let demo = Demo::N(bytes); let mut out = vec![]; let mut ser = serde_json::Serializer::new(&mut out); - let base64_config = base64::Config::new(base64::CharacterSet::UrlSafe, true); - let ser = ByteFmtSerializer::base64(&mut ser, base64_config); + let base64_config = base64::engine::GeneralPurposeConfig::new(); + let ser = ByteFmtSerializer::base64(&mut ser, base64::alphabet::URL_SAFE, base64_config); demo.serialize(ser).unwrap(); let serialized = String::from_utf8(out).unwrap(); @@ -50,8 +51,8 @@ fn serialize_struct_base64() { let mut out = vec![]; let mut ser = serde_json::Serializer::new(&mut out); - let base64_config = base64::Config::new(base64::CharacterSet::UrlSafe, true); - let ser = ByteFmtSerializer::base64(&mut ser, base64_config); + let base64_config = base64::engine::GeneralPurposeConfig::new(); + let ser = ByteFmtSerializer::base64(&mut ser, base64::alphabet::URL_SAFE, base64_config); demo.serialize(ser).unwrap(); let serialized = String::from_utf8(out).unwrap(); @@ -71,8 +72,8 @@ fn serialize_struct_variant_base64() { let mut out = vec![]; let mut ser = serde_json::Serializer::new(&mut out); - let base64_config = base64::Config::new(base64::CharacterSet::UrlSafe, true); - let ser = ByteFmtSerializer::base64(&mut ser, base64_config); + let base64_config = base64::engine::GeneralPurposeConfig::new(); + let ser = ByteFmtSerializer::base64(&mut ser, base64::alphabet::URL_SAFE, base64_config); demo.serialize(ser).unwrap(); let serialized = String::from_utf8(out).unwrap(); @@ -86,8 +87,8 @@ fn serialize_seq_base64() { let mut out = vec![]; let mut ser = serde_json::Serializer::new(&mut out); - let base64_config = base64::Config::new(base64::CharacterSet::UrlSafe, true); - let ser = ByteFmtSerializer::base64(&mut ser, base64_config); + let base64_config = base64::engine::GeneralPurposeConfig::new(); + let ser = ByteFmtSerializer::base64(&mut ser, base64::alphabet::URL_SAFE, base64_config); demo.serialize(ser).unwrap(); let serialized = String::from_utf8(out).unwrap(); @@ -139,8 +140,8 @@ fn serialize_option_base64() { let mut out = vec![]; let mut ser = serde_json::Serializer::new(&mut out); - let base64_config = base64::Config::new(base64::CharacterSet::UrlSafe, true); - let ser = ByteFmtSerializer::base64(&mut ser, base64_config); + let base64_config = base64::engine::GeneralPurposeConfig::new(); + let ser = ByteFmtSerializer::base64(&mut ser, base64::alphabet::URL_SAFE, base64_config); demo.serialize(ser).unwrap(); let serialized = String::from_utf8(out).unwrap();