lib.rs 3.6 KB

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