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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
use std::fmt::Write;
use proc_macro2::{Delimiter, Spacing, TokenTree};
use quote::ToTokens;
pub trait ToTokensExt
{
fn to_str_pretty(&self) -> String;
}
impl<T: ToTokens> ToTokensExt for T
{
fn to_str_pretty(&self) -> String
{
let mut spaceable = Spaceable::None;
self.to_token_stream()
.into_iter()
.fold(String::new(), |mut acc, token_tree| {
let prev_spaceable = spaceable;
spaceable = get_tt_spaceable(&token_tree);
if matches!(prev_spaceable, Spaceable::Left | Spaceable::LeftRight)
&& matches!(spaceable, Spaceable::Right | Spaceable::LeftRight)
{
write!(acc, " ").ok();
}
match token_tree {
TokenTree::Group(group) => match group.delimiter() {
Delimiter::Parenthesis => {
write!(acc, "({})", group.stream().to_str_pretty()).ok();
}
Delimiter::Brace => {
write!(acc, "{{{}}}", group.stream().to_str_pretty()).ok();
}
Delimiter::Bracket => {
write!(acc, "[{}]", group.stream().to_str_pretty()).ok();
}
Delimiter::None => {
write!(acc, "{}", group.stream().to_str_pretty()).ok();
}
},
tt => {
write!(acc, "{tt}").ok();
}
}
acc
})
}
}
fn get_tt_spaceable(token_tree: &TokenTree) -> Spaceable
{
match &token_tree {
TokenTree::Ident(_) => Spaceable::LeftRight,
TokenTree::Punct(punct)
if punct.spacing() == Spacing::Alone && (punct.as_char() == '+') =>
{
Spaceable::LeftRight
}
TokenTree::Punct(punct)
if punct.spacing() == Spacing::Alone
&& (punct.as_char() == '>' || punct.as_char() == ',') =>
{
Spaceable::Left
}
TokenTree::Punct(punct)
if punct.spacing() == Spacing::Joint && punct.as_char() == '-' =>
{
// Is part of ->
Spaceable::Right
}
TokenTree::Punct(punct) if punct.as_char() == '&' => Spaceable::Right,
TokenTree::Group(_) => Spaceable::Left,
_ => Spaceable::None,
}
}
#[derive(Debug, Clone, Copy)]
enum Spaceable
{
Left,
Right,
LeftRight,
None,
}
|