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