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}