355 lines
8.2 KiB
Rust
355 lines
8.2 KiB
Rust
//! Deserialization support for the `application/x-www-form-urlencoded` format.
|
|
|
|
use std::{
|
|
borrow::Cow,
|
|
collections::btree_map::{self, BTreeMap},
|
|
io::Read,
|
|
};
|
|
|
|
use form_urlencoded::{parse, Parse as UrlEncodedParse};
|
|
use serde::{
|
|
de::{self, value::MapDeserializer, Error as de_Error, IntoDeserializer},
|
|
forward_to_deserialize_any,
|
|
};
|
|
|
|
#[doc(inline)]
|
|
pub use serde::de::value::Error;
|
|
|
|
mod val_or_vec;
|
|
|
|
use val_or_vec::ValOrVec;
|
|
|
|
/// Deserializes a `application/x-www-form-urlencoded` value from a `&[u8]`.
|
|
///
|
|
/// ```
|
|
/// let meal = vec![
|
|
/// ("bread".to_owned(), "baguette".to_owned()),
|
|
/// ("cheese".to_owned(), "comté".to_owned()),
|
|
/// ("fat".to_owned(), "butter".to_owned()),
|
|
/// ("meat".to_owned(), "ham".to_owned()),
|
|
/// ];
|
|
///
|
|
/// assert_eq!(
|
|
/// ruma_serde::urlencoded::from_bytes::<Vec<(String, String)>>(
|
|
/// b"bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter"),
|
|
/// Ok(meal));
|
|
/// ```
|
|
pub fn from_bytes<'de, T>(input: &'de [u8]) -> Result<T, Error>
|
|
where
|
|
T: de::Deserialize<'de>,
|
|
{
|
|
T::deserialize(Deserializer::new(parse(input)))
|
|
}
|
|
|
|
/// Deserializes a `application/x-www-form-urlencoded` value from a `&str`.
|
|
///
|
|
/// ```
|
|
/// let meal = vec![
|
|
/// ("bread".to_owned(), "baguette".to_owned()),
|
|
/// ("cheese".to_owned(), "comté".to_owned()),
|
|
/// ("fat".to_owned(), "butter".to_owned()),
|
|
/// ("meat".to_owned(), "ham".to_owned()),
|
|
/// ];
|
|
///
|
|
/// assert_eq!(
|
|
/// ruma_serde::urlencoded::from_str::<Vec<(String, String)>>(
|
|
/// "bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter"),
|
|
/// Ok(meal));
|
|
/// ```
|
|
pub fn from_str<'de, T>(input: &'de str) -> Result<T, Error>
|
|
where
|
|
T: de::Deserialize<'de>,
|
|
{
|
|
from_bytes(input.as_bytes())
|
|
}
|
|
|
|
/// Convenience function that reads all bytes from `reader` and deserializes
|
|
/// them with `from_bytes`.
|
|
pub fn from_reader<T, R>(mut reader: R) -> Result<T, Error>
|
|
where
|
|
T: de::DeserializeOwned,
|
|
R: Read,
|
|
{
|
|
let mut buf = vec![];
|
|
reader
|
|
.read_to_end(&mut buf)
|
|
.map_err(|e| de::Error::custom(format_args!("could not read input: {}", e)))?;
|
|
from_bytes(&buf)
|
|
}
|
|
|
|
/// A deserializer for the `application/x-www-form-urlencoded` format.
|
|
///
|
|
/// * Supported top-level outputs are structs, maps and sequences of pairs, with or without a given
|
|
/// length.
|
|
///
|
|
/// * Main `deserialize` methods defers to `deserialize_map`.
|
|
///
|
|
/// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size` defers to
|
|
/// `deserialize`.
|
|
pub struct Deserializer<'de> {
|
|
inner: MapDeserializer<'de, EntryIterator<'de>, Error>,
|
|
}
|
|
|
|
impl<'de> Deserializer<'de> {
|
|
/// Returns a new `Deserializer`.
|
|
pub fn new(parse: UrlEncodedParse<'de>) -> Self {
|
|
Deserializer { inner: MapDeserializer::new(group_entries(parse).into_iter()) }
|
|
}
|
|
}
|
|
|
|
impl<'de> de::Deserializer<'de> for Deserializer<'de> {
|
|
type Error = Error;
|
|
|
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
|
where
|
|
V: de::Visitor<'de>,
|
|
{
|
|
self.deserialize_map(visitor)
|
|
}
|
|
|
|
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
|
where
|
|
V: de::Visitor<'de>,
|
|
{
|
|
visitor.visit_map(self.inner)
|
|
}
|
|
|
|
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
|
where
|
|
V: de::Visitor<'de>,
|
|
{
|
|
visitor.visit_seq(self.inner)
|
|
}
|
|
|
|
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
|
where
|
|
V: de::Visitor<'de>,
|
|
{
|
|
self.inner.end()?;
|
|
visitor.visit_unit()
|
|
}
|
|
|
|
forward_to_deserialize_any! {
|
|
bool
|
|
u8
|
|
u16
|
|
u32
|
|
u64
|
|
i8
|
|
i16
|
|
i32
|
|
i64
|
|
f32
|
|
f64
|
|
char
|
|
str
|
|
string
|
|
option
|
|
bytes
|
|
byte_buf
|
|
unit_struct
|
|
newtype_struct
|
|
tuple_struct
|
|
struct
|
|
identifier
|
|
tuple
|
|
enum
|
|
ignored_any
|
|
}
|
|
}
|
|
|
|
fn group_entries(parse: UrlEncodedParse<'_>) -> BTreeMap<Part<'_>, ValOrVec<Part<'_>>> {
|
|
use btree_map::Entry::*;
|
|
|
|
let mut res = BTreeMap::new();
|
|
|
|
for (key, value) in parse {
|
|
match res.entry(Part(key)) {
|
|
Vacant(v) => {
|
|
v.insert(ValOrVec::Val(Part(value)));
|
|
}
|
|
Occupied(mut o) => {
|
|
o.get_mut().push(Part(value));
|
|
}
|
|
}
|
|
}
|
|
|
|
res
|
|
}
|
|
|
|
/*
|
|
input: a=b&c=d&a=c
|
|
|
|
vvvvv
|
|
|
|
next(): a => Wrapper([b, c])
|
|
next(): c => Wrapper([d])
|
|
|
|
struct Foo {
|
|
a: Vec<String>,
|
|
c: Vec<String>,
|
|
}
|
|
|
|
struct Bar {
|
|
a: Vec<String>,
|
|
c: String,
|
|
}
|
|
|
|
struct Baz {
|
|
a: String,
|
|
}
|
|
*/
|
|
|
|
type EntryIterator<'de> = btree_map::IntoIter<Part<'de>, ValOrVec<Part<'de>>>;
|
|
|
|
#[derive(PartialEq, PartialOrd, Eq, Ord)]
|
|
struct Part<'de>(Cow<'de, str>);
|
|
|
|
impl<'de> IntoDeserializer<'de> for Part<'de> {
|
|
type Deserializer = Self;
|
|
|
|
fn into_deserializer(self) -> Self::Deserializer {
|
|
self
|
|
}
|
|
}
|
|
|
|
macro_rules! forward_parsed_value {
|
|
($($ty:ident => $method:ident,)*) => {
|
|
$(
|
|
fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
|
where V: de::Visitor<'de>
|
|
{
|
|
match self.0.parse::<$ty>() {
|
|
Ok(val) => val.into_deserializer().$method(visitor),
|
|
Err(e) => Err(de::Error::custom(e))
|
|
}
|
|
}
|
|
)*
|
|
}
|
|
}
|
|
|
|
impl<'de> de::Deserializer<'de> for Part<'de> {
|
|
type Error = Error;
|
|
|
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
|
where
|
|
V: de::Visitor<'de>,
|
|
{
|
|
match self.0 {
|
|
Cow::Borrowed(value) => visitor.visit_borrowed_str(value),
|
|
Cow::Owned(value) => visitor.visit_string(value),
|
|
}
|
|
}
|
|
|
|
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
|
where
|
|
V: de::Visitor<'de>,
|
|
{
|
|
visitor.visit_some(self)
|
|
}
|
|
|
|
fn deserialize_enum<V>(
|
|
self,
|
|
_name: &'static str,
|
|
_variants: &'static [&'static str],
|
|
visitor: V,
|
|
) -> Result<V::Value, Self::Error>
|
|
where
|
|
V: de::Visitor<'de>,
|
|
{
|
|
visitor.visit_enum(ValueEnumAccess(self.0))
|
|
}
|
|
|
|
fn deserialize_newtype_struct<V>(
|
|
self,
|
|
_name: &'static str,
|
|
visitor: V,
|
|
) -> Result<V::Value, Self::Error>
|
|
where
|
|
V: de::Visitor<'de>,
|
|
{
|
|
visitor.visit_newtype_struct(self)
|
|
}
|
|
|
|
forward_to_deserialize_any! {
|
|
char
|
|
str
|
|
string
|
|
unit
|
|
bytes
|
|
byte_buf
|
|
unit_struct
|
|
tuple_struct
|
|
struct
|
|
identifier
|
|
tuple
|
|
ignored_any
|
|
seq
|
|
map
|
|
}
|
|
|
|
forward_parsed_value! {
|
|
bool => deserialize_bool,
|
|
u8 => deserialize_u8,
|
|
u16 => deserialize_u16,
|
|
u32 => deserialize_u32,
|
|
u64 => deserialize_u64,
|
|
i8 => deserialize_i8,
|
|
i16 => deserialize_i16,
|
|
i32 => deserialize_i32,
|
|
i64 => deserialize_i64,
|
|
f32 => deserialize_f32,
|
|
f64 => deserialize_f64,
|
|
}
|
|
}
|
|
|
|
struct ValueEnumAccess<'de>(Cow<'de, str>);
|
|
|
|
impl<'de> de::EnumAccess<'de> for ValueEnumAccess<'de> {
|
|
type Error = Error;
|
|
type Variant = UnitOnlyVariantAccess;
|
|
|
|
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
|
|
where
|
|
V: de::DeserializeSeed<'de>,
|
|
{
|
|
let variant = seed.deserialize(self.0.into_deserializer())?;
|
|
Ok((variant, UnitOnlyVariantAccess))
|
|
}
|
|
}
|
|
|
|
struct UnitOnlyVariantAccess;
|
|
|
|
impl<'de> de::VariantAccess<'de> for UnitOnlyVariantAccess {
|
|
type Error = Error;
|
|
|
|
fn unit_variant(self) -> Result<(), Self::Error> {
|
|
Ok(())
|
|
}
|
|
|
|
fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, Self::Error>
|
|
where
|
|
T: de::DeserializeSeed<'de>,
|
|
{
|
|
Err(Error::custom("expected unit variant"))
|
|
}
|
|
|
|
fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
|
|
where
|
|
V: de::Visitor<'de>,
|
|
{
|
|
Err(Error::custom("expected unit variant"))
|
|
}
|
|
|
|
fn struct_variant<V>(
|
|
self,
|
|
_fields: &'static [&'static str],
|
|
_visitor: V,
|
|
) -> Result<V::Value, Self::Error>
|
|
where
|
|
V: de::Visitor<'de>,
|
|
{
|
|
Err(Error::custom("expected unit variant"))
|
|
}
|
|
}
|