Skip to main content

pct_str/encoder/
uri.rs

1use super::Encoder;
2
3/// URI-reserved characters encoder.
4///
5/// This [`Encoder`] encodes characters that are reserved in the syntax of URI
6/// according to [RFC 3986](https://tools.ietf.org/html/rfc3986).
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum UriReserved {
9	Any,
10	Path,
11	Query,
12	Fragment,
13}
14
15impl UriReserved {
16	fn is_reserved_but_safe(&self, c: char) -> bool {
17		match self {
18			Self::Any => false,
19			Self::Path => is_sub_delim(c) || c == '@',
20			Self::Query | Self::Fragment => is_sub_delim(c) || matches!(c, ':' | '@' | '/' | '?'),
21		}
22	}
23}
24
25impl Encoder for UriReserved {
26	fn encode(&self, c: char) -> bool {
27		!is_unreserved(c) && !self.is_reserved_but_safe(c)
28	}
29}
30
31fn is_sub_delim(c: char) -> bool {
32	matches!(
33		c,
34		'!' | '$' | '&' | '\'' | '(' | ')' | '*' | '+' | ',' | ';' | '='
35	)
36}
37
38fn is_unreserved(c: char) -> bool {
39	c.is_ascii_alphanumeric() || matches!(c, '-' | '.' | '_' | '~')
40}
41
42#[cfg(test)]
43mod tests {
44	use crate::PctString;
45
46	use super::UriReserved;
47
48	#[test]
49	fn uri_encode_cyrillic() {
50		let encoder = UriReserved::Any;
51		let pct_string = PctString::encode("традиционное польское блюдо\0".chars(), encoder);
52		assert_eq!(&pct_string, &"традиционное польское блюдо\0");
53		assert_eq!(
54			&pct_string.as_str(),
55			&"%D1%82%D1%80%D0%B0%D0%B4%D0%B8%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D0%BE%D0%B5%20%D0%BF%D0%BE%D0%BB%D1%8C%D1%81%D0%BA%D0%BE%D0%B5%20%D0%B1%D0%BB%D1%8E%D0%B4%D0%BE%00"
56		);
57	}
58}