base64_url/
escape.rs

1use alloc::{borrow::Cow, string::String, vec::Vec};
2use core::str::from_utf8_unchecked;
3
4/// Escape a Base64 string to a Base64-URL string. The conversion is not concerning with Base64 decoding. You need to make sure the input string is a correct Base64 string by yourself.
5#[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/// Escape Base64 data to Base64-URL data. The conversion is not concerning with Base64 decoding. You need to make sure the input Base64 data is correct by yourself.
24#[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/// In-place escape a Base64 string to a Base64-URL string. The conversion is not concerning with Base64 decoding. You need to make sure the input string is a correct Base64 string by yourself.
97#[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/// In-place escape Base64 data to Base64-URL data. The conversion is not concerning with Base64 decoding. You need to make sure the input Base64 data is correct by yourself.
107#[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/// In-place escape Base64 data to Base64-URL data. The conversion is not concerning with Base64 decoding. You need to make sure the input Base64 data is correct by yourself.
119#[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/// Escape a Base64 string to a Base64-URL string. It is unsafe because the conversion is not concerning with Base64 decoding. You need to make sure the input string is a correct Base64 string by yourself.
142#[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/// In-place escape a Base64 string to a Base64-URL string. It is unsafe because the conversion is not concerning with Base64 decoding. You need to make sure the input string is a correct Base64 string by yourself.
153#[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/// In-place escape Base64 data to Base64-URL data. It is unsafe because the conversion is not concerning with Base64 decoding. You need to make sure the input Base64 data is correct by yourself.
160#[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/// In-place escape Base64 data to Base64-URL data. It is unsafe because the conversion is not concerning with Base64 decoding. You need to make sure the input Base64 data is correct by yourself.
167#[inline]
168pub fn unsafe_escape_u8_slice<S: ?Sized + AsMut<[u8]>>(base64: &mut S) -> &[u8] {
169    escape_u8_slice_in_place(base64)
170}