1use core::fmt;
4use core::num::NonZero;
5use core::str::FromStr;
6
7use powerfmt::smart_display::{FormatterOptions, Metadata, SmartDisplay};
8
9use self::Month::*;
10use crate::iter::MonthIter;
11use crate::{error, util};
12
13#[repr(u8)]
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub enum Month {
17 #[expect(missing_docs)]
18 January = 1,
19 #[expect(missing_docs)]
20 February = 2,
21 #[expect(missing_docs)]
22 March = 3,
23 #[expect(missing_docs)]
24 April = 4,
25 #[expect(missing_docs)]
26 May = 5,
27 #[expect(missing_docs)]
28 June = 6,
29 #[expect(missing_docs)]
30 July = 7,
31 #[expect(missing_docs)]
32 August = 8,
33 #[expect(missing_docs)]
34 September = 9,
35 #[expect(missing_docs)]
36 October = 10,
37 #[expect(missing_docs)]
38 November = 11,
39 #[expect(missing_docs)]
40 December = 12,
41}
42
43impl Month {
44 #[inline]
46 pub(crate) const fn from_number(n: NonZero<u8>) -> Result<Self, error::ComponentRange> {
47 match n.get() {
48 1 => Ok(January),
49 2 => Ok(February),
50 3 => Ok(March),
51 4 => Ok(April),
52 5 => Ok(May),
53 6 => Ok(June),
54 7 => Ok(July),
55 8 => Ok(August),
56 9 => Ok(September),
57 10 => Ok(October),
58 11 => Ok(November),
59 12 => Ok(December),
60 _ => Err(error::ComponentRange::unconditional("month")),
61 }
62 }
63
64 #[inline]
71 pub const fn length(self, year: i32) -> u8 {
72 util::days_in_month(self, year)
73 }
74
75 #[inline]
82 pub const fn previous(self) -> Self {
83 match self {
84 January => December,
85 February => January,
86 March => February,
87 April => March,
88 May => April,
89 June => May,
90 July => June,
91 August => July,
92 September => August,
93 October => September,
94 November => October,
95 December => November,
96 }
97 }
98
99 #[inline]
106 pub const fn next(self) -> Self {
107 match self {
108 January => February,
109 February => March,
110 March => April,
111 April => May,
112 May => June,
113 June => July,
114 July => August,
115 August => September,
116 September => October,
117 October => November,
118 November => December,
119 December => January,
120 }
121 }
122
123 #[inline]
131 pub const fn nth_next(self, n: u8) -> Self {
132 match (self as u8 - 1 + n % 12) % 12 {
133 0 => January,
134 1 => February,
135 2 => March,
136 3 => April,
137 4 => May,
138 5 => June,
139 6 => July,
140 7 => August,
141 8 => September,
142 9 => October,
143 10 => November,
144 val => {
145 debug_assert!(val == 11);
146 December
147 }
148 }
149 }
150
151 #[inline]
159 pub const fn nth_prev(self, n: u8) -> Self {
160 match self as i8 - 1 - (n % 12).cast_signed() {
161 1 | -11 => February,
162 2 | -10 => March,
163 3 | -9 => April,
164 4 | -8 => May,
165 5 | -7 => June,
166 6 | -6 => July,
167 7 | -5 => August,
168 8 | -4 => September,
169 9 | -3 => October,
170 10 | -2 => November,
171 11 | -1 => December,
172 val => {
173 debug_assert!(val == 0);
174 January
175 }
176 }
177 }
178
179 #[inline]
200 pub const fn iter_from(start: Self) -> MonthIter {
201 MonthIter::new(start)
202 }
203}
204
205impl SmartDisplay for Month {
206 type Metadata = ();
207
208 #[inline]
209 fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
210 match self {
211 January => Metadata::new(7, self, ()),
212 February => Metadata::new(8, self, ()),
213 March => Metadata::new(5, self, ()),
214 April => Metadata::new(5, self, ()),
215 May => Metadata::new(3, self, ()),
216 June => Metadata::new(4, self, ()),
217 July => Metadata::new(4, self, ()),
218 August => Metadata::new(6, self, ()),
219 September => Metadata::new(9, self, ()),
220 October => Metadata::new(7, self, ()),
221 November => Metadata::new(8, self, ()),
222 December => Metadata::new(8, self, ()),
223 }
224 }
225
226 #[inline]
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 f.pad(match self {
229 January => "January",
230 February => "February",
231 March => "March",
232 April => "April",
233 May => "May",
234 June => "June",
235 July => "July",
236 August => "August",
237 September => "September",
238 October => "October",
239 November => "November",
240 December => "December",
241 })
242 }
243}
244
245impl fmt::Display for Month {
246 #[inline]
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 SmartDisplay::fmt(self, f)
249 }
250}
251
252impl FromStr for Month {
253 type Err = error::InvalidVariant;
254
255 #[inline]
256 fn from_str(s: &str) -> Result<Self, Self::Err> {
257 match s {
258 "January" => Ok(January),
259 "February" => Ok(February),
260 "March" => Ok(March),
261 "April" => Ok(April),
262 "May" => Ok(May),
263 "June" => Ok(June),
264 "July" => Ok(July),
265 "August" => Ok(August),
266 "September" => Ok(September),
267 "October" => Ok(October),
268 "November" => Ok(November),
269 "December" => Ok(December),
270 _ => Err(error::InvalidVariant),
271 }
272 }
273}
274
275impl From<Month> for u8 {
276 #[inline]
277 fn from(month: Month) -> Self {
278 month as Self
279 }
280}
281
282impl TryFrom<u8> for Month {
283 type Error = error::ComponentRange;
284
285 #[inline]
286 fn try_from(value: u8) -> Result<Self, Self::Error> {
287 match NonZero::new(value) {
288 Some(value) => Self::from_number(value),
289 None => Err(error::ComponentRange::unconditional("month")),
290 }
291 }
292}