url_prefix/lib.rs
1/*!
2# URL Prefix
3
4This crate can be used to create URL prefix strings by inputting a protocol, a domain, a port number and a path without additional parsing.
5
6## Why We Need This?
7
8Sometimes our web applications are run on different protocols(HTTP/HTTPS) and domains. And it is boring to write some code like below to format a URL:
9
10```rust,ignore
11let mut url_prefix = String::new();
12if is_https {
13 url_prefix.push_str("https://");
14} else {
15 url_prefix.push_str("http://");
16}
17url_prefix.push_str(domain);
18
19if is_https && port != 443 || !is_https && port != 80 {
20 url_prefix.push_str(":");
21 url_prefix.push_str(&port.to_string());
22}
23```
24
25Instead, we can easily use this crate to create URL prefix strings. For examples,
26
27```rust
28let prefix = url_prefix::create_prefix(url_prefix::Protocol::HTTPS, "magiclen.org", None, None::<String>);
29
30assert_eq!("https://magiclen.org", prefix);
31```
32
33```rust
34let prefix = url_prefix::create_prefix(url_prefix::Protocol::HTTPS, "magiclen.org", Some(8100), Some("url-prefix"));
35
36assert_eq!("https://magiclen.org:8100/url-prefix", prefix);
37```
38*/
39
40#![no_std]
41
42#[macro_use]
43extern crate alloc;
44
45use core::fmt::Write;
46
47use alloc::string::String;
48
49use cow_utils::CowUtils;
50
51macro_rules! impl_protocol {
52 ( $($protocol:ident, $name:expr, $port:expr); * $(;)* ) => {
53 /// A set of protocols for URLs.
54 #[allow(clippy::upper_case_acronyms)]
55 #[derive(Debug, Clone)]
56 pub enum Protocol {
57 $(
58 $protocol,
59 )+
60 /// Your own custom protocol created by giving a name and a default port number.
61 Custom(String, u16)
62 }
63
64 impl Protocol{
65 pub fn get_default_from_str<S: AsRef<str>>(s: S) -> Option<Self>{
66 let lowered_case = s.as_ref().cow_to_lowercase();
67
68 match lowered_case.as_ref() {
69 $(
70 $name => Some(Protocol::$protocol),
71 )+
72 _ => None
73 }
74 }
75
76 pub fn get_default_port(&self) -> u16 {
77 match self {
78 $(
79 Protocol::$protocol => $port,
80 )+
81 Protocol::Custom(_, port) => *port
82 }
83 }
84
85 pub fn get_name(&self) -> &str {
86 match self {
87 $(
88 Protocol::$protocol => $name,
89 )+
90 Protocol::Custom(name, _) => &name
91 }
92 }
93 }
94 };
95}
96
97impl_protocol! {
98 HTTP, "http", 80;
99 HTTPS, "https", 443;
100 FTP, "ftp", 21;
101 WS, "ws", 80;
102 WSS, "wss", 443;
103}
104
105/// Create a URL prefix string.
106pub fn create_prefix<S: AsRef<str>, P: AsRef<str>>(
107 protocol: Protocol,
108 domain: S,
109 port: Option<u16>,
110 path: Option<P>,
111) -> String {
112 let protocol_name = protocol.get_name();
113
114 let mut prefix = format!("{}://{}", protocol_name, domain.as_ref());
115
116 if let Some(port) = port {
117 let protocol_port = protocol.get_default_port();
118 if port != protocol_port {
119 prefix.write_fmt(format_args!(":{}", port)).unwrap();
120 }
121 }
122
123 if let Some(path) = path {
124 let path = path.as_ref();
125
126 slash_formatter::concat_with_slash_in_place(&mut prefix, path);
127 }
128
129 prefix
130}