aoc-runner-derive 0.2.0

Codegen for aoc-runner & others
Documentation
use aoc_runner_internal::{DayPart, Part};
use crate::types::Generator;
use crate::utils;
use crate::AOC_RUNNER;
use proc_macro as pm;
use syn::*;

pub fn generator_impl(args: pm::TokenStream, input: pm::TokenStream) -> pm::TokenStream {
    let (day, part, name) = utils::extract_meta(args);
    let day = day
        .to_string()
        .parse()
        .expect("generators must have defined day");
    let part = part.and_then(|p| p.to_string().parse().ok());
    let name = name.map(|i| i.to_string());

    let input_cloned = input.clone();

    let input = parse_macro_input!(input as ItemFn);

    let fn_name = input.ident;
    let decl = input.decl;
    let out_t = if let ReturnType::Type(_, p) = decl.output {
        p
    } else {
        panic!("cannot find output type for {}", fn_name)
    };

    let (special_type, out_t) = if let Some((ty, inner)) = utils::extract_result(&*out_t) {
        (Some(ty), Box::new(inner))
    } else {
        (None, out_t)
    };

    AOC_RUNNER.with(|map| {
        let mut map = map
            .borrow_mut()
            .expect("failed to borrow shared map from generator");

        let mut register = |p: Part| {
            let runner = map
                .entry(DayPart {
                    day,
                    part: p,
                    name: name.clone(),
                }).or_default();
            runner.with_generator(Generator::new(&fn_name, &out_t, special_type));
        };

        if let Some(p) = part {
            register(p);
        } else {
            register(Part(1));
            register(Part(2));
        }
    });

    input_cloned
}