aoc_runner_derive/
lib.rs

1#![recursion_limit = "128"]
2
3extern crate aoc_runner_internal;
4extern crate core;
5extern crate proc_macro;
6extern crate proc_macro2;
7extern crate quote;
8extern crate syn;
9
10mod generator;
11mod map;
12mod out;
13mod runner;
14mod types;
15mod utils;
16
17use crate::map::Map;
18use crate::utils::is_rls;
19use proc_macro as pm;
20use proc_macro2 as pm2;
21use quote::quote;
22
23thread_local! {
24    static AOC_RUNNER: Map = Map::new();
25}
26
27#[proc_macro_attribute]
28/// # Solution meta
29///
30/// Use this to flag a function as a solution for a given day :
31/// `#[aoc(day1, part1)]`
32///
33/// You can also add a custom name to the function :
34/// `#[aoc(day1, part1, Bytes)]`, it's useful to have multiple solutions to a given day & part and compare them !
35///
36/// The function must take a single parameter : a `&str` or a `&[u8]`, unless you use a [generator]
37/// and return any type implementing `Display`.
38///
39/// ## Results & Options
40///
41/// Since 0.2.0, you can output `Result` & `Option` from solution function, with the following constraints :
42///  - the output type must be named `Result` or `Option`, `type CustomResult<T> = Result<T, CustomError>;` cannot be used in return position.
43///  - the first generic parameter must implement `Display`
44///  - for `Result`s, the error must implement `Into<std::error::Error>`
45///
46/// You still can use a path before the `Result`/`Option`, like this : `std::io::Result<i32>`
47///
48/// [generator]: attr.aoc_generator.html
49pub fn aoc(args: pm::TokenStream, input: pm::TokenStream) -> pm::TokenStream {
50    if is_rls() {
51        let input: pm2::TokenStream = input.into();
52        return pm::TokenStream::from(quote! {
53            #[allow(unused)]
54            #input
55        });
56    }
57
58    runner::runner_impl(args, input)
59}
60
61#[proc_macro_attribute]
62/// # Generator meta
63///
64/// Use a generator when you need to pre-process your input :
65///
66/// ## Usage
67/// Generator meta have 3 forms :
68///  - a generator for the whole day : `#[aoc_generator(day1)]`
69///  - a generator for a single part : `#[aoc_generator(day1, part1)]`
70///  - a generator for a single (named) solution: `#[aoc_generator(day1, part1, Bytes)]`
71///
72/// The function must take a single parameter : a `&str` or a `&[u8]`, and output any sized type.
73///
74/// The corresponding solutions now take any parameter for which `Borrow` is implemented.
75///
76/// ## Results & Options
77///
78/// Since 0.2.0, you can output `Result` & `Option` from generator function, with the following constraints :
79///  - the output type must be named `Result` or `Option`, `type CustomResult<T> = Result<T, CustomError>;` cannot be used in return position.
80///  - for `Result`s, the error must implement `Into<std::error::Error>`
81///
82/// You still can use a path before the `Result`/`Option`, like this : `std::io::Result<i32>`
83///
84/// ## Note
85/// A generator must be declared before it's solutions.
86///
87pub fn aoc_generator(args: pm::TokenStream, input: pm::TokenStream) -> pm::TokenStream {
88    if is_rls() {
89        let input: pm2::TokenStream = input.into();
90        return pm::TokenStream::from(quote! {
91            #[allow(unused)]
92            #input
93        });
94    }
95
96    generator::generator_impl(args, input)
97}
98
99#[proc_macro]
100/// # Library declaration
101///
102/// This macro must be at the end of lib.rs
103///
104/// ## Usage
105/// `aoc_lib! { year = 2018 }`
106pub fn aoc_lib(input: pm::TokenStream) -> pm::TokenStream {
107    if is_rls() {
108        return pm::TokenStream::new();
109    }
110
111    out::lib_impl(input)
112}
113
114#[proc_macro]
115/// # Main declaration
116///
117/// This macro must be at the end of main.rs
118///
119/// ## Usage
120/// `aoc_main` has 2 forms :
121///  - as a standalone binary : `aoc_main! { year = 2018 }`
122///  - as a link to a library : `aoc_main! { lib = advent_of_code_2018 }` (you must had `extern crate advent_of_code_2018;` before)
123pub fn aoc_main(input: pm::TokenStream) -> pm::TokenStream {
124    if is_rls() {
125        return pm::TokenStream::from(quote! { fn main() {} });
126    }
127
128    out::main_impl(input)
129}