#![doc = include_str!("../README.md")]
use std::str::FromStr;
use client::{Client, ClientError, WebClient};
use data::CheckResult;
pub mod cache;
pub mod client;
pub mod config;
pub mod data;
mod utils;
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct Day(pub usize);
impl std::fmt::Display for Day {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<i32> for Day {
fn from(value: i32) -> Self {
assert!(value >= 0);
Day(value as usize)
}
}
impl From<u32> for Day {
fn from(value: u32) -> Self {
Day(value as usize)
}
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct Year(pub usize);
impl std::fmt::Display for Year {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<i32> for Year {
fn from(value: i32) -> Self {
assert!(value >= 0);
Year(value as usize)
}
}
impl From<Year> for i32 {
fn from(value: Year) -> Self {
value.0 as i32
}
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub enum Part {
One,
Two,
}
impl std::fmt::Display for Part {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Part::One => "One",
Part::Two => "Two",
}
)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Answer {
String(String),
Int(i128),
}
impl Answer {
pub fn to_i128(&self) -> Option<i128> {
match self {
Answer::String(_) => None,
Answer::Int(v) => Some(*v),
}
}
}
impl FromStr for Answer {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(s.parse::<i128>()
.map_or_else(|_| Answer::String(s.to_string()), Answer::Int))
}
}
impl std::fmt::Display for Answer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Answer::String(v) => write!(f, "{}", v),
Answer::Int(v) => write!(f, "{}", v),
}
}
}
impl From<String> for Answer {
fn from(value: String) -> Self {
Self::String(value)
}
}
impl From<&str> for Answer {
fn from(value: &str) -> Self {
Self::String(value.to_string())
}
}
impl From<i8> for Answer {
fn from(value: i8) -> Self {
Self::Int(value as i128)
}
}
impl From<i16> for Answer {
fn from(value: i16) -> Self {
Self::Int(value as i128)
}
}
impl From<i32> for Answer {
fn from(value: i32) -> Self {
Self::Int(value as i128)
}
}
impl From<i64> for Answer {
fn from(value: i64) -> Self {
Self::Int(value as i128)
}
}
impl From<u8> for Answer {
fn from(value: u8) -> Self {
Self::Int(value as i128)
}
}
impl From<u16> for Answer {
fn from(value: u16) -> Self {
Self::Int(value as i128)
}
}
impl From<u32> for Answer {
fn from(value: u32) -> Self {
Self::Int(value as i128)
}
}
impl From<u64> for Answer {
fn from(value: u64) -> Self {
Self::Int(value as i128)
}
}
impl From<isize> for Answer {
fn from(value: isize) -> Self {
Self::Int(value as i128)
}
}
impl From<usize> for Answer {
fn from(value: usize) -> Self {
Self::Int(value as i128)
}
}
pub fn get_input(day: Day, year: Year) -> Result<String, ClientError> {
let client = WebClient::new()?;
client.get_input(day, year)
}
pub fn submit_answer(
answer: Answer,
part: Part,
day: Day,
year: Year,
) -> Result<CheckResult, ClientError> {
let mut client: WebClient = WebClient::new()?;
client.submit_answer(answer, part, day, year)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn print_year() {
let year = Year(2022);
assert_eq!(&format!("{year}"), "2022");
}
#[test]
fn print_day() {
let day = Day(22);
assert_eq!(&format!("{day}"), "22");
}
#[test]
fn print_part() {
assert_eq!(&format!("{}", Part::One), "One");
assert_eq!(&format!("{}", Part::Two), "Two");
}
#[test]
fn print_answer() {
assert_eq!(
&format!("{}", Answer::String("hello world".to_string())),
"hello world"
);
assert_eq!(&format!("{}", Answer::Int(42)), "42");
}
#[test]
#[allow(clippy::unnecessary_cast)]
fn int_answer_conversions() {
let answer: Answer = (-22 as i8).into();
assert_eq!(answer, Answer::Int(-22));
let answer: Answer = (-1317 as i16).into();
assert_eq!(answer, Answer::Int(-1317));
let answer: Answer = (-100_512 as i32).into();
assert_eq!(answer, Answer::Int(-100_512));
let answer: Answer = (-3_183_512_681 as i64).into();
assert_eq!(answer, Answer::Int(-3_183_512_681));
let answer: Answer = (22 as u8).into();
assert_eq!(answer, Answer::Int(22));
let answer: Answer = (1317 as u16).into();
assert_eq!(answer, Answer::Int(1317));
let answer: Answer = (100_512 as u32).into();
assert_eq!(answer, Answer::Int(100_512));
let answer: Answer = (3_183_512_681 as u64).into();
assert_eq!(answer, Answer::Int(3_183_512_681));
}
#[test]
fn string_answer_conversions() {
let answer: Answer = "hello world".to_string().into();
assert_eq!(answer, Answer::String("hello world".to_string()));
let answer: Answer = "testing 123".into();
assert_eq!(answer, Answer::String("testing 123".to_string()));
}
#[test]
fn parse_string_to_answer() {
let answer: Answer = "this is text".parse::<Answer>().unwrap();
assert_eq!(answer, Answer::String("this is text".to_string()));
let answer: Answer = "123".parse::<Answer>().unwrap();
assert_eq!(answer, Answer::Int(123));
}
}