named 0.1.0

Procedural macro which allows you to produce functions which can be called with named arguments, optionally with default values.
Documentation
#![allow(clippy::eval_order_dependence)]

use indexmap::IndexMap;
use syn::parse::{Parse, ParseStream, Result};

mod kw {
    syn::custom_keyword!(defaults);
}

pub struct Attributes {
    items: syn::punctuated::Punctuated<Attribute, syn::Token![,]>,
}

impl Attributes {
    pub fn defaults(&self) -> IndexMap<String, (proc_macro2::Span, syn::Expr)> {
        let mut map = IndexMap::new();
        for attribute in &self.items {
            let Attribute::Defaults(defaults) = attribute;
            for default in &defaults.defaults {
                map.insert(
                    default.name.to_string(),
                    (default.name.span(), default.value.clone()),
                );
            }
        }
        map
    }
}

pub enum Attribute {
    Defaults(Defaults),
}

impl Parse for Attributes {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        Ok(Self {
            items: input.parse_terminated(Attribute::parse)?,
        })
    }
}

impl Parse for Attribute {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let lookahead = input.lookahead1();
        if lookahead.peek(kw::defaults) {
            input.parse().map(Self::Defaults)
        } else {
            Err(lookahead.error())
        }
    }
}

pub struct Default {
    name: syn::Ident,
    _eq_token: syn::Token![=],
    value: syn::Expr,
}

impl Parse for Default {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        Ok(Self {
            name: input.parse()?,
            _eq_token: input.parse()?,
            value: input.parse()?,
        })
    }
}

pub struct Defaults {
    _keyword: kw::defaults,
    _bracket_token: syn::token::Paren,
    defaults: syn::punctuated::Punctuated<Default, syn::Token![,]>,
}

impl Parse for Defaults {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let content;
        Ok(Self {
            _keyword: input.parse()?,
            _bracket_token: syn::parenthesized!(content in input),
            defaults: content.parse_terminated(Default::parse)?,
        })
    }
}