1use core::fmt::{self, Display};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub struct Url<'a> {
5 pub scheme: &'a str,
6 pub host: &'a str,
7 pub path: &'a str,
8}
9
10impl<'a> Url<'a> {
11 pub fn parse(url: &'a str) -> Option<Self> {
12 let scheme_end = url.find("://")?;
13 let scheme = &url[..scheme_end];
14
15 let host_start = scheme_end + 3;
16 let path_start = url[host_start..]
17 .find('/')
18 .map_or(url.len(), |i| host_start + i);
19 let host = &url[host_start..path_start];
20
21 let path = if path_start < url.len() {
22 &url[path_start..]
23 } else {
24 "/"
25 };
26
27 Some(Url { scheme, host, path })
28 }
29}
30
31impl Display for Url<'_> {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
33 write!(f, "{}://{}{}", self.scheme, self.host, self.path)
34 }
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40
41 #[test]
42 fn test_url_parsing() {
43 let url_str = "https://example.com/path/to/resource";
44 let url = Url::parse(url_str).unwrap();
45 assert_eq!(url.scheme, "https");
46 assert_eq!(url.host, "example.com");
47 assert_eq!(url.path, "/path/to/resource");
48 }
49 #[test]
50 fn test_url_parsing_no_path() {
51 let url_str = "http://example.com";
52 let url = Url::parse(url_str).unwrap();
53 assert_eq!(url.scheme, "http");
54 assert_eq!(url.host, "example.com");
55 assert_eq!(url.path, "/");
56 }
57}