use std::fmt;
use serde::{
Deserialize, Serialize,
de::{self, IntoDeserializer, MapAccess, SeqAccess, Visitor},
ser::{self, Impossible, SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple},
};
use snafu::Snafu;
#[derive(Debug, Snafu)]
#[snafu(visibility(pub(crate)))]
pub enum Error {
#[snafu(display(
"parameter `{name}` appears {count} times but a single value is expected (RFC 6749 §3.1)"
))]
DuplicateParameter {
name: String,
count: usize,
},
#[snafu(display("invalid JSON in a form parameter value"), context(false))]
Json {
source: serde_json::Error,
},
#[snafu(display("{message}"))]
Other {
message: String,
},
}
impl Error {
fn other(message: impl Into<String>) -> Self {
Error::Other {
message: message.into(),
}
}
}
impl ser::Error for Error {
fn custom<T: fmt::Display>(msg: T) -> Self {
Error::other(msg.to_string())
}
}
impl de::Error for Error {
fn custom<T: fmt::Display>(msg: T) -> Self {
Error::other(msg.to_string())
}
}
fn top_level_err<T>() -> Result<T, Error> {
Err(Error::other(
"value must be a struct, map, or sequence of key/value pairs",
))
}
pub fn to_string<T: Serialize + ?Sized>(value: &T) -> Result<String, Error> {
let mut ser = FormSerializer::new();
value.serialize(&mut ser)?;
Ok(ser.out.finish())
}
pub fn push_to_string<T: Serialize + ?Sized>(out: &mut String, value: &T) -> Result<(), Error> {
let mut ser = FormSerializer::new();
value.serialize(&mut ser)?;
out.push_str(&ser.out.finish());
Ok(())
}
fn is_scalar(v: &serde_json::Value) -> bool {
v.is_string() || v.is_number() || v.is_boolean()
}
fn scalar_text(v: serde_json::Value) -> String {
match v {
serde_json::Value::String(s) => s,
other => other.to_string(),
}
}
struct FormSerializer {
out: form_urlencoded::Serializer<'static, String>,
}
impl FormSerializer {
fn new() -> Self {
Self {
out: form_urlencoded::Serializer::new(String::new()),
}
}
fn add_field<T: Serialize + ?Sized>(&mut self, key: &str, value: &T) -> Result<(), Error> {
match value.serialize(ScalarProbe {
out: &mut self.out,
key,
}) {
Ok(()) => Ok(()),
Err(Probe::NotScalar) => self.add_structured_field(key, value),
Err(Probe::Fail(e)) => Err(e),
}
}
fn add_structured_field<T: Serialize + ?Sized>(
&mut self,
key: &str,
value: &T,
) -> Result<(), Error> {
use serde_json::Value::{Array, Bool, Null, Number, Object, String as JString};
match serde_json::to_value(value)? {
Null => {}
Bool(b) => {
self.out.append_pair(key, &b.to_string());
}
Number(n) => {
self.out.append_pair(key, &n.to_string());
}
JString(s) => {
self.out.append_pair(key, &s);
}
Array(a) if a.iter().all(is_scalar) => {
for e in a {
self.out.append_pair(key, &scalar_text(e));
}
}
Array(_) | Object(_) => {
self.out.append_pair(key, &serde_json::to_string(value)?);
}
}
Ok(())
}
}
impl<'a> ser::Serializer for &'a mut FormSerializer {
type Ok = ();
type Error = Error;
type SerializeStruct = StructSer<'a>;
type SerializeMap = MapSer<'a>;
type SerializeSeq = SeqSer<'a>;
type SerializeTuple = Impossible<(), Error>;
type SerializeTupleStruct = Impossible<(), Error>;
type SerializeTupleVariant = Impossible<(), Error>;
type SerializeStructVariant = Impossible<(), Error>;
fn serialize_struct(self, _: &'static str, _: usize) -> Result<Self::SerializeStruct, Error> {
Ok(StructSer { ser: self })
}
fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Error> {
Ok(MapSer {
ser: self,
key: None,
})
}
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Error> {
Ok(SeqSer { ser: self })
}
fn serialize_some<T: Serialize + ?Sized>(self, v: &T) -> Result<(), Error> {
v.serialize(self)
}
fn serialize_none(self) -> Result<(), Error> {
Ok(())
}
fn serialize_newtype_struct<T: Serialize + ?Sized>(
self,
_: &'static str,
v: &T,
) -> Result<(), Error> {
v.serialize(self)
}
fn serialize_bool(self, _: bool) -> Result<(), Error> {
top_level_err()
}
fn serialize_i8(self, _: i8) -> Result<(), Error> {
top_level_err()
}
fn serialize_i16(self, _: i16) -> Result<(), Error> {
top_level_err()
}
fn serialize_i32(self, _: i32) -> Result<(), Error> {
top_level_err()
}
fn serialize_i64(self, _: i64) -> Result<(), Error> {
top_level_err()
}
fn serialize_u8(self, _: u8) -> Result<(), Error> {
top_level_err()
}
fn serialize_u16(self, _: u16) -> Result<(), Error> {
top_level_err()
}
fn serialize_u32(self, _: u32) -> Result<(), Error> {
top_level_err()
}
fn serialize_u64(self, _: u64) -> Result<(), Error> {
top_level_err()
}
fn serialize_f32(self, _: f32) -> Result<(), Error> {
top_level_err()
}
fn serialize_f64(self, _: f64) -> Result<(), Error> {
top_level_err()
}
fn serialize_char(self, _: char) -> Result<(), Error> {
top_level_err()
}
fn serialize_str(self, _: &str) -> Result<(), Error> {
top_level_err()
}
fn serialize_bytes(self, _: &[u8]) -> Result<(), Error> {
top_level_err()
}
fn serialize_unit(self) -> Result<(), Error> {
Ok(())
}
fn serialize_unit_struct(self, _: &'static str) -> Result<(), Error> {
Ok(())
}
fn serialize_unit_variant(self, _: &'static str, _: u32, _: &'static str) -> Result<(), Error> {
top_level_err()
}
fn serialize_newtype_variant<T: Serialize + ?Sized>(
self,
_: &'static str,
_: u32,
_: &'static str,
_: &T,
) -> Result<(), Error> {
top_level_err()
}
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Error> {
top_level_err()
}
fn serialize_tuple_struct(
self,
_: &'static str,
_: usize,
) -> Result<Self::SerializeTupleStruct, Error> {
top_level_err()
}
fn serialize_tuple_variant(
self,
_: &'static str,
_: u32,
_: &'static str,
_: usize,
) -> Result<Self::SerializeTupleVariant, Error> {
top_level_err()
}
fn serialize_struct_variant(
self,
_: &'static str,
_: u32,
_: &'static str,
_: usize,
) -> Result<Self::SerializeStructVariant, Error> {
top_level_err()
}
}
struct StructSer<'a> {
ser: &'a mut FormSerializer,
}
impl SerializeStruct for StructSer<'_> {
type Ok = ();
type Error = Error;
fn serialize_field<T: Serialize + ?Sized>(
&mut self,
key: &'static str,
value: &T,
) -> Result<(), Error> {
self.ser.add_field(key, value)
}
fn end(self) -> Result<(), Error> {
Ok(())
}
}
struct MapSer<'a> {
ser: &'a mut FormSerializer,
key: Option<String>,
}
impl SerializeMap for MapSer<'_> {
type Ok = ();
type Error = Error;
fn serialize_key<T: Serialize + ?Sized>(&mut self, key: &T) -> Result<(), Error> {
let k = serde_json::to_value(key)?;
let s = k
.as_str()
.ok_or_else(|| Error::other("map key must be a string"))?;
self.key = Some(s.to_string());
Ok(())
}
fn serialize_value<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
let key = self
.key
.take()
.ok_or_else(|| Error::other("serialize_value called before serialize_key"))?;
self.ser.add_field(&key, value)
}
fn end(self) -> Result<(), Error> {
Ok(())
}
}
struct SeqSer<'a> {
ser: &'a mut FormSerializer,
}
impl SerializeSeq for SeqSer<'_> {
type Ok = ();
type Error = Error;
fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
value.serialize(PairSerializer { ser: self.ser })
}
fn end(self) -> Result<(), Error> {
Ok(())
}
}
enum Probe {
NotScalar,
Fail(Error),
}
impl fmt::Display for Probe {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Probe::NotScalar => f.write_str("value is not a scalar"),
Probe::Fail(e) => e.fmt(f),
}
}
}
impl fmt::Debug for Probe {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self}")
}
}
impl std::error::Error for Probe {}
impl ser::Error for Probe {
fn custom<T: fmt::Display>(msg: T) -> Self {
Probe::Fail(Error::other(msg.to_string()))
}
}
struct ScalarProbe<'a> {
out: &'a mut form_urlencoded::Serializer<'static, String>,
key: &'a str,
}
impl ScalarProbe<'_> {
fn emit(self, value: &str) {
self.out.append_pair(self.key, value);
}
}
impl ser::Serializer for ScalarProbe<'_> {
type Ok = ();
type Error = Probe;
type SerializeSeq = Impossible<(), Probe>;
type SerializeTuple = Impossible<(), Probe>;
type SerializeTupleStruct = Impossible<(), Probe>;
type SerializeTupleVariant = Impossible<(), Probe>;
type SerializeMap = Impossible<(), Probe>;
type SerializeStruct = Impossible<(), Probe>;
type SerializeStructVariant = Impossible<(), Probe>;
fn serialize_str(self, v: &str) -> Result<(), Probe> {
self.emit(v);
Ok(())
}
fn serialize_bool(self, v: bool) -> Result<(), Probe> {
self.emit(if v { "true" } else { "false" });
Ok(())
}
fn serialize_i64(self, v: i64) -> Result<(), Probe> {
self.emit(&v.to_string());
Ok(())
}
fn serialize_i8(self, v: i8) -> Result<(), Probe> {
self.serialize_i64(i64::from(v))
}
fn serialize_i16(self, v: i16) -> Result<(), Probe> {
self.serialize_i64(i64::from(v))
}
fn serialize_i32(self, v: i32) -> Result<(), Probe> {
self.serialize_i64(i64::from(v))
}
fn serialize_u64(self, v: u64) -> Result<(), Probe> {
self.emit(&v.to_string());
Ok(())
}
fn serialize_u8(self, v: u8) -> Result<(), Probe> {
self.serialize_u64(u64::from(v))
}
fn serialize_u16(self, v: u16) -> Result<(), Probe> {
self.serialize_u64(u64::from(v))
}
fn serialize_u32(self, v: u32) -> Result<(), Probe> {
self.serialize_u64(u64::from(v))
}
fn serialize_f64(self, v: f64) -> Result<(), Probe> {
self.emit(&v.to_string());
Ok(())
}
fn serialize_f32(self, v: f32) -> Result<(), Probe> {
self.serialize_f64(f64::from(v))
}
fn serialize_char(self, v: char) -> Result<(), Probe> {
self.emit(v.encode_utf8(&mut [0u8; 4]));
Ok(())
}
fn serialize_none(self) -> Result<(), Probe> {
Ok(())
}
fn serialize_unit(self) -> Result<(), Probe> {
Ok(())
}
fn serialize_unit_struct(self, _: &'static str) -> Result<(), Probe> {
Ok(())
}
fn serialize_some<T: Serialize + ?Sized>(self, v: &T) -> Result<(), Probe> {
v.serialize(self)
}
fn serialize_newtype_struct<T: Serialize + ?Sized>(
self,
_: &'static str,
v: &T,
) -> Result<(), Probe> {
v.serialize(self)
}
fn serialize_bytes(self, _: &[u8]) -> Result<(), Probe> {
Err(Probe::NotScalar)
}
fn serialize_unit_variant(self, _: &'static str, _: u32, _: &'static str) -> Result<(), Probe> {
Err(Probe::NotScalar)
}
fn serialize_newtype_variant<T: Serialize + ?Sized>(
self,
_: &'static str,
_: u32,
_: &'static str,
_: &T,
) -> Result<(), Probe> {
Err(Probe::NotScalar)
}
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Probe> {
Err(Probe::NotScalar)
}
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Probe> {
Err(Probe::NotScalar)
}
fn serialize_tuple_struct(
self,
_: &'static str,
_: usize,
) -> Result<Self::SerializeTupleStruct, Probe> {
Err(Probe::NotScalar)
}
fn serialize_tuple_variant(
self,
_: &'static str,
_: u32,
_: &'static str,
_: usize,
) -> Result<Self::SerializeTupleVariant, Probe> {
Err(Probe::NotScalar)
}
fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Probe> {
Err(Probe::NotScalar)
}
fn serialize_struct(self, _: &'static str, _: usize) -> Result<Self::SerializeStruct, Probe> {
Err(Probe::NotScalar)
}
fn serialize_struct_variant(
self,
_: &'static str,
_: u32,
_: &'static str,
_: usize,
) -> Result<Self::SerializeStructVariant, Probe> {
Err(Probe::NotScalar)
}
}
fn pair_err<T>() -> Result<T, Error> {
Err(Error::other("sequence element must be a (key, value) pair"))
}
struct PairSerializer<'a> {
ser: &'a mut FormSerializer,
}
impl<'a> ser::Serializer for PairSerializer<'a> {
type Ok = ();
type Error = Error;
type SerializeTuple = PairBuilder<'a>;
type SerializeSeq = Impossible<(), Error>;
type SerializeTupleStruct = Impossible<(), Error>;
type SerializeTupleVariant = Impossible<(), Error>;
type SerializeMap = Impossible<(), Error>;
type SerializeStruct = Impossible<(), Error>;
type SerializeStructVariant = Impossible<(), Error>;
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Error> {
if len == 2 {
Ok(PairBuilder {
ser: self.ser,
key: None,
})
} else {
pair_err()
}
}
fn serialize_bool(self, _: bool) -> Result<(), Error> {
pair_err()
}
fn serialize_i8(self, _: i8) -> Result<(), Error> {
pair_err()
}
fn serialize_i16(self, _: i16) -> Result<(), Error> {
pair_err()
}
fn serialize_i32(self, _: i32) -> Result<(), Error> {
pair_err()
}
fn serialize_i64(self, _: i64) -> Result<(), Error> {
pair_err()
}
fn serialize_u8(self, _: u8) -> Result<(), Error> {
pair_err()
}
fn serialize_u16(self, _: u16) -> Result<(), Error> {
pair_err()
}
fn serialize_u32(self, _: u32) -> Result<(), Error> {
pair_err()
}
fn serialize_u64(self, _: u64) -> Result<(), Error> {
pair_err()
}
fn serialize_f32(self, _: f32) -> Result<(), Error> {
pair_err()
}
fn serialize_f64(self, _: f64) -> Result<(), Error> {
pair_err()
}
fn serialize_char(self, _: char) -> Result<(), Error> {
pair_err()
}
fn serialize_str(self, _: &str) -> Result<(), Error> {
pair_err()
}
fn serialize_bytes(self, _: &[u8]) -> Result<(), Error> {
pair_err()
}
fn serialize_none(self) -> Result<(), Error> {
pair_err()
}
fn serialize_some<T: Serialize + ?Sized>(self, _: &T) -> Result<(), Error> {
pair_err()
}
fn serialize_unit(self) -> Result<(), Error> {
pair_err()
}
fn serialize_unit_struct(self, _: &'static str) -> Result<(), Error> {
pair_err()
}
fn serialize_unit_variant(self, _: &'static str, _: u32, _: &'static str) -> Result<(), Error> {
pair_err()
}
fn serialize_newtype_struct<T: Serialize + ?Sized>(
self,
_: &'static str,
_: &T,
) -> Result<(), Error> {
pair_err()
}
fn serialize_newtype_variant<T: Serialize + ?Sized>(
self,
_: &'static str,
_: u32,
_: &'static str,
_: &T,
) -> Result<(), Error> {
pair_err()
}
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Error> {
pair_err()
}
fn serialize_tuple_struct(
self,
_: &'static str,
_: usize,
) -> Result<Self::SerializeTupleStruct, Error> {
pair_err()
}
fn serialize_tuple_variant(
self,
_: &'static str,
_: u32,
_: &'static str,
_: usize,
) -> Result<Self::SerializeTupleVariant, Error> {
pair_err()
}
fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Error> {
pair_err()
}
fn serialize_struct(self, _: &'static str, _: usize) -> Result<Self::SerializeStruct, Error> {
pair_err()
}
fn serialize_struct_variant(
self,
_: &'static str,
_: u32,
_: &'static str,
_: usize,
) -> Result<Self::SerializeStructVariant, Error> {
pair_err()
}
}
struct PairBuilder<'a> {
ser: &'a mut FormSerializer,
key: Option<String>,
}
impl SerializeTuple for PairBuilder<'_> {
type Ok = ();
type Error = Error;
fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
match self.key.take() {
None => {
self.key = Some(key_string(value)?);
Ok(())
}
Some(key) => self.ser.add_field(&key, value),
}
}
fn end(self) -> Result<(), Error> {
Ok(())
}
}
fn key_string<T: Serialize + ?Sized>(value: &T) -> Result<String, Error> {
serde_json::to_value(value)?
.as_str()
.map(ToOwned::to_owned)
.ok_or_else(|| Error::other("pair key must be a string"))
}
pub fn from_str<'de, T: Deserialize<'de>>(input: &str) -> Result<T, Error> {
let mut groups: Vec<(String, Vec<String>)> = Vec::new();
for (k, v) in form_urlencoded::parse(input.as_bytes()) {
match groups.iter_mut().find(|(gk, _)| *gk == k) {
Some(g) => g.1.push(v.into_owned()),
None => groups.push((k.into_owned(), vec![v.into_owned()])),
}
}
T::deserialize(FormDeserializer { groups })
}
struct FormDeserializer {
groups: Vec<(String, Vec<String>)>,
}
impl<'de> de::Deserializer<'de> for FormDeserializer {
type Error = Error;
fn deserialize_any<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
v.visit_map(GroupsMap {
iter: self.groups.into_iter(),
entry: None,
})
}
fn deserialize_struct<V: Visitor<'de>>(
self,
_: &'static str,
_: &'static [&'static str],
v: V,
) -> Result<V::Value, Error> {
self.deserialize_any(v)
}
fn deserialize_map<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
self.deserialize_any(v)
}
serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
enum identifier ignored_any
}
}
struct GroupsMap {
iter: std::vec::IntoIter<(String, Vec<String>)>,
entry: Option<(String, Vec<String>)>,
}
impl<'de> MapAccess<'de> for GroupsMap {
type Error = Error;
fn next_key_seed<K: de::DeserializeSeed<'de>>(
&mut self,
seed: K,
) -> Result<Option<K::Value>, Error> {
match self.iter.next() {
Some((k, vs)) => {
self.entry = Some((k.clone(), vs));
seed.deserialize(k.into_deserializer()).map(Some)
}
None => Ok(None),
}
}
fn next_value_seed<V: de::DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value, Error> {
let (name, values) = self
.entry
.take()
.ok_or_else(|| Error::other("next_value_seed called before next_key_seed"))?;
seed.deserialize(ValueDe { name, values })
}
}
struct ValueDe {
name: String,
values: Vec<String>,
}
impl ValueDe {
fn single(&self) -> Result<&str, Error> {
match self.values.as_slice() {
[one] => Ok(one),
many => Err(Error::DuplicateParameter {
name: self.name.clone(),
count: many.len(),
}),
}
}
fn into_single(self) -> Result<String, Error> {
self.single()?;
self.values
.into_iter()
.next()
.ok_or_else(|| Error::other("empty parameter group"))
}
}
impl<'de> de::Deserializer<'de> for ValueDe {
type Error = Error;
fn deserialize_any<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
if self.values.len() > 1 {
return self.deserialize_seq(v);
}
let s = self.into_single()?;
match serde_json::from_str::<serde_json::Value>(&s) {
Ok(j) if j.is_object() || j.is_array() => {
de::Deserializer::deserialize_any(j, v).map_err(Error::from)
}
_ => v.visit_string(s),
}
}
fn deserialize_str<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
v.visit_str(self.single()?)
}
fn deserialize_string<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
v.visit_string(self.into_single()?)
}
fn deserialize_bool<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
let b = self
.single()?
.parse()
.map_err(|_| Error::other("invalid boolean"))?;
v.visit_bool(b)
}
fn deserialize_i64<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
let n = self
.single()?
.parse()
.map_err(|_| Error::other("invalid integer"))?;
v.visit_i64(n)
}
fn deserialize_u64<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
let n = self
.single()?
.parse()
.map_err(|_| Error::other("invalid integer"))?;
v.visit_u64(n)
}
fn deserialize_option<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
v.visit_some(self) }
fn deserialize_seq<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
if self.values.len() > 1 {
return v.visit_seq(StrSeq {
iter: self.values.into_iter(),
});
}
match serde_json::from_str::<serde_json::Value>(self.single()?) {
Ok(j @ serde_json::Value::Array(_)) => {
de::Deserializer::deserialize_seq(j, v).map_err(Error::from)
}
_ => v.visit_seq(StrSeq {
iter: self.values.into_iter(),
}),
}
}
fn deserialize_struct<V: Visitor<'de>>(
self,
_: &'static str,
_: &'static [&'static str],
v: V,
) -> Result<V::Value, Error> {
self.deserialize_map(v)
}
fn deserialize_map<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
let j: serde_json::Value = serde_json::from_str(self.single()?)?;
de::Deserializer::deserialize_map(j, v).map_err(Error::from)
}
fn deserialize_enum<V: Visitor<'de>>(
self,
name: &'static str,
variants: &'static [&'static str],
v: V,
) -> Result<V::Value, Error> {
let s = self.into_single()?;
match serde_json::from_str::<serde_json::Value>(&s) {
Ok(j @ serde_json::Value::Object(_)) => {
de::Deserializer::deserialize_enum(j, name, variants, v).map_err(Error::from)
}
_ => s.into_deserializer().deserialize_enum(name, variants, v),
}
}
fn deserialize_ignored_any<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
v.visit_unit()
}
serde::forward_to_deserialize_any! {
i8 i16 i32 u8 u16 u32 f32 f64 char bytes byte_buf unit unit_struct
newtype_struct tuple tuple_struct identifier
}
}
struct StrSeq {
iter: std::vec::IntoIter<String>,
}
impl<'de> SeqAccess<'de> for StrSeq {
type Error = Error;
fn next_element_seed<T: de::DeserializeSeed<'de>>(
&mut self,
seed: T,
) -> Result<Option<T::Value>, Error> {
match self.iter.next() {
Some(s) => seed.deserialize(s.into_deserializer()).map(Some),
None => Ok(None),
}
}
}
#[cfg(test)]
mod tests {
use serde::{Deserialize, Serialize};
use super::{Error, from_str, push_to_string, to_string};
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Detail {
r#type: String,
#[serde(flatten)]
rest: serde_json::Map<String, serde_json::Value>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Payload {
response_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
scope: Option<String>,
state: String,
#[serde(skip_serializing_if = "Option::is_none")]
resource: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
authorization_details: Option<Vec<Detail>>,
}
fn sample() -> Payload {
let detail = Detail {
r#type: "payment_initiation".into(),
rest: [("actions".to_string(), serde_json::json!(["initiate"]))]
.into_iter()
.collect(),
};
Payload {
response_type: "code".into(),
scope: Some("openid payments".into()),
state: "af0ifjsldkj".into(),
resource: Some(vec![
"https://a.example/".into(),
"https://b.example/".into(),
]),
authorization_details: Some(vec![detail]),
}
}
#[test]
fn scalars_and_space_follow_appendix_b() {
let form = to_string(&sample()).unwrap();
assert!(form.contains("response_type=code"), "{form}");
assert!(form.contains("scope=openid+payments"), "{form}");
assert!(form.contains("state=af0ifjsldkj"), "{form}");
}
#[test]
fn scalar_sequence_is_repeated_keys_not_json() {
let form = to_string(&sample()).unwrap();
assert_eq!(form.matches("resource=").count(), 2, "{form}");
assert!(
!form.contains("resource=%5B"),
"must not be a JSON array: {form}"
);
}
#[test]
fn structured_param_is_one_json_string_value() {
let form = to_string(&sample()).unwrap();
assert_eq!(form.matches("authorization_details=").count(), 1, "{form}");
assert!(form.contains("authorization_details=%5B%7B"), "{form}");
}
#[test]
fn top_level_field_order_is_preserved() {
let form = to_string(&sample()).unwrap();
let rt = form.find("response_type").unwrap();
let st = form.find("state").unwrap();
assert!(rt < st, "declaration order preserved: {form}");
}
#[test]
fn round_trips() {
let original = sample();
let form = to_string(&original).unwrap();
let back: Payload = from_str(&form).unwrap();
assert_eq!(back, original);
}
#[test]
fn duplicate_single_valued_param_errors() {
let r: Result<Payload, _> = from_str("response_type=code&state=a&state=b");
assert!(
matches!(r, Err(Error::DuplicateParameter { ref name, count: 2 }) if name == "state"),
"{r:?}"
);
}
#[test]
fn single_value_into_vec_is_one_element() {
let p: Payload =
from_str("response_type=code&state=s&resource=https%3A%2F%2Fonly").unwrap();
assert_eq!(p.resource.unwrap().len(), 1);
}
#[test]
fn top_level_sequence_of_pairs() {
let pairs = vec![("client_id", "abc"), ("client_secret", "s3cr3t")];
let form = to_string(&pairs).unwrap();
assert!(form.contains("client_id=abc"), "{form}");
assert!(form.contains("client_secret=s3cr3t"), "{form}");
}
#[test]
fn push_appends_pairs() {
let mut body = String::from("grant_type=authorization_code");
body.push('&');
push_to_string(&mut body, &vec![("client_id", "abc")]).unwrap();
assert_eq!(body, "grant_type=authorization_code&client_id=abc");
}
#[test]
fn pair_value_wrapper_streams_through_scalar_path() {
#[derive(Serialize)]
struct Secret(String);
let pairs = vec![("client_secret", Secret("s3cr3t".into()))];
assert_eq!(to_string(&pairs).unwrap(), "client_secret=s3cr3t");
}
#[test]
fn unit_enum_round_trips() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "snake_case")]
enum Prompt {
Login,
Consent,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct S {
prompt: Prompt,
}
let v = S {
prompt: Prompt::Consent,
};
let form = to_string(&v).unwrap();
assert_eq!(form, "prompt=consent");
assert_eq!(from_str::<S>(&form).unwrap(), v);
}
#[test]
fn no_param_forms_serialize_to_empty() {
#[derive(Serialize)]
struct NoParams;
assert_eq!(to_string(&()).unwrap(), "");
assert_eq!(to_string(&NoParams).unwrap(), "");
assert_eq!(to_string(&Option::<NoParams>::None).unwrap(), "");
}
#[test]
fn externally_tagged_enum_round_trips() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum Variant {
Unit,
Data { x: u32 },
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct S {
v: Variant,
}
for value in [
S { v: Variant::Unit },
S {
v: Variant::Data { x: 7 },
},
] {
let form = to_string(&value).unwrap();
assert_eq!(from_str::<S>(&form).unwrap(), value, "form = {form}");
}
}
#[test]
fn internally_tagged_enum_round_trips() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(tag = "type", rename_all = "snake_case")]
enum Detail {
Payment { amount: String },
Account,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct S {
detail: Detail,
}
for value in [
S {
detail: Detail::Payment {
amount: "12.00".into(),
},
},
S {
detail: Detail::Account,
},
] {
let form = to_string(&value).unwrap();
assert_eq!(from_str::<S>(&form).unwrap(), value, "form = {form}");
}
}
}