Skip to content

Commit b3f01a8

Browse files
committed
add Weekdays
1 parent fa957cc commit b3f01a8

File tree

4 files changed

+335
-1
lines changed

4 files changed

+335
-1
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: All Tests and Builds
22

33
env:
44
# It's really `--all-features`, but not adding the mutually exclusive features from rkyv
5-
ALL_NON_EXCLUSIVE_FEATURES: --features "default unstable-locales rkyv-32 rkyv-validation serde arbitrary"
5+
ALL_NON_EXCLUSIVE_FEATURES: --features "default unstable-locales rkyv-32 rkyv-validation serde arbitrary experimental_weekdays"
66

77
on:
88
push:

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ now = ["std"]
2828
oldtime = []
2929
wasmbind = ["wasm-bindgen", "js-sys"]
3030
unstable-locales = ["pure-rust-locales"]
31+
experimental_weekdays = ["dep:enumflags2"]
3132
# Note that rkyv-16, rkyv-32, and rkyv-64 are mutually exclusive.
3233
rkyv = ["dep:rkyv", "rkyv/size_32"]
3334
rkyv-16 = ["dep:rkyv", "rkyv?/size_16"]
@@ -43,6 +44,7 @@ serde = { version = "1.0.99", default-features = false, optional = true }
4344
pure-rust-locales = { version = "0.8", optional = true }
4445
rkyv = { version = "0.7.43", optional = true, default-features = false }
4546
arbitrary = { version = "1.0.0", features = ["derive"], optional = true }
47+
enumflags2 = { version = "0.7.11", optional = true }
4648

4749
[target.'cfg(all(target_arch = "wasm32", not(any(target_os = "emscripten", target_os = "wasi"))))'.dependencies]
4850
wasm-bindgen = { version = "0.2", optional = true }

src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,11 @@ mod weekday;
580580
pub use weekday::ParseWeekdayError;
581581
pub use weekday::Weekday;
582582

583+
#[cfg(feature = "experimental_weekdays")]
584+
mod weekdays;
585+
#[cfg(feature = "experimental_weekdays")]
586+
pub use weekdays::Weekdays;
587+
583588
mod month;
584589
#[doc(no_inline)]
585590
pub use month::ParseMonthError;

src/weekdays.rs

Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
use core::{
2+
fmt,
3+
iter::FusedIterator,
4+
ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not},
5+
};
6+
7+
use enumflags2::BitFlags;
8+
9+
use crate::Weekday;
10+
11+
/// A set of `Weekday`s.
12+
#[derive(Debug, Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
13+
pub struct Weekdays(BitFlags<InnerWeekday>);
14+
15+
impl Weekdays {
16+
/// An empty `Weekdays`.
17+
pub const EMPTY: Self = Self(BitFlags::EMPTY);
18+
/// A `Weekdays` containing all seven `Weekday`s.
19+
pub const ALL: Self = Self(BitFlags::ALL);
20+
21+
/// A `Weekdays` containing only Monday.
22+
pub const MON: Self = Self::from_bits_truncate(InnerWeekday::Mon as u8);
23+
/// A `Weekdays` containing only Tuesday.
24+
pub const TUE: Self = Self::from_bits_truncate(InnerWeekday::Tue as u8);
25+
/// A `Weekdays` containing only Wednesday.
26+
pub const WED: Self = Self::from_bits_truncate(InnerWeekday::Wed as u8);
27+
/// A `Weekdays` containing only Thursday.
28+
pub const THU: Self = Self::from_bits_truncate(InnerWeekday::Thu as u8);
29+
/// A `Weekdays` containing only Friday.
30+
pub const FRI: Self = Self::from_bits_truncate(InnerWeekday::Fri as u8);
31+
/// A `Weekdays` containing only Saturday.
32+
pub const SAT: Self = Self::from_bits_truncate(InnerWeekday::Sat as u8);
33+
/// A `Weekdays` containing only Sunday.
34+
pub const SUN: Self = Self::from_bits_truncate(InnerWeekday::Sun as u8);
35+
36+
/// Create a `Weekdays` from a bit pattern.
37+
///
38+
/// If present, the 8-th bit is ignored.
39+
///
40+
/// # Example
41+
///
42+
/// ```
43+
/// # use chrono::Weekdays;
44+
/// assert_eq!(Weekdays::EMPTY, Weekdays::from_bits(0));
45+
/// assert_eq!(Weekdays::MON, Weekdays::from_bits(0b1));
46+
/// assert_eq!(Weekdays::TUE, Weekdays::from_bits(0b10));
47+
/// assert_eq!(Weekdays::Mon | Weekdays::Wed, Weekdays::from_bits(0b101));
48+
/// assert_eq!(Weekdays::ALL, Weekdays::from_bits(0b111_1111));
49+
/// assert_eq!(Weekdays::MON, Weekdays::from_bits(0b1000_0001));
50+
/// ```
51+
#[must_use]
52+
pub const fn from_bits_truncate(bits: u8) -> Self {
53+
Self(BitFlags::<InnerWeekday>::from_bits_truncate_c(
54+
bits,
55+
BitFlags::<InnerWeekday>::CONST_TOKEN,
56+
))
57+
}
58+
59+
/// Returns the number of days in the set.
60+
pub const fn len(self) -> usize {
61+
self.0.bits_c().count_ones() as usize
62+
}
63+
/// Returns `true` if the set is empty.
64+
pub const fn is_empty(self) -> bool {
65+
self.0.bits_c() == 0
66+
}
67+
68+
/// Iterate over the `Weekday`s in the set.
69+
///
70+
/// Starting from Monday, in ascending order.
71+
///
72+
/// # Example
73+
/// ```
74+
/// # use chrono::Weekdays;
75+
/// let weekdays = Weekdays::MON | Weekdays::WED | Weekdays::FRI;
76+
/// let mut iter = weekdays.iter();
77+
/// assert_eq!(iter.next(), Some(Weekday::Mon));
78+
/// assert_eq!(iter.next(), Some(Weekday::Wed));
79+
/// assert_eq!(iter.next(), Some(Weekday::Fri));
80+
/// assert_eq!(iter.next(), None);
81+
/// ```
82+
pub fn iter(self) -> WeekdaysIter {
83+
WeekdaysIter(self.0.iter())
84+
}
85+
}
86+
87+
#[derive(Debug, Clone)]
88+
pub struct WeekdaysIter(enumflags2::Iter<InnerWeekday>);
89+
impl Iterator for WeekdaysIter {
90+
type Item = Weekday;
91+
92+
fn next(&mut self) -> Option<Self::Item> {
93+
self.0.next().map(Weekday::from)
94+
}
95+
}
96+
impl ExactSizeIterator for WeekdaysIter {
97+
fn len(&self) -> usize {
98+
self.0.len()
99+
}
100+
}
101+
impl FusedIterator for WeekdaysIter {}
102+
103+
impl fmt::Display for Weekdays {
104+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
105+
let mut iter = self.iter();
106+
if let Some(first) = iter.next() {
107+
write!(f, "{first}")?;
108+
for weekday in iter {
109+
write!(f, " | {weekday}")?;
110+
}
111+
Ok(())
112+
} else {
113+
write!(f, "<empty>")
114+
}
115+
}
116+
}
117+
118+
// impl Bit* for Weekdays
119+
impl BitOr for Weekdays {
120+
type Output = Self;
121+
122+
fn bitor(self, rhs: Self) -> Self::Output {
123+
Self(self.0 | rhs.0)
124+
}
125+
}
126+
impl BitAnd for Weekdays {
127+
type Output = Self;
128+
129+
fn bitand(self, rhs: Self) -> Self::Output {
130+
Self(self.0 & rhs.0)
131+
}
132+
}
133+
impl BitXor for Weekdays {
134+
type Output = Self;
135+
136+
fn bitxor(self, rhs: Self) -> Self::Output {
137+
Self(self.0 ^ rhs.0)
138+
}
139+
}
140+
141+
// impl Bit*Assign for Weekdays
142+
impl BitOrAssign for Weekdays {
143+
fn bitor_assign(&mut self, rhs: Self) {
144+
self.0 |= rhs.0;
145+
}
146+
}
147+
impl BitAndAssign for Weekdays {
148+
fn bitand_assign(&mut self, rhs: Self) {
149+
self.0 &= rhs.0;
150+
}
151+
}
152+
impl BitXorAssign for Weekdays {
153+
fn bitxor_assign(&mut self, rhs: Self) {
154+
self.0 ^= rhs.0;
155+
}
156+
}
157+
158+
impl Not for Weekdays {
159+
type Output = Self;
160+
161+
fn not(self) -> Self::Output {
162+
Self(!self.0)
163+
}
164+
}
165+
166+
#[enumflags2::bitflags]
167+
#[repr(u8)]
168+
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
169+
enum InnerWeekday {
170+
Mon = 1 << Weekday::Mon as u8,
171+
Tue = 1 << Weekday::Tue as u8,
172+
Wed = 1 << Weekday::Wed as u8,
173+
Thu = 1 << Weekday::Thu as u8,
174+
Fri = 1 << Weekday::Fri as u8,
175+
Sat = 1 << Weekday::Sat as u8,
176+
Sun = 1 << Weekday::Sun as u8,
177+
}
178+
179+
impl From<Weekday> for InnerWeekday {
180+
fn from(weekday: Weekday) -> Self {
181+
match weekday {
182+
Weekday::Mon => Self::Mon,
183+
Weekday::Tue => Self::Tue,
184+
Weekday::Wed => Self::Wed,
185+
Weekday::Thu => Self::Thu,
186+
Weekday::Fri => Self::Fri,
187+
Weekday::Sat => Self::Sat,
188+
Weekday::Sun => Self::Sun,
189+
}
190+
}
191+
}
192+
impl From<InnerWeekday> for Weekday {
193+
fn from(value: InnerWeekday) -> Self {
194+
match value {
195+
InnerWeekday::Mon => Self::Mon,
196+
InnerWeekday::Tue => Self::Tue,
197+
InnerWeekday::Wed => Self::Wed,
198+
InnerWeekday::Thu => Self::Thu,
199+
InnerWeekday::Fri => Self::Fri,
200+
InnerWeekday::Sat => Self::Sat,
201+
InnerWeekday::Sun => Self::Sun,
202+
}
203+
}
204+
}
205+
206+
impl From<Weekday> for Weekdays {
207+
fn from(weekday: Weekday) -> Self {
208+
Weekdays(InnerWeekday::from(weekday).into())
209+
}
210+
}
211+
impl Extend<Weekday> for Weekdays {
212+
fn extend<T: IntoIterator<Item = Weekday>>(&mut self, iter: T) {
213+
for weekday in iter {
214+
self.0.insert(InnerWeekday::from(weekday));
215+
}
216+
}
217+
}
218+
impl FromIterator<Weekday> for Weekdays {
219+
fn from_iter<T: IntoIterator<Item = Weekday>>(iter: T) -> Self {
220+
let mut weekdays = Self::EMPTY;
221+
weekdays.extend(iter);
222+
weekdays
223+
}
224+
}
225+
226+
impl IntoIterator for Weekdays {
227+
type Item = Weekday;
228+
type IntoIter = WeekdaysIter;
229+
230+
fn into_iter(self) -> Self::IntoIter {
231+
self.iter()
232+
}
233+
}
234+
235+
// impl Bit*<Weekday> for Weekdays
236+
impl BitOr<Weekday> for Weekdays {
237+
type Output = Self;
238+
239+
fn bitor(self, rhs: Weekday) -> Self::Output {
240+
self | Self::from(rhs)
241+
}
242+
}
243+
impl BitAnd<Weekday> for Weekdays {
244+
type Output = Self;
245+
246+
fn bitand(self, rhs: Weekday) -> Self::Output {
247+
self & Self::from(rhs)
248+
}
249+
}
250+
impl BitXor<Weekday> for Weekdays {
251+
type Output = Self;
252+
253+
fn bitxor(self, rhs: Weekday) -> Self::Output {
254+
self ^ Self::from(rhs)
255+
}
256+
}
257+
258+
// impl Bit*<Weekdays> for Weekday
259+
impl BitOr<Weekdays> for Weekday {
260+
type Output = Weekdays;
261+
262+
fn bitor(self, rhs: Weekdays) -> Self::Output {
263+
Weekdays::from(self) | rhs
264+
}
265+
}
266+
impl BitAnd<Weekdays> for Weekday {
267+
type Output = Weekdays;
268+
269+
fn bitand(self, rhs: Weekdays) -> Self::Output {
270+
Weekdays::from(self) & rhs
271+
}
272+
}
273+
impl BitXor<Weekdays> for Weekday {
274+
type Output = Weekdays;
275+
276+
fn bitxor(self, rhs: Weekdays) -> Self::Output {
277+
Weekdays::from(self) ^ rhs
278+
}
279+
}
280+
281+
// impl Bit*Assign<Weekday> for Weekdays
282+
impl BitOrAssign<Weekday> for Weekdays {
283+
fn bitor_assign(&mut self, rhs: Weekday) {
284+
*self |= Self::from(rhs);
285+
}
286+
}
287+
impl BitAndAssign<Weekday> for Weekdays {
288+
fn bitand_assign(&mut self, rhs: Weekday) {
289+
*self &= Self::from(rhs);
290+
}
291+
}
292+
impl BitXorAssign<Weekday> for Weekdays {
293+
fn bitxor_assign(&mut self, rhs: Weekday) {
294+
*self ^= Self::from(rhs);
295+
}
296+
}
297+
298+
// impl Bit* for Weekday
299+
impl BitOr for Weekday {
300+
type Output = Weekdays;
301+
302+
fn bitor(self, rhs: Self) -> Self::Output {
303+
Weekdays::from(self) | Weekdays::from(rhs)
304+
}
305+
}
306+
impl BitAnd for Weekday {
307+
type Output = Weekdays;
308+
309+
fn bitand(self, rhs: Self) -> Self::Output {
310+
Weekdays::from(self) & Weekdays::from(rhs)
311+
}
312+
}
313+
impl BitXor for Weekday {
314+
type Output = Weekdays;
315+
316+
fn bitxor(self, rhs: Self) -> Self::Output {
317+
Weekdays::from(self) ^ Weekdays::from(rhs)
318+
}
319+
}
320+
321+
impl Not for Weekday {
322+
type Output = Weekdays;
323+
324+
fn not(self) -> Self::Output {
325+
!Weekdays::from(self)
326+
}
327+
}

0 commit comments

Comments
 (0)