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
use core::str::Utf8Error;
use std::borrow::Cow;
use std::fmt;
use std::path::Path;
use crate::utils::{self, convert_to_str};
use percent_encoding::{
percent_decode_str, utf8_percent_encode, AsciiSet, CONTROLS
};
use snafu::{ResultExt, Snafu};
pub const ASCII_SET: &'static AsciiSet = &CONTROLS
.add(b' ')
.add(b'<')
.add(b'>')
.add(b'#')
.add(b'%')
.add(b'"')
.add(b'{')
.add(b'}')
.add(b'|')
.add(b'\\')
.add(b'^')
.add(b'[')
.add(b']')
.add(b'`');
#[derive(Debug, Snafu)]
pub enum Error {
#[snafu(display(
"The decoded form of the string `{}` was not well formed in utf-8",
s,
))]
Decode { s: String, source: Utf8Error },
#[snafu(display("Failed to convert path to a string to be able to percent encode it"))]
ConvertPathDecode { source: utils::Error },
}
type Result<T, E = Error> = ::std::result::Result<T, E>;
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct PercentPath(String);
impl PercentPath {
pub(crate) fn from_path(path: impl AsRef<Path>) -> Result<Self> {
let path = path.as_ref();
let s = convert_to_str(path).context(ConvertPathDecode)?;
Ok(Self(utf8_percent_encode(s, ASCII_SET).to_string()))
}
pub(crate) fn from_str(s: &str) -> Self {
Self(utf8_percent_encode(s, ASCII_SET).to_string())
}
pub fn encoded(&self) -> &str {
&self.0
}
pub fn decoded(&self) -> Result<Cow<'_, str>> {
percent_decode_str(&self.0)
.decode_utf8()
.context(Decode { s: &self.0 })
}
}
impl fmt::Display for PercentPath {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}