forked from helix-editor/helix
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuri.rs
125 lines (109 loc) · 3.04 KB
/
uri.rs
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
125
use std::{
fmt,
path::{Path, PathBuf},
sync::Arc,
};
/// A generic pointer to a file location.
///
/// Currently this type only supports paths to local files.
///
/// Cloning this type is cheap: the internal representation uses an Arc.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[non_exhaustive]
pub enum Uri {
File(Arc<Path>),
}
impl Uri {
// This clippy allow mirrors url::Url::from_file_path
#[allow(clippy::result_unit_err)]
pub fn to_url(&self) -> Result<url::Url, ()> {
match self {
Uri::File(path) => url::Url::from_file_path(path),
}
}
pub fn as_path(&self) -> Option<&Path> {
match self {
Self::File(path) => Some(path),
}
}
}
impl From<PathBuf> for Uri {
fn from(path: PathBuf) -> Self {
Self::File(path.into())
}
}
impl fmt::Display for Uri {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::File(path) => write!(f, "{}", path.display()),
}
}
}
#[derive(Debug)]
pub struct UrlConversionError {
source: url::Url,
kind: UrlConversionErrorKind,
}
#[derive(Debug)]
pub enum UrlConversionErrorKind {
UnsupportedScheme,
UnableToConvert,
}
impl fmt::Display for UrlConversionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.kind {
UrlConversionErrorKind::UnsupportedScheme => {
write!(
f,
"unsupported scheme '{}' in URL {}",
self.source.scheme(),
self.source
)
}
UrlConversionErrorKind::UnableToConvert => {
write!(f, "unable to convert URL to file path: {}", self.source)
}
}
}
}
impl std::error::Error for UrlConversionError {}
fn convert_url_to_uri(url: &url::Url) -> Result<Uri, UrlConversionErrorKind> {
if url.scheme() == "file" {
url.to_file_path()
.map(|path| Uri::File(helix_stdx::path::normalize(path).into()))
.map_err(|_| UrlConversionErrorKind::UnableToConvert)
} else {
Err(UrlConversionErrorKind::UnsupportedScheme)
}
}
impl TryFrom<url::Url> for Uri {
type Error = UrlConversionError;
fn try_from(url: url::Url) -> Result<Self, Self::Error> {
convert_url_to_uri(&url).map_err(|kind| Self::Error { source: url, kind })
}
}
impl TryFrom<&url::Url> for Uri {
type Error = UrlConversionError;
fn try_from(url: &url::Url) -> Result<Self, Self::Error> {
convert_url_to_uri(url).map_err(|kind| Self::Error {
source: url.clone(),
kind,
})
}
}
#[cfg(test)]
mod test {
use super::*;
use url::Url;
#[test]
fn unknown_scheme() {
let url = Url::parse("csharp:/metadata/foo/bar/Baz.cs").unwrap();
assert!(matches!(
Uri::try_from(url),
Err(UrlConversionError {
kind: UrlConversionErrorKind::UnsupportedScheme,
..
})
));
}
}