146 lines
4.9 KiB
Rust
146 lines
4.9 KiB
Rust
//! ron initially encoded byte-slices and byte-bufs as base64-encoded strings.
|
|
//! However, since v0.9, ron now uses Rusty byte string literals instead.
|
|
//!
|
|
//! This example shows how the previous behaviour can be restored by serialising
|
|
//! bytes with strongly-typed base64-encoded strings, or accepting both Rusty
|
|
//! byte strings and the legacy base64-encoded string syntax.
|
|
|
|
use base64::engine::{general_purpose::STANDARD as BASE64, Engine};
|
|
use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
struct Config {
|
|
#[serde(with = "ByteStr")]
|
|
bytes: Vec<u8>,
|
|
#[serde(with = "Base64")]
|
|
base64: Vec<u8>,
|
|
#[serde(with = "ByteStrOrBase64")]
|
|
bytes_or_base64: Vec<u8>,
|
|
}
|
|
|
|
enum ByteStr {}
|
|
|
|
impl ByteStr {
|
|
fn serialize<S: Serializer>(data: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
|
|
serializer.serialize_bytes(data)
|
|
}
|
|
|
|
fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
|
|
struct ByteStrVisitor;
|
|
|
|
impl<'de> Visitor<'de> for ByteStrVisitor {
|
|
type Value = Vec<u8>;
|
|
|
|
fn expecting(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
fmt.write_str("a Rusty byte string")
|
|
}
|
|
|
|
fn visit_bytes<E: serde::de::Error>(self, bytes: &[u8]) -> Result<Self::Value, E> {
|
|
Ok(bytes.to_vec())
|
|
}
|
|
|
|
fn visit_byte_buf<E: serde::de::Error>(self, bytes: Vec<u8>) -> Result<Self::Value, E> {
|
|
Ok(bytes)
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_byte_buf(ByteStrVisitor)
|
|
}
|
|
}
|
|
|
|
enum Base64 {}
|
|
|
|
impl Base64 {
|
|
fn serialize<S: Serializer>(data: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
|
|
serializer.serialize_str(&BASE64.encode(data))
|
|
}
|
|
|
|
fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
|
|
let base64_str = <&str>::deserialize(deserializer)?;
|
|
BASE64.decode(base64_str).map_err(serde::de::Error::custom)
|
|
}
|
|
}
|
|
|
|
enum ByteStrOrBase64 {}
|
|
|
|
impl ByteStrOrBase64 {
|
|
fn serialize<S: Serializer>(data: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
|
|
if cfg!(all()) {
|
|
// either of these would work
|
|
serializer.serialize_str(&BASE64.encode(data))
|
|
} else {
|
|
serializer.serialize_bytes(data)
|
|
}
|
|
}
|
|
|
|
fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
|
|
struct ByteStrOrBase64Visitor;
|
|
|
|
impl<'de> Visitor<'de> for ByteStrOrBase64Visitor {
|
|
type Value = Vec<u8>;
|
|
|
|
fn expecting(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
fmt.write_str("a Rusty byte string or a base64-encoded string")
|
|
}
|
|
|
|
fn visit_str<E: serde::de::Error>(self, base64_str: &str) -> Result<Self::Value, E> {
|
|
BASE64.decode(base64_str).map_err(serde::de::Error::custom)
|
|
}
|
|
|
|
fn visit_bytes<E: serde::de::Error>(self, bytes: &[u8]) -> Result<Self::Value, E> {
|
|
Ok(bytes.to_vec())
|
|
}
|
|
|
|
fn visit_byte_buf<E: serde::de::Error>(self, bytes: Vec<u8>) -> Result<Self::Value, E> {
|
|
Ok(bytes)
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_any(ByteStrOrBase64Visitor)
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let ron = r#"Config(
|
|
bytes: b"only byte strings are allowed",
|
|
base64: "b25seSBiYXNlNjQtZW5jb2RlZCBzdHJpbmdzIGFyZSBhbGxvd2Vk",
|
|
bytes_or_base64: b"both byte strings and base64-encoded strings work",
|
|
)"#;
|
|
|
|
assert_eq!(
|
|
ron::from_str::<Config>(ron).unwrap(),
|
|
Config {
|
|
bytes: b"only byte strings are allowed".to_vec(),
|
|
base64: b"only base64-encoded strings are allowed".to_vec(),
|
|
bytes_or_base64: b"both byte strings and base64-encoded strings work".to_vec()
|
|
}
|
|
);
|
|
|
|
let ron = r#"Config(
|
|
bytes: b"only byte strings are allowed",
|
|
base64: "b25seSBiYXNlNjQtZW5jb2RlZCBzdHJpbmdzIGFyZSBhbGxvd2Vk",
|
|
bytes_or_base64: "Ym90aCBieXRlIHN0cmluZ3MgYW5kIGJhc2U2NC1lbmNvZGVkIHN0cmluZ3Mgd29yaw==",
|
|
)"#;
|
|
|
|
assert_eq!(
|
|
ron::from_str::<Config>(ron).unwrap(),
|
|
Config {
|
|
bytes: b"only byte strings are allowed".to_vec(),
|
|
base64: b"only base64-encoded strings are allowed".to_vec(),
|
|
bytes_or_base64: b"both byte strings and base64-encoded strings work".to_vec()
|
|
}
|
|
);
|
|
|
|
println!(
|
|
"{}",
|
|
ron::ser::to_string_pretty(
|
|
&Config {
|
|
bytes: b"only byte strings are allowed".to_vec(),
|
|
base64: b"only base64-encoded strings are allowed".to_vec(),
|
|
bytes_or_base64: b"both byte strings and base64-encoded strings work".to_vec()
|
|
},
|
|
ron::ser::PrettyConfig::default().struct_names(true)
|
|
)
|
|
.unwrap()
|
|
);
|
|
}
|