urlencodeddata

test, clippy

Ergonomic, Versatile Url-Encoded-Data Manipulator

Manipulate data of application/x-www-form-urlencoded format, eg: * query_string of a url (eg: '?a=1&b=2&c=3&c=3&e=5') * http content-type with: application/x-www-form-urlencoded

Features:

Terminology

Notes

Sample

Sample of url query string

```rust use urlencodeddata::UrlEncodedData; use std::borrow::Cow; // note: the library will not check the validity of the url, it just searchs for url-encoded-data, eg: string after first '?' and then s.trimstart('?') let url = "https://google.com/?q=rust&ei=code"; let q = UrlEncodedData::from(url); // q.tostring(), best performance, (key, value) pairs are in un-deterministic order. asserteq!(q.tostringoforiginalorder(), "https://google.com/?q=rust&ei=code"); asserteq!(q.tostringofsortedorder(), "https://google.com/?ei=code&q=rust");

// pairs length assert_eq!(q.len(), 2);

// keys length asserteq!(q.keyslength(), 2);

// keys assert!(q.keys().contains(&"q")); assert!(q.keys().contains(&"ei"));

// exists assert!(q.exists("q")); assert!(q.exists("ei"));

// let's do some manipulation let url = "https://google.com/?q=rust&ei=code"; let q = UrlEncodedData::parsestr(url) .setone("q", "rust-lang") .set("vector", &vec!["1", "2"]) .setone("a", "1") .setone("b", "2") .set_one("hello", "world") .set("whole", &vec!["world", "世界"]) // utf-8, auto encoding and decoding .delete("ei") // ei is deleted .push("b", "3") .done(); // now b is: vec!["1", "2"]

// q.keys() // performant asserteq!(q.keysoforiginalorder()[0].as_ref(), "q");

// something like: https://google.com/?b=2&b=3&q=rust-lang&a=1&hello=world&vector=1&vector=2&whole=world&whole=%E4%B8%96%E7%95%8C println!("{}", q); // calls q.tofinalstring() actually.

// something like: https://google.com/?b=2&b=3&q=rust-lang&a=1&hello=world&vector=1&vector=2&whole=world&whole=%E4%B8%96%E7%95%8C println!("{}", q.tofinalstring());

// https://google.com/?q=rust-lang&b=2&b=3&a=1&hello=world&vector=1&vector=2&whole=world&whole=%E4%B8%96%E7%95%8C println!("{}", q.tostringoforiginalorder());

// https://google.com/?a=1&b=2&b=3&hello=world&q=rust-lang&vector=1&vector=2&whole=world&whole=%E4%B8%96%E7%95%8C println!("{}", q.tostringofsortedorder());

```

Sample of encoded data in www/x-www-form-urlencoded

```rust use urlencodeddata::UrlEncodedData; use std::borrow::Cow; // note: the library will not check the validity of the url, it just searchs for url-encoded-data, eg: string after first '?' and then s.trimstart('?') let s = "b=2&b=3&q=rust-lang&a=1&hello=world&vector=1&vector=2&whole=world&whole=%E4%B8%96%E7%95%8C"; let q = UrlEncodedData::parsestr(s); // q.tostring(), best performance, (key, value) pairs are in un-deterministic order. asserteq!(q.tostringoforiginalorder(), s);

// [("hello", "world"), ("vector", "1"), ("vector", "2"), ("whole", "world"), ("whole", "世界"), ("b", "2"), ("b", "3"), ("q", "rust-lang"), ("a", "1")] println!("{:?}", q.as_pairs());

// {"a": ["1"], "hello": ["world"], "b": ["2", "3"], "q": ["rust-lang"], "whole": ["world", "世界"], "vector": ["1", "2"]} println!("{:?}", q.asmapofsinglekeytomultiple_values());

// {"b": "2", "a": "1", "q": "rust-lang", "whole": "world", "hello": "world", "vector": "1"} println!("{:?}", q.asmapofsinglekeytofirstoccurrencevalue());

// {"q": "rust-lang", "whole": "世界", "vector": "2", "a": "1", "b": "3", "hello": "world"} println!("{:?}", q.asmapofsinglekeytolastoccurrencevalue()); // assert!(false);

```

Sample of performant pairs iterator: UrlEncodedDataPairScanner (Lazy version)

```rust use urlencodeddata::{UrlEncodedData, UrlEncodedDataPairScanner}; use std::borrow::Cow; // note: the library will not check the validity of the url, it just searchs for url-encoded-data, eg: string after first '?' and then s.trimstart('?') let s = "b=2&b=3&q=rust-lang&a=1&hello=world&vector=1&vector=2&whole=world&whole=%E4%B8%96%E7%95%8C"; let q = UrlEncodedDataPairScanner::from(s); // same: // let q = UrlEncodedDataPairScanner::parsefromdatastr(s);

for (key, value) in q.iter() { // k, v are decoded // process the pair: (key, value) }

```

Some apis

strigify: Stringify pairs to url encoded String

example 1

rust use url_encoded_data::stringify; let encoded = stringify(&[("a", "b"), ("c", "d")]); assert_eq!(encoded, "a=b&c=d");

example 2

rust use url_encoded_data::stringify; let encoded = stringify(&[("hello", "你好"), ("world", "世界")]); assert_eq!(encoded, "hello=%E4%BD%A0%E5%A5%BD&world=%E4%B8%96%E7%95%8C");

UrlEncodedDataPairScanner: Lazy iterator yielding pairs only, performant when you only needs pairs in sequence.

example:

```rust use urlencodeddata::; let qs = "a=1&b=2&c=3&c=4&key_without_value&=value_without_key".to_string(); for s in [ qs.as_str(), ("https://abc.com/?".to_string() + qs.as_str()).as_str(), ("https://abc.com/?????".to_string() + qs.as_str()).as_str(), ] .iter() { let q = UrlEncodedDataPairScanner::from(s); println!("got qs: {}", q);

let pairs_expected_as_str = [
    ("a", "1"),
    ("b", "2"),
    ("c", "3"),
    ("c", "4"),
    ("key_without_value", ""),
    ("", "value_without_key"),
];


for (i, (k, v)) in q.iter().enumerate() {
    let (k_, v_) = pairs_expected_as_str[i];
    assert_eq!(k.as_ref(), k_);
    assert_eq!(v.as_ref(), v_);
}

} ```

UrlEncodedData: parse urlencodeddata to pairs eagerly

some methods:

for string: "a=1&b=2&a=3" * aspairs: ["a", "1"], ["b", "2"], ["c", "3"] * asmapofsinglekeytomultiplevalues: {"a": ["1", "3"], "b": ["2"]} * asmapofsinglekeytofirstoccurrencevalue: {"a": "1", "b": "2"} * asmapofsinglekeytolastoccurrencevalue: {"a": "3", "b": "2"}

get shortcuts note: for multiple get, use the result of map mehtods directly * getmultiplevalues: "a" -> vec!["1".tostring(), "3".tostring()] * getfirstoccurrencevalue: "a" -> "1".tostring() * getlastoccurrencevalue: "a" -> "3".tostring()

Typical usage might be:

```rust use urlencodeddata::*; use std::borrow::Cow; let s = "a=1&b=2&a=3"; let ued = UrlEncodedData::from(s);

// get pairs let pairs = ued.as_pairs();

// 1:N let mapn = ued.asmapofsinglekeytomultiplevalues(); let a = mapn.get(&Cow::from("a")).unwrap(); asserteq!(a[0].asref(), "1"); asserteq!(a[1].as_ref(), "3");

// 1:first-value-met let mapf = ued.asmapofsinglekeytofirstoccurrencevalue(); let a = mapf.get(&Cow::from("a")).unwrap(); asserteq!(a.asref(), "1");

// 1:last-value-met let mapl = ued.asmapofsinglekeytolastoccurrencevalue(); let a = mapl.get(&Cow::from("a")).unwrap(); asserteq!(a.asref(), "3");

```

One time get(For best performance of multiple callings, use the result of method calling of asmap) ```rust use url_encoded_data::; use std::borrow::Cow; let s = "a=1&b=2&a=3"; let ued = UrlEncodedData::from(s);

asserteq!(ued.getmultiplevalues("a").unwrap().iter().map(|x| x.asref()).collect::>(), vec!["1", "3"]);

// get first occurrence value asserteq!(ued.getfirstoccurrencevalue("a").unwrap().as_ref(), "1");

// get last occurrence value asserteq!(ued.getlastoccurrencevalue("a").unwrap().as_ref(), "3");

// no existed key assert!(ued.getlastoccurrencevalue("not-existed-key").isnone()); ```

full example

```rust

[macro_use]

extern crate maplit; use urlencodeddata::*;

fn main() { use std::borrow::Cow; use urlencodeddata::UrlEncodedData; let qs = "a=1&b=2&c=3&c=4&keywithoutvalue&=valuewithoutkey".tostring(); for s in [ qs.asstr(), ("https://abc.com/?".tostring() + qs.asstr()).asstr(), ("https://abc.com/?????".tostring() + qs.asstr()).asstr(), ] .iter() { let q = UrlEncodedData::parsestr(s); // let mut q = UrlEncodedData::prepare(url1); // let q = q.parse(); println!("got qs: {}", q);

    let pairs_expected_as_str = [
        ("a", "1"),
        ("b", "2"),
        ("c", "3"),
        ("c", "4"),
        ("key_without_value", ""),
        ("", "value_without_key"),
    ];

    for (i, (k, v)) in q.as_pairs_of_original_order().iter().enumerate() {
        let (k_, v_) = pairs_expected_as_str[i];
        assert_eq!(k.as_ref(), k_);
        assert_eq!(v.as_ref(), v_);
    }

    //
    let map_of_multiple_values_expected = hashmap! {
        "a"=>vec!("1"),
        "b"=>vec!("2"),
        "c"=>vec!("3", "4"),
        "key_without_value" => vec!(""),
        "" => vec!("value_without_key"),
    };
    dbg!("as_map_of_single_key_to_multiple_values");
    println!("as_map_of_single_key_to_multiple_values");
    let map = q.as_map_of_single_key_to_multiple_values();
    assert_eq!(map.len(), 5);

    for (k1, v1) in map {
        let v2 = map_of_multiple_values_expected.get(k1.as_ref()).unwrap();
        for (i, v2i) in v2.into_iter().enumerate() {
            assert_eq!(v1[i].to_string(), v2i.to_string());
        }
    }

    //
    let map_of_first_occurrence_value_expected = hashmap! {
        "a"=>"1",
        "b"=>"2",
        "c"=>"3",
        "key_without_value" => "",
        "" => "value_without_key",
    };
    dbg!("as_map_of_single_key_to_first_occurrence_value");
    let map = q.as_map_of_single_key_to_first_occurrence_value();
    assert_eq!(map.len(), 5);
    for (k1, v1) in map {
        let v2 = map_of_first_occurrence_value_expected
            .get(k1.as_ref())
            .unwrap();
        // let v3 = &v1;
        assert_eq!(&v1, v2); // ok, signifies comparing with references, it will auto-dereference to compare the value, which is more convenient
        let ptr1 = v1 as *const Cow<'_, str> as *const usize;
        let ptr2 = v2 as *const &str as *const usize;
        let msg = format!("{:p}, {:p}", ptr1, ptr2);
        dbg!(msg);
        println!("{:p}, {:p}", ptr1, ptr2);
        assert!(!std::ptr::eq(ptr1, ptr2));
        assert_eq!(*v1, **v2); // ok, value compare
    }

    //
    let map_of_last_occurrence_value_expected = hashmap! {
        "a"=>"1",
        "b"=>"2",
        "c"=>"4",
        "key_without_value" => "",
        "" => "value_without_key",
    };
    dbg!("as_map_of_single_key_to_last_occurrence_value");
    let map = q.as_map_of_single_key_to_last_occurrence_value();
    assert_eq!(map.len(), 5);

    for (k1, v1) in map {
        let v2 = map_of_last_occurrence_value_expected
            .get(k1.as_ref())
            .unwrap();
        assert_eq!(&v1, v2);
    }
}

} ```