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
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 /// ``` /// 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. /// ``` /// // 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`. /// ``` /// // 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 due to /// [the current limitation](https://github.com/rust-lang/rust/pull/68717) in the stable Rust. /// /// # Examples /// ``` /// #[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 } /// ``` /// /// When the type is `Sync + Send` and is used with `Arc`: /// ``` /// #[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 } /// ``` #[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() }