1#![doc = include_str!("../Readme.md")]
2
3#[macro_export]
4macro_rules! _concat_str_internal {
5 (
6 @pre {$($pre:stmt,)*},
7 @strname $strname:ident,
8 @len $($len:expr)?,
9 @appends {$($appends:expr,)*},
10 $head:literal $(, $($tail:tt)*)?
11 ) => {
12 _concat_str_internal!(
13 @pre {$($pre, )*
14 let tmp_res = $head
15 ,},
16 @strname $strname,
17 @len $($len +)? tmp_res.len(),
18 @appends {
19 $($appends,)*
20 $strname.push_str(tmp_res),
21 },
22 $($($tail)*)?
23 )
24 };
25
26 (
27 @pre {$($pre:stmt,)*},
28 @strname $strname:ident,
29 @len $($len:expr)?,
30 @appends {$($appends:expr,)*},
31 $head:ident $(, $($tail:tt)*)?
32 ) => {
33 $crate::_concat_str_internal!(
34 @pre {$($pre, )*},
35 @strname $strname,
36 @len $($len +)? $head.len(),
37 @appends {
38 $($appends,)*
39 $strname.push_str($head),
40 },
41 $($($tail)*)?
42 )
43 };
44
45 (
46 @pre {$($pre:stmt,)*},
47 @strname $strname:ident,
48 @len $($len:expr)?,
49 @appends {$($appends:expr,)*},
50 $head:expr $(, $($tail:tt)*)?
51 ) => {
52 $crate::_concat_str_internal!(
53 @pre {$($pre, )*
54 let tmp_res = $head
55 ,},
56 @strname $strname,
57 @len $($len +)? tmp_res.len(),
58 @appends {
59 $($appends,)*
60 $strname.push_str(tmp_res),
61 },
62 $($($tail)*)?
63 )
64 };
65
66 (
67 @pre {$($pre:stmt,)*},
68 @strname $strname:ident,
69 @len $len:expr,
70 @appends {$($appends:expr,)*},
71 ) => {
72 {
73 $($pre)*
74 let mut $strname = String::with_capacity($len);
75 $($appends;)*
76 $strname
77 }
78 };
79}
80
81#[macro_export]
126macro_rules! concat_str {
127 ($($tt:tt)+) => {
128 $crate::_concat_str_internal!(@pre {}, @strname res_string, @len, @appends {}, $($tt)+)
129 };
130}
131
132
133#[cfg(test)]
134mod tests {
135 #[test]
136 fn rtest() {
137 let a = "test";
138 let b = "local".to_string();
139 let c = "focal".to_string();
140 let i = 3;
141
142 assert_eq!(
143 concat_str!("", ""),
144 ""
145 );
146
147 assert_eq!(
148 concat_str!("so, ", a, "test"),
149 "so, testtest"
150 );
151
152 assert_eq!(
153 concat_str!("so, ", &b, " ", &c),
154 "so, local focal"
155 );
156
157 assert_eq!(
158 concat_str!("so, ", &i.to_string(), " ", &c),
159 "so, 3 focal"
160 );
161
162 let repeat = "repeat?";
164 let repeat_o = "repeat?".to_string();
165 assert_eq!(
166 concat_str!(
167 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
168 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
169 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
170 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
171 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
172 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
173 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
174 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
175 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
176 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
177 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
178 ),
179 "repeat?".repeat(100)
180 );
181 }
182
183 #[test]
184 fn explicit_failure_test() {
185 let short_str = "1".to_string();
186 let long_str = "long_string".to_string();
187
188 assert_eq!(
189 concat_str!(&short_str, " ", &long_str),
190 "1 long_string"
191 );
192 }
193
194 #[cfg(feature="count-allocations")]
195 #[test]
196 fn test_single_alloc() {
197 let repeat = "repeat?";
198 let repeat_o = "repeat?".to_string();
199 let alloc_count = allocation_counter::measure(|| {
200 let _ = concat_str!(
201 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
202 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
203 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
204 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
205 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
206 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
207 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
208 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
209 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
210 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
211 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
212 );
213 });
214 assert_eq!(alloc_count.count_total, 1);
215 }
216}