├── .github └── workflows │ └── rust.yml ├── .gitignore ├── .travis.yml ├── Cargo.toml ├── README.md ├── src └── lib.rs └── tests ├── fn-dec-args.rs ├── fn-dec-sugar.rs ├── fn-dec.rs ├── nonstatic-methods-dec.rs └── static-methods-dec.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Build 20 | run: cargo build --verbose 21 | - name: Run tests 22 | run: cargo test --verbose 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | sudo: false 7 | 8 | script: 9 | - cargo build 10 | - cargo test 11 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Manish Goregaokar "] 3 | description = "A plugin to provide python-style decorators in Rust" 4 | keywords = ["decorators", "adorn", "plugin", "python"] 5 | license = "MPL-2.0" 6 | name = "adorn" 7 | readme = "README.md" 8 | repository = "https://github.com/Manishearth/rust-adorn" 9 | version = "0.4.0" 10 | 11 | [dependencies] 12 | quote = "0.4" 13 | proc-macro2 = "0.2.3" 14 | 15 | [dependencies.syn] 16 | features = ["full", "extra-traits"] 17 | version = "0.12" 18 | 19 | [lib] 20 | name = "adorn" 21 | proc-macro = true 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-adorn 2 | 3 | [![Build Status](https://travis-ci.org/Manishearth/rust-adorn.svg)](https://travis-ci.org/Manishearth/rust-adorn) 4 | 5 | Python-style function decorators for Rust 6 | 7 | ## Decorate functions 8 | 9 | Example usage: 10 | 11 | ```rust 12 | use adorn::{adorn, make_decorator}; 13 | 14 | #[adorn(bar)] 15 | fn foo(a: &mut u8, b: &mut u8, (c, _): (u8, u8)) { 16 | assert!(c == 4); 17 | *a = c; 18 | *b = c; 19 | } 20 | 21 | 22 | fn bar(f: F, a: &mut u8, b: &mut u8, (c, d): (u8, u8)) where F: Fn(&mut u8, &mut u8, (u8, u8)) { 23 | assert!(c == 0 && d == 0); 24 | f(a, b, (4, 0)); 25 | *b = 100; 26 | } 27 | 28 | fn main() { 29 | let mut x = 0; 30 | let mut y = 1; 31 | foo(&mut x, &mut y, (0, 0)); 32 | assert!(x == 4 && y == 100); 33 | } 34 | ``` 35 | 36 | In this case, `foo` will become: 37 | 38 | ```rust 39 | fn foo(a: &mut u8, b: &mut u8, (c, d): (u8, u8)) { 40 | fn foo_inner(a: &mut u8, b: &mut u8, (c, _): (u8, u8)) { 41 | assert!(c == 4); 42 | *a = c; 43 | *b = c; 44 | } 45 | bar(foo_inner, a, b, (c, d)) 46 | } 47 | ``` 48 | 49 | In other words, calling `foo()` will actually call `bar()` wrapped around `foo()`. 50 | 51 | 52 | There is a `#[make_decorator]` attribute to act as sugar for creating decorators. For example, 53 | 54 | ```rust 55 | #[make_decorator(f)] 56 | fn bar(a: &mut u8, b: &mut u8, (c, d): (u8, u8)) { 57 | assert!(c == 0 && d == 0); 58 | f(a, b, (4, 0)); // `f` was declared in the `make_decorator` annotation 59 | *b = 100; 60 | } 61 | 62 | ``` 63 | 64 | desugars to 65 | 66 | ```rust 67 | fn bar(f: F, a: &mut u8, b: &mut u8, (c, d): (u8, u8)) where F: Fn(&mut u8, &mut u8, (u8, u8)) { 68 | assert!(c == 0 && d == 0); 69 | f(a, b, (4, 0)); 70 | *b = 100; 71 | } 72 | ``` 73 | 74 | ## Decorate nonstatic methods 75 | 76 | Example usage: 77 | 78 | ```rust 79 | use adorn::{adorn_method, make_decorator_method}; 80 | 81 | pub struct Test { 82 | a: u8, 83 | b: u8 84 | } 85 | 86 | impl Test { 87 | #[adorn_method(bar)] 88 | fn foo(&mut self, a: u8, b: u8) { 89 | assert!(a == 0 && b == 0); 90 | self.a = a; 91 | self.b = b; 92 | } 93 | 94 | fn bar(&mut self, f: F, a: u8, b: u8) where F: Fn(Self, u8, u8) { 95 | assert!(a == 0 && b == 0); 96 | f(self, a, b); 97 | self.b = 100; 98 | } 99 | } 100 | 101 | fn main() { 102 | let mut t = Test { 103 | a: 1, 104 | b: 1, 105 | }; 106 | t.foo(0, 0); 107 | assert!(t.a == 0 && t.b == 100); 108 | } 109 | ``` 110 | 111 | In this case, `foo` will become: 112 | 113 | ```rust 114 | impl Test { 115 | fn foo(&mut self, a: u8, b: u8) { 116 | let foo_inner = |s: &mut Self, a: u8, b: u8| { 117 | assert!(a == 0 && b == 0); 118 | s.a = a; 119 | s.b = b; 120 | }; 121 | self.bar(foo_inner, a, b, (c, d)) 122 | } 123 | } 124 | ``` 125 | 126 | Similarly, a `#[make_decorator_method]` attribute is provided to create decorators. For example, 127 | 128 | ```rust 129 | impl Test { 130 | #[make_decorator_method(f)] 131 | fn bar(&mut self, a: u8, b: u8) { 132 | assert!(a == 0 && b == 0); 133 | f(self, a, b); // `f` was declared in the `make_decorator_method` annotation 134 | self.b = 100; 135 | } 136 | } 137 | ``` 138 | 139 | desugars to 140 | 141 | ```rust 142 | impl Test{ 143 | fn bar(&mut self, f: F, a: u8, b: u8) where F: Fn(Self, u8, u8) { 144 | assert!(a == 0 && b == 0); 145 | f(self, a, b); 146 | self.b = 100; 147 | } 148 | } 149 | ``` 150 | 151 | ## Decorate static methods 152 | 153 | Use `#[make_decorator_static]` and `#[adorn_static]` to make a static decorator and then use it to decorate a static method, for example 154 | 155 | ```rust 156 | use adorn::{adorn_method, make_decorator_method}; 157 | 158 | pub struct Test { 159 | a: u8, 160 | b: u8 161 | } 162 | 163 | impl Test { 164 | #[adorn_static(bar)] 165 | fn foo(a: u8, b: u8) -> Self { 166 | assert!(a == 0 && b == 0); 167 | Self { 168 | a, 169 | b 170 | } 171 | } 172 | 173 | #[make_decorator_static(f)] 174 | fn bar(a: u8, b: u8) -> Self { 175 | assert!(a == 0 && b == 0); 176 | let mut retval = f(a, b); 177 | retval.b = 100; 178 | retval 179 | } 180 | } 181 | 182 | fn main() { 183 | let t = Test::foo(0, 0); 184 | assert!(t.a == 0 && t.b == 100); 185 | } 186 | ``` 187 | 188 | The two static methods desugar to 189 | 190 | ```rust 191 | impl Test { 192 | fn foo(a: u8, b: u8) -> Self { 193 | let foo_inner = |a: u8, b: u8| -> Self { 194 | assert!(a == 0 && b == 0); 195 | Self { 196 | a, 197 | b 198 | } 199 | }; 200 | Self::bar(foo, a, b) 201 | } 202 | 203 | fn bar(f: F, a: u8, b: u8) -> Self where F: Fn(u8, u8) -> Self { 204 | assert!(a == 0 && b == 0); 205 | let mut retval = f(a, b); 206 | retval.b = 100; 207 | retval 208 | } 209 | } 210 | ``` 211 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro; 2 | extern crate proc_macro2; 3 | #[macro_use] extern crate quote; 4 | use std::mem; 5 | extern crate syn; 6 | extern crate core; 7 | 8 | use syn::*; 9 | use syn::synom::Synom; 10 | use syn::punctuated::{Punctuated, Pair}; 11 | 12 | use proc_macro::{TokenStream}; 13 | use proc_macro2::{Span, TokenStream as TokenStream2, TokenNode, TokenTree}; 14 | use std::str::FromStr; 15 | use quote::{ToTokens}; 16 | use std::iter::FromIterator; 17 | use std::ops::Index; 18 | 19 | #[derive(Debug)] 20 | struct Args { 21 | name: Ident, 22 | extra: Vec, 23 | } 24 | 25 | impl Synom for Args { 26 | named!(parse -> Self, 27 | do_parse!( 28 | name: syn!(Ident) >> 29 | extra: option!( 30 | map!(parens!(Punctuated::::parse_terminated_nonempty), 31 | |(_parens, vars)| vars.into_iter().collect()) 32 | ) >> 33 | (Args { 34 | name, 35 | extra: extra.unwrap_or(vec!()) 36 | }) 37 | ) 38 | ); 39 | } 40 | 41 | #[proc_macro_attribute] 42 | pub fn adorn(arg: TokenStream, input: TokenStream) -> TokenStream { 43 | let macro_args: Args = match parse(arg) { 44 | Ok(arg) => arg, 45 | Err(..) => panic!("#[adorn()] takes a single identifier input, followed by optional literal parameters in parentheses"), 46 | }; 47 | let mut input: ItemFn = match parse(input) { 48 | Ok(input) => input, 49 | Err(..) => panic!("#[adorn()] must be applied on functions"), 50 | }; 51 | 52 | if input.decl.generics.where_clause.is_some() { 53 | panic!("#[adorn()] does not work with where clauses") 54 | } 55 | 56 | let id: Ident = "_decorated_fn".into(); 57 | let old_ident = mem::replace(&mut input.ident, id); 58 | let mut i = 0; 59 | let mut exprs = Vec::with_capacity(input.decl.inputs.len()+1); 60 | exprs.push(quote!(#id)); 61 | for extra_arg in macro_args.extra { 62 | exprs.push(quote!(#extra_arg)); 63 | } 64 | let mut args = vec!(); 65 | for arg in input.decl.inputs.iter() { 66 | let arg_ident: Ident = format!("_arg_{}", i).into(); 67 | 68 | match *arg { 69 | FnArg::Captured(ref cap) => { 70 | let ty = &cap.ty; 71 | args.push(quote!(#arg_ident: #ty)); 72 | } 73 | _ => panic!("Unexpected argument {:?}", arg) 74 | } 75 | exprs.push(quote!(#arg_ident)); 76 | i += 1; 77 | } 78 | 79 | 80 | let decorator = ¯o_args.name; 81 | let attributes = &input.attrs; 82 | let vis = &input.vis; 83 | let constness = &input.constness; 84 | let unsafety = &input.unsafety; 85 | let abi = &input.abi; 86 | let generics = &input.decl.generics; 87 | let output = &input.decl.output; 88 | let outer = quote!( 89 | #(#attributes),* 90 | #vis #constness #unsafety #abi fn #old_ident #generics(#(#args),*) #output { 91 | #input 92 | #decorator(#(#exprs),*) 93 | } 94 | ); 95 | 96 | outer.into() 97 | } 98 | 99 | #[proc_macro_attribute] 100 | pub fn adorn_static(arg: TokenStream, input: TokenStream) -> TokenStream { 101 | let macro_args: Args = match parse(arg) { 102 | Ok(arg) => arg, 103 | Err(..) => panic!("#[adorn_static()] takes a single identifier input, followed by optional literal parameters in parentheses"), 104 | }; 105 | let input: ImplItemMethod = match parse(input) { 106 | Ok(input) => input, 107 | Err(..) => panic!("#[adorn_static()] must be applied on methods"), 108 | }; 109 | 110 | if input.sig.decl.generics.where_clause.is_some() { 111 | panic!("#[adorn_static()] does not work with where clauses") 112 | } 113 | 114 | match input.sig.decl.inputs.first() { 115 | Some(Pair::End(FnArg::SelfValue(..))) 116 | | Some(Pair::End(FnArg::SelfRef(..))) 117 | | Some(Pair::Punctuated(FnArg::SelfRef(..), _)) 118 | | Some(Pair::Punctuated(FnArg::SelfValue(..), _)) => 119 | panic!("#[make_decorator_static()] must be applied on static methods"), 120 | _ => {} 121 | } 122 | 123 | let id: Ident = "_decorated_fn".into(); 124 | let old_ident = input.sig.ident.clone(); 125 | let mut i = 0; 126 | let mut exprs = Vec::with_capacity(input.sig.decl.inputs.len()+1); 127 | exprs.push(quote!(#id)); 128 | for extra_arg in macro_args.extra { 129 | exprs.push(quote!(#extra_arg)); 130 | } 131 | let mut args = vec!(); 132 | for arg in input.sig.decl.inputs.iter() { 133 | let arg_ident: Ident = format!("_arg_{}", i).into(); 134 | 135 | match *arg { 136 | FnArg::Captured(ref cap) => { 137 | let ty = &cap.ty; 138 | args.push(quote!(#arg_ident: #ty)); 139 | } 140 | _ => panic!("Unexpected argument {:?}", arg) 141 | } 142 | exprs.push(quote!(#arg_ident)); 143 | i += 1; 144 | } 145 | 146 | let closure = ExprClosure { 147 | attrs: input.attrs.clone(), 148 | capture: None, 149 | or1_token: Token![|]([Span::call_site()]), 150 | inputs: input.sig.decl.inputs.clone(), 151 | or2_token: Token![|]([Span::call_site()]), 152 | output: input.sig.decl.output.clone(), 153 | body: Box::new(Expr::Block(ExprBlock{attrs: vec![], block: input.block.clone()})) 154 | }; 155 | 156 | let decorator = ¯o_args.name; 157 | let attributes = &input.attrs; 158 | let vis = &input.vis; 159 | let constness = &input.sig.constness; 160 | let unsafety = &input.sig.unsafety; 161 | let abi = &input.sig.abi; 162 | let generics = &input.sig.decl.generics; 163 | let output = &input.sig.decl.output; 164 | let defaultness = &input.defaultness; 165 | 166 | let outer = quote!( 167 | #(#attributes),* 168 | #vis #defaultness #constness #unsafety #abi fn #old_ident #generics(#(#args),*) #output { 169 | let #id = #closure; 170 | Self::#decorator(#(#exprs),*) 171 | } 172 | ); 173 | 174 | outer.into() 175 | } 176 | 177 | #[proc_macro_attribute] 178 | pub fn adorn_method(arg: TokenStream, input: TokenStream) -> TokenStream { 179 | let macro_args: Args = match parse(arg) { 180 | Ok(arg) => arg, 181 | Err(..) => panic!("#[adorn_static()] takes a single identifier input, followed by optional literal parameters in parentheses"), 182 | }; 183 | let input_backup = TokenStream2::from(input.clone()); 184 | let input_method: ImplItemMethod = match parse(input) { 185 | Ok(input) => input, 186 | Err(..) => panic!("#[adorn_static()] must be applied on methods"), 187 | }; 188 | 189 | if input_method.sig.decl.generics.where_clause.is_some() { 190 | panic!("#[adorn_static()] does not work with where clauses") 191 | } 192 | 193 | fn resolve_name(tokens: TokenStream2, conflict: &mut bool, candidate: &mut String) { 194 | *conflict = true; 195 | let mut tokens = tokens; 196 | while *conflict { 197 | *conflict = false; 198 | let tokens_backup = tokens.clone(); 199 | for token in tokens { 200 | match token.kind { 201 | TokenNode::Group(_, inner) => { 202 | resolve_name(inner, conflict, candidate) 203 | }, 204 | TokenNode::Term(ref term) => { 205 | let id_str = term.as_str(); 206 | if *candidate == id_str { 207 | *conflict = true; 208 | *candidate = "_".to_owned() + candidate; 209 | } 210 | } 211 | _ => {} 212 | } 213 | } 214 | tokens = tokens_backup; 215 | } 216 | } 217 | 218 | let mut new_self = "_self".to_owned(); 219 | resolve_name(input_backup, &mut true, &mut new_self); 220 | 221 | match input_method.sig.decl.inputs.first() { 222 | Some(Pair::End(FnArg::SelfValue(..))) 223 | | Some(Pair::End(FnArg::SelfRef(..))) 224 | | Some(Pair::Punctuated(FnArg::SelfValue(..), _)) 225 | | Some(Pair::Punctuated(FnArg::SelfRef(..), _)) => {}, 226 | _ => panic!("#[adorn_method()] must be applied on nonstatic methods") 227 | }; 228 | 229 | let id: Ident = "_decorated_fn".into(); 230 | let old_ident = input_method.sig.ident.clone(); 231 | let mut exprs = Vec::with_capacity(input_method.sig.decl.inputs.len()+1); 232 | exprs.push(quote!(#id)); 233 | for extra_arg in macro_args.extra { 234 | exprs.push(quote!(#extra_arg)); 235 | } 236 | let mut args = vec!(); 237 | args.push(input_method.sig.decl.inputs.index(0).into_tokens()); 238 | for i in 1..input_method.sig.decl.inputs.len() { 239 | let arg = &input_method.sig.decl.inputs[i]; 240 | let arg_ident: Ident = format!("_arg_{}", i).into(); 241 | 242 | match *arg { 243 | FnArg::Captured(ref cap) => { 244 | let ty = &cap.ty; 245 | args.push(quote!(#arg_ident: #ty)); 246 | } 247 | _ => panic!("Unexpected argument {:?}", arg) 248 | } 249 | exprs.push(quote!(#arg_ident)); 250 | } 251 | 252 | 253 | fn replace_arg(arg: &mut FnArg, new_self: &str) { 254 | let (pat, ty) = match arg { 255 | FnArg::SelfValue(ArgSelf{mutability, ..}) => { 256 | let tmp_ty = TokenStream2::from_str("Self"); 257 | debug_assert!(tmp_ty.is_ok()); 258 | ( 259 | Pat::from( 260 | PatIdent{ 261 | by_ref: None, 262 | mutability: mutability.clone(), 263 | ident: Ident::from(new_self), 264 | subpat: None 265 | } 266 | ), 267 | Type::from(TypeVerbatim {tts: tmp_ty.unwrap()}) 268 | ) 269 | } 270 | FnArg::SelfRef( 271 | ArgSelfRef{ 272 | and_token, 273 | mutability, 274 | lifetime, 275 | .. 276 | } 277 | ) => { 278 | let tmp_ty = TokenStream2::from_str("Self"); 279 | debug_assert!(tmp_ty.is_ok()); 280 | ( 281 | Pat::from( 282 | PatIdent{ 283 | by_ref: None, 284 | mutability: None, 285 | ident: Ident::from(new_self), 286 | subpat: None 287 | } 288 | ), 289 | Type::from( 290 | TypeReference{ 291 | and_token: and_token.clone(), 292 | lifetime: lifetime.clone(), 293 | mutability: (*mutability).clone(), 294 | elem: Box::new(Type::from(TypeVerbatim {tts: tmp_ty.unwrap()})) 295 | } 296 | ) 297 | ) 298 | } 299 | _ => return 300 | }; 301 | 302 | let new_arg = 303 | FnArg::Captured( 304 | ArgCaptured{ 305 | pat, 306 | ty, 307 | colon_token: Token![:]([Span::call_site()]) 308 | } 309 | ); 310 | let _ = mem::replace(arg, new_arg); 311 | } 312 | 313 | fn get_new_tokenstream(tts: TokenStream2, new_self: &str) -> TokenStream2 { 314 | fn get_new_tokentree(tt: TokenTree, new_self: &str) -> TokenTree { 315 | fn get_new_tokennode(tn: TokenNode, new_self: &str) -> TokenNode { 316 | match tn { 317 | TokenNode::Group(d, ts) => 318 | TokenNode::Group(d, get_new_tokenstream(ts, new_self)), 319 | TokenNode::Term(ti) => { 320 | if ti.as_str() == "self" { 321 | TokenNode::Term(proc_macro2::Term::intern(new_self)) 322 | } 323 | else { 324 | TokenNode::Term(ti) 325 | } 326 | }, 327 | other @ _ => other 328 | } 329 | } 330 | TokenTree { 331 | span: tt.span.clone(), 332 | kind: get_new_tokennode(tt.kind, new_self) 333 | } 334 | } 335 | 336 | let mut retval = Vec::new(); 337 | for t in tts { 338 | retval.push(get_new_tokentree(t, new_self)); 339 | } 340 | TokenStream2::from_iter(retval) 341 | } 342 | 343 | fn get_new_block(block: Block, new_self: &str, fn_id: &str) -> Block { 344 | let ts = TokenStream2::from_iter(block.into_tokens()); 345 | let new_ts = get_new_tokenstream(ts, new_self); 346 | let result: Result = parse2(new_ts); 347 | if result.is_ok() { 348 | result.unwrap() 349 | } else { 350 | panic!("Error occurs after replacing `self' in method {} by {}", fn_id, new_self) 351 | } 352 | } 353 | 354 | let mut new_args = input_method.sig.decl.inputs.clone(); 355 | replace_arg(&mut new_args[0], &new_self); 356 | 357 | let new_block = 358 | get_new_block(input_method.block.clone(), &new_self,&old_ident.to_string()); 359 | 360 | let closure = ExprClosure { 361 | attrs: input_method.attrs.clone(), 362 | capture: None, 363 | or1_token: Token![|]([Span::call_site()]), 364 | inputs: new_args, 365 | or2_token: Token![|]([Span::call_site()]), 366 | output: input_method.sig.decl.output.clone(), 367 | body: Box::new(Expr::Block(ExprBlock{attrs: vec![], block: new_block})) 368 | }; 369 | 370 | let decorator = ¯o_args.name; 371 | let attributes = &input_method.attrs; 372 | let vis = &input_method.vis; 373 | let constness = &input_method.sig.constness; 374 | let unsafety = &input_method.sig.unsafety; 375 | let abi = &input_method.sig.abi; 376 | let generics = &input_method.sig.decl.generics; 377 | let output = &input_method.sig.decl.output; 378 | let defaultness = &input_method.defaultness; 379 | 380 | let outer = quote!( 381 | #(#attributes),* 382 | #vis #defaultness #constness #unsafety #abi fn #old_ident #generics(#(#args),*) #output { 383 | let #id = #closure; 384 | self.#decorator(#(#exprs),*) 385 | } 386 | ); 387 | 388 | outer.into() 389 | } 390 | 391 | #[proc_macro_attribute] 392 | pub fn make_decorator_static(arg: TokenStream, input: TokenStream) -> TokenStream { 393 | let macro_args: Args = match parse(arg) { 394 | Ok(arg) => arg, 395 | _ => panic!("#[make_decorator_static()] takes a single identifier input"), 396 | }; 397 | if !macro_args.extra.is_empty() { 398 | panic!("#[make_decorator_static()] takes a single identifier input"); 399 | } 400 | 401 | let input: ImplItemMethod = match parse(input) { 402 | Ok(input) => input, 403 | Err(..) => panic!("#[make_decorator_static()] must be applied on methods"), 404 | }; 405 | 406 | if input.sig.decl.generics.where_clause.is_some() { 407 | panic!("#[make_decorator_static()] does not work with where clauses") 408 | } 409 | 410 | match input.sig.decl.inputs.first() { 411 | | Some(Pair::End(FnArg::SelfValue(..))) 412 | | Some(Pair::End(FnArg::SelfRef(..))) 413 | | Some(Pair::Punctuated(FnArg::SelfRef(..), _)) 414 | | Some(Pair::Punctuated(FnArg::SelfValue(..), _)) => 415 | panic!("#[make_decorator_static()] must be applied on static methods"), 416 | _ => {} 417 | } 418 | 419 | let mut args = vec![]; 420 | 421 | let caller_name = ¯o_args.name; 422 | args.push(quote!(#caller_name: _F)); 423 | let mut where_args = vec![]; 424 | for arg in input.sig.decl.inputs.iter() { 425 | match *arg { 426 | FnArg::Captured(ref cap) => { 427 | let ty = &cap.ty; 428 | let pat = &cap.pat; 429 | where_args.push(quote!(#ty)); 430 | args.push(quote!(#pat: #ty)); 431 | } 432 | _ => panic!("Unexpected argument {:?}", arg) 433 | } 434 | } 435 | 436 | let funcname = &input.sig.ident; 437 | let attributes = &input.attrs; 438 | let vis = &input.vis; 439 | let constness = &input.sig.constness; 440 | let unsafety = &input.sig.unsafety; 441 | let abi = &input.sig.abi; 442 | let output = &input.sig.decl.output; 443 | let body = &input.block; 444 | let defaultness = &input.defaultness; 445 | 446 | quote!( 447 | #(#attributes),* 448 | #vis #defaultness #constness #unsafety #abi fn #funcname <_F> (#(#args),*) #output where _F: (Fn(#(#where_args),*) #output) { 449 | #body 450 | } 451 | ).into() 452 | } 453 | 454 | #[proc_macro_attribute] 455 | pub fn make_decorator_method(arg: TokenStream, input: TokenStream) -> TokenStream { 456 | let macro_args: Args = match parse(arg) { 457 | Ok(arg) => arg, 458 | _ => panic!("#[make_decorator_static()] takes a single identifier input"), 459 | }; 460 | if !macro_args.extra.is_empty() { 461 | panic!("#[make_decorator_static()] takes a single identifier input"); 462 | } 463 | 464 | let input: ImplItemMethod = match parse(input) { 465 | Ok(input) => input, 466 | Err(..) => panic!("#[make_decorator_static()] must be applied on methods"), 467 | }; 468 | 469 | if input.sig.decl.generics.where_clause.is_some() { 470 | panic!("#[make_decorator_static()] does not work with where clauses") 471 | } 472 | 473 | let first_arg = match input.sig.decl.inputs.first() { 474 | Some(Pair::End(first_arg @ FnArg::SelfValue(..))) 475 | | Some(Pair::End(first_arg @ FnArg::SelfRef(..))) 476 | | Some(Pair::Punctuated(first_arg @ FnArg::SelfValue(..), _)) 477 | | Some(Pair::Punctuated(first_arg @ FnArg::SelfRef(..), _)) => 478 | first_arg, 479 | _ => panic!("#[make_decorator_method()] must be applied on nonstatic methods") 480 | }; 481 | 482 | let caller_name = ¯o_args.name; 483 | let mut args = vec![]; 484 | let mut where_args = vec![]; 485 | 486 | match first_arg { 487 | FnArg::SelfValue(ref arg_self) => { 488 | let tmp = TokenStream2::from_str("Self"); 489 | debug_assert!(tmp.is_ok()); 490 | let ty = Type::from(TypeVerbatim {tts: tmp.unwrap()}); 491 | where_args.push(ty.into_tokens()); 492 | args.push(quote!(#arg_self)); 493 | }, 494 | FnArg::SelfRef( 495 | ref arg_self_ref @ ArgSelfRef { .. } 496 | ) => { 497 | let tmp = TokenStream2::from_str("Self"); 498 | debug_assert!(tmp.is_ok()); 499 | let ty = Type::from( 500 | TypeReference{ 501 | and_token: arg_self_ref.and_token.clone(), 502 | lifetime: arg_self_ref.lifetime.clone(), 503 | mutability: arg_self_ref.mutability.clone(), 504 | elem: Box::new(Type::from(TypeVerbatim {tts: tmp.unwrap()})) 505 | } 506 | ); 507 | where_args.push(quote!(#ty)); 508 | args.push(quote!(#arg_self_ref)); 509 | } 510 | _ => panic!() 511 | } 512 | args.push(quote!(#caller_name: _F)); 513 | 514 | for i in 1..input.sig.decl.inputs.len() { 515 | let arg = &input.sig.decl.inputs[i]; 516 | match *arg { 517 | FnArg::Captured(ref cap) => { 518 | let ty = &cap.ty; 519 | let pat = &cap.pat; 520 | where_args.push(quote!(#ty)); 521 | args.push(quote!(#pat: #ty)); 522 | } 523 | _ => panic!("Unexpected argument {:?}", arg) 524 | } 525 | } 526 | 527 | let funcname = &input.sig.ident; 528 | let attributes = &input.attrs; 529 | let vis = &input.vis; 530 | let constness = &input.sig.constness; 531 | let unsafety = &input.sig.unsafety; 532 | let abi = &input.sig.abi; 533 | let output = &input.sig.decl.output; 534 | let body = &input.block; 535 | let defaultness = &input.defaultness; 536 | 537 | quote!( 538 | #(#attributes),* 539 | #vis #defaultness #constness #unsafety #abi fn #funcname <_F> (#(#args),*) #output where _F: (Fn(#(#where_args),*) #output) { 540 | #body 541 | } 542 | ).into() 543 | } 544 | 545 | #[proc_macro_attribute] 546 | pub fn make_decorator(arg: TokenStream, input: TokenStream) -> TokenStream { 547 | let macro_args: Args = match parse(arg) { 548 | Ok(arg) => arg, 549 | _ => panic!("#[make_decorator()] takes a single identifier input"), 550 | }; 551 | if !macro_args.extra.is_empty() { 552 | panic!("#[make_decorator()] takes a single identifier input"); 553 | } 554 | 555 | let input: ItemFn = match parse(input) { 556 | Ok(input) => input, 557 | Err(..) => panic!("#[make_decorator()] must be applied on functions"), 558 | }; 559 | 560 | if input.decl.generics.where_clause.is_some() { 561 | panic!("#[make_decorator()] does not work with where clauses") 562 | } 563 | 564 | let mut args = vec![]; 565 | 566 | let caller_name = ¯o_args.name; 567 | args.push(quote!(#caller_name: _F)); 568 | let mut where_args = vec![]; 569 | for arg in input.decl.inputs.iter() { 570 | match *arg { 571 | FnArg::Captured(ref cap) => { 572 | let ty = &cap.ty; 573 | let pat = &cap.pat; 574 | where_args.push(quote!(#ty)); 575 | args.push(quote!(#pat: #ty)); 576 | } 577 | _ => panic!("Unexpected argument {:?}", arg) 578 | } 579 | } 580 | 581 | let funcname = &input.ident; 582 | let attributes = &input.attrs; 583 | let vis = &input.vis; 584 | let constness = &input.constness; 585 | let unsafety = &input.unsafety; 586 | let abi = &input.abi; 587 | let output = &input.decl.output; 588 | let body = &input.block; 589 | 590 | quote!( 591 | #(#attributes),* 592 | #vis #constness #unsafety #abi fn #funcname <_F> (#(#args),*) #output where _F: (Fn(#(#where_args),*) #output) { 593 | #body 594 | } 595 | ).into() 596 | } 597 | -------------------------------------------------------------------------------- /tests/fn-dec-args.rs: -------------------------------------------------------------------------------- 1 | extern crate adorn; 2 | 3 | use adorn::{adorn, make_decorator}; 4 | 5 | #[adorn(bar)] 6 | fn foo(a: &mut u8, b: &mut u8, (c, _): (u8, u8)) { 7 | assert!(c == 4); 8 | *a = c; 9 | *b = c; 10 | } 11 | 12 | #[make_decorator(f)] 13 | fn bar(a: &mut u8, b: &mut u8, (c, d): (u8, u8)) { 14 | assert!(c == 0 && d == 0); 15 | f(a, b, (4, 0)); 16 | *b = 100; 17 | } 18 | 19 | #[test] 20 | fn test() { 21 | let mut x = 0; 22 | let mut y = 1; 23 | foo(&mut x, &mut y, (0, 0)); 24 | assert!(x == 4 && y == 100); 25 | } 26 | -------------------------------------------------------------------------------- /tests/fn-dec-sugar.rs: -------------------------------------------------------------------------------- 1 | extern crate adorn; 2 | 3 | use adorn::{adorn, make_decorator}; 4 | 5 | #[adorn(bar)] 6 | fn foo(a: &mut u8, b: &mut u8, (c, _): (u8, u8)) { 7 | assert!(c == 4); 8 | *a = c; 9 | *b = c; 10 | } 11 | 12 | #[make_decorator(f)] 13 | fn bar(a: &mut u8, b: &mut u8, (c, d): (u8, u8)) { 14 | assert!(c == 0 && d == 0); 15 | f(a, b, (4, 0)); 16 | *b = 100; 17 | } 18 | 19 | #[test] 20 | fn test() { 21 | let mut x = 0; 22 | let mut y = 1; 23 | foo(&mut x, &mut y, (0, 0)); 24 | assert!(x == 4 && y == 100); 25 | } 26 | -------------------------------------------------------------------------------- /tests/fn-dec.rs: -------------------------------------------------------------------------------- 1 | extern crate adorn; 2 | 3 | use adorn::adorn; 4 | 5 | #[adorn(bar)] 6 | fn foo(a: &mut u8, b: &mut u8, (c, _): (u8, u8)) { 7 | assert!(c == 4); 8 | *a = c; 9 | *b = c; 10 | } 11 | 12 | 13 | fn bar(f: F, a: &mut u8, b: &mut u8, (c, d): (u8, u8)) where F: Fn(&mut u8, &mut u8, (u8, u8)) { 14 | assert!(c == 0 && d == 0); 15 | f(a, b, (4, 0)); 16 | *b = 100; 17 | } 18 | 19 | #[test] 20 | fn test() { 21 | let mut x = 0; 22 | let mut y = 1; 23 | foo(&mut x, &mut y, (0, 0)); 24 | assert!(x == 4 && y == 100); 25 | } 26 | -------------------------------------------------------------------------------- /tests/nonstatic-methods-dec.rs: -------------------------------------------------------------------------------- 1 | extern crate adorn; 2 | use adorn::{adorn_method, make_decorator_method}; 3 | 4 | struct Test { 5 | a: isize, 6 | b: isize 7 | } 8 | 9 | impl Test { 10 | #[adorn_method(bar)] 11 | fn foo(&mut self, a: isize, b: isize) -> Self { 12 | let mut c = |_self, __self| -> Self { 13 | self.a = _self; 14 | self.a = __self; 15 | Self { 16 | a, 17 | b 18 | } 19 | } ; 20 | c(3,2) 21 | } 22 | 23 | #[make_decorator_method(f)] 24 | fn bar(&mut self, a: isize, b: isize) -> Self { 25 | let mut retval = f(self, a, b); 26 | retval.a = 3; 27 | retval 28 | } 29 | 30 | #[adorn_method(bar1)] 31 | fn foo1(mut self) -> Self { 32 | self.a = 1; 33 | self 34 | } 35 | 36 | #[make_decorator_method(f)] 37 | fn bar1(mut self) -> Self { 38 | let mut retval = f(self); 39 | retval.b = 2; 40 | retval 41 | } 42 | } 43 | 44 | #[test] 45 | fn test() { 46 | let mut t1 = Test {a: 0, b: 1}; 47 | let t2 = t1.foo(5, 6); 48 | assert!(t1.a == 2 && t1.b == 1 && t2.a == 3 && t2.b == 6); 49 | 50 | let t3 = Test {a: 3, b: 4}; 51 | let t4 = t3.foo1(); 52 | assert!(t4.a == 1 && t4.b == 2); 53 | } 54 | -------------------------------------------------------------------------------- /tests/static-methods-dec.rs: -------------------------------------------------------------------------------- 1 | extern crate adorn; 2 | use adorn::{adorn_static, make_decorator_static}; 3 | 4 | struct Test { 5 | a: isize, 6 | b: isize 7 | } 8 | 9 | impl Test { 10 | #[adorn_static(bar)] 11 | fn foo(a: isize, b: isize) -> Self { 12 | assert!(a == 1 && b == 0); 13 | Self {a, b} 14 | } 15 | 16 | #[make_decorator_static(f)] 17 | fn bar(a: isize, b: isize) -> Self { 18 | assert!(a == 1 && b == 1); 19 | let mut retval = f(a, 0); 20 | retval.a = 4; 21 | retval 22 | } 23 | } 24 | 25 | #[test] 26 | fn test() { 27 | let t = Test::foo(1, 1); 28 | assert!(t.a == 4 && t.b == 0); 29 | } 30 | --------------------------------------------------------------------------------