8000 Third-party crates support: `proc-macro2`, `quote`, `syn`, `serde` and `serde_derive` by ojeda · Pull Request #1007 · Rust-for-Linux/linux · GitHub
[go: up one dir, main page]

Skip to content

Third-party crates support: proc-macro2, quote, syn, serde and serde_derive #1007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: rust-next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
rust: serde_derive: import crate
This is a subset of the Rust `serde_derive` crate,
version v1.0.156, licensed under "Apache-2.0 OR MIT", from:

    https://github.com/serde-rs/serde/tree/v1.0.156/serde_derive/src

The files are copied as-is, with no modifications whatsoever
(not even adding the SPDX identifiers).

For copyright details, please see:

    https://github.com/serde-rs/serde/blob/v1.0.156/README.md#license
    https://github.com/serde-rs/serde/blob/v1.0.156/LICENSE-APACHE
    https://github.com/serde-rs/serde/blob/v1.0.156/LICENSE-MIT

The next patch modifies these files as needed for use within
the kernel. This patch split allows reviewers to double-check
the import and to clearly see the differences introduced.

The following script may be used to verify the contents:

    for path in $(cd rust/serde_derive/ && find . -type f -name '*.rs'); do
        curl --silent --show-error --location \
            https://github.com/serde-rs/serde/raw/v1.0.156/serde_derive/src/$path \
            | diff --unified rust/serde_derive/$path - && echo $path: OK
    done

Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
  • Loading branch information
ojeda committed May 8, 2023
commit 6f37f9b1932c7ad39722d8ea999138f591e52f4c
406 changes: 406 additions & 0 deletions rust/serde_derive/bound.rs

Large diffs are not rendered by default.

3,146 changes: 3,146 additions & 0 deletions rust/serde_derive/de.rs

Large diffs are not rendered by default.

44 changes: 44 additions & 0 deletions rust/serde_derive/dummy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use proc_macro2::{Ident, TokenStream};
use quote::format_ident;

use syn;
use try;

pub fn wrap_in_const(
serde_path: Option<&syn::Path>,
trait_: &str,
ty: &Ident,
code: TokenStream,
) -> TokenStream {
let try_replacement = try::replacement();

let dummy_const = if cfg!(no_underscore_consts) {
format_ident!("_IMPL_{}_FOR_{}", trait_, unraw(ty))
} else {
format_ident!("_")
};

let use_serde = match serde_path {
Some(path) => quote! {
use #path as _serde;
},
None => quote! {
#[allow(unused_extern_crates, clippy::useless_attribute)]
extern crate serde as _serde;
},
};

quote! {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const #dummy_const: () = {
#use_serde
#try_replacement
#code
};
}
}

fn unraw(ident: &Ident) -> String {
ident.to_string().trim_start_matches("r#").to_owned()
}
74 changes: 74 additions & 0 deletions rust/serde_derive/fragment.rs
10000
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::token;

pub enum Fragment {
/// Tokens that can be used as an expression.
Expr(TokenStream),
/// Tokens that can be used inside a block. The surrounding curly braces are
/// not part of these tokens.
Block(TokenStream),
}

macro_rules! quote_expr {
($($tt:tt)*) => {
$crate::fragment::Fragment::Expr(quote!($($tt)*))
}
}

macro_rules! quote_block {
($($tt:tt)*) => {
$crate::fragment::Fragment::Block(quote!($($tt)*))
}
}

/// Interpolate a fragment in place of an expression. This involves surrounding
/// Block fragments in curly braces.
pub struct Expr(pub Fragment);
impl ToTokens for Expr {
fn to_tokens(&self, out: &mut TokenStream) {
match &self.0 {
Fragment::Expr(expr) => expr.to_tokens(out),
Fragment::Block(block) => {
token::Brace::default().surround(out, |out| block.to_tokens(out));
}
}
}
}

/// Interpolate a fragment as the statements of a block.
pub struct Stmts(pub Fragment);
impl ToTokens for Stmts {
fn to_tokens(&self, out: &mut TokenStream) {
match &self.0 {
Fragment::Expr(expr) => expr.to_tokens(out),
Fragment::Block(block) => block.to_tokens(out),
}
}
}

/// Interpolate a fragment as the value part of a `match` expression. This
/// involves putting a comma after expressions and curly braces around blocks.
pub struct Match(pub Fragment);
impl ToTokens for Match {
fn to_tokens(&self, out: &mut TokenStream) {
match &self.0 {
Fragment::Expr(expr) => {
expr.to_tokens(out);
<Token![,]>::default().to_tokens(out);
}
Fragment::Block(block) => {
token::Brace::default().surround(out, |out| block.to_tokens(out));
}
}
}
}

impl AsRef<TokenStream> for Fragment {
fn as_ref(&self) -> &TokenStream {
match self {
Fragment::Expr(expr) => expr,
Fragment::Block(block) => block,
}
}
}
202 changes: 202 additions & 0 deletions rust/serde_derive/internals/ast.rs
B7AA
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
//! A Serde ast, parsed from the Syn ast and ready to generate Rust code.

use internals::attr;
use internals::check;
use internals::{Ctxt, Derive};
use syn;
use syn::punctuated::Punctuated;

/// A source data structure annotated with `#[derive(Serialize)]` and/or `#[derive(Deserialize)]`,
/// parsed into an internal representation.
pub struct Container<'a> {
/// The struct or enum name (without generics).
pub ident: syn::Ident,
/// Attributes on the structure, parsed for Serde.
pub attrs: attr::Container,
/// The contents of the struct or enum.
pub data: Data<'a>,
/// Any generics on the struct or enum.
pub generics: &'a syn::Generics,
/// Original input.
pub original: &'a syn::DeriveInput,
}

< 6D4E span class='blob-code-inner blob-code-marker ' data-code-marker="+">/// The fields of a struct or enum.
///
/// Analogous to `syn::Data`.
pub enum Data<'a> {
Enum(Vec<Variant<'a>>),
Struct(Style, Vec<Field<'a>>),
}

/// A variant of an enum.
pub struct Variant<'a> {
pub ident: syn::Ident,
pub attrs: attr::Variant,
pub style: Style,
pub fields: Vec<Field<'a>>,
pub original: &'a syn::Variant,
}

/// A field of a struct.
pub struct Field<'a> {
pub member: syn::Member,
pub attrs: attr::Field,
pub ty: &'a syn::Type,
pub original: &'a syn::Field,
}

#[derive(Copy, Clone)]
pub enum Style {
/// Named fields.
Struct,
/// Many unnamed fields.
Tuple,
/// One unnamed field.
Newtype,
/// No fields.
Unit,
}

impl<'a> Container<'a> {
/// Convert the raw Syn ast into a parsed container object, collecting errors in `cx`.
pub fn from_ast(
cx: &Ctxt,
item: &'a syn::DeriveInput,
derive: Derive,
) -> Option<Container<'a>> {
let mut attrs = attr::Container::from_ast(cx, item);

let mut data = match &item.data {
syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())),
syn::Data::Struct(data) => {
let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default());
Data::Struct(style, fields)
}
syn::Data::Union(_) => {
cx.error_spanned_by(item, "Serde does not support derive for unions");
return None;
}
};

let mut has_flatten = false;
match &mut data {
Data::Enum(variants) => {
for variant in variants {
variant.attrs.rename_by_rules(attrs.rename_all_rules());
for field in &mut variant.fields {
if field.attrs.flatten() {
has_flatten = true;
}
field
.attrs
.rename_by_rules(variant.attrs.rename_all_rules());
}
}
}
Data::Struct(_, fields) => {
for field in fields {
if field.attrs.flatten() {
has_flatten = true;
}
field.attrs.rename_by_rules(attrs.rename_all_rules());
}
}
}

if has_flatten {
attrs.mark_has_flatten();
}

let mut item = Container {
ident: item.ident.clone(),
attrs,
data,
generics: &item.generics,
original: item,
};
check::check(cx, &mut item, derive);
Some(item)
}
}

impl<'a> Data<'a> {
pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
match self {
Data::Enum(variants) => {
Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
}
Data::Struct(_, fields) => Box::new(fields.iter()),
}
}

pub fn has_getter(&self) -> bool {
self.all_fields().any(|f| f.attrs.getter().is_some())
}
}

fn enum_from_ast<'a>(
cx: &Ctxt,
variants: &'a Punctuated<syn::Variant, Token![,]>,
container_default: &attr::Default,
) -> Vec<Variant<'a>> {
variants
.iter()
.map(|variant| {
let attrs = attr::Variant::from_ast(cx, variant);
let (style, fields) =
struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
Variant {
ident: variant.ident.clone(),
attrs,
style,
fields,
original: variant,
}
})
.collect()
}

fn struct_from_ast<'a>(
cx: &Ctxt,
fields: &'a syn::Fields,
attrs: Option<&attr::Variant>,
container_default: &attr::Default,
) -> (Style, Vec<Field<'a>>) {
match fields {
syn::Fields::Named(fields) => (
Style::Struct,
fields_from_ast(cx, &fields.named, attrs, container_default),
),
syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => (
Style::Newtype,
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
),
syn::Fields::Unnamed(fields) => (
Style::Tuple,
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
),
syn::Fields::Unit => (Style::Unit, Vec::new()),
}
}

fn fields_from_ast<'a>(
cx: &Ctxt,
fields: &'a Punctuated<syn::Field, Token![,]>,
attrs: Option<&attr::Variant>,
container_default: &attr::Default,
) -> Vec<Field<'a>> {
fields
.iter()
.enumerate()
.map(|(i, field)| Field {
member: match &field.ident {
Some(ident) => syn::Member::Named(ident.clone()),
None => syn::Member::Unnamed(i.into()),
},
attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
ty: &field.ty,
original: field,
})
.collect()
}
Loading
0