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