Coverage Report

Created: 2026-03-14 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/hifitime-4.2.5/src/weekday.rs
Line
Count
Source
1
/*
2
* Hifitime
3
* Copyright (C) 2017-onward Christopher Rabotin <christopher.rabotin@gmail.com> et al. (cf. https://github.com/nyx-space/hifitime/graphs/contributors)
4
* This Source Code Form is subject to the terms of the Mozilla Public
5
* License, v. 2.0. If a copy of the MPL was not distributed with this
6
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
*
8
* Documentation: https://nyxspace.com/
9
*/
10
11
use crate::{Duration, ParsingError, Unit};
12
use core::fmt;
13
use core::ops::{Add, AddAssign, Sub, SubAssign};
14
use core::str::FromStr;
15
16
#[cfg(feature = "python")]
17
use pyo3::prelude::*;
18
19
#[cfg(feature = "serde")]
20
use serde_derive::{Deserialize, Serialize};
21
22
#[cfg_attr(kani, derive(kani::Arbitrary))]
23
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
24
#[repr(u8)]
25
#[cfg_attr(feature = "python", pyclass(eq, eq_int))]
26
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27
#[derive(Default)]
28
pub enum Weekday {
29
    #[default]
30
    Monday = 0,
31
    Tuesday = 1,
32
    Wednesday = 2,
33
    Thursday = 3,
34
    Friday = 4,
35
    Saturday = 5,
36
    Sunday = 6,
37
}
38
39
impl Weekday {
40
    /// Max: last weekday <=> `Sunday`, used only for conversion to/from u8.
41
    const MAX: u8 = 7;
42
    /// Trivial, but avoid magic numbers.
43
    pub(crate) const DAYS_PER_WEEK: f64 = 7.0;
44
    /// Trivial, but avoid magic numbers.
45
    pub(crate) const DAYS_PER_WEEK_I128: i128 = 7;
46
47
    // C89 defines Sunday as zero (which is stupid)
48
0
    pub(crate) fn to_c89_weekday(self) -> u8 {
49
0
        let c89_weekday: u8 = (self + 1).into();
50
0
        c89_weekday
51
0
    }
52
}
53
54
impl From<u8> for Weekday {
55
0
    fn from(u: u8) -> Self {
56
0
        match u.rem_euclid(Self::MAX) {
57
0
            0 => Self::Monday,
58
0
            1 => Self::Tuesday,
59
0
            2 => Self::Wednesday,
60
0
            3 => Self::Thursday,
61
0
            4 => Self::Friday,
62
0
            5 => Self::Saturday,
63
0
            6 => Self::Sunday,
64
0
            _ => Self::default(), // Defaults back to default for other values.
65
        }
66
0
    }
67
}
68
69
impl From<i8> for Weekday {
70
0
    fn from(i: i8) -> Self {
71
0
        Self::from((i.rem_euclid(Self::MAX as i8) + Self::MAX as i8) as u8)
72
0
    }
73
}
74
75
impl From<Weekday> for u8 {
76
0
    fn from(week: Weekday) -> Self {
77
0
        match week {
78
0
            Weekday::Monday => 0,
79
0
            Weekday::Tuesday => 1,
80
0
            Weekday::Wednesday => 2,
81
0
            Weekday::Thursday => 3,
82
0
            Weekday::Friday => 4,
83
0
            Weekday::Saturday => 5,
84
0
            Weekday::Sunday => 6,
85
        }
86
0
    }
87
}
88
89
impl FromStr for Weekday {
90
    type Err = ParsingError;
91
0
    fn from_str(s: &str) -> Result<Self, Self::Err> {
92
0
        match s.trim() {
93
0
            "mon" | "Mon" | "MON" | "monday" | "Monday" | "MONDAY" => Ok(Self::Monday),
94
0
            "tue" | "Tue" | "TUE" | "tuesday" | "Tuesday" | "TUESDAY" => Ok(Self::Tuesday),
95
0
            "wed" | "Wed" | "WED" | "wednesday" | "Wednesday" | "WEDNESDAY" => Ok(Self::Wednesday),
96
0
            "thu" | "Thu" | "THU" | "thursday" | "Thursday" | "THURSDAY" => Ok(Self::Thursday),
97
0
            "fri" | "Fri" | "FRI" | "friday" | "Friday" | "FRIDAY" => Ok(Self::Friday),
98
0
            "sat" | "Sat" | "SAT" | "saturday" | "Saturday" | "SATURDAY" => Ok(Self::Saturday),
99
0
            "sun" | "Sun" | "SUN" | "sunday" | "Sunday" | "SUNDAY" => Ok(Self::Sunday),
100
0
            _ => Err(ParsingError::UnknownWeekday),
101
        }
102
0
    }
103
}
104
105
impl Add for Weekday {
106
    type Output = Self;
107
0
    fn add(self, rhs: Self) -> Self {
108
0
        Self::from(u8::from(self) + u8::from(rhs))
109
0
    }
110
}
111
112
impl Sub for Weekday {
113
    type Output = Duration;
114
0
    fn sub(self, rhs: Self) -> Self::Output {
115
        // We can safely cast the weekdays as u8 into i8 because the maximum value is 6, and the max value of a i8 is 127.
116
0
        let self_i8 = u8::from(self) as i8;
117
0
        let mut rhs_i8 = u8::from(rhs) as i8;
118
0
        if rhs_i8 - self_i8 < 0 {
119
0
            rhs_i8 += 7;
120
0
        }
121
0
        i64::from(rhs_i8 - self_i8) * Unit::Day
122
0
    }
123
}
124
125
impl Add<u8> for Weekday {
126
    type Output = Self;
127
0
    fn add(self, rhs: u8) -> Self {
128
0
        Self::from(u8::from(self) + rhs)
129
0
    }
130
}
131
132
impl Sub<u8> for Weekday {
133
    type Output = Self;
134
0
    fn sub(self, rhs: u8) -> Self {
135
        // We can safely cast the weekdays as u8 into i8 because the maximum value is 6, and the max value of a i8 is 127.
136
0
        Self::from(u8::from(self) as i8 - rhs as i8)
137
0
    }
138
}
139
140
impl AddAssign<u8> for Weekday {
141
0
    fn add_assign(&mut self, rhs: u8) {
142
0
        *self = *self + rhs;
143
0
    }
144
}
145
146
impl SubAssign<u8> for Weekday {
147
0
    fn sub_assign(&mut self, rhs: u8) {
148
0
        *self = *self - rhs;
149
0
    }
150
}
151
152
impl fmt::Display for Weekday {
153
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154
0
        write!(f, "{self:?}")
155
0
    }
156
}
157
158
/// LowerHex allows printing the week day in its shortened form in English
159
impl fmt::LowerHex for Weekday {
160
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161
0
        match self {
162
0
            Self::Monday => write!(f, "Mon"),
163
0
            Self::Tuesday => write!(f, "Tue"),
164
0
            Self::Wednesday => write!(f, "Wed"),
165
0
            Self::Thursday => write!(f, "Thu"),
166
0
            Self::Friday => write!(f, "Fri"),
167
0
            Self::Saturday => write!(f, "Sat"),
168
0
            Self::Sunday => write!(f, "Sun"),
169
        }
170
0
    }
171
}
172
173
#[test]
174
fn test_wrapping() {
175
    assert_eq!(Weekday::default(), Weekday::Monday);
176
    assert_eq!(Weekday::from(Weekday::MAX), Weekday::Monday);
177
178
    let monday = Weekday::default();
179
    for i in 0..24 {
180
        // Test wrapping
181
        let add = monday + i;
182
        let expected: Weekday = i.rem_euclid(Weekday::MAX).into();
183
        assert_eq!(
184
            add, expected,
185
            "expecting {expected:?} got {add:?} for {i:02} conversion"
186
        );
187
        // Test FromStr
188
    }
189
}
190
191
#[test]
192
fn test_iso_weekday() {
193
    assert_eq!(Weekday::Sunday.to_c89_weekday(), 0);
194
    assert_eq!(Weekday::Monday.to_c89_weekday(), 1);
195
    assert_eq!(Weekday::Tuesday.to_c89_weekday(), 2);
196
    assert_eq!(Weekday::Wednesday.to_c89_weekday(), 3);
197
    assert_eq!(Weekday::Thursday.to_c89_weekday(), 4);
198
    assert_eq!(Weekday::Friday.to_c89_weekday(), 5);
199
    assert_eq!(Weekday::Saturday.to_c89_weekday(), 6);
200
}