#![doc(html_root_url = "https://docs.rs/syn-mid/0.1.0")]
#![deny(unsafe_code)]
#![cfg_attr(
feature = "cargo-clippy",
allow(
renamed_and_removed_lints,
redundant_field_names,
const_static_lifetime,
deprecated_cfg_attr,
map_clone,
large_enum_variant
)
)]
#[cfg(not(any(feature = "full", feature = "derive")))]
compile_error!("To use this crate you need to enable \"derive\" or \"full\" feature");
extern crate proc_macro2;
extern crate quote;
#[allow(unused_imports)]
#[macro_use]
extern crate syn;
#[macro_use]
mod macros;
mod expr;
mod item;
#[cfg(not(feature = "full"))]
mod path;
#[cfg(not(feature = "full"))]
mod print;
#[cfg(feature = "extra-traits")]
mod tt;
pub use self::expr::*;
pub use self::item::*;
use proc_macro2::TokenStream;
#[cfg(not(feature = "full"))]
use syn::punctuated::Punctuated;
use syn::{token, Abi, AttrStyle, Attribute, Ident, Visibility};
#[cfg(feature = "extra-traits")]
use std::hash::{Hash, Hasher};
#[cfg(feature = "extra-traits")]
use tt::TokenStreamHelper;
ast_struct! {
pub struct Block #manual_extra_traits {
pub brace_token: token::Brace,
pub stmts: TokenStream,
}
}
#[cfg(feature = "extra-traits")]
impl Eq for Block {}
#[cfg(feature = "extra-traits")]
impl PartialEq for Block {
fn eq(&self, other: &Self) -> bool {
self.brace_token == other.brace_token
&& TokenStreamHelper(&self.stmts) == TokenStreamHelper(&other.stmts)
}
}
#[cfg(feature = "extra-traits")]
impl Hash for Block {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.brace_token.hash(state);
TokenStreamHelper(&self.stmts).hash(state);
}
}
ast_struct! {
pub struct ItemFn {
pub attrs: Vec<Attribute>,
pub vis: Visibility,
pub constness: Option<Token![const]>,
pub unsafety: Option<Token![unsafe]>,
pub asyncness: Option<Token![async]>,
pub abi: Option<Abi>,
pub ident: Ident,
pub decl: Box<FnDecl>,
pub block: Block,
}
}
mod parsing {
use syn::parse::{Parse, ParseStream, Result};
use syn::{Abi, Attribute, Generics, Ident, ReturnType, Visibility, WhereClause};
use super::*;
fn attrs(outer: Vec<Attribute>, inner: Vec<Attribute>) -> Vec<Attribute> {
let mut attrs = outer;
attrs.extend(inner);
attrs
}
impl Parse for ItemFn {
fn parse(input: ParseStream) -> Result<Self> {
let outer_attrs = input.call(Attribute::parse_outer)?;
let vis: Visibility = input.parse()?;
let constness: Option<Token![const]> = input.parse()?;
let unsafety: Option<Token![unsafe]> = input.parse()?;
let asyncness: Option<Token![async]> = input.parse()?;
let abi: Option<Abi> = input.parse()?;
let fn_token: Token![fn] = input.parse()?;
let ident: Ident = input.parse()?;
let generics: Generics = input.parse()?;
let content;
let paren_token = parenthesized!(content in input);
let inputs = content.parse_terminated(FnArg::parse)?;
let output: ReturnType = input.parse()?;
let where_clause: Option<WhereClause> = input.parse()?;
let content;
let brace_token = braced!(content in input);
let inner_attrs = content.call(Attribute::parse_inner)?;
let stmts = content.parse()?;
Ok(ItemFn {
attrs: attrs(outer_attrs, inner_attrs),
vis: vis,
constness: constness,
unsafety: unsafety,
asyncness: asyncness,
abi: abi,
ident: ident,
decl: Box::new(FnDecl {
fn_token: fn_token,
paren_token: paren_token,
inputs: inputs,
output: output,
variadic: None,
generics: Generics {
where_clause: where_clause,
..generics
},
}),
block: Block {
brace_token: brace_token,
stmts: stmts,
},
})
}
}
}
mod printing {
use proc_macro2::TokenStream;
use quote::{ToTokens, TokenStreamExt};
use std::iter;
use super::*;
impl ToTokens for Block {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.brace_token.surround(tokens, |tokens| {
tokens.append_all(self.stmts.clone());
});
}
}
trait FilterAttrs<'a> {
type Ret: Iterator<Item = &'a Attribute>;
fn outer(self) -> Self::Ret;
fn inner(self) -> Self::Ret;
}
impl<'a, T> FilterAttrs<'a> for T
where
T: IntoIterator<Item = &'a Attribute>,
{
type Ret = iter::Filter<T::IntoIter, fn(&&Attribute) -> bool>;
fn outer(self) -> Self::Ret {
#[cfg_attr(feature = "cargo-clippy", allow(trivially_copy_pass_by_ref))]
fn is_outer(attr: &&Attribute) -> bool {
match attr.style {
AttrStyle::Outer => true,
_ => false,
}
}
self.into_iter().filter(is_outer)
}
fn inner(self) -> Self::Ret {
#[cfg_attr(feature = "cargo-clippy", allow(trivially_copy_pass_by_ref))]
fn is_inner(attr: &&Attribute) -> bool {
match attr.style {
AttrStyle::Inner(_) => true,
_ => false,
}
}
self.into_iter().filter(is_inner)
}
}
impl ToTokens for ItemFn {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.append_all(self.attrs.outer());
self.vis.to_tokens(tokens);
self.constness.to_tokens(tokens);
self.unsafety.to_tokens(tokens);
self.asyncness.to_tokens(tokens);
self.abi.to_tokens(tokens);
NamedDecl(&self.decl, &self.ident).to_tokens(tokens);
self.block.brace_token.surround(tokens, |tokens| {
tokens.append_all(self.attrs.inner());
tokens.append_all(self.block.stmts.clone());
});
}
}
struct NamedDecl<'a>(&'a FnDecl, &'a Ident);
impl<'a> ToTokens for NamedDecl<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.0.fn_token.to_tokens(tokens);
self.1.to_tokens(tokens);
self.0.generics.to_tokens(tokens);
self.0.paren_token.surround(tokens, |tokens| {
self.0.inputs.to_tokens(tokens);
if self.0.variadic.is_some() && !self.0.inputs.empty_or_trailing() {
<Token![,]>::default().to_tokens(tokens);
}
self.0.variadic.to_tokens(tokens);
});
self.0.output.to_tokens(tokens);
self.0.generics.where_clause.to_tokens(tokens);
}
}
}
#[cfg(feature = "full")]
mod convert {
use quote::ToTokens;
use syn;
use syn::parse::{Parse, ParseStream, Result};
use super::*;
struct Parser(Vec<syn::Stmt>);
impl Parse for Parser {
fn parse(input: ParseStream) -> Result<Self> {
input.call(syn::Block::parse_within).map(Parser)
}
}
impl Into<syn::Block> for Block {
fn into(self) -> syn::Block {
syn::Block {
brace_token: self.brace_token,
stmts: syn::parse2::<Parser>(self.stmts)
.unwrap_or_else(|err| panic!("{}", err))
.0,
}
}
}
impl From<syn::Block> for Block {
fn from(other: ::syn::Block) -> Block {
Block {
brace_token: other.brace_token,
stmts: other
.stmts
.into_iter()
.map(ToTokens::into_token_stream)
.collect(),
}
}
}
impl Into<syn::ItemFn> for ItemFn {
fn into(self) -> ::syn::ItemFn {
syn::ItemFn {
attrs: self.attrs,
vis: self.vis,
constness: self.constness,
unsafety: self.unsafety,
asyncness: self.asyncness,
abi: self.abi,
ident: self.ident,
decl: self.decl,
block: Box::new(self.block.into()),
}
}
}
impl From<syn::ItemFn> for ItemFn {
fn from(other: ::syn::ItemFn) -> ItemFn {
ItemFn {
attrs: other.attrs,
vis: other.vis,
constness: other.constness,
unsafety: other.unsafety,
asyncness: other.asyncness,
abi: other.abi,
ident: other.ident,
decl: other.decl,
block: (*other.block).into(),
}
}
}
}