url_params_serializer 0.1.1

Allows serialization of types to URL GET parameters
Documentation
//! Allows the serialization of types which implement [Serde's](https://serde.rs/) `Serializer`
//!  trait to HTTP GET query parameters. Typical usage:
//!
//! ```rust
//! use serde_derive::Serialize;
//! use url::Url;
//! use url_params_serializer::to_url_params;
//!
//! #[derive(Serialize)]
//! struct Params {
//!     bar: &'static str,
//!     baz: usize,
//! }
//!
//! let params = Params { bar: "spam", baz: 5 };
//! let url = Url::parse_with_params("https://foo.com", to_url_params(params)).unwrap();
//!
//! assert_eq!(url.into_string(), "https://foo.com/?bar=spam&baz=5");
//! ```
//!
//! Some more complex types can be serialized too; see the documentation for [`to_url_params`](fn.to_url_params.html) for
//! more information.

use serde::ser::Serialize;

mod map_ser;
mod param_segment;
mod param_serializer_trait;
mod serializer_wrapper;

use crate::map_ser::MapSer;
use crate::serializer_wrapper::Wrap;

/// Produces a list of key-value pairs, compatible with [url's](https://docs.rs/url/1.7.2/url/)
/// `Url::parse_with_params` method.
///
/// ## Serde data model rules
///
/// - Structs behave like maps with string keys
/// - Enum unit variant labels are used as values
/// - Enum newtype/tuple/struct variant labels are used as keys
/// - Newtype names & tuple struct names are not used in output
/// - Units & unit structs are not used in output
///
/// ## Supported types
///
/// Structs with only primitive/string fields, and maps with primitive/string keys & values, will
/// serialize as you'd expect:
///
/// ```rust
/// #[derive(serde_derive::Serialize)]
/// struct Data {
///     a: &'static str,
///     b: i32
/// }
///
/// let data = Data { a: "foo", b: 5 };
/// let params = url_params_serializer::to_url_params(data);
///
/// assert_eq!(
///     params,
///     vec![
///         ("a".to_owned(), "foo".to_owned()),
///         ("b".to_owned(), "5".to_owned()),
///     ]
/// );
///
/// let mut map = std::collections::HashMap::new();
/// map.insert(100, "foo");
/// map.insert(101, "bar");
/// let mut params = url_params_serializer::to_url_params(map);
/// params.sort(); // HashMap does not preserve insert order

/// assert_eq!(
///     params,
///     vec![
///         ("100".to_owned(), "foo".to_owned()),
///         ("101".to_owned(), "bar".to_owned()),
///     ]
/// );
/// ```
///
/// Nested structs/maps will produce key-value pairs with dot-separated key paths:
///
/// ```rust
/// #[derive(serde_derive::Serialize)]
/// struct Data {
///     a: InnerData,
///     b: InnerData
/// }
///
/// #[derive(serde_derive::Serialize)]
/// struct InnerData {
///     c: &'static str,
///     d: i32
/// }
///
/// let data = Data {
///     a: InnerData { c: "foo", d: 5 },
///     b: InnerData { c: "bar", d: 6 },
/// };
///
/// let params = url_params_serializer::to_url_params(data);
///
/// assert_eq!(
///     params,
///     vec![
///         ("a.c".to_owned(), "foo".to_owned()),
///         ("a.d".to_owned(), "5".to_owned()),
///         ("b.c".to_owned(), "bar".to_owned()),
///         ("b.d".to_owned(), "6".to_owned()),
///     ]
/// );
/// ```
///
/// Fields which are sequences will be serialized to a comma-separated list, then treated as a
///  string value. Nested sequences will be flattened into a single sequence.
///
/// ```rust
/// #[derive(serde_derive::Serialize)]
/// struct Data {
///     seq: Vec<&'static str>,
///     nested_seq: Vec<Vec<&'static str>>,
/// }
///
/// let data = Data {
///     seq: vec!["foo", "bar"],
///     nested_seq: vec![vec!["baz", "qux"], vec!["quux"]]
/// };
///
/// let params = url_params_serializer::to_url_params(data);
///
/// assert_eq!(
///     params,
///     vec![
///         ("seq".to_owned(), "foo,bar".to_owned()),
///         ("nested_seq".to_owned(), "baz,qux,quux".to_owned()),
///     ]
/// );
/// ```
///
/// ## Unsupported types
///
/// Since `Serde` does not support the implementation of serializers for only certain types, types
/// with unsupported structures will panic at runtime. These are:
///
/// ### Types with nested values (i.e. structs or maps) within a sequence
///
/// e.g.:
///
/// ```rust,should_panic
/// #[derive(serde_derive::Serialize)]
/// struct Data {
///     inner: Vec<InnerData>
/// }
///
/// #[derive(serde_derive::Serialize)]
/// struct InnerData {
///     a: &'static str,
///     b: i32,
/// }
///
/// let data = Data {
///     inner: vec![
///         InnerData { a: "foo", b: 5 },
///         InnerData { a: "bar", b: 6 },
///     ]
/// };
///
/// url_params_serializer::to_url_params(data); // panics
/// ```
///
/// ### Types which are not nested values at the bottom level, (i.e. sequences, primitives, strings)
///
/// e.g.:
///
/// ```rust,should_panic
/// url_params_serializer::to_url_params(["a", "b"]); // panics
/// ```
/// ```rust,should_panic
/// url_params_serializer::to_url_params("foo"); // panics
/// ```
/// ```rust,should_panic
/// url_params_serializer::to_url_params(500); // panics
/// ```

pub fn to_url_params(value: impl Serialize) -> Vec<(String, String)> {
    let mut ser = Wrap(MapSer::new());
    value.serialize(&mut ser).unwrap();

    ser.0.pairs
}