base64_simd/
heap.rs

1use crate::decode::decoded_length;
2use crate::encode::encoded_length_unchecked;
3use crate::{AppendBase64Decode, AppendBase64Encode};
4use crate::{Base64, Error};
5use crate::{FromBase64Decode, FromBase64Encode};
6
7use vsimd::tools::{alloc_uninit_bytes, assume_init, boxed_str, slice_parts};
8
9use alloc::boxed::Box;
10use alloc::string::String;
11use alloc::vec::Vec;
12
13#[inline]
14fn encode_to_boxed_str(base64: &Base64, data: &[u8]) -> Box<str> {
15    if data.is_empty() {
16        return Box::from("");
17    }
18
19    unsafe {
20        let m = encoded_length_unchecked(data.len(), base64.config);
21        assert!(m <= usize::MAX / 2);
22
23        let mut buf = alloc_uninit_bytes(m);
24
25        {
26            let (src, len) = slice_parts(data);
27            let dst: *mut u8 = buf.as_mut_ptr().cast();
28            crate::multiversion::encode::auto(src, len, dst, base64.config);
29        }
30
31        boxed_str(assume_init(buf))
32    }
33}
34
35#[inline]
36fn encode_append_vec(base64: &Base64, src: &[u8], buf: &mut Vec<u8>) {
37    if src.is_empty() {
38        return;
39    }
40
41    unsafe {
42        let m = encoded_length_unchecked(src.len(), base64.config);
43        assert!(m <= usize::MAX / 2);
44
45        buf.reserve_exact(m);
46        let prev_len = buf.len();
47
48        {
49            let (src, len) = slice_parts(src);
50            let dst = buf.as_mut_ptr().add(prev_len);
51            crate::multiversion::encode::auto(src, len, dst, base64.config);
52        }
53
54        buf.set_len(prev_len + m);
55    }
56}
57
58#[inline]
59fn decode_to_boxed_bytes(base64: &Base64, data: &[u8]) -> Result<Box<[u8]>, Error> {
60    if data.is_empty() {
61        return Ok(Box::from([]));
62    }
63
64    unsafe {
65        let (n, m) = decoded_length(data, base64.config)?;
66
67        // safety: 0 < m < isize::MAX
68        let mut buf = alloc_uninit_bytes(m);
69
70        {
71            let dst = buf.as_mut_ptr().cast();
72            let src = data.as_ptr();
73            crate::multiversion::decode::auto(src, dst, n, base64.config)?;
74        }
75
76        Ok(assume_init(buf))
77    }
78}
79
80#[inline]
81fn decode_append_vec(base64: &Base64, src: &[u8], buf: &mut Vec<u8>) -> Result<(), Error> {
82    if src.is_empty() {
83        return Ok(());
84    }
85
86    unsafe {
87        let (n, m) = decoded_length(src, base64.config)?;
88
89        buf.reserve_exact(m);
90        let prev_len = buf.len();
91
92        let dst = buf.as_mut_ptr().add(prev_len);
93        let src = src.as_ptr();
94        crate::multiversion::decode::auto(src, dst, n, base64.config)?;
95
96        buf.set_len(prev_len + m);
97        Ok(())
98    }
99}
100
101#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
102impl FromBase64Decode for Box<[u8]> {
103    #[inline]
104    fn from_base64_decode(base64: &Base64, data: &[u8]) -> Result<Self, Error> {
105        decode_to_boxed_bytes(base64, data)
106    }
107}
108
109#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
110impl FromBase64Decode for Vec<u8> {
111    #[inline]
112    fn from_base64_decode(base64: &Base64, data: &[u8]) -> Result<Self, crate::Error> {
113        let ans = decode_to_boxed_bytes(base64, data)?;
114        Ok(Vec::from(ans))
115    }
116}
117
118#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
119impl FromBase64Encode for Box<[u8]> {
120    #[inline]
121    fn from_base64_encode(base64: &Base64, data: &[u8]) -> Self {
122        let ans = encode_to_boxed_str(base64, data);
123        ans.into_boxed_bytes()
124    }
125}
126
127#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
128impl FromBase64Encode for Box<str> {
129    #[inline]
130    fn from_base64_encode(base64: &Base64, data: &[u8]) -> Self {
131        encode_to_boxed_str(base64, data)
132    }
133}
134
135#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
136impl FromBase64Encode for Vec<u8> {
137    #[inline]
138    fn from_base64_encode(base64: &Base64, data: &[u8]) -> Self {
139        let ans = encode_to_boxed_str(base64, data);
140        Vec::from(ans.into_boxed_bytes())
141    }
142}
143
144#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
145impl FromBase64Encode for String {
146    #[inline]
147    fn from_base64_encode(base64: &Base64, data: &[u8]) -> Self {
148        let ans = encode_to_boxed_str(base64, data);
149        String::from(ans)
150    }
151}
152
153#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
154impl AppendBase64Encode for Vec<u8> {
155    #[inline]
156    fn append_base64_encode(base64: &Base64, src: &[u8], dst: &mut Self) {
157        encode_append_vec(base64, src, dst);
158    }
159}
160
161#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
162impl AppendBase64Encode for String {
163    #[inline]
164    fn append_base64_encode(base64: &Base64, src: &[u8], dst: &mut Self) {
165        unsafe { encode_append_vec(base64, src, dst.as_mut_vec()) };
166    }
167}
168
169#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
170impl AppendBase64Decode for Vec<u8> {
171    #[inline]
172    fn append_base64_decode(base64: &Base64, src: &[u8], dst: &mut Self) -> Result<(), Error> {
173        decode_append_vec(base64, src, dst)
174    }
175}