-
-
Notifications
You must be signed in to change notification settings - Fork 793
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement fallback to compiling serde_derive from source
- Loading branch information
Showing
17 changed files
with
303 additions
and
240 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../LICENSE-APACHE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../LICENSE-MIT |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../README.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../crates-io.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../serde_derive/src/bound.rs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../serde_derive/src/de.rs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../serde_derive/src/dummy.rs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../serde_derive/src/fragment.rs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../serde_derive/src/internals/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,221 +1,25 @@ | ||
extern crate proc_macro; | ||
|
||
mod buffer; | ||
mod bytecode; | ||
//! This crate provides Serde's two derive macros. | ||
//! | ||
//! ```edition2021 | ||
//! # use serde_derive::{Deserialize, Serialize}; | ||
//! # | ||
//! #[derive(Serialize, Deserialize)] | ||
//! # struct S; | ||
//! # | ||
//! # fn main() {} | ||
//! ``` | ||
//! | ||
//! Please refer to [https://serde.rs/derive.html] for how to set this up. | ||
//! | ||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html | ||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.171")] | ||
#![allow(unknown_lints, bare_trait_objects)] | ||
|
||
use crate::buffer::{InputBuffer, OutputBuffer}; | ||
use crate::bytecode::Bytecode; | ||
use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; | ||
use std::io::{Read, Write}; | ||
use std::iter::FromIterator; | ||
use std::process::{Command, Stdio}; | ||
use std::str::FromStr; | ||
extern crate proc_macro; | ||
|
||
#[cfg(not(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu")))] | ||
compile_error! { | ||
"this proof of concept is only compiled for x86_64-unknown-linux-gnu" | ||
} | ||
|
||
#[proc_macro_derive(Serialize, attributes(serde))] | ||
pub fn derive_serialize(input: TokenStream) -> TokenStream { | ||
derive(0, input) | ||
} | ||
|
||
#[proc_macro_derive(Deserialize, attributes(serde))] | ||
pub fn derive_deserialize(input: TokenStream) -> TokenStream { | ||
derive(1 + cfg!(feature = "deserialize_in_place") as u8, input) | ||
} | ||
|
||
fn derive(select: u8, input: TokenStream) -> TokenStream { | ||
let mut memory = TokenMemory::default(); | ||
let mut buf = OutputBuffer::new(); | ||
buf.write_u8(select); | ||
|
||
memory.spans.push(Span::call_site()); | ||
for token in input { | ||
memory.linearize_token(token, &mut buf); | ||
} | ||
|
||
let path = concat!( | ||
env!("CARGO_MANIFEST_DIR"), | ||
"/serde_derive-x86_64-unknown-linux-gnu", | ||
); | ||
let mut child = Command::new(path) | ||
.stdin(Stdio::piped()) | ||
.stdout(Stdio::piped()) | ||
.spawn() | ||
.expect("failed to spawn process"); | ||
|
||
let mut stdin = child.stdin.take().unwrap(); | ||
let mut buf = buf.into_bytes(); | ||
stdin.write_all(&buf).unwrap(); | ||
drop(stdin); | ||
|
||
let mut stdout = child.stdout.take().unwrap(); | ||
buf.clear(); | ||
stdout.read_to_end(&mut buf).unwrap(); | ||
|
||
let mut buf = InputBuffer::new(&buf); | ||
memory.receive(&mut buf) | ||
} | ||
|
||
#[derive(Default)] | ||
struct TokenMemory { | ||
spans: Vec<Span>, | ||
groups: Vec<Group>, | ||
idents: Vec<Ident>, | ||
puncts: Vec<Punct>, | ||
literals: Vec<Literal>, | ||
} | ||
|
||
enum Kind { | ||
Group(Delimiter), | ||
Ident, | ||
Punct(Spacing), | ||
Literal, | ||
} | ||
|
||
impl TokenMemory { | ||
// Depth-first post-order traversal. | ||
fn linearize_token(&mut self, token: TokenTree, buf: &mut OutputBuffer) { | ||
match token { | ||
TokenTree::Group(group) => { | ||
let mut len = 0usize; | ||
for token in group.stream() { | ||
self.linearize_token(token, buf); | ||
len += 1; | ||
} | ||
assert!(len <= u32::MAX as usize); | ||
buf.write_u8(match group.delimiter() { | ||
Delimiter::Parenthesis => Bytecode::GROUP_PARENTHESIS, | ||
Delimiter::Brace => Bytecode::GROUP_BRACE, | ||
Delimiter::Bracket => Bytecode::GROUP_BRACKET, | ||
Delimiter::None => Bytecode::GROUP_NONE, | ||
}); | ||
buf.write_u32(len as u32); | ||
self.spans | ||
.extend([group.span(), group.span_open(), group.span_close()]); | ||
self.groups.push(group); | ||
} | ||
TokenTree::Ident(ident) => { | ||
buf.write_u8(Bytecode::IDENT); | ||
let repr = ident.to_string(); | ||
assert!(repr.len() <= u16::MAX as usize); | ||
buf.write_u16(repr.len() as u16); | ||
buf.write_str(&repr); | ||
self.spans.push(ident.span()); | ||
self.idents.push(ident); | ||
} | ||
TokenTree::Punct(punct) => { | ||
buf.write_u8(match punct.spacing() { | ||
Spacing::Alone => Bytecode::PUNCT_ALONE, | ||
Spacing::Joint => Bytecode::PUNCT_JOINT, | ||
}); | ||
let ch = punct.as_char(); | ||
assert!(ch.is_ascii()); | ||
buf.write_u8(ch as u8); | ||
self.spans.push(punct.span()); | ||
self.puncts.push(punct); | ||
} | ||
TokenTree::Literal(literal) => { | ||
buf.write_u8(Bytecode::LITERAL); | ||
let repr = literal.to_string(); | ||
assert!(repr.len() <= u16::MAX as usize); | ||
buf.write_u16(repr.len() as u16); | ||
buf.write_str(&repr); | ||
self.spans.push(literal.span()); | ||
self.literals.push(literal); | ||
} | ||
} | ||
} | ||
|
||
fn receive(&self, buf: &mut InputBuffer) -> TokenStream { | ||
let mut trees = Vec::new(); | ||
while !buf.is_empty() { | ||
match match buf.read_u8() { | ||
Bytecode::GROUP_PARENTHESIS => Kind::Group(Delimiter::Parenthesis), | ||
Bytecode::GROUP_BRACE => Kind::Group(Delimiter::Brace), | ||
Bytecode::GROUP_BRACKET => Kind::Group(Delimiter::Bracket), | ||
Bytecode::GROUP_NONE => Kind::Group(Delimiter::None), | ||
Bytecode::IDENT => Kind::Ident, | ||
Bytecode::PUNCT_ALONE => Kind::Punct(Spacing::Alone), | ||
Bytecode::PUNCT_JOINT => Kind::Punct(Spacing::Joint), | ||
Bytecode::LITERAL => Kind::Literal, | ||
Bytecode::LOAD_GROUP => { | ||
let identity = buf.read_u32(); | ||
let group = self.groups[identity as usize].clone(); | ||
trees.push(TokenTree::Group(group)); | ||
continue; | ||
} | ||
Bytecode::LOAD_IDENT => { | ||
let identity = buf.read_u32(); | ||
let ident = self.idents[identity as usize].clone(); | ||
trees.push(TokenTree::Ident(ident)); | ||
continue; | ||
} | ||
Bytecode::LOAD_PUNCT => { | ||
let identity = buf.read_u32(); | ||
let punct = self.puncts[identity as usize].clone(); | ||
trees.push(TokenTree::Punct(punct)); | ||
continue; | ||
} | ||
Bytecode::LOAD_LITERAL => { | ||
let identity = buf.read_u32(); | ||
let literal = self.literals[identity as usize].clone(); | ||
trees.push(TokenTree::Literal(literal)); | ||
continue; | ||
} | ||
Bytecode::SET_SPAN => { | ||
trees.last_mut().unwrap().set_span(self.read_span(buf)); | ||
continue; | ||
} | ||
_ => unreachable!(), | ||
} { | ||
Kind::Group(delimiter) => { | ||
let len = buf.read_u32(); | ||
let stream = trees.drain(trees.len() - len as usize..).collect(); | ||
let group = Group::new(delimiter, stream); | ||
trees.push(TokenTree::Group(group)); | ||
} | ||
Kind::Ident => { | ||
let len = buf.read_u16(); | ||
let repr = buf.read_str(len as usize); | ||
let span = self.read_span(buf); | ||
let ident = if let Some(repr) = repr.strip_prefix("r#") { | ||
Ident::new_raw(repr, span) | ||
} else { | ||
Ident::new(repr, span) | ||
}; | ||
trees.push(TokenTree::Ident(ident)); | ||
} | ||
Kind::Punct(spacing) => { | ||
let ch = buf.read_u8(); | ||
assert!(ch.is_ascii()); | ||
let punct = Punct::new(ch as char, spacing); | ||
trees.push(TokenTree::Punct(punct)); | ||
} | ||
Kind::Literal => { | ||
let len = buf.read_u16(); | ||
let repr = buf.read_str(len as usize); | ||
let literal = Literal::from_str(repr).unwrap(); | ||
trees.push(TokenTree::Literal(literal)); | ||
} | ||
} | ||
} | ||
|
||
TokenStream::from_iter(trees) | ||
} | ||
include!("lib_from_source.rs"); | ||
|
||
fn read_span(&self, buf: &mut InputBuffer) -> Span { | ||
let lo = buf.read_u32(); | ||
let hi = buf.read_u32(); | ||
let span = self.spans[lo as usize]; | ||
if lo == hi { | ||
span | ||
} else { | ||
#[cfg(any())] // FIXME | ||
return span.join(self.spans[hi as usize]).unwrap_or(span); | ||
span | ||
} | ||
} | ||
} | ||
#[cfg(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu"))] | ||
include!("lib_precompiled.rs"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#[macro_use] | ||
extern crate quote; | ||
#[macro_use] | ||
extern crate syn; | ||
|
||
extern crate proc_macro2; | ||
|
||
mod internals; | ||
|
||
use proc_macro::TokenStream; | ||
use syn::DeriveInput; | ||
|
||
#[macro_use] | ||
mod bound; | ||
#[macro_use] | ||
mod fragment; | ||
|
||
mod de; | ||
mod dummy; | ||
mod pretend; | ||
mod ser; | ||
mod this; | ||
mod try; | ||
|
||
#[proc_macro_derive(Serialize, attributes(serde))] | ||
pub fn derive_serialize(input: TokenStream) -> TokenStream { | ||
let mut input = parse_macro_input!(input as DeriveInput); | ||
ser::expand_derive_serialize(&mut input) | ||
.unwrap_or_else(syn::Error::into_compile_error) | ||
.into() | ||
} | ||
|
||
#[proc_macro_derive(Deserialize, attributes(serde))] | ||
pub fn derive_deserialize(input: TokenStream) -> TokenStream { | ||
let mut input = parse_macro_input!(input as DeriveInput); | ||
de::expand_derive_deserialize(&mut input) | ||
.unwrap_or_else(syn::Error::into_compile_error) | ||
.into() | ||
} |
Oops, something went wrong.