Extend Require macro to support impl block

This commit is contained in:
Jianfeng Jiang 2023-05-08 11:13:49 +08:00 committed by Tate, Hongliang Tian
parent 1ae1881240
commit dba89b508d
4 changed files with 42 additions and 12 deletions

View File

@ -6,5 +6,6 @@
"x86_64-custom.json",
"-Zbuild-std=core,alloc,compiler_builtins",
"-Zbuild-std-features=compiler-builtins-mem"
]
],
"rust-analyzer.showUnlinkedFileNotification": false
}

View File

@ -15,7 +15,7 @@
//! Below is a simple example.
//! Suppose we have a channel that may have read and write capability.
//!
//! ```rust
//! ```ignore
//! /// A simple channel, only for demonstration.
//! struct Channel<R: RightSet> {
//! rights: PhantomData<R>,
@ -42,7 +42,7 @@
//! ```
//! When we initialize channels with different rights, it can check whether the function
//! are wrongly used due to lack of capabilities at compilation time.
//! ```rust
//! ```ignore
//! let read_channel = Channel::<R>::new();
//! read_channel.read();
//! // read_channel.write(); // compilation error!
@ -73,20 +73,21 @@
#![feature(proc_macro_diagnostic)]
#![allow(dead_code)]
use require_item::RequireItem;
use syn::parse_macro_input;
use syn::ItemFn;
use crate::require_attr::expand_require;
use crate::require_attr::RequireAttr;
mod require_attr;
mod require_item;
#[proc_macro_attribute]
pub fn require(
attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let item_fn = parse_macro_input!(item as ItemFn);
let require_item = parse_macro_input!(item as RequireItem);
let require_attr = parse_macro_input!(attr as RequireAttr);
expand_require(item_fn, require_attr).into()
expand_require(require_item, require_attr).into()
}

View File

@ -4,9 +4,11 @@ use proc_macro2::{Ident, TokenStream};
use quote::quote;
use syn::{
fold::Fold, parse::Parse, parse_quote, punctuated::Punctuated, token::Comma, GenericParam,
Generics, ItemFn, Token, Type, WhereClause,
Generics, Token, Type, WhereClause,
};
use super::require_item::RequireItem;
pub struct RequireAttr {
type_set: Type,
required_types: Punctuated<Ident, Token![|]>,
@ -61,12 +63,20 @@ impl Fold for RequireAttr {
}
}
pub fn expand_require(item_fn: ItemFn, mut require_attr: RequireAttr) -> TokenStream {
pub fn expand_require(item: RequireItem, mut require_attr: RequireAttr) -> TokenStream {
match item {
RequireItem::Impl(item_impl) => {
let new_item_impl = require_attr.fold_item_impl(item_impl);
quote!(#new_item_impl)
}
RequireItem::Fn(item_fn) => {
let new_item_fn = require_attr.fold_item_fn(item_fn);
quote!(
#new_item_fn
)
}
}
}
fn is_generic_param(ident: Ident, generic_params: &Punctuated<GenericParam, Comma>) -> bool {
for generic_param in generic_params {

View File

@ -0,0 +1,18 @@
use syn::{parse::Parse, ItemFn, ItemImpl, Token};
pub enum RequireItem {
Impl(ItemImpl),
Fn(ItemFn),
}
impl Parse for RequireItem {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let token = input.lookahead1();
if token.peek(Token!(impl)) {
// FIXME: is there any possible token before impl?
input.parse().map(RequireItem::Impl)
} else {
input.parse().map(RequireItem::Fn)
}
}
}