1use alloc::string::String;
2
3use url::{Position, Url};
4
5use crate::ToQRText;
6
7fn is_special_scheme(scheme: &str) -> bool {
9 matches!(scheme, "ftp" | "file" | "http" | "https" | "ws" | "wss")
10}
11
12fn uppercase_percent_escapes(text: &str) -> String {
13 let bytes = text.as_bytes();
14 let mut normalized = String::with_capacity(text.len());
15 let mut copied = 0;
16 let mut index = 0;
17
18 while index + 2 < bytes.len() {
20 if bytes[index] == b'%'
21 && bytes[index + 1].is_ascii_hexdigit()
22 && bytes[index + 2].is_ascii_hexdigit()
23 {
24 normalized.push_str(&text[copied..index]);
25 normalized.push('%');
26 normalized.push(char::from(bytes[index + 1].to_ascii_uppercase()));
27 normalized.push(char::from(bytes[index + 2].to_ascii_uppercase()));
28
29 index += 3;
30 copied = index;
31 } else {
32 index += 1;
33 }
34 }
35
36 normalized.push_str(&text[copied..]);
37 normalized
38}
39
40impl ToQRText for Url {
41 fn to_qr_text(&self) -> String {
42 let serialized = self.as_str();
43 let scheme_end = self[..Position::AfterScheme].len();
44 let path_start = self[..Position::BeforePath].len();
45 let path_end = self[..Position::AfterPath].len();
46 let omit_root_path = matches!(self.scheme(), "http" | "https") && self.path() == "/";
47 let mut normalized = String::with_capacity(serialized.len());
48
49 normalized.push_str(&serialized[..scheme_end].to_ascii_uppercase());
50
51 if self.has_host() {
53 let host_start = self[..Position::BeforeHost].len();
54 let host_end = self[..Position::AfterHost].len();
55 let host = &serialized[host_start..host_end];
56
57 normalized.push_str(&serialized[scheme_end..host_start]);
58
59 if is_special_scheme(self.scheme()) {
61 normalized.push_str(&host.to_ascii_uppercase());
62 } else {
63 normalized.push_str(host);
64 }
65
66 normalized.push_str(&serialized[host_end..path_start]);
67 } else {
68 normalized.push_str(&serialized[scheme_end..path_start]);
69 }
70
71 if !omit_root_path {
72 normalized.push_str(&serialized[path_start..path_end]);
73 }
74
75 normalized.push_str(&serialized[path_end..]);
76 uppercase_percent_escapes(&normalized)
77 }
78}