1use icu_calendar::{Date, cal::Hebrew, types::Weekday};
2
3use crate::limudim::{
4 BAVLI_DAF_COUNT_MODERN, HebrewDateExt, Limud,
5 cycle::Cycle,
6 interval::Interval,
7 limud::{CycleFinder, InternalLimud},
8 units::{BAVLI_TRACTATES, Daf, Tractate},
9};
10
11fn initial_cycle_date() -> Date<Hebrew> {
12 #[allow(clippy::expect_used)]
13 let date = Date::try_new_gregorian(2005, 3, 6)
14 .expect("hard-coded Gregorian date should be valid")
15 .to_calendar(Hebrew);
16 date
17}
18
19fn day_of_week_number(date: Date<Hebrew>) -> i32 {
20 match date.weekday() {
21 Weekday::Sunday => 1,
22 Weekday::Monday => 2,
23 Weekday::Tuesday => 3,
24 Weekday::Wednesday => 4,
25 Weekday::Thursday => 5,
26 Weekday::Friday => 6,
27 Weekday::Saturday => 7,
28 }
29}
30
31const fn start_daf(tractate: Tractate) -> u16 {
32 match tractate {
33 Tractate::Kinnim => 23,
34 Tractate::Tamid => 26,
35 Tractate::Midos => 34,
36 _ => 2,
37 }
38}
39
40const fn end_daf(tractate: Tractate) -> Option<u16> {
41 let daf = match tractate {
42 Tractate::Berachos => 64,
43 Tractate::Shabbos => 157,
44 Tractate::Eruvin => 105,
45 Tractate::Pesachim => 121,
46 Tractate::Shekalim => 22,
47 Tractate::Yoma => 88,
48 Tractate::Sukkah => 56,
49 Tractate::Beitzah => 40,
50 Tractate::RoshHashanah => 35,
51 Tractate::Taanis => 31,
52 Tractate::Megillah => 32,
53 Tractate::MoedKatan => 29,
54 Tractate::Chagigah => 27,
55 Tractate::Yevamos => 122,
56 Tractate::Kesubos => 112,
57 Tractate::Nedarim => 91,
58 Tractate::Nazir => 66,
59 Tractate::Sotah => 49,
60 Tractate::Gitin => 90,
61 Tractate::Kiddushin => 82,
62 Tractate::BavaKamma => 119,
63 Tractate::BavaMetzia => 119,
64 Tractate::BavaBasra => 176,
65 Tractate::Sanhedrin => 113,
66 Tractate::Makkos => 24,
67 Tractate::Shevuos => 49,
68 Tractate::AvodahZarah => 76,
69 Tractate::Horiyos => 14,
70 Tractate::Zevachim => 120,
71 Tractate::Menachos => 110,
72 Tractate::Chullin => 142,
73 Tractate::Bechoros => 61,
74 Tractate::Arachin => 34,
75 Tractate::Temurah => 34,
76 Tractate::Kerisos => 28,
77 Tractate::Meilah => 22,
78 Tractate::Kinnim => 25,
79 Tractate::Tamid => 33,
80 Tractate::Midos => 37,
81 Tractate::Niddah => 73,
82 _ => 0,
83 };
84 if daf == 0 { None } else { Some(daf) }
85}
86
87#[derive(Default)]
88pub struct DafHashavuaBavli {}
90
91impl InternalLimud<Daf> for DafHashavuaBavli {
92 fn interval_end_calculation(_cycle: Cycle, hebrew_date: Date<Hebrew>) -> Option<Date<Hebrew>> {
93 let day_number = day_of_week_number(hebrew_date);
94 hebrew_date.add_days(7 - day_number)
95 }
96 fn cycle_finder(&self) -> CycleFinder {
97 CycleFinder::Initial(initial_cycle_date())
98 }
99 fn cycle_end_calculation(hebrew_date: Date<Hebrew>, _iteration: Option<i32>) -> Option<Date<Hebrew>> {
100 let day_number = day_of_week_number(hebrew_date);
101 hebrew_date.add_days((BAVLI_DAF_COUNT_MODERN * 7) - day_number)
102 }
103
104 fn unit_for_interval(&self, interval: &Interval, _limud_date: &Date<Hebrew>) -> Option<Daf> {
105 interval.cycle.iteration?;
106 daf_at_offset((interval.iteration - 1) as usize)
107 }
108}
109
110impl Limud<Daf> for DafHashavuaBavli {}
111
112fn daf_at_offset(offset: usize) -> Option<Daf> {
113 let mut remaining = offset;
114 for tractate in BAVLI_TRACTATES {
115 let start = start_daf(tractate);
116 let end = end_daf(tractate)?;
117 let count = usize::from(end - start + 1);
118 if remaining < count {
119 return Some(Daf {
120 tractate,
121 page: start + remaining as u16,
122 });
123 }
124 remaining -= count;
125 }
126 None
127}
128#[cfg(test)]
129#[allow(clippy::expect_used)]
130mod tests {
131 use crate::limudim::from_gregorian_date;
132
133 use super::*;
134
135 #[test]
136 fn daf_hashavua_bavli_simple_date() {
137 let test_date = from_gregorian_date(2018, 10, 10);
138 let limud = DafHashavuaBavli::default().limud(test_date).expect("limud exists");
139 assert_eq!(limud.tractate, Tractate::Megillah);
140 assert_eq!(limud.page, 2);
141 }
142
143 #[test]
144 fn daf_hashavua_bavli_before_cycle_began() {
145 let test_date = from_gregorian_date(2005, 3, 5);
146 let limud = DafHashavuaBavli::default().limud(test_date);
147 assert!(limud.is_none());
148 }
149
150 #[test]
151 fn daf_hashavua_bavli_first_day_of_cycle() {
152 let test_date = from_gregorian_date(2057, 2, 18);
153 let limud = DafHashavuaBavli::default().limud(test_date).expect("limud exists");
154 assert_eq!(limud.page, 2);
155 assert_eq!(limud.tractate, Tractate::Berachos);
156 }
157
158 #[test]
159 fn daf_hashavua_bavli_last_day_of_cycle() {
160 let test_date = from_gregorian_date(2057, 2, 17);
161 let limud = DafHashavuaBavli::default().limud(test_date).expect("limud exists");
162 assert_eq!(limud.page, 73);
163 assert_eq!(limud.tractate, Tractate::Niddah);
164 }
165}