micro-tower-codegen 0.1.0

micro-tower proc-macros and attributes for code generation
Documentation
#![feature(proc_macro_diagnostic)]

use darling::FromMeta;
use proc_macro::TokenStream;
use service::Service;
use syn::{parse_macro_input, AttributeArgs};

mod service;
mod util;

/// Proc macro attribute to generate service implementation from function declaration. Will
/// generate a struct which implements `micro_tower::Service`.
///
/// # Usage
///
/// A service can be generated by putting `#[micro_tower::codegen::service]` in front of `async`
/// functions.
///
/// ```rust
/// #[micro_tower::codegen::service]
/// async fn service_name(request: ()) -> &'static str {
///     "Hello, World!"
/// }
/// ```
///
/// Errors can be handled using [`Result`].
///
/// ```rust
/// #[micro_tower::codegen::service]
/// async fn service_name(request: ()) -> Result<&'static str, Infallible> {
///     Ok("Hello, World!")
/// }
/// ```
///
/// It is possible to use other services (inner service) in a service by putting an argument with
/// the type of the service.
///
/// ```rust
/// #[micro_tower::codegen::service]
/// async fn service_other(request: (), inner: service_name) -> Result<&'static str, BoxError> {
///     Ok(inner.call(request).await?)
/// }
/// ```
///
/// A service generated with this macro can be build using the builder pattern.
///
/// ```rust
/// let service = service_name::builder().build();
/// ```
///
/// or in case an inner service is used
///
/// ```rust
/// let inner = service_name::builder().build();
/// let service = service_other::builder().inner(inner).build();
/// ```
///
/// the setter for inner services will always be named the same as the service argument.
///
/// # Attributes
///
/// - `crate = "<path>"`: Use to specify a crate path different from `::micro_tower`.
/// - `name = "<name>"`: Change log name of service to `<name>`.
/// - `extend`: Specifies that the service already exists and only `tower::Service` should be
///   implemented.
///
/// # Caveats / Notes
///
/// - non-`async` functions are not supported
/// - for error handling [`std::result::Result`] must be used (and no specialized like
///   [`std::io::Result`])
/// - the generated service is **not** clonable
#[proc_macro_attribute]
pub fn service(args: TokenStream, items: TokenStream) -> TokenStream {
    let args = parse_macro_input!(args as AttributeArgs);
    let args = match service::args::Args::from_list(&args) {
        Ok(args) => args,
        Err(err) => return TokenStream::from(err.write_errors()),
    };
    let decl = parse_macro_input!(items as syn::ItemFn);
    Service::new(&args, decl).generate(&args).into()
}