macros: Clean up bitfield macro by replacing the input item

Before:

    #[derive(BitField)]
    #[passthrough(derive(Clone, Copy, PartialEq))]
    pub struct TrbSchema {
        parameter: B64,
        status: B32,
        cycle: B1,
        flags: B9,
        trb_type: B6,
        control: B16,
    }

After:

    #[bitfield]
    #[derive(Clone, Copy, PartialEq)]
    pub struct Trb {
        parameter: B64,
        status: B32,
        cycle: B1,
        flags: B9,
        trb_type: B6,
        control: B16,
    }

This change eliminates the need for the `passthrough` attribute, and
avoids the separate `FooSchema` struct continuing to float around and
disrupt IDE autocomplete.

TEST=`cargo test` the bit_field_derive crate
TEST=`cargo check` the devices crate against a migrated CL:1144264

Change-Id: I950ce896607468c73852aa181827f1a5dc0f0227
Reviewed-on: https://chromium-review.googlesource.com/1366539
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: David Tolnay <dtolnay@chromium.org>
Reviewed-by: Jingkui Wang <jkwang@google.com>
This commit is contained in:
David Tolnay 2018-12-06 15:50:29 -08:00 committed by chrome-bot
parent 088e7f3025
commit caf32ee5bb
2 changed files with 17 additions and 78 deletions

View file

@ -15,14 +15,14 @@ extern crate syn;
use std::string::String;
use std::vec::Vec;
use proc_macro2::{Span, TokenStream, TokenTree};
use syn::{Attribute, Data, DeriveInput, Fields, Ident};
use proc_macro2::{Span, TokenStream};
use syn::{Data, DeriveInput, Fields, Ident};
type Result<T> = std::result::Result<T, String>;
/// The function that derives the actual implementation.
#[proc_macro_derive(BitField, attributes(passthrough))]
pub fn bitfield(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
#[proc_macro_attribute]
pub fn bitfield(_args: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let derive_input = parse_macro_input!(input as DeriveInput);
bitfield_impl(derive_input).into()
}
@ -30,36 +30,17 @@ pub fn bitfield(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
fn bitfield_impl(ast: DeriveInput) -> TokenStream {
if !ast.generics.params.is_empty() {
return quote! {
compile_error!("derive(BitField) does not support generic parameters");
compile_error!("#[bitfield] does not support generic parameters");
};
}
let name = ast.ident.to_string();
let struct_name = match get_struct_name(name.as_str()) {
Some(name) => name,
None => {
return quote! {
compile_error!("Check schema name, it should end with Schema.");
};
}
};
let ident = Ident::new(struct_name, Span::call_site());
let name = ast.ident.clone();
let test_mod_ident = Ident::new(
format!("test_{}", struct_name.to_lowercase()).as_str(),
format!("test_{}", name.to_string().to_lowercase()).as_str(),
Span::call_site(),
);
// Name of the struct
let name = quote!(#ident);
let vis = ast.vis.clone();
let attrs = match get_attrs(ast.attrs.as_slice()) {
Ok(attrs) => attrs,
Err(err_str) => {
return quote! {
compile_error!(#err_str);
};
}
};
let attrs = ast.attrs.clone();
// Visibility.
let vis = quote!(#vis);
let fields = match get_struct_fields(ast) {
@ -92,18 +73,6 @@ fn bitfield_impl(ast: DeriveInput) -> TokenStream {
}
}
// Generate struct name from schema_name. "MyTypeSchema" -> "MyType".
fn get_struct_name(schema_name: &str) -> Option<&str> {
let struct_name = schema_name.trim_right_matches("Schema");
if struct_name.len() + "Schema".len() != schema_name.len() {
return None;
}
if struct_name.len() == 0 {
return None;
}
Some(struct_name)
}
// Unwrap ast to get the named fields. Anything unexpected will be treated as an
// error.
// We only care about field names and types.
@ -137,28 +106,9 @@ fn get_struct_fields(ast: DeriveInput) -> Result<Vec<(String, TokenStream)>> {
Ok(vec)
}
// We only support attributes of the form #[passthrough(derive(Clone))].
// Any other attribute will cause undefined behavior.
fn get_attrs(attrs: &[Attribute]) -> Result<Vec<TokenStream>> {
let mut attr_tokens = Vec::new();
for a in attrs {
let tts = a.tts.clone();
for t in tts {
match t {
TokenTree::Group(group) => {
let nested = group.stream();
attr_tokens.push(quote!(#[#nested]))
}
_ => return Err(format!("Unsupported attribute.")),
}
}
}
Ok(attr_tokens)
}
fn get_struct_def(
vis: &TokenStream,
name: &TokenStream,
name: &Ident,
fields: &[(String, TokenStream)],
) -> TokenStream {
let mut field_types = Vec::new();
@ -216,7 +166,7 @@ fn get_fields_impl(fields: &[(String, TokenStream)]) -> Vec<TokenStream> {
}
// Implement setter and getter for all fields.
fn get_debug_fmt_impl(name: &TokenStream, fields: &[(String, TokenStream)]) -> TokenStream {
fn get_debug_fmt_impl(name: &Ident, fields: &[(String, TokenStream)]) -> TokenStream {
// print fields:
let mut impls = Vec::new();
for &(ref name, ref _ty) in fields {
@ -239,7 +189,7 @@ fn get_debug_fmt_impl(name: &TokenStream, fields: &[(String, TokenStream)]) -> T
}
// Implement test.
fn get_tests_impl(struct_name: &TokenStream, fields: &[(String, TokenStream)]) -> Vec<TokenStream> {
fn get_tests_impl(struct_name: &Ident, fields: &[(String, TokenStream)]) -> Vec<TokenStream> {
let mut field_types = Vec::new();
for &(ref _name, ref ty) in fields {
field_types.push(ty.clone());
@ -291,7 +241,7 @@ fn get_tests_impl(struct_name: &TokenStream, fields: &[(String, TokenStream)]) -
impls
}
fn get_bits_impl(name: &TokenStream) -> TokenStream {
fn get_bits_impl(name: &Ident) -> TokenStream {
quote! {
impl #name {
#[inline]
@ -363,21 +313,11 @@ fn get_bits_impl(name: &TokenStream) -> TokenStream {
mod tests {
use super::*;
#[test]
fn struct_name_parsing_valid() {
assert_eq!(get_struct_name("MyBitFieldSchema"), Some("MyBitField"));
}
#[test]
fn struct_name_parsing_invalid() {
assert_eq!(get_struct_name("MyBitFieldS"), None);
}
#[test]
fn end_to_end() {
let input: DeriveInput = parse_quote! {
#[passthrough(derive(Clone))]
struct MyBitFieldSchema {
#[derive(Clone)]
struct MyBitField {
a: BitField1,
b: BitField2,
c: BitField5,

View file

@ -9,9 +9,9 @@ extern crate bit_field_derive;
pub use bit_field_derive::*;
/// BitFieldSpecifier is a group of structs help defining bitfield. It should only
/// be used with bit_field custom derive. (#[derive(BitField)]).
/// be used with the #[bitfield] attribute macro.
/// Example:
/// #[derive(BitField)]
/// #[bitfield]
/// pub struct MyBitFieldSchema {
/// field_a : BitField1,
/// field_b : BitField3,
@ -30,8 +30,7 @@ pub use bit_field_derive::*;
/// fn set_field_d(&self, val: u32)
///
/// You can also pass attributes to the defined bitfield structs. Simply do this:
/// #[passthrough(derive(Clone))]
/// Any attributes other than #[passthrough(*)] will cause undefined behavior.
/// #[derive(Clone)]
/// For more details, refer to bit_field_derive.
pub trait BitFieldSpecifier {
/// Width of this field in bits.