1use alloc::{
4 string::{FromUtf8Error, String},
5 vec,
6 vec::Vec,
7};
8
9use crate::{
10 encoding::{Encoding, Kind, same_encoding},
11 simd::{NARROW, TRANS_WIDE, ascii_run},
12 unit::{Unit, fold_case_scalar},
13 utf8::Utf8,
14};
15
16pub trait TextBuf: Sized {
22 type Unit: Unit;
25
26 fn from_units(units: Vec<Self::Unit>) -> Self;
31}
32
33impl TextBuf for String {
34 type Unit = u8;
35
36 #[inline]
37 fn from_units(units: Vec<u8>) -> Self {
38 match Self::from_utf8(units) {
39 Ok(s) => s,
40 Err(e) => Self::from_utf8_lossy(&e.into_bytes()).into_owned(),
41 }
42 }
43}
44
45impl TextBuf for Vec<u8> {
46 type Unit = u8;
47
48 #[inline]
49 fn from_units(units: Self) -> Self {
50 units
51 }
52}
53
54impl TextBuf for Vec<u16> {
55 type Unit = u16;
56
57 #[inline]
58 fn from_units(units: Self) -> Self {
59 units
60 }
61}
62
63impl TextBuf for Vec<u32> {
64 type Unit = u32;
65
66 #[inline]
67 fn from_units(units: Self) -> Self {
68 units
69 }
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub enum AsciiCase {
75 Preserve,
77 Lower,
79 Upper,
81}
82
83impl AsciiCase {
84 #[inline(always)]
86 const fn base(self) -> u32 {
87 match self {
88 Self::Preserve => u32::MAX,
92 Self::Lower => 'A' as u32,
93 Self::Upper => 'a' as u32,
94 }
95 }
96}
97
98#[inline(always)]
100fn bridge<F: Unit, T: Unit>(u: F) -> T {
101 T::from_u32(u.to_u32())
102}
103
104#[inline]
115pub fn transcode_into<F: Encoding, T: Encoding>(
116 src: &[F::Unit],
117 dst: &mut [T::Unit],
118 case: AsciiCase,
119) -> (usize, usize) {
120 let same = const { same_encoding::<F, T>() };
121 if same && case == AsciiCase::Preserve {
122 let n = src.len().min(dst.len());
123 for (d, s) in dst[..n].iter_mut().zip(&src[..n]) {
124 *d = bridge(*s);
125 }
126 return (n, n);
127 }
128
129 if case == AsciiCase::Preserve
130 && let Some(result) = crate::native::transcode::<F, T>(src, dst)
131 {
132 return result;
133 }
134
135 let simd_ok = const { !F::FOREIGN && !T::FOREIGN };
138 let fold = case != AsciiCase::Preserve;
139 let base = case.base();
140
141 let mut i = 0;
142 let mut o = 0;
143 while i < src.len() {
144 if simd_ok {
145 let limit = (src.len() - i).min(dst.len() - o);
146 let n = if limit >= TRANS_WIDE {
147 ascii_run::<F::Unit, TRANS_WIDE>(&src[i..], limit, |v, at| {
148 let mut w = F::Unit::cast::<T::Unit, TRANS_WIDE>(v);
149 if fold {
150 w = T::Unit::fold_case(w, base);
151 }
152 w.copy_to_slice(&mut dst[o + at..o + at + TRANS_WIDE]);
153 })
154 } else if limit >= NARROW {
155 ascii_run::<F::Unit, NARROW>(&src[i..], limit, |v, at| {
156 let mut w = F::Unit::cast::<T::Unit, NARROW>(v);
157 if fold {
158 w = T::Unit::fold_case(w, base);
159 }
160 w.copy_to_slice(&mut dst[o + at..o + at + NARROW]);
161 })
162 } else {
163 0
164 };
165 i += n;
166 o += n;
167 if i == src.len() {
168 break;
169 }
170 }
171
172 if same {
173 let front = src[i];
176 let len = F::run_length(front).min(src.len() - i);
179 if dst.len() - o < len {
180 break;
181 }
182 let mut lead = front.to_u32();
183 if fold {
184 let native = if F::FOREIGN {
185 front.swap_bytes().to_u32()
186 } else {
187 lead
188 };
189 if native.wrapping_sub(base) <= 25 {
190 let folded = F::Unit::from_u32(native ^ 0x20);
191 lead = if F::FOREIGN {
192 folded.swap_bytes().to_u32()
193 } else {
194 folded.to_u32()
195 };
196 }
197 }
198 dst[o] = T::Unit::from_u32(lead);
199 for k in 1..len {
200 dst[o + k] = bridge(src[i + k]);
201 }
202 i += len;
203 o += len;
204 } else {
205 let mut cur = &src[i..];
206 let mut cp = F::decode(&mut cur);
207 let consumed = src.len() - i - cur.len();
208 if fold {
209 cp = fold_case_scalar(cp, base);
210 }
211 if dst.len() - o < T::encoded_length(cp) {
212 break; }
214 o += T::encode(cp, &mut dst[o..]);
215 i += consumed;
216 }
217 }
218 (i, o)
219}
220
221#[inline]
223pub fn transcode<F: Encoding, T: Encoding>(src: &[F::Unit]) -> Vec<T::Unit> {
224 transcode_with_case::<F, T>(src, AsciiCase::Preserve)
225}
226
227pub fn transcode_with_case<F: Encoding, T: Encoding>(
229 src: &[F::Unit],
230 case: AsciiCase,
231) -> Vec<T::Unit> {
232 let mut out = vec![T::Unit::default(); src.len() * T::MAX_UNITS];
233 let (read, written) = transcode_into::<F, T>(src, &mut out, case);
234 debug_assert_eq!(read, src.len());
235 out.truncate(written);
236 out
237}
238
239pub fn transcoded_len<F: Encoding, T: Encoding>(src: &[F::Unit]) -> usize {
241 let unit_preserving = const {
246 size_of::<F::Unit>() == size_of::<T::Unit>()
247 && (same_encoding::<F, T>() || F::KIND as u8 != Kind::Utf16 as u8)
248 };
249 if unit_preserving {
250 return src.len();
251 }
252 let simd_ok = const { !F::FOREIGN };
253 let mut n = 0;
254 let mut i = 0;
255 while i < src.len() {
256 if simd_ok {
257 let limit = src.len() - i;
258 let c = if limit >= TRANS_WIDE {
259 ascii_run::<F::Unit, TRANS_WIDE>(&src[i..], limit, |_, _| {})
260 } else if limit >= NARROW {
261 ascii_run::<F::Unit, NARROW>(&src[i..], limit, |_, _| {})
262 } else {
263 0
264 };
265 i += c;
266 n += c;
267 if i == src.len() {
268 break;
269 }
270 }
271 let mut cur = &src[i..];
272 let cp = F::decode(&mut cur);
273 i = src.len() - cur.len();
274 n += T::encoded_length(cp);
275 }
276 n
277}
278
279pub fn to_string<F: Encoding>(src: &[F::Unit]) -> Result<String, FromUtf8Error> {
285 String::from_utf8(transcode::<F, Utf8>(src))
286}