fast_concat/lib.rs
1#![no_std]
2#![doc = include_str!("../README.md")]
3#![deny(clippy::unwrap_used)]
4#![deny(clippy::expect_used)]
5#![warn(clippy::pedantic)]
6#![warn(clippy::nursery)]
7#![deny(clippy::unwrap_used, clippy::expect_used)]
8#![allow(clippy::must_use_candidate)]
9#![warn(missing_debug_implementations)]
10#![warn(missing_copy_implementations)]
11#![allow(clippy::module_name_repetitions)]
12#![warn(
13 clippy::arithmetic_side_effects,
14 clippy::unreachable,
15 clippy::unchecked_duration_subtraction,
16 clippy::todo,
17 clippy::string_slice,
18 clippy::panic_in_result_fn,
19 clippy::indexing_slicing,
20 clippy::panic,
21 clippy::exit,
22 clippy::as_conversions,
23 clippy::large_futures,
24 clippy::large_stack_arrays,
25 clippy::large_stack_frames,
26 clippy::modulo_one,
27 clippy::mem_replace_with_uninit,
28 clippy::iterator_step_by_zero,
29 clippy::invalid_regex,
30 clippy::print_stdout,
31 clippy::print_stderr
32)]
33
34/// Concatenates string expressions.
35///
36/// If you only pass in literals or constants, you will get a const `&'static str` back.
37/// Otherwise, this macro will create a buffer with the optimal capacity and push every string to it.
38///
39/// # Syntax
40///
41/// Any amount of expressions that evaluate to a `&str` separated by commas.
42/// An expression can be prefixed with `const` to indicate that it is constant.
43///
44/// # Examples
45///
46/// ```rust
47/// # use fast_concat_macro::fast_concat;
48/// const CONST: &str = "const ";
49/// let var = "var ";
50/// let mut buf = String::new();
51///
52/// // use const keyword to indicate that it is constant
53/// let expansion = fast_concat!("lit0 ", const CONST, var, "lit1 ", "lit2 ", 9, {
54/// for i in 0..10 {
55/// buf.push_str(&i.to_string());
56/// }
57///
58/// &buf
59/// });
60///
61/// buf.clear();
62///
63/// // what the value is
64/// assert_eq!(expansion, "lit0 const var lit1 lit2 90123456789");
65///
66/// // what code gets generated
67/// assert_eq!(expansion, {
68/// extern crate alloc;
69/// // constcat generates these
70/// const _0: &'static str = "lit0 const ";
71/// let _1: &str = var;
72/// const _2: &'static str = "lit1 lit2 9";
73/// let _3: &str = {
74/// for i in 0..10 {
75/// buf.push_str(&i.to_string());
76/// }
77///
78/// &buf
79/// };
80///
81/// let mut buf = alloc::string::String::with_capacity(0 + _0.len() + _1.len() + _2.len() + _3.len());
82/// buf.push_str(_0);
83/// buf.push_str(_1);
84/// buf.push_str(_2);
85/// buf.push_str(_3);
86/// buf
87/// });
88/// ```
89///
90/// ```rust
91/// # use fast_concat_macro::fast_concat;
92///
93/// const ASSETS_DIR: &str = "./assets";
94/// const ICON: &str = fast_concat!(const ASSETS_DIR, '/', "icon.png");
95///
96/// assert_eq!(ICON, "./assets/icon.png");
97/// assert_eq!(ICON, {
98/// const OUTPUT: &'static str = ::constcat::concat!(ASSETS_DIR, '/', "icon.png" , );
99/// OUTPUT
100/// });
101/// ```
102pub use fast_concat_macro::fast_concat;
103
104#[cfg(test)]
105mod tests {
106 extern crate alloc;
107 use alloc::string::{String, ToString};
108 use fast_concat_macro::fast_concat;
109
110 #[test]
111 fn concat() {
112 const CONST: &str = "const ";
113 let var = "var ";
114 let mut buf = String::new();
115
116 macro_rules! impure_expr {
117 ($buf:ident) => {{
118 for i in 0..10 {
119 $buf.push_str(&i.to_string());
120 }
121 &$buf
122 }};
123 }
124
125 let correct_output = "lit0 const var lit1 lit2 90123456789";
126
127 assert_eq!(
128 fast_concat!("lit0 ", const CONST, var, "lit1 ", "lit2 ", 9, impure_expr!(buf)),
129 correct_output
130 );
131
132 let correct_output = "lit0 const var lit1 lit2 901234567890123456789";
133
134 assert_eq!(
135 fast_concat!("lit0 ", const CONST, var, "lit1 ", "lit2 ", 9, impure_expr!(buf)),
136 correct_output
137 );
138 }
139}