tailwindcss_to_rust_macros/
lib.rs1#![doc = include_str!("../README.md")]
2#![doc = include_str!("../examples/css/mod.rs")]
12pub mod to_option_vec_string;
19pub use to_option_vec_string::ToOptionVecString;
20
21#[macro_export]
40macro_rules! C {
41 ( $($class:expr $(,)?)+ ) => {
42 {
43 let mut all_classes = vec![];
49 $(
50 $crate::_push_all_strings(&mut all_classes, $class.to_option_vec_string());
51 )*
52 all_classes.join(" ")
53 }
54 };
55}
56
57#[macro_export]
73macro_rules! DC {
74 ( $($class:expr $(,)?)+ ) => {
75 {
76 let mut all_classes = vec![];
77 $(
78 $crate::_push_all_strings(&mut all_classes, $class.to_option_vec_string());
79 )*
80 format_args!("{}", all_classes.join(" "))
81 }
82 };
83}
84
85#[macro_export]
98macro_rules! M {
99 ( $($modifier:expr $(,)?)* ) => {
100 {
101 let mut all_modifiers = vec![];
102 $(
103 $crate::_push_all_strings(&mut all_modifiers, $modifier.to_option_vec_string());
104 )*
105 all_modifiers.join(":")
106 }
107 };
108}
109
110pub fn _push_all_strings(all_strings: &mut Vec<String>, classes: Option<Vec<String>>) {
112 if let Some(classes) = classes {
113 all_strings.append(
114 &mut classes
115 .into_iter()
116 .filter(|c| !c.is_empty())
117 .collect::<Vec<_>>(),
118 );
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn test() {
128 assert_eq!(C![""], "");
129 assert_eq!(C!["x"], "x");
130
131 let x = "x";
132 let y = "y";
133 assert_eq!(C![x, y], "x y");
134 assert_eq!(C![x, y, "z"], "x y z");
135
136 assert_eq!(C![M!["md", "x"]], "md:x");
137 assert_eq!(C![M!["md", "hover", "x"]], "md:hover:x");
138 assert_eq!(C![M!["md", "x"], M!["hover", "y"]], "md:x hover:y");
139 assert_eq!(C![x, M!["md", y], M!["hover", "z"]], "x md:y hover:z");
140
141 let z = "z".to_string();
142 assert_eq!(C![x, y, z, "foo"], "x y z foo");
143
144 let z = "z".to_string();
145 assert_eq!(C![M![x, y, z, "foo"]], "x:y:z:foo");
146 }
147
148 #[test]
158 fn to_option_vec_string_ref_str() {
159 let text: &str = "foo";
160 assert_eq!(C![text], "foo");
161 assert_eq!(M![text], "foo");
162 }
163
164 #[test]
165 fn to_option_vec_string_ref_str_empty() {
166 let text: &str = "";
167 assert!(C![text].is_empty());
168 assert!(M![text].is_empty());
169 }
170
171 #[test]
172 fn to_option_vec_string_string() {
173 let text = String::from("bar");
174 assert_eq!(C![text], "bar");
175 let text = String::from("bar");
176 assert_eq!(M![text], "bar");
177 }
178
179 #[test]
180 fn to_option_vec_string_ref_string() {
181 let text = &String::from("ref_bar");
182 assert_eq!(C![text], "ref_bar");
183 let text = &String::from("ref_bar");
184 assert_eq!(M![text], "ref_bar");
185 }
186
187 #[test]
190 fn to_option_vec_string_vec() {
191 let vec: Vec<&str> = vec!["foo_1", "foo_2"];
192 assert_eq!(C![vec], "foo_1 foo_2");
193 let vec: Vec<&str> = vec!["foo_1", "foo_2"];
194 assert_eq!(M![vec], "foo_1:foo_2");
195 }
196
197 #[test]
198 fn to_option_vec_string_ref_vec() {
199 let vec: &Vec<&str> = &vec!["foo_1", "foo_2"];
200 assert_eq!(C![vec], "foo_1 foo_2");
201 let vec: &Vec<&str> = &vec!["foo_1", "foo_2"];
202 assert_eq!(M![vec], "foo_1:foo_2");
203 }
204
205 #[test]
206 fn to_option_vec_string_slice() {
207 let slice: &[&str] = &["foo_1", "foo_2"];
208 assert_eq!(C![slice], "foo_1 foo_2");
209 assert_eq!(M![slice], "foo_1:foo_2");
210 }
211
212 #[test]
213 fn to_option_vec_string_option_some() {
214 let option: Option<&str> = Some("foo_opt");
215 assert_eq!(C![option], "foo_opt");
216 assert_eq!(M![option], "foo_opt");
217 }
218
219 #[test]
220 fn to_option_vec_string_ref_option_some() {
221 let option: &Option<&str> = &Some("foo_opt");
222 assert_eq!(C![option], "foo_opt");
223 assert_eq!(M![option], "foo_opt");
224 }
225
226 #[test]
227 fn to_option_vec_string_option_none() {
228 let option: Option<&str> = None;
229 assert!(C![option].is_empty());
230 assert!(M![option].is_empty());
231 }
232
233 #[test]
234 fn to_option_vec_string_option_vec() {
235 let option_vec: Option<Vec<&str>> = Some(vec!["foo_1", "foo_2"]);
236 assert_eq!(C![option_vec], "foo_1 foo_2");
237 let option_vec: Option<Vec<&str>> = Some(vec!["foo_1", "foo_2"]);
238 assert_eq!(M![option_vec], "foo_1:foo_2");
239 }
240
241 #[test]
244 fn with_fmt() {
245 struct Classes {
246 classes: String,
247 }
248
249 impl std::fmt::Display for Classes {
250 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
251 write!(f, "{} {}", self.classes, C!["foo", "bar" M!["md", "baz"]],)
252 }
253 }
254
255 let classes = Classes {
256 classes: "x y z".to_string(),
257 };
258 assert_eq!(format!("{classes}"), "x y z foo bar md:baz");
259 }
260}