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}