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
#![forbid(unsafe_code)]
#![deny(rust_2018_idioms)]
use std::{
convert::TryFrom,
fmt::{self, Write},
};
use bstr::ByteSlice;
pub mod parse;
#[doc(inline)]
pub use parse::parse;
pub mod expand_path;
#[doc(inline)]
pub use expand_path::expand_path;
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
pub enum Scheme {
File,
Git,
Ssh,
Http,
Https,
Radicle,
}
impl fmt::Display for Scheme {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Scheme::*;
f.write_str(match self {
File => "file",
Git => "git",
Ssh => "ssh",
Http => "http",
Https => "https",
Radicle => "rad",
})
}
}
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
pub struct Url {
pub scheme: Scheme,
pub user: Option<String>,
pub host: Option<String>,
pub port: Option<u16>,
pub path: bstr::BString,
}
impl Default for Url {
fn default() -> Self {
Url {
scheme: Scheme::Ssh,
user: None,
host: None,
port: None,
path: bstr::BString::default(),
}
}
}
impl fmt::Display for Url {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.scheme.fmt(f)?;
f.write_str("://")?;
match (&self.user, &self.host) {
(Some(user), Some(host)) => f.write_fmt(format_args!("{}@{}", user, host)),
(None, Some(host)) => f.write_str(host),
(None, None) => Ok(()),
_ => return Err(fmt::Error),
}?;
if let Some(port) = &self.port {
f.write_char(':')?;
f.write_fmt(format_args!("{}", port))?;
}
f.write_str(self.path.to_str_lossy().as_ref())
}
}
impl Url {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, parse::Error> {
parse(bytes)
}
}
impl TryFrom<&[u8]> for Url {
type Error = parse::Error;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
Self::from_bytes(value)
}
}
impl<'a> TryFrom<std::borrow::Cow<'a, [u8]>> for Url {
type Error = parse::Error;
fn try_from(value: std::borrow::Cow<'a, [u8]>) -> Result<Self, Self::Error> {
Self::try_from(&*value)
}
}