Skip to main content

holidays_ru/
day_flags.rs

1/// Компактное представление свойств дня через битовые флаги.
2///
3/// Каждый бит обозначает одно свойство:
4/// - `WEEKEND` — суббота или воскресенье
5/// - `HOLIDAY` — федеральный нерабочий праздничный день (ст. 112 ТК РФ)
6/// - `DAY_OFF` — день является выходным
7/// - `WORKING_DAY` — день является рабочим
8/// - `SHORT_DAY` — сокращённый рабочий день
9/// - `TRANSFERRED` — день затронут переносом выходного
10///
11/// # Пример
12///
13/// ```rust
14/// use holidays_ru::DayFlags;
15///
16/// let flags = DayFlags::HOLIDAY.with(DayFlags::DAY_OFF);
17/// assert!(flags.is_holiday());
18/// assert!(flags.is_day_off());
19/// assert!(!flags.is_working_day());
20/// ```
21#[repr(transparent)]
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23pub struct DayFlags(u8);
24
25impl DayFlags {
26    /// Выходной день недели (суббота или воскресенье).
27    pub const WEEKEND: Self = Self(1 << 0);
28
29    /// Федеральный нерабочий праздничный день.
30    pub const HOLIDAY: Self = Self(1 << 1);
31
32    /// День является выходным (нерабочим).
33    pub const DAY_OFF: Self = Self(1 << 2);
34
35    /// День является рабочим.
36    pub const WORKING_DAY: Self = Self(1 << 3);
37
38    /// Сокращённый рабочий день (предпраздничный).
39    pub const SHORT_DAY: Self = Self(1 << 4);
40
41    /// День затронут переносом выходного.
42    pub const TRANSFERRED: Self = Self(1 << 5);
43
44    /// Пустой набор флагов (ни одно свойство не установлено).
45    pub const EMPTY: Self = Self(0);
46
47    /// Добавляет флаги `other` к текущему набору.
48    #[inline]
49    #[must_use]
50    pub const fn with(self, other: Self) -> Self {
51        Self(self.0 | other.0)
52    }
53
54    /// Добавляет `other`, если `condition` истинно.
55    #[inline]
56    #[must_use]
57    pub const fn with_if(self, condition: bool, other: Self) -> Self {
58        Self(self.0 | (other.0 & (condition as u8).wrapping_neg()))
59    }
60
61    /// Является ли день выходным днём недели (суббота или воскресенье).
62    #[inline]
63    pub const fn is_weekend(self) -> bool {
64        self.0 & Self::WEEKEND.0 != 0
65    }
66
67    /// Является ли день федеральным нерабочим праздничным днём.
68    #[inline]
69    pub const fn is_holiday(self) -> bool {
70        self.0 & Self::HOLIDAY.0 != 0
71    }
72
73    /// Является ли день выходным (нерабочим).
74    #[inline]
75    pub const fn is_day_off(self) -> bool {
76        self.0 & Self::DAY_OFF.0 != 0
77    }
78
79    /// Является ли день рабочим.
80    #[inline]
81    pub const fn is_working_day(self) -> bool {
82        self.0 & Self::WORKING_DAY.0 != 0
83    }
84
85    /// Является ли день сокращённым рабочим днём.
86    #[inline]
87    pub const fn is_short_day(self) -> bool {
88        self.0 & Self::SHORT_DAY.0 != 0
89    }
90
91    /// Затронут ли день переносом выходного.
92    #[inline]
93    pub const fn is_transferred(self) -> bool {
94        self.0 & Self::TRANSFERRED.0 != 0
95    }
96
97    /// Возвращает сырое значение битовой маски.
98    #[inline]
99    pub const fn bits(self) -> u8 {
100        self.0
101    }
102
103    /// Создаёт `DayFlags` из сырой битовой маски.
104    ///
105    /// Не выполняет проверку корректности комбинации флагов.
106    #[inline]
107    pub const fn from_bits(bits: u8) -> Self {
108        Self(bits)
109    }
110}
111
112#[cfg(feature = "serde")]
113impl serde::Serialize for DayFlags {
114    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
115        serializer.serialize_u8(self.0)
116    }
117}
118
119#[cfg(feature = "serde")]
120impl<'de> serde::Deserialize<'de> for DayFlags {
121    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
122        <u8 as serde::Deserialize>::deserialize(deserializer).map(Self)
123    }
124}
125
126#[cfg(all(test, feature = "serde"))]
127mod serde_tests {
128    use super::*;
129
130    #[test]
131    fn test_serde_json_as_bits() {
132        let flags = DayFlags::HOLIDAY.with(DayFlags::DAY_OFF);
133        let json = serde_json::to_string(&flags).unwrap();
134
135        assert_eq!(json, "6");
136        assert_eq!(serde_json::from_str::<DayFlags>(&json).unwrap(), flags);
137    }
138}