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 #[proc_macro_attribute]
cast_to(args: TokenStream, input: TokenStream) -> TokenStream65 pub fn cast_to(args: TokenStream, input: TokenStream) -> TokenStream {
66 match parse::<Targets>(args) {
67 Ok(Targets { flags, paths }) => {
68 if paths.is_empty() {
69 item_impl::process(&flags, parse_macro_input!(input as ItemImpl))
70 } else {
71 item_type::process(&flags, paths, parse_macro_input!(input as DeriveInput))
72 }
73 }
74 Err(err) => vec![err.to_compile_error(), input.into()]
75 .into_iter()
76 .collect(),
77 }
78 .into()
79 }
80
81 /// Declares target traits for casting implemented by a type.
82 ///
83 /// This macro is for registering both a concrete type and its traits to be targets for casting.
84 /// Useful when the type definition and the trait implementations are in an external crate.
85 ///
86 /// **Note**: this macro cannot be used in an expression or statement prior to Rust 1.45.0,
87 /// due to [a previous limitation](https://github.com/rust-lang/rust/pull/68717).
88 /// If you want to use it in an expression or statement, use Rust 1.45.0 or later.
89 ///
90 /// # Examples
91 /// ```
92 /// use intertrait::*;
93 ///
94 /// #[derive(std::fmt::Debug)]
95 /// enum Data {
96 /// A, B, C
97 /// }
98 /// trait Greet {
99 /// fn greet(&self);
100 /// }
101 /// impl Greet for Data {
102 /// fn greet(&self) {
103 /// println!("Hello");
104 /// }
105 /// }
106 ///
107 /// castable_to! { Data => std::fmt::Debug, Greet }
108 ///
109 /// # fn main() {}
110 /// ```
111 ///
112 /// When the type is `Sync + Send` and is used with `Arc`:
113 /// ```
114 /// use intertrait::*;
115 ///
116 /// #[derive(std::fmt::Debug)]
117 /// enum Data {
118 /// A, B, C
119 /// }
120 /// trait Greet {
121 /// fn greet(&self);
122 /// }
123 /// impl Greet for Data {
124 /// fn greet(&self) {
125 /// println!("Hello");
126 /// }
127 /// }
128 /// castable_to! { Data => [sync] std::fmt::Debug, Greet }
129 ///
130 /// # fn main() {}
131 /// ```
132 #[proc_macro]
castable_to(input: TokenStream) -> TokenStream133 pub fn castable_to(input: TokenStream) -> TokenStream {
134 let Casts {
135 ty,
136 targets: Targets { flags, paths },
137 } = parse_macro_input!(input);
138
139 paths
140 .iter()
141 .map(|t| generate_caster(&ty, t, flags.contains(&Flag::Sync)))
142 .collect::<proc_macro2::TokenStream>()
143 .into()
144 }
145