274 lines
7.2 KiB
Rust
274 lines
7.2 KiB
Rust
use std::{borrow::Cow, mem};
|
|
|
|
use serde::ser;
|
|
use url::form_urlencoded::{
|
|
Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget,
|
|
};
|
|
|
|
use crate::urlencoded::{
|
|
error::{Error, Result},
|
|
ser::{key::KeySink, part::PartSerializer, value::ValueSink},
|
|
};
|
|
|
|
macro_rules! serialize_pair {
|
|
($($ty:ty => $name:ident,)*) => {
|
|
$(
|
|
fn $name(self, value: $ty) -> Result<()> {
|
|
let key = if let Some(key) = self.key {
|
|
key.clone()
|
|
} else {
|
|
return Err(Error::no_key());
|
|
};
|
|
let value_sink = ValueSink::new(self.urlencoder, &key);
|
|
let value_serializer = PartSerializer::new(value_sink);
|
|
value_serializer.$name(value)
|
|
}
|
|
)*
|
|
};
|
|
}
|
|
|
|
pub struct PairSerializer<'input, 'target, Target: 'target + UrlEncodedTarget> {
|
|
urlencoder: &'target mut UrlEncodedSerializer<'input, Target>,
|
|
state: PairState,
|
|
key: Option<&'target Cow<'target, str>>,
|
|
count: &'target mut usize,
|
|
}
|
|
|
|
impl<'input, 'target, Target> PairSerializer<'input, 'target, Target>
|
|
where
|
|
Target: 'target + UrlEncodedTarget,
|
|
{
|
|
pub fn new(
|
|
urlencoder: &'target mut UrlEncodedSerializer<'input, Target>,
|
|
key: Option<&'target Cow<'target, str>>,
|
|
count: &'target mut usize,
|
|
) -> Self {
|
|
PairSerializer {
|
|
urlencoder,
|
|
state: PairState::WaitingForKey,
|
|
key,
|
|
count,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'input, 'target, Target> ser::Serializer
|
|
for PairSerializer<'input, 'target, Target>
|
|
where
|
|
Target: 'target + UrlEncodedTarget,
|
|
{
|
|
type Ok = ();
|
|
type Error = Error;
|
|
type SerializeSeq = Self;
|
|
type SerializeTuple = Self;
|
|
type SerializeTupleStruct = ser::Impossible<(), Error>;
|
|
type SerializeTupleVariant = ser::Impossible<(), Error>;
|
|
type SerializeMap = ser::Impossible<(), Error>;
|
|
type SerializeStruct = ser::Impossible<(), Error>;
|
|
type SerializeStructVariant = ser::Impossible<(), Error>;
|
|
|
|
serialize_pair! {
|
|
bool => serialize_bool,
|
|
u8 => serialize_u8,
|
|
u16 => serialize_u16,
|
|
u32 => serialize_u32,
|
|
u64 => serialize_u64,
|
|
i8 => serialize_i8,
|
|
i16 => serialize_i16,
|
|
i32 => serialize_i32,
|
|
i64 => serialize_i64,
|
|
f32 => serialize_f32,
|
|
f64 => serialize_f64,
|
|
char => serialize_char,
|
|
&str => serialize_str,
|
|
}
|
|
|
|
fn serialize_bytes(self, _value: &[u8]) -> Result<()> {
|
|
Err(Error::unsupported_pair())
|
|
}
|
|
|
|
fn serialize_unit(self) -> Result<()> {
|
|
Err(Error::unsupported_pair())
|
|
}
|
|
|
|
fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
|
|
Err(Error::unsupported_pair())
|
|
}
|
|
|
|
fn serialize_unit_variant(
|
|
self,
|
|
_name: &'static str,
|
|
_variant_index: u32,
|
|
variant: &'static str,
|
|
) -> Result<()> {
|
|
let key = if let Some(key) = self.key {
|
|
key.clone()
|
|
} else {
|
|
let key = Cow::Owned(self.count.to_string());
|
|
*self.count += 1;
|
|
key
|
|
};
|
|
let value_sink = ValueSink::new(self.urlencoder, &key);
|
|
let value_serializer = PartSerializer::new(value_sink);
|
|
value_serializer.serialize_str(variant)
|
|
}
|
|
|
|
fn serialize_newtype_struct<T: ?Sized + ser::Serialize>(
|
|
self,
|
|
_name: &'static str,
|
|
value: &T,
|
|
) -> Result<()> {
|
|
value.serialize(self)
|
|
}
|
|
|
|
fn serialize_newtype_variant<T: ?Sized + ser::Serialize>(
|
|
self,
|
|
_name: &'static str,
|
|
_variant_index: u32,
|
|
_variant: &'static str,
|
|
_value: &T,
|
|
) -> Result<()> {
|
|
Err(Error::unsupported_pair())
|
|
}
|
|
|
|
fn serialize_none(self) -> Result<()> {
|
|
Ok(())
|
|
}
|
|
|
|
fn serialize_some<T: ?Sized + ser::Serialize>(
|
|
self,
|
|
value: &T,
|
|
) -> Result<()> {
|
|
value.serialize(self)
|
|
}
|
|
|
|
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
|
|
Ok(self)
|
|
}
|
|
|
|
fn serialize_tuple(self, len: usize) -> Result<Self> {
|
|
if len == 2 {
|
|
Ok(self)
|
|
} else {
|
|
Err(Error::unsupported_pair())
|
|
}
|
|
}
|
|
|
|
fn serialize_tuple_struct(
|
|
self,
|
|
_name: &'static str,
|
|
_len: usize,
|
|
) -> Result<Self::SerializeTupleStruct> {
|
|
Err(Error::unsupported_pair())
|
|
}
|
|
|
|
fn serialize_tuple_variant(
|
|
self,
|
|
_name: &'static str,
|
|
_variant_index: u32,
|
|
_variant: &'static str,
|
|
_len: usize,
|
|
) -> Result<Self::SerializeTupleVariant> {
|
|
Err(Error::unsupported_pair())
|
|
}
|
|
|
|
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
|
|
Err(Error::unsupported_pair())
|
|
}
|
|
|
|
fn serialize_struct(
|
|
self,
|
|
_name: &'static str,
|
|
_len: usize,
|
|
) -> Result<Self::SerializeStruct> {
|
|
Err(Error::unsupported_pair())
|
|
}
|
|
|
|
fn serialize_struct_variant(
|
|
self,
|
|
_name: &'static str,
|
|
_variant_index: u32,
|
|
_variant: &'static str,
|
|
_len: usize,
|
|
) -> Result<Self::SerializeStructVariant> {
|
|
Err(Error::unsupported_pair())
|
|
}
|
|
}
|
|
|
|
impl<'input, 'target, Target> ser::SerializeSeq
|
|
for PairSerializer<'input, 'target, Target>
|
|
where
|
|
Target: 'target + UrlEncodedTarget,
|
|
{
|
|
type Ok = ();
|
|
type Error = Error;
|
|
|
|
fn serialize_element<T: ?Sized + ser::Serialize>(
|
|
&mut self,
|
|
value: &T,
|
|
) -> Result<()> {
|
|
value.serialize(PairSerializer::new(
|
|
self.urlencoder,
|
|
self.key,
|
|
&mut self.count,
|
|
))
|
|
}
|
|
|
|
fn end(self) -> Result<Self::Ok> {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<'input, 'target, Target> ser::SerializeTuple
|
|
for PairSerializer<'input, 'target, Target>
|
|
where
|
|
Target: 'target + UrlEncodedTarget,
|
|
{
|
|
type Ok = ();
|
|
type Error = Error;
|
|
|
|
fn serialize_element<T: ?Sized + ser::Serialize>(
|
|
&mut self,
|
|
value: &T,
|
|
) -> Result<()> {
|
|
match mem::replace(&mut self.state, PairState::Done) {
|
|
PairState::WaitingForKey => {
|
|
let key_sink = KeySink::new(|key| Ok(key.into()));
|
|
let key_serializer = PartSerializer::new(key_sink);
|
|
self.state = PairState::WaitingForValue {
|
|
key: value.serialize(key_serializer)?,
|
|
};
|
|
Ok(())
|
|
},
|
|
PairState::WaitingForValue { key } => {
|
|
let result = {
|
|
let value_sink = ValueSink::new(self.urlencoder, &key);
|
|
let value_serializer = PartSerializer::new(value_sink);
|
|
value.serialize(value_serializer)
|
|
};
|
|
if result.is_ok() {
|
|
self.state = PairState::Done;
|
|
} else {
|
|
self.state = PairState::WaitingForValue { key };
|
|
}
|
|
result
|
|
},
|
|
PairState::Done => Err(Error::done()),
|
|
}
|
|
}
|
|
|
|
fn end(self) -> Result<()> {
|
|
if let PairState::Done = self.state {
|
|
Ok(())
|
|
} else {
|
|
Err(Error::not_done())
|
|
}
|
|
}
|
|
}
|
|
|
|
enum PairState {
|
|
WaitingForKey,
|
|
WaitingForValue { key: Cow<'static, str> },
|
|
Done,
|
|
}
|