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}