1use alloc::{borrow::Cow, string::String, vec::Vec};
2use core::str::from_utf8_unchecked;
3
4#[inline]
6pub fn escape<S: ?Sized + AsRef<str>>(base64: &S) -> Cow<'_, str> {
7 let base64 = base64.as_ref();
8
9 match escape_u8_slice(base64) {
10 Cow::Owned(base64_url) => {
11 let base64_url = unsafe { String::from_utf8_unchecked(base64_url) };
12
13 Cow::from(base64_url)
14 },
15 Cow::Borrowed(base64_url) => {
16 let base64_url = unsafe { from_utf8_unchecked(base64_url) };
17
18 Cow::from(base64_url)
19 },
20 }
21}
22
23#[inline]
25pub fn escape_u8_slice<S: ?Sized + AsRef<[u8]>>(base64: &S) -> Cow<'_, [u8]> {
26 let base64 = base64.as_ref();
27
28 let length = base64.len();
29
30 let mut p = 0;
31
32 let first = loop {
33 if p == length {
34 return Cow::from(base64);
35 }
36
37 let e = base64[p];
38
39 match e {
40 43 => {
41 break 45;
42 },
43 47 => {
44 break 95;
45 },
46 61 => {
47 return Cow::from(&base64[..p]);
48 },
49 _ => (),
50 }
51
52 p += 1;
53 };
54
55 let mut base64_url = Vec::with_capacity(base64.len());
56
57 base64_url.extend_from_slice(&base64[..p]);
58 base64_url.push(first);
59
60 p += 1;
61
62 let mut start = p;
63
64 loop {
65 if p == length {
66 break;
67 }
68
69 let e = base64[p];
70
71 match e {
72 43 => {
73 base64_url.extend_from_slice(&base64[start..p]);
74 start = p + 1;
75
76 base64_url.push(45);
77 },
78 47 => {
79 base64_url.extend_from_slice(&base64[start..p]);
80 start = p + 1;
81
82 base64_url.push(95);
83 },
84 61 => break,
85 _ => (),
86 }
87
88 p += 1;
89 }
90
91 base64_url.extend_from_slice(&base64[start..p]);
92
93 Cow::from(base64_url)
94}
95
96#[inline]
98pub fn escape_in_place(base64: &mut String) -> &str {
99 let v = unsafe { base64.as_mut_vec() };
100
101 escape_vec_in_place(v);
102
103 base64.as_str()
104}
105
106#[inline]
108pub fn escape_vec_in_place(base64: &mut Vec<u8>) -> &[u8] {
109 let length = escape_u8_slice_in_place(base64.as_mut_slice()).len();
110
111 unsafe {
112 base64.set_len(length);
113 }
114
115 base64.as_slice()
116}
117
118#[inline]
120pub fn escape_u8_slice_in_place<S: ?Sized + AsMut<[u8]>>(base64: &mut S) -> &[u8] {
121 let base64 = base64.as_mut();
122
123 let mut len = base64.len();
124
125 for (index, n) in base64.iter_mut().enumerate() {
126 match *n {
127 43 => *n = 45,
128 47 => *n = 95,
129 61 => {
130 len = index;
131 break;
132 },
133 _ => (),
134 }
135 }
136
137 &base64[..len]
138}
139
140#[deprecated(since = "1.3.0", note = "Please use the `escape_in_place` function instead")]
141#[inline]
143pub fn unsafe_escape<S: Into<String>>(base64: S) -> String {
144 let mut base64 = base64.into();
145
146 escape_in_place(&mut base64);
147
148 base64
149}
150
151#[deprecated(since = "1.3.0", note = "Please use the `escape_in_place` function instead")]
152#[inline]
154pub fn unsafe_escape_string(base64: &mut String) {
155 escape_in_place(base64);
156}
157
158#[deprecated(since = "1.3.0", note = "Please use the `escape_vec_in_place` function instead")]
159#[inline]
161pub fn unsafe_escape_vec(base64: &mut Vec<u8>) {
162 escape_vec_in_place(base64);
163}
164
165#[deprecated(since = "1.3.0", note = "Please use the `escape_u8_slice_in_place` function instead")]
166#[inline]
168pub fn unsafe_escape_u8_slice<S: ?Sized + AsMut<[u8]>>(base64: &mut S) -> &[u8] {
169 escape_u8_slice_in_place(base64)
170}