diff --git a/precompiled/.gitignore b/precompiled/.gitignore new file mode 100644 index 000000000..b4ac4d993 --- /dev/null +++ b/precompiled/.gitignore @@ -0,0 +1 @@ +/x86_64-unknown-linux-gnu/serde_derive diff --git a/precompiled/Cargo.toml b/precompiled/Cargo.toml new file mode 100644 index 000000000..44a1d8953 --- /dev/null +++ b/precompiled/Cargo.toml @@ -0,0 +1,14 @@ +[workspace] +members = ["proc-macro2", "serde_derive"] +resolver = "2" + +[patch.crates-io] +proc-macro2 = { path = "proc-macro2" } + +[profile.precompiled] +inherits = "release" +codegen-units = 1 +lto = true +opt-level = "z" +panic = "abort" +strip = true diff --git a/precompiled/build.sh b/precompiled/build.sh new file mode 100755 index 000000000..38134ae06 --- /dev/null +++ b/precompiled/build.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null + +cargo +nightly build \ + --manifest-path serde_derive/Cargo.toml \ + --bin serde_derive \ + --profile precompiled \ + -Z unstable-options \ + -Z build-std=std,panic_abort \ + -Z build-std-features=panic_immediate_abort \ + --target x86_64-unknown-linux-musl \ + --out-dir x86_64-unknown-linux-gnu + +#upx --best --lzma x86_64-unknown-linux-gnu/serde_derive diff --git a/precompiled/proc-macro2/Cargo.toml b/precompiled/proc-macro2/Cargo.toml new file mode 100644 index 000000000..e0788842e --- /dev/null +++ b/precompiled/proc-macro2/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "proc-macro2" +version = "1.0.66" +edition = "2021" +publish = false + +[dependencies] +proc-macro2 = { package = "proc-macro2-fallback", version = "1" } diff --git a/precompiled/proc-macro2/src/lib.rs b/precompiled/proc-macro2/src/lib.rs new file mode 100644 index 000000000..530897a98 --- /dev/null +++ b/precompiled/proc-macro2/src/lib.rs @@ -0,0 +1,816 @@ +#[doc(hidden)] +pub mod watt; + +use crate::extra::DelimSpan; +use crate::watt::Identity; +use std::cmp::Ordering; +use std::fmt::{self, Debug, Display}; +use std::hash::{Hash, Hasher}; +use std::ops::RangeBounds; +use std::str::FromStr; + +pub use proc_macro2::{Delimiter, Spacing}; + +#[derive(Copy, Clone)] +pub struct Span { + lo: u32, + hi: u32, +} + +impl Span { + pub fn call_site() -> Self { + Span { lo: 0, hi: 0 } + } + + pub fn join(&self, other: Self) -> Option { + Some(Span { + lo: self.lo, + hi: other.hi, + }) + } +} + +#[derive(Clone)] +pub enum TokenTree { + Group(Group), + Ident(Ident), + Punct(Punct), + Literal(Literal), +} + +impl TokenTree { + pub fn span(&self) -> Span { + match self { + TokenTree::Group(group) => group.span(), + TokenTree::Ident(ident) => ident.span(), + TokenTree::Punct(punct) => punct.span(), + TokenTree::Literal(literal) => literal.span(), + } + } + + pub fn set_span(&mut self, span: Span) { + match self { + TokenTree::Group(group) => group.set_span(span), + TokenTree::Ident(ident) => ident.set_span(span), + TokenTree::Punct(punct) => punct.set_span(span), + TokenTree::Literal(literal) => literal.set_span(span), + } + } +} + +impl From for TokenTree { + fn from(group: Group) -> Self { + TokenTree::Group(group) + } +} + +impl From for TokenTree { + fn from(ident: Ident) -> Self { + TokenTree::Ident(ident) + } +} + +impl From for TokenTree { + fn from(punct: Punct) -> Self { + TokenTree::Punct(punct) + } +} + +impl From for TokenTree { + fn from(literal: Literal) -> Self { + TokenTree::Literal(literal) + } +} + +impl Debug for TokenTree { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + TokenTree::Group(group) => Debug::fmt(group, formatter), + TokenTree::Ident(ident) => { + let mut debug = formatter.debug_struct("Ident"); + debug.field("sym", &format_args!("{}", ident)); + debug.finish() + } + TokenTree::Punct(punct) => Debug::fmt(punct, formatter), + TokenTree::Literal(literal) => Debug::fmt(literal, formatter), + } + } +} + +#[derive(Clone)] +pub struct Group { + delimiter: Delimiter, + stream: Vec, + span: Span, + span_open: Span, + span_close: Span, + identity: u32, +} + +impl Group { + pub fn new(delimiter: Delimiter, stream: TokenStream) -> Self { + Group { + delimiter, + stream: stream.content, + span: Span::call_site(), + span_open: Span::call_site(), + span_close: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn stream(&self) -> TokenStream { + TokenStream { + content: self.stream.clone(), + } + } + + pub fn delimiter(&self) -> Delimiter { + self.delimiter + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn span_open(&self) -> Span { + self.span_open + } + + pub fn span_close(&self) -> Span { + self.span_close + } + + pub fn delim_span(&self) -> DelimSpan { + DelimSpan { + open: self.span_open(), + close: self.span_close(), + } + } + + pub fn set_span(&mut self, span: Span) { + self.span = span; + self.identity |= Identity::RESPANNED; + } +} + +impl Display for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let (open, close) = match self.delimiter { + Delimiter::Parenthesis => ("(", ")"), + Delimiter::Brace => ("{ ", "}"), + Delimiter::Bracket => ("[", "]"), + Delimiter::None => ("", ""), + }; + + formatter.write_str(open)?; + display_tokens(&self.stream, formatter)?; + if self.delimiter == Delimiter::Brace && !self.stream.is_empty() { + formatter.write_str(" ")?; + } + formatter.write_str(close)?; + + Ok(()) + } +} + +impl Debug for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut debug = formatter.debug_struct("Group"); + debug.field("delimiter", &self.delimiter); + debug.field("stream", &self.stream); + debug.finish() + } +} + +#[derive(Clone)] +pub struct Ident { + fallback: proc_macro2::Ident, + span: Span, + identity: u32, +} + +impl Ident { + pub fn new(string: &str, span: Span) -> Self { + Ident { + fallback: proc_macro2::Ident::new(string, proc_macro2::Span::call_site()), + span, + identity: Identity::NOVEL, + } + } + + pub fn new_raw(string: &str, span: Span) -> Self { + Ident { + fallback: proc_macro2::Ident::new_raw(string, proc_macro2::Span::call_site()), + span, + identity: Identity::NOVEL, + } + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn set_span(&mut self, span: Span) { + self.span = span; + self.identity |= Identity::RESPANNED; + } +} + +impl Display for Ident { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.fallback, formatter) + } +} + +impl Debug for Ident { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.fallback, formatter) + } +} + +impl Eq for Ident {} + +impl PartialEq for Ident { + fn eq(&self, other: &Self) -> bool { + PartialEq::eq(&self.fallback, &other.fallback) + } +} + +impl PartialEq for Ident +where + T: ?Sized + AsRef, +{ + fn eq(&self, other: &T) -> bool { + PartialEq::eq(&self.fallback, other) + } +} + +impl Ord for Ident { + fn cmp(&self, other: &Self) -> Ordering { + Ord::cmp(&self.fallback, &other.fallback) + } +} + +impl PartialOrd for Ident { + fn partial_cmp(&self, other: &Self) -> Option { + PartialOrd::partial_cmp(&self.fallback, &other.fallback) + } +} + +impl Hash for Ident { + fn hash(&self, hasher: &mut H) { + Hash::hash(&self.fallback, hasher); + } +} + +#[derive(Clone)] +pub struct Punct { + fallback: proc_macro2::Punct, + span: Span, + identity: u32, +} + +impl Punct { + pub fn new(ch: char, spacing: Spacing) -> Self { + Punct { + fallback: proc_macro2::Punct::new(ch, spacing), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn as_char(&self) -> char { + self.fallback.as_char() + } + + pub fn spacing(&self) -> Spacing { + self.fallback.spacing() + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn set_span(&mut self, span: Span) { + self.span = span; + self.identity |= Identity::RESPANNED; + } +} + +impl Display for Punct { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.fallback, formatter) + } +} + +impl Debug for Punct { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.fallback, formatter) + } +} + +#[derive(Clone)] +pub struct Literal { + fallback: proc_macro2::Literal, + span: Span, + identity: u32, +} + +impl Literal { + pub fn u8_suffixed(n: u8) -> Self { + Literal { + fallback: proc_macro2::Literal::u8_suffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn u16_suffixed(n: u16) -> Self { + Literal { + fallback: proc_macro2::Literal::u16_suffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn u32_suffixed(n: u32) -> Self { + Literal { + fallback: proc_macro2::Literal::u32_suffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn u64_suffixed(n: u64) -> Self { + Literal { + fallback: proc_macro2::Literal::u64_suffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn u128_suffixed(n: u128) -> Self { + Literal { + fallback: proc_macro2::Literal::u128_suffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn usize_suffixed(n: usize) -> Self { + Literal { + fallback: proc_macro2::Literal::usize_suffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn i8_suffixed(n: i8) -> Self { + Literal { + fallback: proc_macro2::Literal::i8_suffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn i16_suffixed(n: i16) -> Self { + Literal { + fallback: proc_macro2::Literal::i16_suffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn i32_suffixed(n: i32) -> Self { + Literal { + fallback: proc_macro2::Literal::i32_suffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn i64_suffixed(n: i64) -> Self { + Literal { + fallback: proc_macro2::Literal::i64_suffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn i128_suffixed(n: i128) -> Self { + Literal { + fallback: proc_macro2::Literal::i128_suffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn isize_suffixed(n: isize) -> Self { + Literal { + fallback: proc_macro2::Literal::isize_suffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn u8_unsuffixed(n: u8) -> Self { + Literal { + fallback: proc_macro2::Literal::u8_unsuffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn u16_unsuffixed(n: u16) -> Self { + Literal { + fallback: proc_macro2::Literal::u16_unsuffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn u32_unsuffixed(n: u32) -> Self { + Literal { + fallback: proc_macro2::Literal::u32_unsuffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn u64_unsuffixed(n: u64) -> Self { + Literal { + fallback: proc_macro2::Literal::u64_unsuffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn u128_unsuffixed(n: u128) -> Self { + Literal { + fallback: proc_macro2::Literal::u128_unsuffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn usize_unsuffixed(n: usize) -> Self { + Literal { + fallback: proc_macro2::Literal::usize_unsuffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn i8_unsuffixed(n: i8) -> Self { + Literal { + fallback: proc_macro2::Literal::i8_unsuffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn i16_unsuffixed(n: i16) -> Self { + Literal { + fallback: proc_macro2::Literal::i16_unsuffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn i32_unsuffixed(n: i32) -> Self { + Literal { + fallback: proc_macro2::Literal::i32_unsuffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn i64_unsuffixed(n: i64) -> Self { + Literal { + fallback: proc_macro2::Literal::i64_unsuffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn i128_unsuffixed(n: i128) -> Self { + Literal { + fallback: proc_macro2::Literal::i128_unsuffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn isize_unsuffixed(n: isize) -> Self { + Literal { + fallback: proc_macro2::Literal::isize_unsuffixed(n), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn f64_unsuffixed(f: f64) -> Self { + Literal { + fallback: proc_macro2::Literal::f64_unsuffixed(f), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn f64_suffixed(f: f64) -> Self { + Literal { + fallback: proc_macro2::Literal::f64_suffixed(f), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn f32_unsuffixed(f: f32) -> Self { + Literal { + fallback: proc_macro2::Literal::f32_unsuffixed(f), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn f32_suffixed(f: f32) -> Self { + Literal { + fallback: proc_macro2::Literal::f32_suffixed(f), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn string(string: &str) -> Self { + Literal { + fallback: proc_macro2::Literal::string(string), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn character(ch: char) -> Self { + Literal { + fallback: proc_macro2::Literal::character(ch), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn byte_string(s: &[u8]) -> Self { + Literal { + fallback: proc_macro2::Literal::byte_string(s), + span: Span::call_site(), + identity: Identity::NOVEL, + } + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn set_span(&mut self, span: Span) { + self.span = span; + self.identity |= Identity::RESPANNED; + } + + pub fn subspan>(&self, range: R) -> Option { + let _ = range; + None + } +} + +impl FromStr for Literal { + type Err = LexError; + + fn from_str(repr: &str) -> Result { + let fallback = match proc_macro2::Literal::from_str(repr) { + Ok(literal) => literal, + Err(error) => { + return Err(LexError { + fallback: error, + span: Span::call_site(), + }); + } + }; + Ok(Literal { + fallback, + span: Span::call_site(), + identity: Identity::NOVEL, + }) + } +} + +impl Display for Literal { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.fallback, formatter) + } +} + +impl Debug for Literal { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.fallback, formatter) + } +} + +#[derive(Clone)] +pub struct TokenStream { + content: Vec, +} + +impl TokenStream { + pub fn new() -> Self { + TokenStream { + content: Vec::new(), + } + } + + pub fn is_empty(&self) -> bool { + self.content.is_empty() + } +} + +impl IntoIterator for TokenStream { + type Item = TokenTree; + type IntoIter = token_stream::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + token_stream::IntoIter { + iter: self.content.into_iter(), + } + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I) { + self.content.extend(streams.into_iter().flatten()); + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I) { + self.content.extend(streams); + } +} + +impl FromIterator for TokenStream { + fn from_iter>(streams: I) -> Self { + let content = streams.into_iter().flatten().collect(); + TokenStream { content } + } +} + +impl FromIterator for TokenStream { + fn from_iter>(streams: I) -> Self { + let content = streams.into_iter().collect(); + TokenStream { content } + } +} + +impl FromStr for TokenStream { + type Err = LexError; + + fn from_str(string: &str) -> Result { + let fallback = match proc_macro2::TokenStream::from_str(string) { + Ok(token_stream) => token_stream, + Err(error) => { + return Err(LexError { + fallback: error, + span: Span::call_site(), + }); + } + }; + + fn convert_token_stream(stream: proc_macro2::TokenStream) -> TokenStream { + TokenStream { + content: stream.into_iter().map(convert_token_tree).collect(), + } + } + + fn convert_token_tree(token: proc_macro2::TokenTree) -> TokenTree { + match token { + proc_macro2::TokenTree::Group(group) => TokenTree::Group(Group::new( + group.delimiter(), + convert_token_stream(group.stream()), + )), + proc_macro2::TokenTree::Ident(ident) => TokenTree::Ident(Ident { + fallback: ident, + span: Span::call_site(), + identity: Identity::NOVEL, + }), + proc_macro2::TokenTree::Punct(punct) => TokenTree::Punct(Punct { + fallback: punct, + span: Span::call_site(), + identity: Identity::NOVEL, + }), + proc_macro2::TokenTree::Literal(literal) => TokenTree::Literal(Literal { + fallback: literal, + span: Span::call_site(), + identity: Identity::NOVEL, + }), + } + } + + Ok(convert_token_stream(fallback)) + } +} + +fn display_tokens(tokens: &[TokenTree], formatter: &mut fmt::Formatter) -> fmt::Result { + let mut joint = false; + for (i, token) in tokens.iter().enumerate() { + if i != 0 && !joint { + write!(formatter, " ")?; + } + joint = false; + match token { + TokenTree::Group(group) => Display::fmt(group, formatter), + TokenTree::Ident(ident) => Display::fmt(ident, formatter), + TokenTree::Punct(punct) => { + joint = punct.spacing() == Spacing::Joint; + Display::fmt(punct, formatter) + } + TokenTree::Literal(literal) => Display::fmt(literal, formatter), + }?; + } + + Ok(()) +} + +impl Display for TokenStream { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + display_tokens(&self.content, formatter) + } +} + +impl Debug for TokenStream { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("TokenStream ")?; + formatter.debug_list().entries(&self.content).finish() + } +} + +pub struct LexError { + fallback: proc_macro2::LexError, + span: Span, +} + +impl LexError { + pub fn span(&self) -> Span { + self.span + } +} + +impl Debug for LexError { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.fallback, formatter) + } +} + +pub mod token_stream { + use super::*; + + #[derive(Clone)] + pub struct IntoIter { + pub(crate) iter: as IntoIterator>::IntoIter, + } + + impl Iterator for IntoIter { + type Item = TokenTree; + + fn next(&mut self) -> Option { + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + } +} + +pub mod extra { + use crate::Span; + + #[derive(Copy, Clone)] + pub struct DelimSpan { + pub(crate) open: Span, + pub(crate) close: Span, + } + + impl DelimSpan { + pub fn join(&self) -> Span { + Span { + lo: self.open.lo, + hi: self.close.hi, + } + } + + pub fn open(&self) -> Span { + self.open + } + + pub fn close(&self) -> Span { + self.close + } + } +} diff --git a/precompiled/proc-macro2/src/watt/buffer.rs b/precompiled/proc-macro2/src/watt/buffer.rs new file mode 100644 index 000000000..887e806dc --- /dev/null +++ b/precompiled/proc-macro2/src/watt/buffer.rs @@ -0,0 +1,69 @@ +use std::str; + +pub struct OutputBuffer { + bytes: Vec, +} + +impl OutputBuffer { + pub fn new() -> Self { + OutputBuffer { bytes: Vec::new() } + } + + pub fn write_u8(&mut self, value: u8) { + self.bytes.push(value); + } + + pub fn write_u16(&mut self, value: u16) { + self.bytes.extend_from_slice(&value.to_le_bytes()); + } + + pub fn write_u32(&mut self, value: u32) { + self.bytes.extend_from_slice(&value.to_le_bytes()); + } + + pub fn write_str(&mut self, value: &str) { + self.bytes.extend_from_slice(value.as_bytes()); + } + + pub fn into_bytes(self) -> Vec { + self.bytes + } +} + +pub struct InputBuffer<'a> { + bytes: &'a [u8], +} + +impl<'a> InputBuffer<'a> { + pub fn new(bytes: &'a [u8]) -> Self { + InputBuffer { bytes } + } + + pub fn is_empty(&self) -> bool { + self.bytes.is_empty() + } + + pub fn read_u8(&mut self) -> u8 { + let (first, rest) = self.bytes.split_first().unwrap(); + self.bytes = rest; + *first + } + + pub fn read_u16(&mut self) -> u16 { + let (value, rest) = self.bytes.split_at(2); + self.bytes = rest; + u16::from_le_bytes([value[0], value[1]]) + } + + pub fn read_u32(&mut self) -> u32 { + let (value, rest) = self.bytes.split_at(4); + self.bytes = rest; + u32::from_le_bytes([value[0], value[1], value[2], value[3]]) + } + + pub fn read_str(&mut self, len: usize) -> &'a str { + let (string, rest) = self.bytes.split_at(len); + self.bytes = rest; + str::from_utf8(string).unwrap() + } +} diff --git a/precompiled/proc-macro2/src/watt/bytecode.rs b/precompiled/proc-macro2/src/watt/bytecode.rs new file mode 100644 index 000000000..a0f3edb23 --- /dev/null +++ b/precompiled/proc-macro2/src/watt/bytecode.rs @@ -0,0 +1,17 @@ +pub enum Bytecode {} + +impl Bytecode { + pub const GROUP_PARENTHESIS: u8 = 0; + pub const GROUP_BRACE: u8 = 1; + pub const GROUP_BRACKET: u8 = 2; + pub const GROUP_NONE: u8 = 3; + pub const IDENT: u8 = 4; + pub const PUNCT_ALONE: u8 = 5; + pub const PUNCT_JOINT: u8 = 6; + pub const LITERAL: u8 = 7; + pub const LOAD_GROUP: u8 = 8; + pub const LOAD_IDENT: u8 = 9; + pub const LOAD_PUNCT: u8 = 10; + pub const LOAD_LITERAL: u8 = 11; + pub const SET_SPAN: u8 = 12; +} diff --git a/precompiled/proc-macro2/src/watt/mod.rs b/precompiled/proc-macro2/src/watt/mod.rs new file mode 100644 index 000000000..833b54c00 --- /dev/null +++ b/precompiled/proc-macro2/src/watt/mod.rs @@ -0,0 +1,196 @@ +pub mod buffer; +pub mod bytecode; + +use crate::watt::buffer::{InputBuffer, OutputBuffer}; +use crate::watt::bytecode::Bytecode; +use crate::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; +use std::str::FromStr; + +pub enum Kind { + Group(Delimiter), + Ident, + Punct(Spacing), + Literal, +} + +pub enum Identity {} + +impl Identity { + pub const RESPANNED: u32 = 1 << 31; + pub const NOVEL: u32 = u32::MAX; +} + +impl Span { + fn is_call_site(&self) -> bool { + self.lo == 0 && self.hi == 0 + } +} + +fn post_increment(counter: &mut u32) -> impl FnMut() -> u32 + '_ { + || { + let value = *counter; + *counter += 1; + value + } +} + +pub fn load(buf: &mut InputBuffer) -> TokenStream { + let mut span_counter = 0; + let mut next_span = post_increment(&mut span_counter); + let mut next_span = || { + let next = next_span(); + Span { lo: next, hi: next } + }; + + let [mut group_counter, mut ident_counter, mut punct_counter, mut literal_counter] = [0; 4]; + let mut next_group = post_increment(&mut group_counter); + let mut next_ident = post_increment(&mut ident_counter); + let mut next_punct = post_increment(&mut punct_counter); + let mut next_literal = post_increment(&mut literal_counter); + + 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, + _ => unreachable!(), + } { + Kind::Group(delimiter) => { + let len = buf.read_u32(); + let stream = trees.drain(trees.len() - len as usize..).collect(); + trees.push(TokenTree::Group(Group { + delimiter, + stream, + span: next_span(), + span_open: next_span(), + span_close: next_span(), + identity: next_group(), + })); + } + Kind::Ident => { + let len = buf.read_u16(); + let repr = buf.read_str(len as usize); + trees.push(TokenTree::Ident(Ident { + fallback: proc_macro2::Ident::new(repr, proc_macro2::Span::call_site()), + span: next_span(), + identity: next_ident(), + })); + } + Kind::Punct(spacing) => { + let ch = buf.read_u8(); + assert!(ch.is_ascii()); + trees.push(TokenTree::Punct(Punct { + fallback: proc_macro2::Punct::new(ch as char, spacing), + span: next_span(), + identity: next_punct(), + })); + } + Kind::Literal => { + let len = buf.read_u16(); + let repr = buf.read_str(len as usize); + trees.push(TokenTree::Literal(Literal { + fallback: proc_macro2::Literal::from_str(repr).unwrap(), + span: next_span(), + identity: next_literal(), + })); + } + } + } + + TokenStream { content: trees } +} + +pub fn linearize(tokens: TokenStream) -> Vec { + let mut buf = OutputBuffer::new(); + for token in &tokens.content { + linearize_token(token, &mut buf); + } + buf.into_bytes() +} + +fn linearize_token(token: &TokenTree, buf: &mut OutputBuffer) { + let needs_span; + match token { + TokenTree::Group(group) => { + if group.identity < Identity::NOVEL { + buf.write_u8(Bytecode::LOAD_GROUP); + buf.write_u32(group.identity & !Identity::RESPANNED); + needs_span = group.identity >= Identity::RESPANNED; + } else { + let len = group.stream.len(); + assert!(len <= u32::MAX as usize); + for token in &group.stream { + linearize_token(token, buf); + } + 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); + needs_span = !group.span.is_call_site(); + } + } + TokenTree::Ident(ident) => { + if ident.identity < Identity::NOVEL { + buf.write_u8(Bytecode::LOAD_IDENT); + buf.write_u32(ident.identity & !Identity::RESPANNED); + needs_span = ident.identity >= Identity::RESPANNED; + } else { + 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); + linearize_span(ident.span, buf); + needs_span = false; + } + } + TokenTree::Punct(punct) => { + if punct.identity < Identity::NOVEL { + buf.write_u8(Bytecode::LOAD_PUNCT); + buf.write_u32(punct.identity & !Identity::RESPANNED); + needs_span = punct.identity >= Identity::RESPANNED; + } else { + 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); + needs_span = !punct.span.is_call_site(); + } + } + TokenTree::Literal(literal) => { + if literal.identity < Identity::NOVEL { + buf.write_u8(Bytecode::LOAD_LITERAL); + buf.write_u32(literal.identity & !Identity::RESPANNED); + needs_span = literal.identity >= Identity::RESPANNED; + } else { + 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); + needs_span = !literal.span.is_call_site(); + } + } + } + if needs_span { + buf.write_u8(Bytecode::SET_SPAN); + linearize_span(token.span(), buf); + } +} + +fn linearize_span(span: Span, buf: &mut OutputBuffer) { + buf.write_u32(span.lo); + buf.write_u32(span.hi); +} diff --git a/precompiled/serde_derive/Cargo.toml b/precompiled/serde_derive/Cargo.toml new file mode 100644 index 000000000..aa812d95e --- /dev/null +++ b/precompiled/serde_derive/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "serde_derive" +version = "1.0.171" +authors = ["David Tolnay "] +publish = false + +[lib] +doctest = false + +[[bin]] +name = "serde_derive" +path = "main.rs" + +[dependencies] +proc-macro2 = "1" +quote = { version = "1", default-features = false } +syn = { version = "2.0.25", default-features = false, features = ["clone-impls", "derive", "parsing", "printing"] } diff --git a/precompiled/serde_derive/build.rs b/precompiled/serde_derive/build.rs new file mode 100644 index 000000000..a5d2d1fe0 --- /dev/null +++ b/precompiled/serde_derive/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo:rustc-cfg=precompiled"); +} diff --git a/precompiled/serde_derive/main.rs b/precompiled/serde_derive/main.rs new file mode 100644 index 000000000..443300b24 --- /dev/null +++ b/precompiled/serde_derive/main.rs @@ -0,0 +1,22 @@ +extern crate proc_macro2; + +use proc_macro2::watt; +use proc_macro2::watt::buffer::InputBuffer; +use std::io::{self, Read, Write}; + +fn main() { + let mut buf = Vec::new(); + io::stdin().read_to_end(&mut buf).unwrap(); + + let mut buf = InputBuffer::new(&buf); + let derive = match buf.read_u8() { + 0 => serde_derive::derive_serialize, + 1 => serde_derive::derive_deserialize, + _ => unreachable!(), + }; + + let input = watt::load(&mut buf); + let output = derive(input); + let bytes = watt::linearize(output); + io::stdout().write_all(&bytes).unwrap(); +} diff --git a/precompiled/serde_derive/src b/precompiled/serde_derive/src new file mode 120000 index 000000000..0456a6209 --- /dev/null +++ b/precompiled/serde_derive/src @@ -0,0 +1 @@ +../../serde_derive/src \ No newline at end of file diff --git a/precompiled/x86_64-unknown-linux-gnu/Cargo.toml b/precompiled/x86_64-unknown-linux-gnu/Cargo.toml new file mode 100644 index 000000000..8dd79246a --- /dev/null +++ b/precompiled/x86_64-unknown-linux-gnu/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "serde_derive-x86_64-unknown-linux-gnu" +version = "1.0.171-alpha.0" +authors = ["David Tolnay "] +categories = ["no-std", "no-std::no-alloc"] +description = "Precompiled implementation of #[derive(Serialize, Deserialize)]" +documentation = "https://serde.rs/derive.html" +edition = "2015" +homepage = "https://serde.rs" +include = ["serde_derive", "src"] +keywords = ["serde", "serialization", "no_std", "derive"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/serde-rs/serde" + +[lib] +name = "serde_derive" +proc-macro = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[workspace] diff --git a/precompiled/x86_64-unknown-linux-gnu/README.md b/precompiled/x86_64-unknown-linux-gnu/README.md new file mode 100644 index 000000000..7f1cbac5a --- /dev/null +++ b/precompiled/x86_64-unknown-linux-gnu/README.md @@ -0,0 +1,16 @@ +```toml +# Cargo.toml + +[dependencies] +serde = "1" # no features=["derive"] +serde_derive-x86_64-unknown-linux-gnu = "1.0.171-alpha.0" +``` + +```rust +use serde_derive::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize)] +pub struct MyStruct { + /* ... */ +} +``` diff --git a/precompiled/x86_64-unknown-linux-gnu/src/buffer.rs b/precompiled/x86_64-unknown-linux-gnu/src/buffer.rs new file mode 120000 index 000000000..d2a542ad8 --- /dev/null +++ b/precompiled/x86_64-unknown-linux-gnu/src/buffer.rs @@ -0,0 +1 @@ +../../proc-macro2/src/watt/buffer.rs \ No newline at end of file diff --git a/precompiled/x86_64-unknown-linux-gnu/src/bytecode.rs b/precompiled/x86_64-unknown-linux-gnu/src/bytecode.rs new file mode 120000 index 000000000..209bf359c --- /dev/null +++ b/precompiled/x86_64-unknown-linux-gnu/src/bytecode.rs @@ -0,0 +1 @@ +../../proc-macro2/src/watt/bytecode.rs \ No newline at end of file diff --git a/precompiled/x86_64-unknown-linux-gnu/src/lib.rs b/precompiled/x86_64-unknown-linux-gnu/src/lib.rs new file mode 100644 index 000000000..0e868801b --- /dev/null +++ b/precompiled/x86_64-unknown-linux-gnu/src/lib.rs @@ -0,0 +1,213 @@ +extern crate proc_macro; + +mod buffer; +mod bytecode; + +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; + +#[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, 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 mut child = Command::new(concat!(env!("CARGO_MANIFEST_DIR"), "/serde_derive")) + .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, + groups: Vec, + idents: Vec, + puncts: Vec, + literals: Vec, +} + +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 = 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) + } + + 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 + } + } +} diff --git a/serde_derive/src/lib.rs b/serde_derive/src/lib.rs index 176628ad5..399bbc0a0 100644 --- a/serde_derive/src/lib.rs +++ b/serde_derive/src/lib.rs @@ -68,9 +68,13 @@ extern crate quote; #[macro_use] extern crate syn; +#[cfg(not(precompiled))] extern crate proc_macro; extern crate proc_macro2; +#[cfg(precompiled)] +extern crate proc_macro2 as proc_macro; + mod internals; use proc_macro::TokenStream; @@ -88,7 +92,17 @@ mod ser; mod this; mod try; -#[proc_macro_derive(Serialize, attributes(serde))] +#[cfg(precompiled)] +macro_rules! parse_macro_input { + ($tokenstream:ident as $ty:ty) => { + match syn::parse2::<$ty>($tokenstream) { + Ok(data) => data, + Err(err) => return err.to_compile_error(), + } + }; +} + +#[cfg_attr(not(precompiled), 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) @@ -96,7 +110,7 @@ pub fn derive_serialize(input: TokenStream) -> TokenStream { .into() } -#[proc_macro_derive(Deserialize, attributes(serde))] +#[cfg_attr(not(precompiled), 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)