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]
cast_to(args: TokenStream, input: TokenStream) -> TokenStream66 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]
castable_to(input: TokenStream) -> TokenStream134 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