Created
June 22, 2020 23:24
-
-
Save cfsamson/18009ca988ab1405b6ea6aaac819aed6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use core::fmt; | |
use fmt::Display; | |
use serde::{ | |
ser::{Error, SerializeMap, SerializeSeq}, | |
serde_if_integer128, Deserialize, Serialize, Serializer, | |
}; | |
fn main() { | |
#[derive(Serialize, Deserialize)] | |
struct Demo { | |
#[serde(with = "serde_bytes")] | |
bytes: Vec<u8>, | |
} | |
let bytes = b"testing".to_vec(); | |
// Using `with = "serde_bytes"` seems to call `Serializer::serialize_seq` and not | |
// `Serializer::serialize_bytes` as I would expect so uncommenting this won't work: | |
// let demo = Demo { bytes }; | |
let demo = serde_bytes::ByteBuf::from(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 = BytesRepr::base64(&mut ser, base64_config); | |
demo.serialize(ser).unwrap(); | |
println!("{}", String::from_utf8_lossy(&out)); | |
} | |
enum EncodeKind { | |
Base64(base64::Config), | |
} | |
struct BytesRepr<S: Serializer> { | |
inner: S, | |
encode_kind: EncodeKind, | |
} | |
impl<S: Serializer> BytesRepr<S> { | |
fn base64(ser: S, cfg: base64::Config) -> Self { | |
Self { | |
inner: ser, | |
encode_kind: EncodeKind::Base64(cfg), | |
} | |
} | |
} | |
impl<S: Serializer> Serializer for BytesRepr<S> { | |
type Ok = S::Ok; | |
type Error = S::Error; | |
type SerializeSeq = S::SerializeSeq; | |
type SerializeTuple = S::SerializeTuple; | |
type SerializeTupleStruct = S::SerializeTupleStruct; | |
type SerializeTupleVariant = S::SerializeTupleVariant; | |
type SerializeMap = S::SerializeMap; | |
type SerializeStruct = S::SerializeStruct; | |
type SerializeStructVariant = S::SerializeStructVariant; | |
fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> { | |
S::serialize_bool(self.inner, v) | |
} | |
fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> { | |
S::serialize_i8(self.inner, v) | |
} | |
fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> { | |
S::serialize_i16(self.inner, v) | |
} | |
fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> { | |
S::serialize_i32(self.inner, v) | |
} | |
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> { | |
S::serialize_i64(self.inner, v) | |
} | |
serde_if_integer128! { | |
fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> { | |
let _ = v; | |
Err(Error::custom("i128 is not supported")) | |
} | |
} | |
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> { | |
S::serialize_u8(self.inner, v) | |
} | |
fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> { | |
S::serialize_u16(self.inner, v) | |
} | |
fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> { | |
S::serialize_u32(self.inner, v) | |
} | |
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> { | |
S::serialize_u64(self.inner, v) | |
} | |
serde_if_integer128! { | |
fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> { | |
let _ = v; | |
Err(Error::custom("u128 is not supported")) | |
} | |
} | |
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> { | |
S::serialize_f32(self.inner, v) | |
} | |
fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> { | |
S::serialize_f64(self.inner, v) | |
} | |
fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error> { | |
S::serialize_char(self.inner, v) | |
} | |
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> { | |
S::serialize_str(self.inner, v) | |
} | |
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> { | |
let encoded = match self.encode_kind { | |
EncodeKind::Base64(cfg) => base64::encode_config(&v, cfg), | |
}; | |
S::serialize_str(self.inner, encoded.as_str()) | |
} | |
fn serialize_none(self) -> Result<Self::Ok, Self::Error> { | |
S::serialize_none(self.inner) | |
} | |
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error> | |
where | |
T: Serialize, | |
{ | |
S::serialize_some(self.inner, value) | |
} | |
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { | |
S::serialize_unit(self.inner) | |
} | |
fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> { | |
S::serialize_unit_struct(self.inner, name) | |
} | |
fn serialize_unit_variant( | |
self, | |
name: &'static str, | |
variant_index: u32, | |
variant: &'static str, | |
) -> Result<Self::Ok, Self::Error> { | |
S::serialize_unit_variant(self.inner, name, variant_index, variant) | |
} | |
fn serialize_newtype_struct<T: ?Sized>( | |
self, | |
name: &'static str, | |
value: &T, | |
) -> Result<Self::Ok, Self::Error> | |
where | |
T: Serialize, | |
{ | |
S::serialize_newtype_struct(self.inner, name, value) | |
} | |
fn serialize_newtype_variant<T: ?Sized>( | |
self, | |
name: &'static str, | |
variant_index: u32, | |
variant: &'static str, | |
value: &T, | |
) -> Result<Self::Ok, Self::Error> | |
where | |
T: Serialize, | |
{ | |
S::serialize_newtype_variant(self.inner, name, variant_index, variant, value) | |
} | |
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { | |
S::serialize_seq(self.inner, len) | |
} | |
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> { | |
S::serialize_tuple(self.inner, len) | |
} | |
fn serialize_tuple_struct( | |
self, | |
name: &'static str, | |
len: usize, | |
) -> Result<Self::SerializeTupleStruct, Self::Error> { | |
S::serialize_tuple_struct(self.inner, name, len) | |
} | |
fn serialize_tuple_variant( | |
self, | |
name: &'static str, | |
variant_index: u32, | |
variant: &'static str, | |
len: usize, | |
) -> Result<Self::SerializeTupleVariant, Self::Error> { | |
S::serialize_tuple_variant(self.inner, name, variant_index, variant, len) | |
} | |
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { | |
S::serialize_map(self.inner, len) | |
} | |
fn serialize_struct( | |
self, | |
name: &'static str, | |
len: usize, | |
) -> Result<Self::SerializeStruct, Self::Error> { | |
S::serialize_struct(self.inner, name, len) | |
} | |
/// ``` | |
fn serialize_struct_variant( | |
self, | |
name: &'static str, | |
variant_index: u32, | |
variant: &'static str, | |
len: usize, | |
) -> Result<Self::SerializeStructVariant, Self::Error> { | |
S::serialize_struct_variant(self.inner, name, variant_index, variant, len) | |
} | |
fn collect_seq<I>(self, iter: I) -> Result<Self::Ok, Self::Error> | |
where | |
I: IntoIterator, | |
<I as IntoIterator>::Item: Serialize, | |
{ | |
let iter = iter.into_iter(); | |
let mut serializer = self.serialize_seq(iterator_len_hint(&iter))?; | |
for item in iter { | |
serializer.serialize_element(&item)?; | |
} | |
serializer.end() | |
} | |
fn collect_map<K, V, I>(self, iter: I) -> Result<Self::Ok, Self::Error> | |
where | |
K: Serialize, | |
V: Serialize, | |
I: IntoIterator<Item = (K, V)>, | |
{ | |
let iter = iter.into_iter(); | |
let mut serializer = self.serialize_map(iterator_len_hint(&iter))?; | |
for (key, value) in iter { | |
serializer.serialize_entry(&key, &value)?; | |
} | |
serializer.end() | |
} | |
#[cfg(any(feature = "std", feature = "alloc"))] | |
fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error> | |
where | |
T: Display, | |
{ | |
self.serialize_str(&value.to_string()) | |
} | |
#[cfg(not(any(feature = "std", feature = "alloc")))] | |
fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error> | |
where | |
T: Display, | |
{ | |
S::collect_str(self.inner, value) | |
} | |
#[inline] | |
fn is_human_readable(&self) -> bool { | |
true | |
} | |
} | |
fn iterator_len_hint<I>(iter: &I) -> Option<usize> | |
where | |
I: Iterator, | |
{ | |
match iter.size_hint() { | |
(lo, Some(hi)) if lo == hi => Some(lo), | |
_ => None, | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment