default_kwargs 0.1.0

The macro wich enables you to use default and keyword arguments in Rust
Documentation
#![doc = include_str!("../README.md")]

extern crate proc_macro;
mod default_args;
mod keyword_args;
mod utils;

use proc_macro::TokenStream;
use quote::quote;

/// Turns your function with default arguments into valid Rust function.
///
/// This macro will move all the arguments with default values into generated
/// struct and implement [`Default`] for it, modifying the function's signature
/// from `bar(x: A, b: B = B)` to `bar(x: A, BarArgs { b }: BarArgs)`. You don't
/// need to change function's body or anything else (hopefully).
///
/// Generic types would be used in the struct's declaration if defaulted types
/// are generic.
///
/// If you use this, consider also using [`keyword_args!`] when calling the
/// function, otherwise you will have to pass the generated struct manually.
///
/// # Example:
///
/// ```rust
/// default_kwargs::default_args! {
///     #[must_use]
///     #[allow(unused, clippy::unnecessary_wraps)]
///     #[allow(clippy::toplevel_ref_arg, clippy::extra_unused_lifetimes)]
///     pub(in self) unsafe fn unsafe_thingy<'asd, T: Sized>(
///         #[allow(unused)] ref mut _x: &mut (),
///         ref mut y: T = T::default(),
///     ) -> Option<*mut T>
///     where
///         T: Default + Copy,
///     {
///         Some(Box::into_raw(Box::new(*y)))
///     }
/// }
/// ```
///
/// is literally turned into
///
/// ```rust
/// #[allow(unused)]
/// pub(self) struct Unsafe_thingyArgs<T>
/// where
///     T: Default + Copy,
/// {
///     pub(self) y: T,
/// }
/// impl<T> ::core::default::Default for Unsafe_thingyArgs<T>
/// where
///     T: Default + Copy,
/// {
///     fn default() -> Self {
///         Self { y: T::default() }
///     }
/// }
/// #[must_use]
/// #[allow(unused, clippy::unnecessary_wraps)]
/// #[allow(clippy::toplevel_ref_arg, clippy::extra_unused_lifetimes)]
/// pub(self) unsafe fn unsafe_thingy<'asd, T: Sized>(
///     #[allow(unused)] ref mut _x: &mut (),
///     Unsafe_thingyArgs { ref mut y }: Unsafe_thingyArgs<T>,
/// ) -> Option<*mut T>
/// where
///     T: Default + Copy,
/// {
///     Some(Box::into_raw(Box::new(*y)))
/// }
/// ```
///
/// See [crate-level docs](crate) for more info.
#[proc_macro]
pub fn default_args(item: TokenStream) -> TokenStream {
    let item = syn::parse_macro_input!(item as default_args::DefaultFn);
    quote! { #item }.into()
}

/// Turns function call with keyword arguments into plain function, passing the
/// arguments struct, generated by [`default_args!`] macro.
///
/// The main downside is, if you call the function that is not declared in the
/// current scope, this will not work. [`default_args!`] macro responsible of
/// declaring the args struct cannot communicate with this macro, and it is not
/// possible for this macro to see the surrounding scope, so we can't get full
/// path to the struct without knowing the path of the function. That said, when
/// using this macro, either manually import the generated struct (but that
/// might confuse the readers (and possibly you)) or write the full path to the
/// function when calling it inside this macro.
///
/// # Example
///
/// ```rust
/// # mod path { pub(super) struct FooArgs { pub(super) u: () }
/// # impl Default for FooArgs { fn default() -> Self { Self { u: () } } }
/// # pub(super) fn foo(_: FooArgs) {} }
/// use default_kwargs::keyword_args;
/// keyword_args! { path::foo(u = ()) };
/// ```
///
/// is literally turned into
///
/// ```rust
/// # mod path { pub(super) struct FooArgs { pub(super) u: () }
/// # impl Default for FooArgs { fn default() -> Self { Self { u: () } } }
/// # pub(super) fn foo(_: FooArgs) {} }
/// use default_kwargs::keyword_args;
/// path::foo(
///     #[allow(clippy::needless_update)]
///     path::FooArgs {
///         u: (),
///         ..path::FooArgs::default()
///     },
/// );
/// ```
///
/// See [crate-level docs](crate) for more info.
#[proc_macro]
pub fn keyword_args(item: TokenStream) -> TokenStream {
    let item = syn::parse_macro_input!(item as keyword_args::KeywordFn);
    quote! { #item }.into()
}