advent_of_utils/
options.rs

1use std::fmt::Debug;
2use std::fmt::Display;
3use std::num::TryFromIntError;
4
5/// Represents different types of option values that can be returned from your Advent of Code solutions.
6/// This enum provides a type-safe way to handle different value types that might be
7/// encountered as results.
8///
9/// # Variants
10/// - `Str(String)` - Contains a String value for text-based results
11/// - `Int(i64)` - Contains a 64-bit signed integer value for numeric results
12/// - `None` - Represents the absence of a value or an unset option
13///
14/// # Automatic Conversions
15/// This type implements `From` for multiple common types to make working with Advent of Code inputs easier:
16/// - `String` and `&str` -> `AocOption::Str`
17/// - Small numeric types (`i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `isize`, `usize`) -> `AocOption::Int`
18/// - `Option<T>` where T implements `Into<AocOption>`
19///
20/// For larger numeric types, `TryFrom` is implemented to handle potential conversion failures:
21/// - `u64`, `i128`, `u128` -> `Result<AocOption::Int, TryFromIntError>`
22///
23/// # Example
24/// ```rust
25/// let string_opt: AocOption = "puzzle input".to_string().into();   // Creates AocOption::Str
26/// let num_opt: AocOption = 42_i32.into();                          // Creates AocOption::Int
27/// let some_opt: AocOption = Some(42_i32).into();                   // Creates AocOption::Int
28/// let none_opt: AocOption = None::<String>.into();                 // Creates AocOption::None
29///
30/// // Using TryFrom for larger numbers
31/// let big_num = u64::MAX;
32/// let result = AocOption::try_from(big_num);                       // Returns Result
33/// ```
34#[derive(Clone, Hash, Eq, PartialEq, Default)]
35pub enum AocOption {
36    /// Contains a String value for text-based results
37    Str(String),
38    /// Contains a 128-bit signed integer value for numeric results
39    Int(i64),
40    /// Represents the absence of a value or an unset option
41    #[default]
42    None,
43}
44
45impl From<String> for AocOption {
46    fn from(value: String) -> Self {
47        AocOption::Str(value)
48    }
49}
50
51impl From<&str> for AocOption {
52    fn from(value: &str) -> Self {
53        AocOption::Str(value.to_string())
54    }
55}
56
57macro_rules! impl_from_number {
58    ($($t:ty),*) => {
59        $(
60            impl From<$t> for AocOption {
61                fn from(value: $t) -> Self {
62                    AocOption::Int(value as i64)
63                }
64            }
65        )*
66    }
67}
68
69impl_from_number!(i8, i16, i32, i64, u8, u16, u32, isize, usize);
70
71impl<T: Into<AocOption>> From<Option<T>> for AocOption {
72    fn from(value: Option<T>) -> Self {
73        match value {
74            Some(value) => value.into(),
75            None => AocOption::None,
76        }
77    }
78}
79
80macro_rules! impl_try_from_number {
81    ($($t:ty),*) => {
82        $(
83            impl TryFrom<$t> for AocOption {
84                fn try_from(value: $t) -> Result<Self, Self::Error> {
85                    Ok(AocOption::Int(i64::try_from(value)?))
86                }
87
88                type Error = TryFromIntError;
89            }
90        )*
91    }
92}
93
94impl_try_from_number!(u64, i128, u128);
95
96impl Debug for AocOption {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        match self {
99            AocOption::Str(s) => write!(f, "Str: {}", s),
100            AocOption::Int(i) => write!(f, "Int: {}", i),
101            AocOption::None => write!(f, "None"),
102        }
103    }
104}
105
106impl Display for AocOption {
107    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108        match self {
109            AocOption::Str(s) => write!(f, "{}", s),
110            AocOption::Int(i) => write!(f, "{}", i),
111            AocOption::None => write!(f, "None"),
112        }
113    }
114}