1use core::fmt::{
2 self,
3 Write,
4};
5use core::num;
6
7use castaway::{
8 match_type,
9 LifetimeFree,
10};
11
12use super::repr::{
13 IntoRepr,
14 Repr,
15};
16use crate::CompactString;
17
18pub trait ToCompactString {
25 fn to_compact_string(&self) -> CompactString;
41}
42
43unsafe impl LifetimeFree for CompactString {}
49unsafe impl LifetimeFree for Repr {}
50
51impl<T: fmt::Display> ToCompactString for T {
69 #[inline]
70 fn to_compact_string(&self) -> CompactString {
71 let repr = match_type!(self, {
72 &u8 as s => s.into_repr(),
73 &i8 as s => s.into_repr(),
74 &u16 as s => s.into_repr(),
75 &i16 as s => s.into_repr(),
76 &u32 as s => s.into_repr(),
77 &i32 as s => s.into_repr(),
78 &u64 as s => s.into_repr(),
79 &i64 as s => s.into_repr(),
80 &u128 as s => s.into_repr(),
81 &i128 as s => s.into_repr(),
82 &usize as s => s.into_repr(),
83 &isize as s => s.into_repr(),
84 &f32 as s => s.into_repr(),
85 &f64 as s => s.into_repr(),
86 &bool as s => s.into_repr(),
87 &char as s => s.into_repr(),
88 &String as s => Repr::new(s),
89 &CompactString as s => Repr::new(s),
90 &num::NonZeroU8 as s => s.into_repr(),
91 &num::NonZeroI8 as s => s.into_repr(),
92 &num::NonZeroU16 as s => s.into_repr(),
93 &num::NonZeroI16 as s => s.into_repr(),
94 &num::NonZeroU32 as s => s.into_repr(),
95 &num::NonZeroI32 as s => s.into_repr(),
96 &num::NonZeroU64 as s => s.into_repr(),
97 &num::NonZeroI64 as s => s.into_repr(),
98 &num::NonZeroUsize as s => s.into_repr(),
99 &num::NonZeroIsize as s => s.into_repr(),
100 &num::NonZeroU128 as s => s.into_repr(),
101 &num::NonZeroI128 as s => s.into_repr(),
102 s => {
103 let mut c = CompactString::new_inline("");
104 write!(&mut c, "{}", s).expect("fmt::Display incorrectly implemented!");
105 return c;
106 }
107 });
108
109 CompactString(repr)
110 }
111}
112
113pub trait CompactStringExt {
135 fn concat_compact(&self) -> CompactString;
147
148 fn join_compact<S: AsRef<str>>(&self, seperator: S) -> CompactString;
161}
162
163impl<I, C> CompactStringExt for C
164where
165 I: AsRef<str>,
166 for<'a> &'a C: IntoIterator<Item = &'a I>,
167{
168 fn concat_compact(&self) -> CompactString {
169 self.into_iter()
170 .fold(CompactString::new_inline(""), |mut s, item| {
171 s.push_str(item.as_ref());
172 s
173 })
174 }
175
176 fn join_compact<S: AsRef<str>>(&self, seperator: S) -> CompactString {
177 let mut compact_string = CompactString::new_inline("");
178
179 let mut iter = self.into_iter().peekable();
180 let sep = seperator.as_ref();
181
182 while let Some(item) = iter.next() {
183 compact_string.push_str(item.as_ref());
184 if iter.peek().is_some() {
185 compact_string.push_str(sep);
186 }
187 }
188
189 compact_string
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use core::num;
196
197 use proptest::prelude::*;
198 use test_strategy::proptest;
199
200 use super::{
201 CompactStringExt,
202 ToCompactString,
203 };
204 use crate::CompactString;
205
206 #[test]
207 fn test_join() {
208 let slice = ["hello", "world"];
209 let c = slice.join_compact(" ");
210 assert_eq!(c, "hello world");
211
212 let vector = vec!["🍎", "🍊", "🍌"];
213 let c = vector.join_compact(",");
214 assert_eq!(c, "🍎,🍊,🍌");
215 }
216
217 #[proptest]
218 #[cfg_attr(miri, ignore)]
219 fn proptest_join(items: Vec<String>, seperator: String) {
220 let c: CompactString = items.join_compact(&seperator);
221 let s: String = items.join(&seperator);
222 assert_eq!(c, s);
223 }
224
225 #[test]
226 fn test_concat() {
227 let items = vec!["hello", "world"];
228 let c = items.join_compact(" ");
229 assert_eq!(c, "hello world");
230
231 let vector = vec!["🍎", "🍊", "🍌"];
232 let c = vector.concat_compact();
233 assert_eq!(c, "🍎🍊🍌");
234 }
235
236 #[proptest]
237 #[cfg_attr(miri, ignore)]
238 fn proptest_concat(items: Vec<String>) {
239 let c: CompactString = items.concat_compact();
240 let s: String = items.concat();
241 assert_eq!(c, s);
242 }
243
244 #[proptest]
245 #[cfg_attr(miri, ignore)]
246 fn proptest_to_compact_string_u8(val: u8) {
247 let compact = val.to_compact_string();
248 prop_assert_eq!(compact.as_str(), val.to_string());
249 }
250
251 #[proptest]
252 #[cfg_attr(miri, ignore)]
253 fn proptest_to_compact_string_i8(val: i8) {
254 let compact = val.to_compact_string();
255 prop_assert_eq!(compact.as_str(), val.to_string());
256 }
257
258 #[proptest]
259 #[cfg_attr(miri, ignore)]
260 fn proptest_to_compact_string_u16(val: u16) {
261 let compact = val.to_compact_string();
262 prop_assert_eq!(compact.as_str(), val.to_string());
263 }
264
265 #[proptest]
266 #[cfg_attr(miri, ignore)]
267 fn proptest_to_compact_string_i16(val: i16) {
268 let compact = val.to_compact_string();
269 prop_assert_eq!(compact.as_str(), val.to_string());
270 }
271 #[proptest]
272 #[cfg_attr(miri, ignore)]
273 fn proptest_to_compact_string_u32(val: u32) {
274 let compact = val.to_compact_string();
275 prop_assert_eq!(compact.as_str(), val.to_string());
276 }
277 #[proptest]
278 #[cfg_attr(miri, ignore)]
279 fn proptest_to_compact_string_i32(val: i32) {
280 let compact = val.to_compact_string();
281 prop_assert_eq!(compact.as_str(), val.to_string());
282 }
283 #[proptest]
284 #[cfg_attr(miri, ignore)]
285 fn proptest_to_compact_string_u64(val: u64) {
286 let compact = val.to_compact_string();
287 prop_assert_eq!(compact.as_str(), val.to_string());
288 }
289 #[proptest]
290 #[cfg_attr(miri, ignore)]
291 fn proptest_to_compact_string_i64(val: i64) {
292 let compact = val.to_compact_string();
293 prop_assert_eq!(compact.as_str(), val.to_string());
294 }
295 #[proptest]
296 #[cfg_attr(miri, ignore)]
297 fn proptest_to_compact_string_usize(val: usize) {
298 let compact = val.to_compact_string();
299 prop_assert_eq!(compact.as_str(), val.to_string());
300 }
301 #[proptest]
302 #[cfg_attr(miri, ignore)]
303 fn proptest_to_compact_string_isize(val: isize) {
304 let compact = val.to_compact_string();
305 prop_assert_eq!(compact.as_str(), val.to_string());
306 }
307 #[proptest]
308 #[cfg_attr(miri, ignore)]
309 fn proptest_to_compact_string_u128(val: u128) {
310 let compact = val.to_compact_string();
311 prop_assert_eq!(compact.as_str(), val.to_string());
312 }
313 #[proptest]
314 #[cfg_attr(miri, ignore)]
315 fn proptest_to_compact_string_i128(val: i128) {
316 let compact = val.to_compact_string();
317 prop_assert_eq!(compact.as_str(), val.to_string());
318 }
319
320 #[proptest]
321 #[cfg_attr(miri, ignore)]
322 fn proptest_to_compact_string_non_zero_u8(
323 #[strategy((1..=u8::MAX).prop_map(|x| unsafe { num::NonZeroU8::new_unchecked(x)} ))]
324 val: num::NonZeroU8,
325 ) {
326 let compact = val.to_compact_string();
327 prop_assert_eq!(compact.as_str(), val.to_string());
328 }
329
330 #[proptest]
331 #[cfg_attr(miri, ignore)]
332 fn proptest_to_compact_string_non_zero_u16(
333 #[strategy((1..=u16::MAX).prop_map(|x| unsafe { num::NonZeroU16::new_unchecked(x)} ))]
334 val: num::NonZeroU16,
335 ) {
336 let compact = val.to_compact_string();
337 prop_assert_eq!(compact.as_str(), val.to_string());
338 }
339
340 #[proptest]
341 #[cfg_attr(miri, ignore)]
342 fn proptest_to_compact_string_non_zero_u32(
343 #[strategy((1..=u32::MAX).prop_map(|x| unsafe { num::NonZeroU32::new_unchecked(x)} ))]
344 val: num::NonZeroU32,
345 ) {
346 let compact = val.to_compact_string();
347 prop_assert_eq!(compact.as_str(), val.to_string());
348 }
349
350 #[proptest]
351 #[cfg_attr(miri, ignore)]
352 fn proptest_to_compact_string_non_zero_u64(
353 #[strategy((1..=u64::MAX).prop_map(|x| unsafe { num::NonZeroU64::new_unchecked(x)} ))]
354 val: num::NonZeroU64,
355 ) {
356 let compact = val.to_compact_string();
357 prop_assert_eq!(compact.as_str(), val.to_string());
358 }
359
360 #[proptest]
361 #[cfg_attr(miri, ignore)]
362 fn proptest_to_compact_string_non_zero_u128(
363 #[strategy((1..=u128::MAX).prop_map(|x| unsafe { num::NonZeroU128::new_unchecked(x)} ))]
364 val: num::NonZeroU128,
365 ) {
366 let compact = val.to_compact_string();
367 prop_assert_eq!(compact.as_str(), val.to_string());
368 }
369
370 #[proptest]
371 #[cfg_attr(miri, ignore)]
372 fn proptest_to_compact_string_non_zero_usize(
373 #[strategy((1..=usize::MAX).prop_map(|x| unsafe { num::NonZeroUsize::new_unchecked(x)} ))]
374 val: num::NonZeroUsize,
375 ) {
376 let compact = val.to_compact_string();
377 prop_assert_eq!(compact.as_str(), val.to_string());
378 }
379
380 #[proptest]
381 #[cfg_attr(miri, ignore)]
382 fn proptest_to_compact_string_non_zero_i8(
383 #[strategy((1..=u8::MAX).prop_map(|x| unsafe { num::NonZeroI8::new_unchecked(x as i8)} ))]
384 val: num::NonZeroI8,
385 ) {
386 let compact = val.to_compact_string();
387 prop_assert_eq!(compact.as_str(), val.to_string());
388 }
389
390 #[proptest]
391 #[cfg_attr(miri, ignore)]
392 fn proptest_to_compact_string_non_zero_i16(
393 #[strategy((1..=u16::MAX).prop_map(|x| unsafe { num::NonZeroI16::new_unchecked(x as i16)} ))]
394 val: num::NonZeroI16,
395 ) {
396 let compact = val.to_compact_string();
397 prop_assert_eq!(compact.as_str(), val.to_string());
398 }
399
400 #[proptest]
401 #[cfg_attr(miri, ignore)]
402 fn proptest_to_compact_string_non_zero_i32(
403 #[strategy((1..=u32::MAX).prop_map(|x| unsafe { num::NonZeroI32::new_unchecked(x as i32)} ))]
404 val: num::NonZeroI32,
405 ) {
406 let compact = val.to_compact_string();
407 prop_assert_eq!(compact.as_str(), val.to_string());
408 }
409
410 #[proptest]
411 #[cfg_attr(miri, ignore)]
412 fn proptest_to_compact_string_non_zero_i64(
413 #[strategy((1..=u64::MAX).prop_map(|x| unsafe { num::NonZeroI64::new_unchecked(x as i64)} ))]
414 val: num::NonZeroI64,
415 ) {
416 let compact = val.to_compact_string();
417 prop_assert_eq!(compact.as_str(), val.to_string());
418 }
419
420 #[proptest]
421 #[cfg_attr(miri, ignore)]
422 fn proptest_to_compact_string_non_zero_i128(
423 #[strategy((1..=u128::MAX).prop_map(|x| unsafe { num::NonZeroI128::new_unchecked(x as i128)} ))]
424 val: num::NonZeroI128,
425 ) {
426 let compact = val.to_compact_string();
427 prop_assert_eq!(compact.as_str(), val.to_string());
428 }
429
430 #[proptest]
431 #[cfg_attr(miri, ignore)]
432 fn proptest_to_compact_string_non_zero_isize(
433 #[strategy((1..=usize::MAX).prop_map(|x| unsafe { num::NonZeroIsize::new_unchecked(x as isize)} ))]
434 val: num::NonZeroIsize,
435 ) {
436 let compact = val.to_compact_string();
437 prop_assert_eq!(compact.as_str(), val.to_string());
438 }
439}