1extern crate proc_macro;
2
3mod buffer;
4mod bytecode;
5
6use crate::buffer::{InputBuffer, OutputBuffer};
7use crate::bytecode::Bytecode;
8use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
9use std::io::{Read, Write};
10use std::iter::FromIterator;
11use std::process::{Command, Stdio};
12use std::str::FromStr;
13
14#[cfg(not(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu")))]
15compile_error! {
16 "this proof of concept is only compiled for x86_64-unknown-linux-gnu"
17}
18
19#[proc_macro_derive(Serialize, attributes(serde))]
20pub fn derive_serialize(input: TokenStream) -> TokenStream {
21 derive(0, input)
22}
23
24#[proc_macro_derive(Deserialize, attributes(serde))]
25pub fn derive_deserialize(input: TokenStream) -> TokenStream {
26 derive(1 + cfg!(feature = "deserialize_in_place") as u8, input)
27}
28
29fn derive(select: u8, input: TokenStream) -> TokenStream {
30 let mut memory = TokenMemory::default();
31 let mut buf = OutputBuffer::new();
32 buf.write_u8(select);
33
34 memory.spans.push(Span::call_site());
35 for token in input {
36 memory.linearize_token(token, &mut buf);
37 }
38
39 let mut child = Command::new(concat!(env!("CARGO_MANIFEST_DIR"), "/serde_derive"))
40 .stdin(Stdio::piped())
41 .stdout(Stdio::piped())
42 .spawn()
43 .expect("failed to spawn process");
44
45 let mut stdin = child.stdin.take().unwrap();
46 let mut buf = buf.into_bytes();
47 stdin.write_all(&buf).unwrap();
48 drop(stdin);
49
50 let mut stdout = child.stdout.take().unwrap();
51 buf.clear();
52 stdout.read_to_end(&mut buf).unwrap();
53
54 let mut buf = InputBuffer::new(&buf);
55 memory.receive(&mut buf)
56}
57
58#[derive(Default)]
59struct TokenMemory {
60 spans: Vec<Span>,
61 groups: Vec<Group>,
62 idents: Vec<Ident>,
63 puncts: Vec<Punct>,
64 literals: Vec<Literal>,
65}
66
67enum Kind {
68 Group(Delimiter),
69 Ident,
70 Punct(Spacing),
71 Literal,
72}
73
74impl TokenMemory {
75 fn linearize_token(&mut self, token: TokenTree, buf: &mut OutputBuffer) {
77 match token {
78 TokenTree::Group(group) => {
79 let mut len = 0usize;
80 for token in group.stream() {
81 self.linearize_token(token, buf);
82 len += 1;
83 }
84 assert!(len <= u32::MAX as usize);
85 buf.write_u8(match group.delimiter() {
86 Delimiter::Parenthesis => Bytecode::GROUP_PARENTHESIS,
87 Delimiter::Brace => Bytecode::GROUP_BRACE,
88 Delimiter::Bracket => Bytecode::GROUP_BRACKET,
89 Delimiter::None => Bytecode::GROUP_NONE,
90 });
91 buf.write_u32(len as u32);
92 self.spans
93 .extend([group.span(), group.span_open(), group.span_close()]);
94 self.groups.push(group);
95 }
96 TokenTree::Ident(ident) => {
97 buf.write_u8(Bytecode::IDENT);
98 let repr = ident.to_string();
99 assert!(repr.len() <= u16::MAX as usize);
100 buf.write_u16(repr.len() as u16);
101 buf.write_str(&repr);
102 self.spans.push(ident.span());
103 self.idents.push(ident);
104 }
105 TokenTree::Punct(punct) => {
106 buf.write_u8(match punct.spacing() {
107 Spacing::Alone => Bytecode::PUNCT_ALONE,
108 Spacing::Joint => Bytecode::PUNCT_JOINT,
109 });
110 let ch = punct.as_char();
111 assert!(ch.is_ascii());
112 buf.write_u8(ch as u8);
113 self.spans.push(punct.span());
114 self.puncts.push(punct);
115 }
116 TokenTree::Literal(literal) => {
117 buf.write_u8(Bytecode::LITERAL);
118 let repr = literal.to_string();
119 assert!(repr.len() <= u16::MAX as usize);
120 buf.write_u16(repr.len() as u16);
121 buf.write_str(&repr);
122 self.spans.push(literal.span());
123 self.literals.push(literal);
124 }
125 }
126 }
127
128 fn receive(&self, buf: &mut InputBuffer) -> TokenStream {
129 let mut trees = Vec::new();
130 while !buf.is_empty() {
131 match match buf.read_u8() {
132 Bytecode::GROUP_PARENTHESIS => Kind::Group(Delimiter::Parenthesis),
133 Bytecode::GROUP_BRACE => Kind::Group(Delimiter::Brace),
134 Bytecode::GROUP_BRACKET => Kind::Group(Delimiter::Bracket),
135 Bytecode::GROUP_NONE => Kind::Group(Delimiter::None),
136 Bytecode::IDENT => Kind::Ident,
137 Bytecode::PUNCT_ALONE => Kind::Punct(Spacing::Alone),
138 Bytecode::PUNCT_JOINT => Kind::Punct(Spacing::Joint),
139 Bytecode::LITERAL => Kind::Literal,
140 Bytecode::LOAD_GROUP => {
141 let identity = buf.read_u32();
142 let group = self.groups[identity as usize].clone();
143 trees.push(TokenTree::Group(group));
144 continue;
145 }
146 Bytecode::LOAD_IDENT => {
147 let identity = buf.read_u32();
148 let ident = self.idents[identity as usize].clone();
149 trees.push(TokenTree::Ident(ident));
150 continue;
151 }
152 Bytecode::LOAD_PUNCT => {
153 let identity = buf.read_u32();
154 let punct = self.puncts[identity as usize].clone();
155 trees.push(TokenTree::Punct(punct));
156 continue;
157 }
158 Bytecode::LOAD_LITERAL => {
159 let identity = buf.read_u32();
160 let literal = self.literals[identity as usize].clone();
161 trees.push(TokenTree::Literal(literal));
162 continue;
163 }
164 Bytecode::SET_SPAN => {
165 trees.last_mut().unwrap().set_span(self.read_span(buf));
166 continue;
167 }
168 _ => unreachable!(),
169 } {
170 Kind::Group(delimiter) => {
171 let len = buf.read_u32();
172 let stream = trees.drain(trees.len() - len as usize..).collect();
173 let group = Group::new(delimiter, stream);
174 trees.push(TokenTree::Group(group));
175 }
176 Kind::Ident => {
177 let len = buf.read_u16();
178 let repr = buf.read_str(len as usize);
179 let span = self.read_span(buf);
180 let ident = if let Some(repr) = repr.strip_prefix("r#") {
181 Ident::new_raw(repr, span)
182 } else {
183 Ident::new(repr, span)
184 };
185 trees.push(TokenTree::Ident(ident));
186 }
187 Kind::Punct(spacing) => {
188 let ch = buf.read_u8();
189 assert!(ch.is_ascii());
190 let punct = Punct::new(ch as char, spacing);
191 trees.push(TokenTree::Punct(punct));
192 }
193 Kind::Literal => {
194 let len = buf.read_u16();
195 let repr = buf.read_str(len as usize);
196 let literal = Literal::from_str(repr).unwrap();
197 trees.push(TokenTree::Literal(literal));
198 }
199 }
200 }
201
202 TokenStream::from_iter(trees)
203 }
204
205 fn read_span(&self, buf: &mut InputBuffer) -> Span {
206 let lo = buf.read_u32();
207 let hi = buf.read_u32();
208 let span = self.spans[lo as usize];
209 if lo == hi {
210 span
211 } else {
212 #[cfg(any())] return span.join(self.spans[hi as usize]).unwrap_or(span);
214 span
215 }
216 }
217}