macro_loop 0.4.3

A macro for writing repetitive Rust code using loops, conditionals, and bindings
Documentation
use derive_syn_parse::Parse;
use syn::{Error, Ident, Token, punctuated::Punctuated, token::Bracket};

use super::*;

#[derive(Clone, Parse)]
pub enum Pattern {
    #[peek(Ident, name = "identifer")]
    Ident(Name),

    #[allow(private_interfaces)]
    #[peek(Bracket, name = "list")]
    List(PatternList),
}

impl<'p, 'v> Namespace<'p, 'v> {
    pub fn insert_pat(&mut self, pat: &Pattern, value: ValueRef<'v>) -> syn::Result<()> {
        match pat {
            Pattern::Ident(self_) => self.insert(self_, value)?,

            Pattern::List(self_) => match value {
                ValueRef::Owned(Value::List(value)) => {
                    if self_.items.len() != value.items.len() {
                        return Err(Error::new_spanned(
                            value,
                            format!(
                                "value doesn't match pattern. expected {} items",
                                self_.items.len()
                            ),
                        ));
                    }

                    for (pat_item, value) in self_.items.iter().zip(value.items) {
                        self.insert_pat(pat_item, value)?;
                    }
                }

                ValueRef::Ref(Value::List(value)) => {
                    if self_.items.len() != value.items.len() {
                        return Err(Error::new_spanned(
                            value,
                            format!(
                                "value doesn't match pattern. expected {} items",
                                self_.items.len()
                            ),
                        ));
                    }

                    for (pat_item, value) in self_.items.iter().zip(&value.items) {
                        self.insert_pat(pat_item, ValueRef::Ref(value))?;
                    }
                }

                _ => {
                    return Err(Error::new_spanned(
                        &*value,
                        "value doesn't match pattern. expected a list",
                    ));
                }
            },
        }

        Ok(())
    }
}

#[derive(Clone, Parse)]
struct PatternList {
    #[bracket]
    _brackets: Bracket,

    #[inside(_brackets)]
    #[call(Punctuated::parse_terminated)]
    items: Punctuated<Pattern, Token![,]>,
}