1use crate::urlencode::BASE_SET;
12use aws_smithy_types::date_time::{DateTimeFormatError, Format};
13use aws_smithy_types::DateTime;
14use percent_encoding::utf8_percent_encode;
15
16pub fn fmt_string<T: AsRef<str>>(t: T) -> String {
18    utf8_percent_encode(t.as_ref(), BASE_SET).to_string()
19}
20
21pub fn fmt_timestamp(t: &DateTime, format: Format) -> Result<String, DateTimeFormatError> {
23    Ok(fmt_string(t.fmt(format)?))
24}
25
26#[allow(missing_debug_implementations)]
37pub struct Writer<'a> {
38    out: &'a mut String,
39    prefix: char,
40}
41
42impl<'a> Writer<'a> {
43    pub fn new(out: &'a mut String) -> Self {
45        Writer { out, prefix: '?' }
46    }
47
48    pub fn push_kv(&mut self, k: &str, v: &str) {
50        self.out.push(self.prefix);
51        self.out.push_str(k);
52        self.out.push('=');
53        self.out.push_str(v);
54        self.prefix = '&';
55    }
56
57    pub fn push_v(&mut self, v: &str) {
59        self.out.push(self.prefix);
60        self.out.push_str(v);
61        self.prefix = '&';
62    }
63}
64
65#[cfg(test)]
66mod test {
67    use crate::query::{fmt_string, Writer};
68    use http_02x::Uri;
69    use proptest::proptest;
70
71    #[test]
72    fn url_encode() {
73        assert_eq!(fmt_string("y̆").as_str(), "y%CC%86");
74        assert_eq!(fmt_string(" ").as_str(), "%20");
75        assert_eq!(fmt_string("foo/baz%20").as_str(), "foo%2Fbaz%2520");
76        assert_eq!(fmt_string("&=").as_str(), "%26%3D");
77        assert_eq!(fmt_string("🐱").as_str(), "%F0%9F%90%B1");
78        assert_eq!(fmt_string("a:b"), "a%3Ab")
80    }
81
82    #[test]
83    fn writer_sets_prefix_properly() {
84        let mut out = String::new();
85        let mut writer = Writer::new(&mut out);
86        writer.push_v("a");
87        writer.push_kv("b", "c");
88        assert_eq!(out, "?a&b=c");
89    }
90
91    proptest! {
92        #[test]
93        fn test_encode_request(s: String) {
94            let _: Uri = format!("http://host.example.com/?{}", fmt_string(s)).parse().expect("all strings should be encoded properly");
95        }
96    }
97}