Skip to content

Commit 1d19403

Browse files
committed
add input.rs
1 parent cb77021 commit 1d19403

File tree

2 files changed

+128
-118
lines changed

2 files changed

+128
-118
lines changed

src/input.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use std::error::Error;
2+
use std::fs::{create_dir_all, read_to_string, File};
3+
use std::io::Write;
4+
use std::io::{stdin, stdout};
5+
use std::path::PathBuf;
6+
use std::time::Instant;
7+
8+
const BASE_URL: &str = "https://adventofcode.com";
9+
const INPUT_DIR: &str = "input";
10+
const CONN_TOKEN_FILE: &str = ".token";
11+
12+
pub fn get_input(year: u16, day: u8) -> Result<String, Box<dyn Error>> {
13+
let mut result = get_from_path_or_else(&input_path(year, day), || {
14+
let start = Instant::now();
15+
let url = format!("{}/{}/day/{}/input", BASE_URL, year, day);
16+
let session_cookie = format!("session={}", get_conn_token()?);
17+
let resp = attohttpc::get(&url)
18+
.header(attohttpc::header::COOKIE, session_cookie)
19+
.send()?;
20+
let elapsed = start.elapsed();
21+
22+
crate::print_with_duration("downloaded input file", None, elapsed);
23+
resp.text()
24+
})?;
25+
26+
if result.ends_with('\n') {
27+
result.pop();
28+
}
29+
30+
Ok(result)
31+
}
32+
33+
fn input_path(year: u16, day: u8) -> String {
34+
format!("{}/{}/day{}.txt", INPUT_DIR, year, day)
35+
}
36+
37+
fn get_from_path_or_else<E: Error>(
38+
path: &str,
39+
fallback: impl FnOnce() -> Result<String, E>,
40+
) -> Result<String, E> {
41+
let from_path = read_to_string(path);
42+
43+
if let Ok(res) = from_path {
44+
Ok(res.trim().to_string())
45+
} else {
46+
let res = fallback()?;
47+
create_dir_all(PathBuf::from(path).parent().unwrap())
48+
.and_then(|_| File::create(path))
49+
.and_then(|mut file| file.write_all(res.as_bytes()))
50+
.unwrap_or_else(|err| eprintln!("could not write {}: {}", path, err));
51+
Ok(res)
52+
}
53+
}
54+
55+
fn get_conn_token() -> Result<String, std::io::Error> {
56+
get_from_path_or_else(CONN_TOKEN_FILE, || {
57+
let mut stdout = stdout();
58+
write!(&mut stdout, "Write your connection token: ")?;
59+
stdout.flush()?;
60+
61+
let mut output = String::new();
62+
stdin().read_line(&mut output)?;
63+
64+
let mut file = File::create(CONN_TOKEN_FILE)?;
65+
file.write_all(output.as_bytes())?;
66+
Ok(output.trim().to_string())
67+
})
68+
}

src/lib.rs

Lines changed: 60 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,14 @@
1+
pub mod input;
2+
13
use std::cmp::min;
2-
use std::error::Error;
3-
use std::fs::{create_dir_all, read_to_string, File};
4-
use std::io::Write;
5-
use std::io::{stdin, stdout};
64
use std::iter;
7-
use std::path::PathBuf;
8-
use std::time::{Duration, Instant};
5+
use std::time::Duration;
96

107
pub use clap::Clap;
118
pub use colored;
129
use colored::*;
1310

1411
const DISPLAY_WIDTH: usize = 40;
15-
const BASE_URL: &str = "https://adventofcode.com";
16-
const INPUT_DIR: &str = "input";
17-
const CONN_TOKEN_FILE: &str = ".token";
18-
19-
#[derive(Debug, Clap)]
20-
#[clap(
21-
name = "Advent of Code",
22-
about = concat!("Main page of the event: https://adventofcode.com/")
23-
)]
24-
pub struct Opt {
25-
/// Read input from stdin instead of downloading it
26-
#[clap(short, long)]
27-
pub stdin: bool,
28-
29-
/// Days to execute. By default all implemented days will run.
30-
#[clap(short, long)]
31-
pub days: Vec<String>,
32-
}
3312

3413
pub fn print_with_duration(line: &str, output: Option<&str>, duration: Duration) {
3514
let duration = format!("({:.2?})", duration);
@@ -55,62 +34,19 @@ pub fn print_with_duration(line: &str, output: Option<&str>, duration: Duration)
5534
}
5635
}
5736

58-
fn input_path(year: u16, day: u8) -> String {
59-
format!("{}/{}/day{}.txt", INPUT_DIR, year, day)
60-
}
61-
62-
fn get_from_path_or_else<E: Error>(
63-
path: &str,
64-
fallback: impl FnOnce() -> Result<String, E>,
65-
) -> Result<String, E> {
66-
let from_path = read_to_string(path);
67-
68-
if let Ok(res) = from_path {
69-
Ok(res.trim().to_string())
70-
} else {
71-
let res = fallback()?;
72-
create_dir_all(PathBuf::from(path).parent().unwrap())
73-
.and_then(|_| File::create(path))
74-
.and_then(|mut file| file.write_all(res.as_bytes()))
75-
.unwrap_or_else(|err| eprintln!("could not write {}: {}", path, err));
76-
Ok(res)
77-
}
78-
}
79-
80-
pub fn get_input(year: u16, day: u8) -> Result<String, Box<dyn Error>> {
81-
let mut result = get_from_path_or_else(&input_path(year, day), || {
82-
let start = Instant::now();
83-
let url = format!("{}/{}/day/{}/input", BASE_URL, year, day);
84-
let session_cookie = format!("session={}", get_conn_token()?);
85-
let resp = attohttpc::get(&url)
86-
.header(attohttpc::header::COOKIE, session_cookie)
87-
.send()?;
88-
let elapsed = start.elapsed();
89-
90-
print_with_duration("downloaded input file", None, elapsed);
91-
resp.text()
92-
})?;
93-
94-
if result.ends_with('\n') {
95-
result.pop();
96-
}
97-
98-
Ok(result)
99-
}
100-
101-
pub fn get_conn_token() -> Result<String, std::io::Error> {
102-
get_from_path_or_else(CONN_TOKEN_FILE, || {
103-
let mut stdout = stdout();
104-
write!(&mut stdout, "Write your connection token: ")?;
105-
stdout.flush()?;
106-
107-
let mut output = String::new();
108-
stdin().read_line(&mut output)?;
37+
#[derive(Debug, Clap)]
38+
#[clap(
39+
name = "Advent of Code",
40+
about = concat!("Main page of the event: https://adventofcode.com/")
41+
)]
42+
pub struct Opt {
43+
/// Read input from stdin instead of downloading it
44+
#[clap(short, long)]
45+
pub stdin: bool,
10946

110-
let mut file = File::create(CONN_TOKEN_FILE)?;
111-
file.write_all(output.as_bytes())?;
112-
Ok(output.trim().to_string())
113-
})
47+
/// Days to execute. By default all implemented days will run.
48+
#[clap(short, long)]
49+
pub days: Vec<String>,
11450
}
11551

11652
#[macro_export]
@@ -135,51 +71,57 @@ macro_rules! main {
13571
opt.days = DAYS.iter().map(|s| s[3..].to_string()).collect();
13672
}
13773

138-
for (i, day) in opt.days.iter().enumerate() {$({
74+
for (i, day) in opt.days.iter().enumerate() {
13975
let module_name = format!("day{}", day);
14076
let day = day.parse().expect("days must be integers");
14177

14278
if !DAYS.contains(&module_name.as_str()) {
143-
eprintln!("Module `{}` was not registered", module_name);
79+
eprintln!(
80+
"Module `{}` was not registered, available are: {}",
81+
module_name,
82+
DAYS.join(", "),
83+
);
14484
}
14585

146-
if stringify!($day) == module_name {
147-
if i != 0 { println!() }
148-
println!("Day {}", day);
149-
150-
let data = {
151-
if opt.stdin {
152-
let mut data = String::new();
153-
std::io::stdin().read_to_string(&mut data)
154-
.expect("failed to read from stdin");
155-
data
156-
} else {
157-
$crate::get_input(YEAR, day).expect("could not fetch input")
158-
}
159-
};
160-
161-
let input = data.as_str();
162-
163-
$(
164-
let start = Instant::now();
165-
let input = $day::$generator(&data);
166-
let elapsed = start.elapsed();
167-
$crate::print_with_duration("generator", None, elapsed);
168-
)?
169-
170-
$({
171-
let start = Instant::now();
172-
let response = $day::$solution(&input);
173-
let elapsed = start.elapsed();
174-
175-
$crate::print_with_duration(
176-
stringify!($solution),
177-
Some(&format!("{}", response)),
178-
elapsed,
179-
);
180-
})+
181-
}
182-
})+}
86+
$(
87+
if stringify!($day) == module_name {
88+
if i != 0 { println!() }
89+
println!("Day {}", day);
90+
91+
let data = {
92+
if opt.stdin {
93+
let mut data = String::new();
94+
std::io::stdin().read_to_string(&mut data)
95+
.expect("failed to read from stdin");
96+
data
97+
} else {
98+
$crate::input::get_input(YEAR, day).expect("could not fetch input")
99+
}
100+
};
101+
102+
let input = data.as_str();
103+
104+
$(
105+
let start = Instant::now();
106+
let input = $day::$generator(&data);
107+
let elapsed = start.elapsed();
108+
$crate::print_with_duration("generator", None, elapsed);
109+
)?
110+
111+
$({
112+
let start = Instant::now();
113+
let response = $day::$solution(&input);
114+
let elapsed = start.elapsed();
115+
116+
$crate::print_with_duration(
117+
stringify!($solution),
118+
Some(&format!("{}", response)),
119+
elapsed,
120+
);
121+
})+
122+
}
123+
)+
124+
}
183125
}
184126
};
185127
}

0 commit comments

Comments
 (0)