1use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
2
3#[proc_macro]
8pub fn deborrow(ts: TokenStream) -> TokenStream {
9 let mut ts = ts.into_iter();
10 let item = ts
11 .next()
12 .expect("expected item in deborrow!($item $(,$|:) $($field $(,)? )*)");
13 if !matches!(
14 ts.next(),
15 Some(TokenTree::Punct(x))
16 if x.as_char() == ',' || x.as_char() == ':'
17 ) {
18 panic!("expected , in deborrow!($item $(,$|:) $($field $(,)? )*)");
19 }
20 let fields = ts
21 .filter(|x| !matches!(x, TokenTree::Punct(_)))
22 .collect::<Vec<_>>();
23 let mut result = Vec::new();
24 result.append(
25 &mut ("fn __deborrow_unify<'a, "
26 .parse::<TokenStream>()
27 .unwrap()
28 .into_iter()
29 .collect::<Vec<_>>()),
30 );
31 result.append(
32 &mut fields
33 .iter()
34 .flat_map(|x| {
35 vec![
36 TokenTree::Ident(Ident::new(
37 &("T".to_owned() + &x.to_string()),
38 Span::mixed_site(),
39 )),
40 TokenTree::Punct(Punct::new(',', Spacing::Alone)),
41 ]
42 })
43 .collect::<Vec<_>>(),
44 );
45 result.push(TokenTree::Punct(Punct::new('>', Spacing::Alone)));
46 result.push(TokenTree::Group(Group::new(
47 Delimiter::Parenthesis,
48 TokenStream::from_iter(fields.iter().flat_map(|x| {
49 vec![
50 x.to_owned(),
51 TokenTree::Punct(Punct::new(':', Spacing::Alone)),
52 TokenTree::Punct(Punct::new('&', Spacing::Joint)),
53 TokenTree::Punct(Punct::new('\'', Spacing::Joint)),
54 TokenTree::Ident(Ident::new("a", Span::mixed_site())),
55 TokenTree::Ident(Ident::new("mut", Span::mixed_site())),
56 TokenTree::Ident(Ident::new(
57 &("T".to_owned() + &x.to_string()),
58 Span::mixed_site(),
59 )),
60 TokenTree::Punct(Punct::new(',', Spacing::Alone)),
61 ]
62 })),
63 )));
64 result.append(
65 &mut ("->"
66 .parse::<TokenStream>()
67 .unwrap()
68 .into_iter()
69 .collect::<Vec<_>>()),
70 );
71 result.push(TokenTree::Group(Group::new(
72 Delimiter::Parenthesis,
73 TokenStream::from_iter(fields.iter().flat_map(|x| {
74 vec![
75 TokenTree::Punct(Punct::new('&', Spacing::Joint)),
76 TokenTree::Punct(Punct::new('\'', Spacing::Joint)),
77 TokenTree::Ident(Ident::new("a", Span::mixed_site())),
78 TokenTree::Ident(Ident::new("mut", Span::mixed_site())),
79 TokenTree::Ident(Ident::new(
80 &("T".to_owned() + &x.to_string()),
81 Span::mixed_site(),
82 )),
83 TokenTree::Punct(Punct::new(',', Spacing::Alone)),
84 ]
85 })),
86 )));
87 result.push(TokenTree::Group(Group::new(
88 Delimiter::Brace,
89 TokenTree::Group(Group::new(
90 Delimiter::Parenthesis,
91 TokenStream::from_iter(fields.iter().flat_map(|x| {
92 vec![
93 x.to_owned(),
94 TokenTree::Punct(Punct::new(',', Spacing::Alone)),
95 ]
96 })),
97 ))
98 .into(),
99 )));
100 let mut tuple = vec![];
101 for field in &fields[0..fields.len() - 1] {
102 tuple.push(TokenTree::Ident(Ident::new("unsafe", Span::mixed_site())));
103 let mut e = ("::deborrow::deborrow_mut".parse::<TokenStream>().unwrap())
104 .into_iter()
105 .collect::<Vec<_>>();
106 e.push(TokenTree::Group(Group::new(
107 Delimiter::Parenthesis,
108 TokenStream::from_iter(vec![
109 TokenTree::Punct(Punct::new('&', Spacing::Joint)),
110 TokenTree::Ident(Ident::new("mut", Span::mixed_site())),
111 item.clone(),
112 TokenTree::Punct(Punct::new('.', Spacing::Alone)),
113 field.clone(),
114 ]),
115 )));
116 tuple.push(TokenTree::Group(Group::new(
117 Delimiter::Brace,
118 TokenStream::from_iter(e.into_iter()),
119 )));
120 tuple.push(TokenTree::Punct(Punct::new(',', Spacing::Alone)));
121 }
122 if !fields.is_empty() {
123 tuple.push(TokenTree::Group(Group::new(
124 Delimiter::Parenthesis,
125 TokenStream::from_iter(vec![
126 TokenTree::Punct(Punct::new('&', Spacing::Joint)),
127 TokenTree::Ident(Ident::new("mut", Span::mixed_site())),
128 item,
129 TokenTree::Punct(Punct::new('.', Spacing::Alone)),
130 fields[fields.len() - 1].clone(),
131 ]),
132 )));
133 tuple.push(TokenTree::Punct(Punct::new(',', Spacing::Alone)));
134 }
135 result.push(TokenTree::Ident(Ident::new(
136 "__deborrow_unify",
137 Span::mixed_site(),
138 )));
139 result.push(TokenTree::Group(Group::new(
140 Delimiter::Parenthesis,
141 TokenStream::from_iter(tuple.into_iter()),
142 )));
143 TokenStream::from(TokenTree::Group(Group::new(
144 Delimiter::Brace,
145 TokenStream::from_iter(result.into_iter()),
146 )))
147}