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
//! The procedural macros for Tsukuyomi.
#![recursion_limit = "256"]
#![deny(nonstandard_style, rust_2018_idioms, rust_2018_compatibility, unused)]
#![cfg_attr(test, deny(warnings))]
#![forbid(clippy::unimplemented)]
#![doc(test(attr(deny(deprecated))))]
extern crate proc_macro;
mod derive_into_response;
mod path_impl;
use proc_macro::TokenStream;
/// A procedural macro for deriving the implementation of `IntoResponse`.
///
/// # Examples
///
/// This macro has a parameter `#[response(preset = "..")]`, which specifies
/// the path to a type that implements a trait [`Preset`]:
///
/// ```
/// # use tsukuyomi::IntoResponse;
/// use serde::Serialize;
///
/// #[derive(Debug, Serialize, IntoResponse)]
/// #[response(preset = "tsukuyomi::output::preset::Json")]
/// struct Post {
/// title: String,
/// text: String,
/// }
/// # fn main() {}
/// ```
///
/// You can specify the additional trait bounds to type parameters
/// by using the parameter `#[response(bound = "..")]`:
///
/// ```
/// # use tsukuyomi::IntoResponse;
/// # use serde::Serialize;
/// #[derive(Debug, IntoResponse)]
/// #[response(
/// preset = "tsukuyomi::output::preset::Json",
/// bound = "T: Serialize",
/// bound = "U: Serialize",
/// )]
/// struct CustomValue<T, U> {
/// t: T,
/// u: U,
/// }
/// # fn main() {}
/// ```
///
/// # Notes
/// 1. When `preset = ".."` is omitted for struct, a field in the specified
/// struct is chosen and the the implementation of `IntoResponse` for its
/// type is used. For example, the impls derived to the following types
/// outputs eventually the same result as the implementation of
/// `IntoResponse` for `String`:
/// ```
/// # use tsukuyomi::IntoResponse;
/// #[derive(IntoResponse)]
/// struct Foo(String);
///
/// #[derive(IntoResponse)]
/// struct Bar {
/// inner: String,
/// }
/// ```
/// 1. When `preset = ".."` is omitted for enum, the same rule as struct is
/// applied to each variant:
/// ```
/// # use tsukuyomi::IntoResponse;
/// # use tsukuyomi::vendor::http::Response;
/// #[derive(IntoResponse)]
/// enum MyResponse {
/// Text(String),
/// Raw { response: Response<String> },
/// }
/// ```
/// 1. Without specifying the preset, the number of fields in the struct
/// or the number of fields of each variant inside of the enum must be
/// at most one. This is because the field that implements `IntoResponse`
/// cannot be determined if there are two or more fields in a struct or
/// a variant:
/// ```compile_fail
/// # use tsukuyomi::IntoResponse;
/// #[derive(IntoResponse)]
/// enum ApiResponse {
/// Text(String),
/// Post { title: String, text: String },
/// }
/// ```
/// If you want to apply the derivation to complex enums,
/// consider cutting each variant into one struct and specifying
/// the preset explicitly as follows:
/// ```
/// # use tsukuyomi::IntoResponse;
/// # use serde::Serialize;
/// #[derive(IntoResponse)]
/// enum ApiResponse {
/// Text(String),
/// Post(Post),
/// }
///
/// #[derive(Debug, Serialize, IntoResponse)]
/// #[response(preset = "tsukuyomi::output::preset::Json")]
/// struct Post {
/// title: String,
/// text: String,
/// }
/// ```
///
/// [`Preset`]: https://tsukuyomi-rs.github.io/tsukuyomi/tsukuyomi/output/preset/trait.Preset.html
#[proc_macro_derive(IntoResponse, attributes(response))]
#[allow(nonstandard_style)]
#[cfg_attr(tarpaulin, skip)]
pub fn IntoResponse(input: TokenStream) -> TokenStream {
crate::derive_into_response::derive(input.into())
.unwrap_or_else(|err| err.to_compile_error())
.into()
}
#[proc_macro]
pub fn path_impl(input: TokenStream) -> TokenStream {
crate::path_impl::path_impl(input.into())
.unwrap_or_else(|err| err.to_compile_error())
.into()
}