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