1#![doc = include_str!("../Readme.md")]
2
3
4#[macro_export]
49macro_rules! concat_str {
50 (
51 @pre {$($pre:stmt,)*},
52 @strname $strname:ident,
53 @len $($len:expr)?,
54 @appends {$($appends:expr,)*},
55 $head:literal $(, $($tail:tt)*)?
56 ) => {
57 $crate::concat_str!(
58 @pre {$($pre, )*
59 let tmp_res = $head
60 ,},
61 @strname $strname,
62 @len $($len +)? tmp_res.len(),
63 @appends {
64 $($appends,)*
65 $strname.push_str(tmp_res),
66 },
67 $($($tail)*)?
68 )
69 };
70
71 (
72 @pre {$($pre:stmt,)*},
73 @strname $strname:ident,
74 @len $($len:expr)?,
75 @appends {$($appends:expr,)*},
76 $head:ident $(, $($tail:tt)*)?
77 ) => {
78 $crate::concat_str!(
79 @pre {$($pre, )*},
80 @strname $strname,
81 @len $($len +)? $head.len(),
82 @appends {
83 $($appends,)*
84 $strname.push_str($head),
85 },
86 $($($tail)*)?
87 )
88 };
89
90 (
91 @pre {$($pre:stmt,)*},
92 @strname $strname:ident,
93 @len $($len:expr)?,
94 @appends {$($appends:expr,)*},
95 $head:expr $(, $($tail:tt)*)?
96 ) => {
97 $crate::concat_str!(
98 @pre {$($pre, )*
99 let tmp_res = $head
100 ,},
101 @strname $strname,
102 @len $($len +)? tmp_res.len(),
103 @appends {
104 $($appends,)*
105 $strname.push_str(tmp_res),
106 },
107 $($($tail)*)?
108 )
109 };
110
111 (
112 @pre {$($pre:stmt,)*},
113 @strname $strname:ident,
114 @len $len:expr,
115 @appends {$($appends:expr,)*},
116 ) => {
117 {
118 $($pre)*
119 let mut $strname = String::with_capacity($len);
120 $($appends;)*
121 $strname
122 }
123 };
124
125 ($($tt:tt)+) => {
126 $crate::concat_str!(@pre {}, @strname res_string, @len, @appends {}, $($tt)+)
127 };
128}
129
130
131#[cfg(test)]
132mod tests {
133 #[test]
134 fn rtest() {
135 let a = "test";
136 let b = "local".to_string();
137 let c = "focal".to_string();
138 let i = 3;
139
140 assert_eq!(
141 concat_str!("", ""),
142 ""
143 );
144
145 assert_eq!(
146 concat_str!("so, ", a, "test"),
147 "so, testtest"
148 );
149
150 assert_eq!(
151 concat_str!("so, ", &b, " ", &c),
152 "so, local focal"
153 );
154
155 assert_eq!(
156 concat_str!("so, ", &i.to_string(), " ", &c),
157 "so, 3 focal"
158 );
159
160 let repeat = "repeat?";
162 let repeat_o = "repeat?".to_string();
163 assert_eq!(
164 concat_str!(
165 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
166 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
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 ),
176 "repeat?".repeat(100)
177 );
178 }
179
180 #[test]
181 fn explicit_failure_test() {
182 let short_str = "1".to_string();
183 let long_str = "long_string".to_string();
184
185 assert_eq!(
186 concat_str!(&short_str, " ", &long_str),
187 "1 long_string"
188 );
189 }
190
191 #[cfg(feature="count-allocations")]
192 #[test]
193 fn test_single_alloc() {
194 let repeat = "repeat?";
195 let repeat_o = "repeat?".to_string();
196 let alloc_count = allocation_counter::measure(|| {
197 let _ = concat_str!(
198 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
199 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
200 "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, "repeat?", repeat, &repeat_o, repeat,
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 );
210 });
211 assert_eq!(alloc_count.count_total, 1);
212 }
213}