xref: /DragonOS/kernel/crates/intertrait/macros/src/lib.rs (revision 7c28051e8c601312d3d0fd7bcb71bc71450d10c0)
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