advent_of_utils/
options.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use std::fmt::Debug;
use std::fmt::Display;
use std::num::TryFromIntError;

/// Represents different types of option values that can be returned from your Advent of Code solutions.
/// This enum provides a type-safe way to handle different value types that might be
/// encountered as results.
///
/// # Variants
/// - `Str(String)` - Contains a String value for text-based results
/// - `Int(i64)` - Contains a 64-bit signed integer value for numeric results
/// - `None` - Represents the absence of a value or an unset option
///
/// # Automatic Conversions
/// This type implements `From` for multiple common types to make working with Advent of Code inputs easier:
/// - `String` and `&str` -> `AocOption::Str`
/// - Small numeric types (`i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `isize`, `usize`) -> `AocOption::Int`
/// - `Option<T>` where T implements `Into<AocOption>`
///
/// For larger numeric types, `TryFrom` is implemented to handle potential conversion failures:
/// - `u64`, `i128`, `u128` -> `Result<AocOption::Int, TryFromIntError>`
///
/// # Example
/// ```rust
/// let string_opt: AocOption = "puzzle input".to_string().into();   // Creates AocOption::Str
/// let num_opt: AocOption = 42_i32.into();                          // Creates AocOption::Int
/// let some_opt: AocOption = Some(42_i32).into();                   // Creates AocOption::Int
/// let none_opt: AocOption = None::<String>.into();                 // Creates AocOption::None
///
/// // Using TryFrom for larger numbers
/// let big_num = u64::MAX;
/// let result = AocOption::try_from(big_num);                       // Returns Result
/// ```
#[derive(Clone, Hash, Eq, PartialEq, Default)]
pub enum AocOption {
    /// Contains a String value for text-based results
    Str(String),
    /// Contains a 128-bit signed integer value for numeric results
    Int(i64),
    /// Represents the absence of a value or an unset option
    #[default]
    None,
}

impl From<String> for AocOption {
    fn from(value: String) -> Self {
        AocOption::Str(value)
    }
}

impl From<&str> for AocOption {
    fn from(value: &str) -> Self {
        AocOption::Str(value.to_string())
    }
}

macro_rules! impl_from_number {
    ($($t:ty),*) => {
        $(
            impl From<$t> for AocOption {
                fn from(value: $t) -> Self {
                    AocOption::Int(value as i64)
                }
            }
        )*
    }
}

impl_from_number!(i8, i16, i32, i64, u8, u16, u32, isize, usize);

impl<T: Into<AocOption>> From<Option<T>> for AocOption {
    fn from(value: Option<T>) -> Self {
        match value {
            Some(value) => value.into(),
            None => AocOption::None,
        }
    }
}

macro_rules! impl_try_from_number {
    ($($t:ty),*) => {
        $(
            impl TryFrom<$t> for AocOption {
                fn try_from(value: $t) -> Result<Self, Self::Error> {
                    Ok(AocOption::Int(i64::try_from(value)?))
                }

                type Error = TryFromIntError;
            }
        )*
    }
}

impl_try_from_number!(u64, i128, u128);

impl Debug for AocOption {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            AocOption::Str(s) => write!(f, "Str: {}", s),
            AocOption::Int(i) => write!(f, "Int: {}", i),
            AocOption::None => write!(f, "None"),
        }
    }
}

impl Display for AocOption {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            AocOption::Str(s) => write!(f, "{}", s),
            AocOption::Int(i) => write!(f, "{}", i),
            AocOption::None => write!(f, "None"),
        }
    }
}