1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#[macro_export]
macro_rules! kvfmt_inner {
    // base case
    ([$fmt:expr] [$($args:tt)*]) => {
        format_args!($fmt, $( $args )*)
    };

    // Entry case(s)
    ([""] [$($args:tt)*] ?$name:expr $(, $($t:tt)*)?) => {
        $crate::kvfmt_inner!([concat!(stringify!($name), "={:?}")] [$( $args )* $name] $($($t)*)?);
    };
    ([""] [$($args:tt)*] $name:expr $(, $($t:tt)*)?) => {
        $crate::kvfmt_inner!([concat!(stringify!($name), "={}")] [$( $args )* $name ] $($($t)*)?);
    };

    // Munching case(s)
    ([$fmt:expr] [$($args:tt)*] ?$name:expr $(, $($t:tt)*)?) => {
        $crate::kvfmt_inner!([concat!($fmt, " ", stringify!($name), "={:?}")] [$( $args )*, $name] $($($t)*)?);
    };
    ([$fmt:expr] [$($args:tt)*] $name:expr $(, $($t:tt)*)?) => {
        $crate::kvfmt_inner!([concat!($fmt, " ", stringify!($name), "={}")] [$( $args )*, $name ] $($($t)*)?);
    };

}

#[macro_export]
macro_rules! kvfmt {
    ($($t:tt)*) => {
        std::fmt::format($crate::kvfmt_inner!([""] [] $($t)*));
    };
}

#[cfg(test)]
mod tests {

    #[test]
    fn kv() {
        let hi = "henlo!";
        assert!(!kvfmt!(?hi, ?hi).is_empty());
        assert!(!kvfmt!(hi, hi).is_empty());
        assert!(!kvfmt!(?hi, hi).is_empty());
        assert!(!kvfmt!(hi, hi, hi).is_empty());
        assert!(!kvfmt!(hi, ?hi, hi).is_empty());
        assert_eq!("hi=henlo! hi=\"henlo!\"", kvfmt!(hi, ?hi));
    }

    // #[test]
    // fn it_works() {
    //     let msg = "Failed to get root of the current git repository";
    //     let note = "gsync can only be run from within git repositories";
    //     let dbg = || format!("local={:?}", local);

    //     let err = UserErr::msg(msg).note(note).with_debug(dbg);

    //     let expected = format!("{}\nnote: {}\ndebug: {}", msg, note, dbg);

    //     assert_eq!(expected, err.to_string());
    // }
}