devela/text/str/ext_string.rs
1// devela::text::ext::string
2//
3//!
4//
5
6#[cfg(feature = "alloc")]
7use crate::{Arc, Box, Rc, String, ToString};
8
9/// Marker trait to prevent downstream implementations of the [`ExtString`] trait.
10#[cfg(feature = "alloc")]
11trait Sealed {}
12#[cfg(feature = "alloc")]
13impl Sealed for String {}
14
15/// Extension trait providing additional methods for [`String`].
16#[expect(private_bounds, reason = "Sealed")]
17#[cfg(feature = "alloc")]
18#[cfg_attr(feature = "nightly_doc", doc(notable_trait, cfg(feature = "alloc")))]
19pub trait ExtString: Sealed {
20 /// Converts the string into a `Box<str>`.
21 ///
22 /// Allows single ownership with exact allocation,
23 /// for when you don't need to clone or share.
24 fn to_box(self) -> Box<str>;
25
26 /// Converts the string into an `Rc<str>`.
27 ///
28 /// Allows shared ownership with reference counting,
29 /// reducing memory duplication in single-threaded scenarios.
30 fn to_rc(self) -> Rc<str>;
31
32 /// Converts the string into an `Arc<str>`.
33 ///
34 /// When you need shared ownership of a string slice across multiple threads.
35 fn to_arc(self) -> Arc<str>;
36
37 /// Returns a [`String`] where you always know each character's position.
38 ///
39 /// A [*counter string*][0] is a graduated string of arbitrary `length`,
40 /// with a `separator` positioned after the immediately preceding number.
41 ///
42 /// # Examples
43 /// ```
44 /// use devela::ExtString;
45 ///
46 /// assert_eq!("2*4*6*8*11*14*", String::new_counter(14, '*'));
47 /// assert_eq!("_3_5_7_9_12_15_", String::new_counter(15, '_'));
48 /// ```
49 /// [0]: https://www.satisfice.com/blog/archives/22
50 #[must_use]
51 fn new_counter(length: usize, separator: char) -> String;
52}
53
54#[cfg(feature = "alloc")]
55impl ExtString for String {
56 /// It just calls the method [`String::into_boxed_str`].
57 fn to_box(self) -> Box<str> {
58 self.into_boxed_str()
59 }
60 fn to_rc(self) -> Rc<str> {
61 Rc::from(self)
62 }
63 fn to_arc(self) -> Arc<str> {
64 Arc::from(self)
65 }
66
67 fn new_counter(mut length: usize, separator: char) -> String {
68 let mut cstr = String::new();
69
70 while length > 0 {
71 let mut tmpstr = separator.to_string();
72 tmpstr.push_str(&length.to_string().chars().rev().collect::<String>());
73
74 if tmpstr.len() > length {
75 tmpstr = tmpstr[..length].to_string();
76 }
77
78 cstr.push_str(&tmpstr);
79 length -= tmpstr.len();
80 }
81 cstr.chars().rev().collect::<String>()
82 }
83}