1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
/// This crate contains macros used by `telers` crate
///
/// # Macros
///
/// ## `FromContext`
///
/// Derive an implementation of `FromEventAndContext` for the given type.
/// This macro will generate an implementation of `FromEventAndContext` for the whole given type.
/// It will use the key attribute by which this type will be extracted from context.
pub(crate) mod attrs_parsing;
pub(crate) mod stream;
mod from_context;
mod from_event;
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::parse::Parse;
/// Derive an implementation of `FromEventAndContext` for the given type.
///
/// This macro supports the following attributes:
/// * `#[context(key = "...")]` - the key by which the type will be extracted from context.
/// * `#[context(into = "...")]` - the type into which the type will be converted.
/// * `#[context(from = "...")]` - the type from which the type will be converted.
/// * `#[context(description = "...")]` - the description of the type in context. \
/// This attribute is used only for documentation purposes and perhaps for debugging.
///
/// Check the examples below to see how to use this macro and what types of deriving are supported.
///
/// ## Whole struct by key in context
///
/// ```rust
/// use telers_macros::FromContext;
///
/// #[derive(Clone, FromContext)]
/// #[context(key = "my_struct")]
/// struct MyStruct {
/// field: i32,
/// }
///
/// async fn handler(my_struct: MyStruct) {
/// // ...
/// }
/// ```
///
/// ## Whole enum by key in context
///
/// ```rust
/// use telers_macros::FromContext;
///
/// #[derive(Clone, FromContext)]
/// #[context(key = "my_enum")]
/// enum MyEnum {
/// Variant1,
/// Variant2,
/// }
///
/// async fn handler(my_enum: MyEnum) {
/// // ...
/// }
/// ```
///
/// ## Whole struct that can be converted from another one type that is in context by key
///
/// You need to implement `From`/`Into` trait for your type by yourself.
/// This can be useful when you want to wrap your type to another one or if the type in context is a foreign type,
/// and you want to convert it to your own type to use it in handler (because you can't implement a foreign trait for a foreign type).
///
/// ```rust
/// use telers_macros::FromContext;
///
/// #[derive(Clone, FromContext)]
/// #[context(key = "my_struct", into = MyStructWrapper)]
/// struct MyStruct {
/// field: i32,
/// }
///
/// struct MyStructWrapper(MyStruct);
///
/// impl From<MyStruct> for MyStructWrapper {
/// fn from(my_struct: MyStruct) -> Self {
/// Self(my_struct)
/// }
/// }
/// ```
///
/// You can also use `#[context(from = "...")]` attribute to specify the type from which the type will be converted.
///
/// ```rust
/// use telers_macros::FromContext;
///
/// #[derive(Clone)]
/// struct MyStruct {
/// field: i32,
/// }
///
/// #[derive(FromContext)]
/// #[context(key = "my_struct", from = MyStruct)]
/// struct MyStructWrapper(MyStruct);
///
/// impl From<MyStruct> for MyStructWrapper {
/// fn from(my_struct: MyStruct) -> Self {
/// Self(my_struct)
/// }
/// }
/// ```
///
/// ## Whole enum that can be converted from another one type that is in context by key
///
/// You need to implement `From`/`Into` trait for your type by yourself.
/// This can be useful when you want to wrap your type to another one or if the type in context is a foreign type,
/// and you want to convert it to your own type to use it in handler (because you can't implement a foreign trait for a foreign type).
///
/// ```rust
/// use telers_macros::FromContext;
///
/// #[derive(Clone, FromContext)]
/// #[context(key = "my_enum", into = MyEnumWrapper)]
/// enum MyEnum {
/// Variant1,
/// Variant2,
/// }
///
/// struct MyEnumWrapper(MyEnum);
///
/// impl From<MyEnum> for MyEnumWrapper {
/// fn from(my_enum: MyEnum) -> Self {
/// Self(my_enum)
/// }
/// }
/// ```
///
/// You can also use `#[context(from = "...")]` attribute to specify the type from which the type will be converted.
///
/// ```rust
/// use telers_macros::FromContext;
///
/// #[derive(Clone)]
/// enum MyEnum {
/// Variant1,
/// Variant2,
/// }
///
/// #[derive(FromContext)]
/// #[context(key = "my_enum", from = MyEnum)]
/// struct MyEnumWrapper(MyEnum);
///
/// impl From<MyEnum> for MyEnumWrapper {
/// fn from(my_enum: MyEnum) -> Self {
/// Self(my_enum)
/// }
/// }
/// ```
#[proc_macro_derive(FromContext, attributes(context))]
pub fn derive_from_context(item: TokenStream) -> TokenStream {
expand_with(item, from_context::expand)
}
/// Derive an implementation of `FromEventAndContext` for the given type.
///
/// This macro supports the following attributes:
/// * `#[event(from = "...")]` - the from which the type will be converted.
/// * `#[event(try_from = "...")]` - the from which the type will be converted.
/// * `#[event(error = "...")]` - the error type that will be returned if conversion fails. \
/// Used only if `try_from` is specified. \
/// If it's empty, then we use `ConvertToTypeError` type as error type. \
/// If it's not empty, then we use this type as error type.
/// * `#[event(description = "...")]` - the description of the type. \s
/// This attribute is used only for documentation purposes.
///
/// "..." it can be either a type, or a type path to one of them:
/// * `Update` - the main type of the crate, which contains all the information about the event.
///
/// Check examples below to see how to use this macro and what types of deriving are supported.
///
/// ## Whole struct that can be converted from `Update`
///
/// You need to implement `From`/`TryFrom` trait for your type by yourself.
/// This can be useful when you want to use some type from the `Update` in your handler in a more convenient way.
///
/// ```rust
/// use telers_macros::FromEvent;
/// use telers::types::Update;
///
/// #[derive(FromEvent)]
/// #[event(from = Update)]
/// struct UpdateId(i64);
///
/// impl From<Update> for UpdateId {
/// fn from(update: Update) -> Self {
/// Self(update.id)
/// }
/// }
/// ```
///
/// You can also use `#[event(try_from = "...")]` attribute to specify the type from which the type will be converted.
///
/// ```rust
/// use telers_macros::FromEvent;
/// use telers::types::Update;
/// use std::convert::Infallible;
///
/// #[derive(FromEvent)]
/// #[event(try_from = Update, error = Infallible)] // we can don't specify error type, but it will be `ConvertToTypeError` by default
/// struct UpdateId(i64);
///
/// impl TryFrom<Update> for UpdateId { // we use `TryFrom` here just for example, you need to use `From` if error is impossible
/// type Error = Infallible;
///
/// fn try_from(update: Update) -> Result<Self, Self::Error> {
/// Ok(Self(update.id))
/// }
/// }
/// ```
///
/// Another example, but with default error type:
///
/// ```rust
/// use telers_macros::FromEvent;
/// use telers::{types::Update, errors::ConvertToTypeError};
/// use std::convert::Infallible;
///
/// #[derive(FromEvent)]
/// #[event(try_from = Update)] // you can specify `ConvertToTypeError` as error type, but it's not necessary, because it's default
/// struct UpdateFromId(i64);
///
/// impl TryFrom<Update> for UpdateFromId {
/// type Error = ConvertToTypeError;
///
/// fn try_from(update: Update) -> Result<Self, Self::Error> {
/// match update.from_id() {
/// Some(id) => Ok(Self(id)),
/// None => Err(ConvertToTypeError::new("Update", "UpdateFromId")),
/// }
/// }
/// }
/// ```
/// # Notes
/// This macros is used in the library to implement `FromEventAndContext` for types that impl `From` for `Update`,
/// but you can use it for your own types.
#[proc_macro_derive(FromEvent, attributes(event))]
pub fn derive_from_event(item: TokenStream) -> TokenStream {
expand_with(item, from_event::expand)
}
fn expand_with<F, I, K>(input: TokenStream, f: F) -> TokenStream
where
F: FnOnce(I) -> syn::Result<K>,
I: Parse,
K: ToTokens,
{
expand(syn::parse(input).and_then(f))
}
fn expand<T>(result: syn::Result<T>) -> TokenStream
where
T: ToTokens,
{
match result {
Ok(tokens) => {
let tokens = (quote! { #tokens }).into();
if std::env::var_os("MACROS_DEBUG").is_some() {
eprintln!("{tokens}");
}
tokens
}
Err(err) => err.into_compile_error().into(),
}
}