macro_rules! json_str {
    ([]) => {
        "[]"
    };
    ([ $e1:tt $(, $e:tt)* ]) => {
        concat!("[",
            json_str!($e1),
            $(",", json_str!($e),)*
        "]")
    };
    ({}) => {
        "{}"
    };
    ({ $k1:tt : $v1:tt $(, $k:tt : $v:tt)* }) => {
        concat!("{",
            stringify!($k1), ":", json_str!($v1),
            $(",", stringify!($k), ":", json_str!($v),)*
        "}")
    };
    (($other:tt)) => {
        $other
    };
    ($other:tt) => {
        stringify!($other)
    };
}

macro_rules! pretty_str {
    ($json:tt) => {
        pretty_str_impl!("", $json)
    };
}

macro_rules! pretty_str_impl {
    ($indent:expr, []) => {
        "[]"
    };
    ($indent:expr, [ $e1:tt $(, $e:tt)* ]) => {
        concat!("[\n  ",
            $indent, pretty_str_impl!(concat!("  ", $indent), $e1),
            $(",\n  ", $indent, pretty_str_impl!(concat!("  ", $indent), $e),)*
        "\n", $indent, "]")
    };
    ($indent:expr, {}) => {
        "{}"
    };
    ($indent:expr, { $k1:tt : $v1:tt $(, $k:tt : $v:tt)* }) => {
        concat!("{\n  ",
            $indent, stringify!($k1), ": ", pretty_str_impl!(concat!("  ", $indent), $v1),
            $(",\n  ", $indent, stringify!($k), ": ", pretty_str_impl!(concat!("  ", $indent), $v),)*
        "\n", $indent, "}")
    };
    ($indent:expr, ($other:tt)) => {
        $other
    };
    ($indent:expr, $other:tt) => {
        stringify!($other)
    };
}
