1 extern crate proc_macro; 2 3 use proc_macro::TokenStream; 4 5 use syn::{parse, parse_macro_input, DeriveInput, ItemImpl}; 6 7 use args::{Casts, Flag, Targets}; 8 use gen_caster::generate_caster; 9 10 mod args; 11 mod gen_caster; 12 mod item_impl; 13 mod item_type; 14 15 /// Attached on an `impl` item or type definition, registers traits as targets for casting. 16 /// 17 /// If on an `impl` item, no argument is allowed. But on a type definition, the target traits 18 /// must be listed explicitly. 19 /// 20 /// Add `[sync]` before the list of traits if the underlying type is `Sync + Send` and you 21 /// need `std::sync::Arc`. 22 /// 23 /// # Examples 24 /// ## On a trait impl 25 /// ``` 26 /// use intertrait::*; 27 /// 28 /// struct Data; 29 /// 30 /// trait Greet { 31 /// fn greet(&self); 32 /// } 33 /// 34 /// // Greet can be cast into from any sub-trait of CastFrom implemented by Data. 35 /// #[cast_to] 36 /// impl Greet for Data { 37 /// fn greet(&self) { 38 /// println!("Hello"); 39 /// } 40 /// } 41 /// ``` 42 /// 43 /// ## On a type definition 44 /// Use when a target trait is derived or implemented in an external crate. 45 /// ``` 46 /// use intertrait::*; 47 /// 48 /// // Debug can be cast into from any sub-trait of CastFrom implemented by Data 49 /// #[cast_to(std::fmt::Debug)] 50 /// #[derive(std::fmt::Debug)] 51 /// struct Data; 52 /// ``` 53 /// 54 /// ## For Arc 55 /// Use when the underlying type is `Sync + Send` and you want to use `Arc`. 56 /// ``` 57 /// use intertrait::*; 58 /// 59 /// // Debug can be cast into from any sub-trait of CastFrom implemented by Data 60 /// #[cast_to([sync] std::fmt::Debug)] 61 /// #[derive(std::fmt::Debug)] 62 /// struct Data; 63 /// ``` 64 65 #[proc_macro_attribute] 66 pub fn cast_to(args: TokenStream, input: TokenStream) -> TokenStream { 67 match parse::<Targets>(args) { 68 Ok(Targets { flags, paths }) => { 69 if paths.is_empty() { 70 item_impl::process(&flags, parse_macro_input!(input as ItemImpl)) 71 } else { 72 item_type::process(&flags, paths, parse_macro_input!(input as DeriveInput)) 73 } 74 } 75 Err(err) => vec![err.to_compile_error(), input.into()] 76 .into_iter() 77 .collect(), 78 } 79 .into() 80 } 81 82 /// Declares target traits for casting implemented by a type. 83 /// 84 /// This macro is for registering both a concrete type and its traits to be targets for casting. 85 /// Useful when the type definition and the trait implementations are in an external crate. 86 /// 87 /// **Note**: this macro cannot be used in an expression or statement prior to Rust 1.45.0, 88 /// due to [a previous limitation](https://github.com/rust-lang/rust/pull/68717). 89 /// If you want to use it in an expression or statement, use Rust 1.45.0 or later. 90 /// 91 /// # Examples 92 /// ``` 93 /// use intertrait::*; 94 /// 95 /// #[derive(std::fmt::Debug)] 96 /// enum Data { 97 /// A, B, C 98 /// } 99 /// trait Greet { 100 /// fn greet(&self); 101 /// } 102 /// impl Greet for Data { 103 /// fn greet(&self) { 104 /// println!("Hello"); 105 /// } 106 /// } 107 /// 108 /// castable_to! { Data => std::fmt::Debug, Greet } 109 /// 110 /// # fn main() {} 111 /// ``` 112 /// 113 /// When the type is `Sync + Send` and is used with `Arc`: 114 /// ``` 115 /// use intertrait::*; 116 /// 117 /// #[derive(std::fmt::Debug)] 118 /// enum Data { 119 /// A, B, C 120 /// } 121 /// trait Greet { 122 /// fn greet(&self); 123 /// } 124 /// impl Greet for Data { 125 /// fn greet(&self) { 126 /// println!("Hello"); 127 /// } 128 /// } 129 /// castable_to! { Data => [sync] std::fmt::Debug, Greet } 130 /// 131 /// # fn main() {} 132 /// ``` 133 #[proc_macro] 134 pub fn castable_to(input: TokenStream) -> TokenStream { 135 let Casts { 136 ty, 137 targets: Targets { flags, paths }, 138 } = parse_macro_input!(input); 139 140 paths 141 .iter() 142 .map(|t| generate_caster(&ty, t, flags.contains(&Flag::Sync))) 143 .collect::<proc_macro2::TokenStream>() 144 .into() 145 } 146