slash_formatter/
backslash.rs

1use alloc::{borrow::Cow, string::String};
2
3/// Delete an ending backslash in a string except for '\\\\'.
4///
5/// ```
6/// assert_eq!("path", slash_formatter::delete_end_backslash("path\\"));
7/// ```
8#[inline]
9pub fn delete_end_backslash<S: ?Sized + AsRef<str>>(s: &S) -> &str {
10    let s = s.as_ref();
11
12    let length = s.len();
13
14    if length > 1 && s.ends_with('\\') {
15        unsafe { s.get_unchecked(..length - 1) }
16    } else {
17        s
18    }
19}
20
21/// Delete an ending backslash in a string except for '\\\\'.
22///
23/// ```
24/// let mut s = String::from("path\\");
25///
26/// slash_formatter::delete_end_backslash_in_place(&mut s);
27///
28/// assert_eq!("path", s);
29/// ```
30#[inline]
31pub fn delete_end_backslash_in_place(s: &mut String) {
32    let length = s.len();
33
34    if length > 1 && s.ends_with('\\') {
35        unsafe {
36            s.as_mut_vec().set_len(length - 1);
37        }
38    }
39}
40
41/// Delete a starting backslash in a string except for '\\\\'.
42///
43/// ```
44/// assert_eq!("path", slash_formatter::delete_start_backslash("\\path"));
45/// ```
46#[inline]
47pub fn delete_start_backslash<S: ?Sized + AsRef<str>>(s: &S) -> &str {
48    let s = s.as_ref();
49
50    let length = s.len();
51
52    if length > 1 && s.starts_with('\\') {
53        unsafe { s.get_unchecked(1..) }
54    } else {
55        s
56    }
57}
58
59/// Delete a starting backslash in a string except for '\\\\'.
60///
61/// ```
62/// let mut s = String::from("\\path");
63///
64/// slash_formatter::delete_start_backslash_in_place(&mut s);
65///
66/// assert_eq!("path", s);
67/// ```
68#[inline]
69pub fn delete_start_backslash_in_place(s: &mut String) {
70    let length = s.len();
71
72    if length > 1 && s.starts_with('\\') {
73        s.remove(0);
74    }
75}
76
77/// Add a starting backslash into a string.
78///
79/// ```
80/// assert_eq!("\\path", slash_formatter::add_start_backslash("path"));
81/// ```
82#[inline]
83pub fn add_start_backslash<S: ?Sized + AsRef<str>>(s: &S) -> Cow<str> {
84    let s = s.as_ref();
85
86    if s.starts_with('\\') {
87        Cow::from(s)
88    } else {
89        Cow::from(format!("\\{}", s))
90    }
91}
92
93/// Add a starting backslash into a string.
94///
95/// ```
96/// let mut s = String::from("path");
97///
98/// slash_formatter::add_start_backslash_in_place(&mut s);
99///
100/// assert_eq!("\\path", s);
101/// ```
102#[inline]
103pub fn add_start_backslash_in_place(s: &mut String) {
104    if !s.starts_with('\\') {
105        s.insert(0, '\\');
106    }
107}
108
109/// Add an ending backslash into a string.
110///
111/// ```
112/// assert_eq!("path\\", slash_formatter::add_end_backslash("path"));
113/// ```
114#[inline]
115pub fn add_end_backslash<S: ?Sized + AsRef<str>>(s: &S) -> Cow<str> {
116    let s = s.as_ref();
117
118    if s.ends_with('\\') {
119        Cow::from(s)
120    } else {
121        Cow::from(format!("{}\\", s))
122    }
123}
124
125/// Add an ending backslash into a string.
126///
127/// ```
128/// let mut s = String::from("path");
129///
130/// slash_formatter::add_end_backslash_in_place(&mut s);
131///
132/// assert_eq!("path\\", s);
133/// ```
134#[inline]
135pub fn add_end_backslash_in_place(s: &mut String) {
136    if !s.ends_with('\\') {
137        s.push('\\');
138    }
139}
140
141/// Concatenate two strings with a backslash.
142///
143/// ```
144/// assert_eq!(
145///     "path\\to",
146///     slash_formatter::concat_with_backslash("path", "to\\")
147/// );
148/// ```
149#[inline]
150pub fn concat_with_backslash<S1: Into<String>, S2: AsRef<str>>(s1: S1, s2: S2) -> String {
151    let mut s1 = s1.into();
152
153    concat_with_backslash_in_place(&mut s1, s2);
154
155    s1
156}
157
158/// Concatenate two strings with a backslash.
159///
160/// ```
161/// let mut s = String::from("path");
162///
163/// slash_formatter::concat_with_backslash_in_place(&mut s, "to\\");
164///
165/// assert_eq!("path\\to", s);
166/// ```
167#[inline]
168pub fn concat_with_backslash_in_place<S2: AsRef<str>>(s1: &mut String, s2: S2) {
169    add_end_backslash_in_place(s1);
170    s1.push_str(delete_start_backslash(s2.as_ref()));
171    delete_end_backslash_in_place(s1);
172}
173
174/**
175Concatenate multiple strings with backslashes.
176
177```
178assert_eq!("path\\to\\file", slash_formatter::backslash!("path", "to\\", "\\file\\"));
179
180let s = String::from("path");
181
182let s = slash_formatter::backslash!(s, "to\\", "\\file\\");
183
184assert_eq!("path\\to\\file", s);
185```
186*/
187#[macro_export]
188macro_rules! backslash {
189    () => {
190        '\\'
191    };
192    ($s:expr $(, $sc:expr)* $(,)*) => {
193        {
194            let mut s = $s.to_owned();
195
196            $(
197                $crate::concat_with_backslash_in_place(&mut s, $sc);
198            )*
199
200            s
201        }
202    };
203}
204
205/**
206Concatenate multiple strings with backslashes.
207
208```
209let mut s = String::from("path");
210
211slash_formatter::backslash_in_place!(&mut s, "to\\", "\\file\\");
212
213assert_eq!("path\\to\\file", s);
214```
215*/
216#[macro_export]
217macro_rules! backslash_in_place {
218    () => {
219        '\\'
220    };
221    ($s:expr $(, $sc:expr)* $(,)*) => {
222        $(
223            $crate::concat_with_backslash_in_place($s, $sc);
224        )*
225    };
226}
227
228concat_with::concat_impl! {
229    #[macro_export]
230    /// Concatenates literals into a static string slice separated by a backslash. Prefixes and suffixes can also be added.
231    ///
232    /// ```rust
233    /// assert_eq!("test\\10\\b\\true", slash_formatter::concat_with_backslash!("test", 10, 'b', true));
234    /// ```
235    concat_with_backslash => "\\"
236}