1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#[cfg(test)]mod test;
struct Visitor<T>(std::marker::PhantomData<T>);
impl<T> Visitor<T> {
fn new() -> Self {
Visitor(std::marker::PhantomData)
}
}
impl<'a, T: FromPercentDecode> serde::de::Visitor<'a> for Visitor<T> {
type Value = T;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "a sequence of bytes")
}
fn visit_borrowed_str<E: serde::de::Error>(self, v: &'a str) -> Result<Self::Value, E> {
let decoded = percent_encoding::percent_decode(v.as_bytes());
FromPercentDecode::from(decoded)
}
}
pub trait FromPercentDecode: Sized {
fn from<E: serde::de::Error>(pd: percent_encoding::PercentDecode) -> Result<Self, E>;
}
impl FromPercentDecode for Vec<u8> {
fn from<E: serde::de::Error>(pd: percent_encoding::PercentDecode) -> Result<Self, E> {
Ok(pd.collect())
}
}
impl FromPercentDecode for String {
fn from<E: serde::de::Error>(pd: percent_encoding::PercentDecode) -> Result<Self, E> {
pd.decode_utf8()
.map(|cow| cow.into_owned())
.map_err(E::custom)
}
}
fn deserialize<'d, T: FromPercentDecode, D: serde::Deserializer<'d>>(
de: D,
) -> Result<T, D::Error> {
de.deserialize_str(Visitor::new())
}
fn serialize<S: serde::Serializer>(
data: impl AsRef<[u8]>,
ser: S,
encoding_set: &'static percent_encoding::AsciiSet,
) -> Result<S::Ok, S::Error> {
let encoded = percent_encoding::percent_encode(data.as_ref(), encoding_set)
.collect::<String>();
ser.serialize_str(&encoded)
}
macro_rules! version {
($name:ident, $set:path) => {
pub mod $name {
pub fn deserialize<'d, T: crate::FromPercentDecode, D: serde::Deserializer<'d>>(
de: D,
) -> Result<T, D::Error> {
crate::deserialize(de)
}
pub fn serialize<S: serde::Serializer>(
data: impl AsRef<[u8]>,
ser: S,
) -> Result<S::Ok, S::Error> {
crate::serialize(data, ser, &$set)
}
}
}
}
const QUERY_ENCODE_SET: percent_encoding::AsciiSet = percent_encoding::CONTROLS.add(b' ').add(b'"').add(b'#').add(b'<').add(b'>');
const DEFAULT_ENCODE_SET: percent_encoding::AsciiSet = QUERY_ENCODE_SET.add(b'`').add(b'?').add(b'{').add(b'}');
const PATH_SEGMENT_ENCODE_SET: percent_encoding::AsciiSet = DEFAULT_ENCODE_SET.add(b'%').add(b'/');
const USERINFO_ENCODE_SET: percent_encoding::AsciiSet = DEFAULT_ENCODE_SET.add(b'/').add(b':').add(b';').add(b'=').add(b'@').add(b'[').add(b'\\').add(b']').add(b'^').add(b'|');
version!(default, crate::DEFAULT_ENCODE_SET);
version!(path_segment, crate::PATH_SEGMENT_ENCODE_SET);
version!(query, crate::QUERY_ENCODE_SET);
version!(simple, percent_encoding::CONTROLS);
version!(userinfo, crate::USERINFO_ENCODE_SET);