diff --git a/inputs/1.txt b/.aoc-cache/1.txt similarity index 100% rename from inputs/1.txt rename to .aoc-cache/1.txt diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3b11770 --- /dev/null +++ b/.envrc @@ -0,0 +1,2 @@ +use flake +dotenv diff --git a/.gitignore b/.gitignore index ea8c4bf..ff2fe4c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /target +.env +/.direnv diff --git a/Cargo.lock b/Cargo.lock index 7ecbe5f..d565394 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,7 +21,17 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" name = "aoc-2022" version = "0.1.0" dependencies = [ + "aoc_proc", "color-eyre", + "ureq", +] + +[[package]] +name = "aoc_proc" +version = "0.1.0" +dependencies = [ + "quote", + "syn", ] [[package]] @@ -34,11 +44,23 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.5.4", "object", "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "bumpalo" +version = "3.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" + [[package]] name = "cc" version = "1.0.77" @@ -51,6 +73,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chunked_transfer" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" + [[package]] name = "color-eyre" version = "0.6.2" @@ -78,6 +106,15 @@ dependencies = [ "tracing-error", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + [[package]] name = "eyre" version = "0.6.8" @@ -88,18 +125,56 @@ dependencies = [ "once_cell", ] +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "miniz_oxide 0.6.2", +] + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + [[package]] name = "gimli" version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indenter" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -112,6 +187,15 @@ version = "0.2.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + [[package]] name = "memchr" version = "2.5.0" @@ -127,6 +211,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + [[package]] name = "object" version = "0.29.0" @@ -148,18 +241,79 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + [[package]] name = "pin-project-lite" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + [[package]] name = "rustc-demangle" version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +[[package]] +name = "rustls" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -169,6 +323,23 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "syn" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "thread_local" version = "1.1.4" @@ -178,6 +349,21 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + [[package]] name = "tracing" version = "0.1.37" @@ -220,8 +406,168 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "ureq" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97acb4c28a254fd7a4aeec976c46a7fa404eac4d7c134b30c75144846d7cb8f" +dependencies = [ + "base64", + "chunked_transfer", + "flate2", + "log", + "once_cell", + "rustls", + "url", + "webpki", + "webpki-roots", +] + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368bfe657969fb01238bb756d351dcade285e0f6fcbd36dcb23359a5169975be" +dependencies = [ + "webpki", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index f576efd..ff2c32e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,5 +5,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[workspace] +members = ["aoc_proc"] + [dependencies] color-eyre = "0.6.2" +aoc_proc = { path = "aoc_proc" } +ureq = "2.5.0" diff --git a/aoc_proc/Cargo.toml b/aoc_proc/Cargo.toml new file mode 100644 index 0000000..10527f0 --- /dev/null +++ b/aoc_proc/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "aoc_proc" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0.21" +syn = { version = "1.0.105", features = ["full"] } diff --git a/aoc_proc/src/lib.rs b/aoc_proc/src/lib.rs new file mode 100644 index 0000000..52d36af --- /dev/null +++ b/aoc_proc/src/lib.rs @@ -0,0 +1,150 @@ +use proc_macro::TokenStream; +use syn::{parse_macro_input, ItemFn, LitInt, Ident, parse::Parse, Token, punctuated::Punctuated, Expr}; +use quote::{quote, ToTokens}; + +struct Args { + day: LitInt, + parse: Ident, + test_cases: Option, +} + +impl Parse for Args { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + fn arg_err(prev: T, current: U) -> syn::Error { + let mut err = syn::Error::new_spanned(prev, "this parameter is overriden by a later parameter of the same name"); + err.combine(syn::Error::new_spanned(current, "this parameter overrides an earlier parameter of the same name")); + err + } + + #[derive(Default)] + struct WipArgs { + day: Option, + parse: Option, + test_cases: Option, + } + + let mut wip = WipArgs::default(); + + let vars = Punctuated::::parse_terminated(input)?; + for var in vars { + match var { + Arg::Day(day) => { + if let Some(wip_day) = wip.day { + return Err(arg_err(wip_day, day)); + } + wip.day = Some(day); + } + Arg::Parse(parse) => { + if let Some(wip_parse) = wip.parse { + return Err(arg_err(wip_parse, parse)); + } + wip.parse = Some(parse); + } + Arg::TestCases(test_cases) => { + if let Some(wip_test_cases) = wip.test_cases { + return Err(arg_err(wip_test_cases, test_cases)); + } + wip.test_cases = Some(test_cases); + } + } + } + + let day = match wip.day { + Some(day) => day, + None => { + return Err(input.error("missing argument `day`")); + } + }; + + let parse = match wip.parse { + Some(parse) => parse, + None => { + return Err(input.error("missing argument `parse`")); + } + }; + + Ok(Self { + day, + parse, + test_cases: wip.test_cases, + }) + } +} + +enum Arg { + Day(LitInt), + Parse(Ident), + TestCases(Expr), +} + +impl Parse for Arg { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let lookahead = input.lookahead1(); + let ident: Ident = input.parse()?; + input.parse::()?; + + match &*ident.to_string() { + "day" => Ok(Self::Day(input.parse()?)), + "parse" => Ok(Self::Parse(input.parse()?)), + "test_cases" => Ok(Self::TestCases(input.parse()?)), + _ => Err(lookahead.error()), + } + } +} + +#[proc_macro_attribute] +pub fn aoc(attr: TokenStream, item: TokenStream) -> TokenStream { + let Args { + day, + parse, + test_cases, + } = parse_macro_input!(attr as Args); + let input = parse_macro_input!(item as ItemFn); + + let fn_name = input.sig.ident.clone(); + + if let Some(test_cases) = test_cases { + TokenStream::from(quote! { + #input + + fn main_case() -> ::color_eyre::Result<()> { + let input = ::aoc_2022::load_data(#day, #parse)?; + #fn_name(input) + } + + fn test_cases() -> ::color_eyre::Result<()> { + let test_cases: &[&str] = &#test_cases; + + println!("!!! WARNING: RUNNING TEST CASES ONLY !!!"); + + for case in test_cases { + println!("=== {case} ===", case = case); + let input_path = ::std::path::Path::new("test_cases").join(case); + let input = ::std::fs::read_to_string(input_path)?; + let parsed = #parse(&input)?; + #fn_name(parsed)?; + println!(); + } + + Ok(()) + } + + fn main() -> ::color_eyre::Result<()> { + let run_actual_data = std::env::args().any(|arg| arg == "--full-data"); + if run_actual_data { + main_case() + } else { + test_cases() + } + } + }) + } else { + TokenStream::from(quote! { + fn main() -> ::color_eyre::Result<()> { + #input + let input = ::aoc_2022::load_data(#day, #parse)?; + #fn_name(input) + } + }) + } +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..e29b492 --- /dev/null +++ b/flake.lock @@ -0,0 +1,123 @@ +{ + "nodes": { + "crane": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ], + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1669853699, + "narHash": "sha256-SvyPRwJeET7PCifBOvu+reQUUlyc4Ya1K37GrtZyiXY=", + "owner": "ipetkov", + "repo": "crane", + "rev": "0428181b7b8f619e71095cf2fab051bccdf10041", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1650374568, + "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "b4a34015c698c7793d592d66adbab377907a2be8", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1669809720, + "narHash": "sha256-RMT77f6CPOYtLLQ2esj+EJ1BPVWxf4RDidjrSvA5OhI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "227de2b3bbec142f912c09d5e8a1b4e778aa54fb", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "crane": "crane", + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs" + } + }, + "rust-overlay": { + "inputs": { + "flake-utils": [ + "crane", + "flake-utils" + ], + "nixpkgs": [ + "crane", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1667487142, + "narHash": "sha256-bVuzLs1ZVggJAbJmEDVO9G6p8BH3HRaolK70KXvnWnU=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "cf668f737ac986c0a89e83b6b2e3c5ddbd8cf33b", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..5c00470 --- /dev/null +++ b/flake.nix @@ -0,0 +1,79 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + crane.url = "github:ipetkov/crane"; + crane.inputs.nixpkgs.follows = "nixpkgs"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, crane, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + system = system; + }; + inherit (pkgs) lib; + + craneLib = crane.lib.${system}; + + src = craneLib.cleanCargoSource ./.; + + buildInputs = [ + pkgs.bintools + ] ++ lib.optionals pkgs.stdenv.isDarwin [ + # Additional darwin specific inputs can be set here + pkgs.libiconv + ]; + + cargoArtifacts = craneLib.buildDepsOnly { + inherit src buildInputs; + }; + + # Build the actual crate itself, reusing the dependency + # artifacts from above. + aoc-2022 = craneLib.buildPackage { + inherit cargoArtifacts src buildInputs; + }; + in + { + checks = { + # Build the crate as part of `nix flake check` for convenience + inherit aoc-2022; + + # Run clippy (and deny all warnings) on the crate source, + # again, resuing the dependency artifacts from above. + # + # Note that this is done as a separate derivation so that + # we can block the CI if there are issues here, but not + # prevent downstream consumers from building our crate by itself. + aoc-2022-clippy = craneLib.cargoClippy { + inherit cargoArtifacts src buildInputs; + cargoClippyExtraArgs = "--all-targets -- --deny warnings"; + }; + + # Check formatting + aoc-2022-fmt = craneLib.cargoFmt { + inherit src; + }; + }; + + packages.default = aoc-2022; + + apps.default = flake-utils.lib.mkApp { + drv = aoc-2022; + }; + + devShells.default = pkgs.mkShell { + inputsFrom = builtins.attrValues self.checks; + + # Extra inputs can be added here + nativeBuildInputs = with pkgs; [ + cargo + cargo-expand + rustc + rustfmt + bintools + ]; + }; + }); +} diff --git a/src/bin/day_1.rs b/src/bin/day_1.rs index 3efa996..480e895 100644 --- a/src/bin/day_1.rs +++ b/src/bin/day_1.rs @@ -1,6 +1,8 @@ -use color_eyre::{eyre::eyre, Result}; +use aoc_2022::prelude::*; -fn parse(s: String) -> Result> { +type Input = Vec<(usize, usize)>; + +fn parse(s: &str) -> Result { let mut elves = vec![]; let mut current_elf = 1; @@ -19,9 +21,8 @@ fn parse(s: String) -> Result> { Ok(elves) } -fn main() -> Result<()> { - let mut input = aoc_2022::load_data(1, parse)?; - +#[aoc(day = 1, parse = parse, test_cases = ["day_1.txt"])] +fn day_1(mut input: Input) -> Result<()> { input.sort_by_key(|(_, sum)| *sum); let max = input[input.len() - 1].1; diff --git a/src/lib.rs b/src/lib.rs index 0623c6c..0d44d79 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,42 @@ -use color_eyre::Result; +use std::path::Path; -pub fn load_data Result>(day: u8, parse: F) -> Result { - let s = std::fs::read_to_string(format!("inputs/{day}.txt"))?; - parse(s) +use color_eyre::{eyre::eyre, Result}; + +pub fn load_data Result>(day: u8, parse: F) -> Result { + let s = fetch_input(day)?; + parse(&s) +} + +#[macro_export] +macro_rules! data { + ($day:expr) => { + $crate::load_data($day, parse)? + }; +} + +const AOC_SESSION_COOKIE: &str = concat!("session=", env!("AOC_SESSION")); + +pub fn fetch_input(day: u8) -> Result { + let cache_dir = Path::new(".aoc-cache"); + let cache = cache_dir.join(format!("{day}.txt")); + std::fs::create_dir_all(cache_dir).map_err(|e| eyre!("failed to create cache directory: {e}"))?; + + if cache.exists() { + println!("hit! we already have input for day {day}"); + std::fs::read_to_string(cache).map_err(|e| eyre!("failed to read input cache: {e}")) + } else { + println!("miss! fetching input for day {day}"); + let body: String = ureq::get(&format!("https://adventofcode.com/2022/day/{day}/input")) + .set("Cookie", AOC_SESSION_COOKIE) + .call()? + .into_string()?; + std::fs::write(cache, &body).map_err(|e| eyre!("failed to save input to cache: {e}"))?; + Ok(body) + } +} + +pub mod prelude { + pub use super::{data, load_data}; + pub use color_eyre::{eyre::eyre, Result}; + pub use aoc_proc::aoc; } diff --git a/test_cases/day_1.txt b/test_cases/day_1.txt new file mode 100644 index 0000000..444e241 --- /dev/null +++ b/test_cases/day_1.txt @@ -0,0 +1,14 @@ +1000 +2000 +3000 + +4000 + +5000 +6000 + +7000 +8000 +9000 + +10000 \ No newline at end of file