serde_derive/
lib.rs

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    // Depth-first post-order traversal.
76    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())] // FIXME
213            return span.join(self.spans[hi as usize]).unwrap_or(span);
214            span
215        }
216    }
217}