portable_intertrait_macros/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4
5use syn::{parse, parse_macro_input, DeriveInput, ItemImpl};
6
7use args::{Casts, Flag, Targets};
8use gen_caster::generate_caster;
9
10mod args;
11mod gen_caster;
12mod item_impl;
13mod 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]
65pub 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]
133pub 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}