pub fn to_url_params(value: impl Serialize) -> Vec<(String, String)>
Expand description

Produces a list of key-value pairs, compatible with url’s 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:

#[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:

#[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.

#[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.:

#[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.:

url_params_serializer::to_url_params(["a", "b"]); // panics
url_params_serializer::to_url_params("foo"); // panics
url_params_serializer::to_url_params(500); // panics