1use core::fmt;
4use core::num::NonZeroU8;
5use core::str::FromStr;
6
7use powerfmt::smart_display::{FormatterOptions, Metadata, SmartDisplay};
8
9use self::Month::*;
10use crate::error;
11
12#[repr(u8)]
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub enum Month {
16 #[allow(missing_docs)]
17 January = 1,
18 #[allow(missing_docs)]
19 February = 2,
20 #[allow(missing_docs)]
21 March = 3,
22 #[allow(missing_docs)]
23 April = 4,
24 #[allow(missing_docs)]
25 May = 5,
26 #[allow(missing_docs)]
27 June = 6,
28 #[allow(missing_docs)]
29 July = 7,
30 #[allow(missing_docs)]
31 August = 8,
32 #[allow(missing_docs)]
33 September = 9,
34 #[allow(missing_docs)]
35 October = 10,
36 #[allow(missing_docs)]
37 November = 11,
38 #[allow(missing_docs)]
39 December = 12,
40}
41
42impl Month {
43 pub(crate) const fn from_number(n: NonZeroU8) -> Result<Self, error::ComponentRange> {
45 match n.get() {
46 1 => Ok(January),
47 2 => Ok(February),
48 3 => Ok(March),
49 4 => Ok(April),
50 5 => Ok(May),
51 6 => Ok(June),
52 7 => Ok(July),
53 8 => Ok(August),
54 9 => Ok(September),
55 10 => Ok(October),
56 11 => Ok(November),
57 12 => Ok(December),
58 n => Err(error::ComponentRange {
59 name: "month",
60 minimum: 1,
61 maximum: 12,
62 value: n as _,
63 conditional_range: false,
64 }),
65 }
66 }
67
68 pub const fn previous(self) -> Self {
75 match self {
76 January => December,
77 February => January,
78 March => February,
79 April => March,
80 May => April,
81 June => May,
82 July => June,
83 August => July,
84 September => August,
85 October => September,
86 November => October,
87 December => November,
88 }
89 }
90
91 pub const fn next(self) -> Self {
98 match self {
99 January => February,
100 February => March,
101 March => April,
102 April => May,
103 May => June,
104 June => July,
105 July => August,
106 August => September,
107 September => October,
108 October => November,
109 November => December,
110 December => January,
111 }
112 }
113
114 pub const fn nth_next(self, n: u8) -> Self {
122 match (self as u8 - 1 + n % 12) % 12 {
123 0 => January,
124 1 => February,
125 2 => March,
126 3 => April,
127 4 => May,
128 5 => June,
129 6 => July,
130 7 => August,
131 8 => September,
132 9 => October,
133 10 => November,
134 val => {
135 debug_assert!(val == 11);
136 December
137 }
138 }
139 }
140
141 pub const fn nth_prev(self, n: u8) -> Self {
149 match self as i8 - 1 - (n % 12) as i8 {
150 1 | -11 => February,
151 2 | -10 => March,
152 3 | -9 => April,
153 4 | -8 => May,
154 5 | -7 => June,
155 6 | -6 => July,
156 7 | -5 => August,
157 8 | -4 => September,
158 9 | -3 => October,
159 10 | -2 => November,
160 11 | -1 => December,
161 val => {
162 debug_assert!(val == 0);
163 January
164 }
165 }
166 }
167}
168
169mod private {
170 #[non_exhaustive]
171 #[derive(Debug, Clone, Copy)]
172 pub struct MonthMetadata;
173}
174use private::MonthMetadata;
175
176impl SmartDisplay for Month {
177 type Metadata = MonthMetadata;
178
179 fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
180 match self {
181 January => Metadata::new(7, self, MonthMetadata),
182 February => Metadata::new(8, self, MonthMetadata),
183 March => Metadata::new(5, self, MonthMetadata),
184 April => Metadata::new(5, self, MonthMetadata),
185 May => Metadata::new(3, self, MonthMetadata),
186 June => Metadata::new(4, self, MonthMetadata),
187 July => Metadata::new(4, self, MonthMetadata),
188 August => Metadata::new(6, self, MonthMetadata),
189 September => Metadata::new(9, self, MonthMetadata),
190 October => Metadata::new(7, self, MonthMetadata),
191 November => Metadata::new(8, self, MonthMetadata),
192 December => Metadata::new(8, self, MonthMetadata),
193 }
194 }
195
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 f.pad(match self {
198 January => "January",
199 February => "February",
200 March => "March",
201 April => "April",
202 May => "May",
203 June => "June",
204 July => "July",
205 August => "August",
206 September => "September",
207 October => "October",
208 November => "November",
209 December => "December",
210 })
211 }
212}
213
214impl fmt::Display for Month {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 SmartDisplay::fmt(self, f)
217 }
218}
219
220impl FromStr for Month {
221 type Err = error::InvalidVariant;
222
223 fn from_str(s: &str) -> Result<Self, Self::Err> {
224 match s {
225 "January" => Ok(January),
226 "February" => Ok(February),
227 "March" => Ok(March),
228 "April" => Ok(April),
229 "May" => Ok(May),
230 "June" => Ok(June),
231 "July" => Ok(July),
232 "August" => Ok(August),
233 "September" => Ok(September),
234 "October" => Ok(October),
235 "November" => Ok(November),
236 "December" => Ok(December),
237 _ => Err(error::InvalidVariant),
238 }
239 }
240}
241
242impl From<Month> for u8 {
243 fn from(month: Month) -> Self {
244 month as _
245 }
246}
247
248impl TryFrom<u8> for Month {
249 type Error = error::ComponentRange;
250
251 fn try_from(value: u8) -> Result<Self, Self::Error> {
252 match NonZeroU8::new(value) {
253 Some(value) => Self::from_number(value),
254 None => Err(error::ComponentRange {
255 name: "month",
256 minimum: 1,
257 maximum: 12,
258 value: 0,
259 conditional_range: false,
260 }),
261 }
262 }
263}