1#[cfg(doc)]
2use crate::{format, write};
3
4#[macro_export]
18macro_rules! iformat {
19 ($fmt:expr, $($context:tt)*) => {
20 $crate::format($fmt, &$crate::context!($($context)*))
21 };
22}
23
24#[macro_export]
39macro_rules! iwrite {
40 ($buf: expr, $fmt:expr, $($context:tt)*) => {
41 $crate::write($buf, $fmt, &$crate::context!($($context)*))
42 };
43}
44
45#[macro_export]
59macro_rules! iwriteln {
60 ($buf: expr, $($fmt:tt)*) => {
61 match $crate::iwrite!($buf, $($fmt)*) {
62 Ok(()) => std::write!($buf, "\n").map_err(|e| $crate::Error::Fmt(e, 0)),
64 e => e
65 }
66 };
67}
68
69#[macro_export]
80macro_rules! iprint {
81 ($($fmt:tt)*) => {
82 $crate::iformat!($($fmt)*).map(|f| std::print!("{f}"))
83 };
84}
85
86#[macro_export]
97macro_rules! iprintln {
98 ($($fmt:tt)*) => {
99 $crate::iformat!($($fmt)*).map(|f| std::println!("{f}"))
100 };
101}
102
103#[macro_export]
114macro_rules! ieprint {
115 ($($fmt:tt)*) => {
116 $crate::iformat!($($fmt)*).map(|f| std::eprint!("{f}"))
117 };
118}
119
120#[macro_export]
131macro_rules! ieprintln {
132 ($($fmt:tt)*) => {
133 $crate::iformat!($($fmt)*).map(|f| std::eprintln!("{f}"))
134 };
135}
136
137#[macro_export]
178macro_rules! context {
179 ($($tts:tt)*) => {
180 {
181 #[allow(unused)]
182 let mut map = ::std::collections::HashMap::<&str, $crate::Formattable>::new();
183 $crate::inner_context!(map; $($tts)*);
184 map
185 }
186 };
187}
188
189#[macro_export]
228#[cfg(doc)]
229macro_rules! list {
230 ($($(: $($trait:tt)?)*;)?($values:expr), *) => {};
231}
232
233#[cfg(not(doc))]
234#[allow(missing_docs)]
235#[macro_export]
236macro_rules! list {
237 ($($traits:ident),* : ; $($values:tt)*) => {
238 $crate::list!($($traits,)* display; $($values)*)
239 };
240 ($($traits:ident),* :: $($values:tt)*) => {
241 $crate::list!($($traits,)* display : $($values)*)
242 };
243 ($($traits:ident),* : : $($values:tt)*) => {
244 $crate::list!($($traits,)* display : $($values)*)
245 };
246 ($($traits:ident),* : ? $($values:tt)*) => {
247 $crate::list!($($traits,)* debug $($values)*)
248 };
249 ($($traits:ident),* : $trait:ident $($values:tt)*) => {
250 $crate::list!($($traits,)* $trait $($values)*)
251 };
252 ($(;)? $($value:expr),* $(,)?) => {
253 $crate::list!(:; $($value),*)
254 };
255 ($($traits:ident),*; $($value:expr),*) => {
256 $crate::apply!([], ($($traits)*), $($value),*)
257 };
258}
259
260#[doc(hidden)]
261#[macro_export]
262macro_rules! apply {
263 ($previous:tt, ($($traits:tt)*),) => {
264 $previous
265 };
266 ([$($previous:tt),*], ($($traits:tt)*), $value:expr $(, $($values:expr),*)?) => {
267 $crate::apply!( [ $($previous,)* {
268 #[allow(unused)]
269 let mut value = $crate::Formattable::default();
270 $($crate::set_trait!(value, $traits, $value);)*
271 value
272 }], ($($traits)*), $($($values),*)?)
273 };
274}
275
276#[macro_export]
277#[doc(hidden)]
278macro_rules! inner_context {
279 ($map:ident; $ident:ident$(:)? $(, $($tts:tt)*)?) => {
280 $crate::inner_context!($map, $ident, display; , $($($tts)*)?);
281 $crate::inner_context!($map; $($($tts)*)?)
282 };
283 ($map:ident; $ident:ident$(:)? = $($tts:tt)*) => {
284 $crate::inner_context!($map, $ident, display; = $($tts)*);
285 };
286 ($map:ident; $ident:ident : $($tts:tt)*) => {
287 $crate::inner_context!($map, $ident; : $($tts)*)
288 };
289 ($map:ident; $ident:ident :: $($tts:tt)*) => {
290 $crate::inner_context!($map, $ident; :: $($tts)*)
291 };
292 ($map:ident, $ident:ident$(, $traits:tt)*; :: $($tts:tt)*) => {
293 $crate::inner_context!($map, $ident$(, $traits)*, display; : $($tts)*)
294 };
295 ($map:ident, $ident:ident$(, $traits:tt)*; : : $($tts:tt)*) => {
296 $crate::inner_context!($map, $ident$(, $traits)*, display; : $($tts)*)
297 };
298 ($map:ident, $ident:ident$(, $traits:tt)*; : = $($tts:tt)*) => {
299 $crate::inner_context!($map, $ident$(, $traits)*, display; => $($tts)*)
300 };
301 ($map:ident, $ident:ident$(, $traits:tt)*; : $(, $($tts:tt)*)?) => {
302 $crate::inner_context!($map, $ident$(, $traits)*, display; $(, $($tts)*)?)
303 };
304 ($map:ident, $ident:ident$(, $traits:tt)*; :? $($tts:tt)*) => {
305 $crate::inner_context!($map, $ident$(, $traits)*, ?; $($tts)*)
306 };
307 ($map:ident, $ident:ident$(, $traits:tt)*; : $trait:ident $($tts:tt)*) => {
308 $crate::inner_context!($map, $ident$(, $traits)*, $trait; $($tts)*)
309 };
310 ($map:ident, $ident:ident$(, $traits:tt)*; $(, $($tts:tt)*)?) => {
311 $crate::inner_context!($map, $ident$(, $traits)*; = $ident, $($($tts)*)?)
312 };
313 ($map:ident, $ident:ident$(, $traits:tt)*; = $value:expr $(, $($tts:tt)*)?) => {
314 $($crate::set_trait!($map.entry(stringify!($ident)).or_default(), $traits, $value);)*
315 $crate::inner_context!($map; $($($tts)*)?)
316 };
317 ($map:ident;) => {};
318}
319
320#[doc(hidden)]
322#[macro_export]
323macro_rules! set_trait {
324 ($formattable:expr, ? , $value:expr) => {
325 $crate::set_trait!($formattable, set_debug, $value);
326 };
327 ($formattable:expr,debug, $value:expr) => {
328 $crate::set_trait!($formattable, set_debug, $value);
329 };
330 ($formattable:expr, , $value:expr) => {
331 $crate::set_trait!($formattable, set_display, $value);
332 };
333 ($formattable:expr,display, $value:expr) => {
334 $crate::set_trait!($formattable, set_display, $value);
335 };
336 ($formattable:expr,integer, $value:expr) => {
337 $crate::set_trait!($formattable, set_integer, $value);
338 };
339 ($formattable:expr,float, $value:expr) => {
340 $crate::set_trait!($formattable, set_float, $value);
341 };
342 ($formattable:expr,b, $value:expr) => {
343 $crate::set_trait!($formattable, set_binary, $value);
344 };
345 ($formattable:expr,binary, $value:expr) => {
346 $crate::set_trait!($formattable, set_binary, $value);
347 };
348 ($formattable:expr,e, $value:expr) => {
349 $crate::set_trait!($formattable, set_lower_exp, $value);
350 };
351 ($formattable:expr,lower_exp, $value:expr) => {
352 $crate::set_trait!($formattable, set_lower_exp, $value);
353 };
354 ($formattable:expr,x, $value:expr) => {
355 $crate::set_trait!($formattable, set_lower_hex, $value);
356 };
357 ($formattable:expr,lower_hex, $value:expr) => {
358 $crate::set_trait!($formattable, set_lower_hex, $value);
359 };
360 ($formattable:expr,o, $value:expr) => {
361 $crate::set_trait!($formattable, set_octal, $value);
362 };
363 ($formattable:expr,octal, $value:expr) => {
364 $crate::set_trait!($formattable, set_octal, $value);
365 };
366 ($formattable:expr,E, $value:expr) => {
367 $crate::set_trait!($formattable, set_upper_exp, $value);
368 };
369 ($formattable:expr,upper_exp, $value:expr) => {
370 $crate::set_trait!($formattable, set_upper_exp, $value);
371 };
372 ($formattable:expr,X, $value:expr) => {
373 $crate::set_trait!($formattable, set_upper_hex, $value);
374 };
375 ($formattable:expr,upper_hex, $value:expr) => {
376 $crate::set_trait!($formattable, set_upper_hex, $value);
377 };
378 ($formattable:expr,p, $value:expr) => {
379 $crate::set_trait!($formattable, set_pointer, $value);
380 };
381 ($formattable:expr,pointer, $value:expr) => {
382 $crate::set_trait!($formattable, set_pointer, $value);
383 };
384 ($formattable:expr,i, $value:expr) => {
385 $crate::set_trait!($formattable, set_iter, $value);
386 };
387 ($formattable:expr,iter, $value:expr) => {
388 $crate::set_trait!($formattable, set_iter, $value);
389 };
390 ($formattable:expr, $setter:ident, $value:expr) => {
391 $formattable.$setter(&$value);
392 };
393}
394
395#[cfg(test)]
396mod test {
397 #[allow(unused)]
398 use std::f32::consts::PI;
399
400 #[allow(unused)]
401 macro_rules! assert_fmt {
402 ($fmt:tt, $context:tt. $($fn:tt),+($key:tt), $expected:tt) => {
403 assert_eq!(
404 format!(
405 $fmt,
406 $($context.get(stringify!($key)).unwrap().$fn().unwrap()),+),
407 $expected
408 );
409 };
410 }
411
412 #[test]
413 #[cfg(all(feature = "debug", feature = "number", feature = "pointer"))]
414 fn context() {
415 let pointer = &32;
416 let context = context! {
417 a = "",
418 a:? = "",
419 b:?:b = 10,
420 d: :? = "hello",
421 };
422 assert_fmt!("{}", context.get_display(a), "");
423 assert_fmt!("{:?}", context.get_debug(a), "\"\"");
424 assert_fmt!("{:?}", context.get_debug(b), "10");
425 assert_fmt!("{:b}", context.get_binary(b), "1010");
426 assert_fmt!("{:}", context.get_display(d), "hello");
427 assert_fmt!("{:?}", context.get_debug(d), "\"hello\"");
428 let context = context! {
429 debug1:? = "debug",
430 debug2:debug = "debug",
431 display1 = "display",
432 display2: = "display",
433 display3:display = "display",
434 integer:integer = 42,
435 float:float = PI,
436 binary1:b = 12,
437 binary2:binary = 12,
438 lower_exp1:e = 0.01,
439 lower_exp2:lower_exp = 0.01,
440 lower_hex1:x = 0xA9,
441 lower_hex2:lower_hex = 0xA9,
442 octal1:o = 0o20,
443 octal2:octal = 0o20,
444 upper_exp1:E = 0.01,
445 upper_exp2:upper_exp = 0.01,
446 upper_hex1:X = 0xA9,
447 upper_hex2:upper_hex = 0xA9,
448 pointer1:p = pointer,
449 pointer2:pointer = pointer,
450 };
452 assert_fmt!("{}", context.get_display(display1), "display");
453 assert_fmt!("{}", context.get_display(display2), "display");
454 assert_fmt!("{}", context.get_display(display3), "display");
455 assert_fmt!("{:?}", context.get_debug(debug1), "\"debug\"");
456 assert_fmt!("{:?}", context.get_debug(debug2), "\"debug\"");
457 assert_fmt!(
458 "{:b} {:?} {:} {:e} {:x} {:o} {:E} {:X}",
459 context.get_binary,
460 get_debug,
461 get_display,
462 get_lower_exp,
463 get_lower_hex,
464 get_octal,
465 get_upper_exp,
466 get_upper_hex(integer),
467 "101010 42 42 4.2e1 2a 52 4.2E1 2A"
468 );
469 assert_fmt!(
470 "{:?} {:} {:e} {:E}",
471 context.get_debug,
472 get_display,
473 get_lower_exp,
474 get_upper_exp(float),
475 "3.1415927 3.1415927 3.1415927e0 3.1415927E0"
476 );
477 assert_fmt!("{:b}", context.get_binary(binary1), "1100");
478 assert_fmt!("{:b}", context.get_binary(binary2), "1100");
479 assert_fmt!("{:e}", context.get_lower_exp(lower_exp1), "1e-2");
480 assert_fmt!("{:e}", context.get_lower_exp(lower_exp2), "1e-2");
481 assert_fmt!("{:x}", context.get_lower_hex(lower_hex1), "a9");
482 assert_fmt!("{:x}", context.get_lower_hex(lower_hex2), "a9");
483 assert_fmt!("{:o}", context.get_octal(octal1), "20");
484 assert_fmt!("{:o}", context.get_octal(octal2), "20");
485 assert_fmt!("{:E}", context.get_upper_exp(upper_exp1), "1E-2");
486 assert_fmt!("{:E}", context.get_upper_exp(upper_exp2), "1E-2");
487 assert_fmt!("{:X}", context.get_upper_hex(upper_hex1), "A9");
488 assert_fmt!("{:X}", context.get_upper_hex(upper_hex2), "A9");
489 assert_fmt!(
490 "{:p}",
491 context.get_pointer(pointer1),
492 (format!("{pointer:p}"))
493 );
494 assert_fmt!(
495 "{:p}",
496 context.get_pointer(pointer2),
497 (format!("{pointer:p}"))
498 );
499 }
500 #[allow(unused)]
501 macro_rules! assert_i {
502 ($fmt:literal, $variable:ident, $rhs:literal) => {
503 assert_eq!(
504 iformat!(concat!("{list:i(", $fmt, ")(,)}"), $variable: i).unwrap(),
505 $rhs
506 );
507 };
508 }
509
510 #[test]
511 #[cfg(feature = "iter")]
512 fn list() {
513 let list = list!["a", 1];
514 assert_i!("{}", list, "a,1");
515 #[cfg(feature = "debug")]
516 {
517 let list = list![:?; "a", 1];
518 assert_i!("{:?}", list, "\"a\",1");
519 #[cfg(feature = "number")]
520 {
521 let list = list![::?:X; 2, 1];
522 assert_i!("{}{:?}{:X}", list, "222,111");
523 }
524 }
525 }
526}