clockwork_cron/time_unit/
mod.rs1mod days_of_month;
2mod days_of_week;
3mod hours;
4mod minutes;
5mod months;
6mod seconds;
7mod years;
8
9pub use self::days_of_month::DaysOfMonth;
10pub use self::days_of_week::DaysOfWeek;
11pub use self::hours::Hours;
12pub use self::minutes::Minutes;
13pub use self::months::Months;
14pub use self::seconds::Seconds;
15pub use self::years::Years;
16
17use crate::error::*;
18use crate::ordinal::{Ordinal, OrdinalSet};
19use crate::specifier::{RootSpecifier, Specifier};
20use std::borrow::Cow;
21use std::iter;
22
23pub trait TimeUnitSpec {
41 fn includes(&self, ordinal: Ordinal) -> bool;
56
57 fn count(&self) -> u32;
69
70 fn is_all(&self) -> bool;
83}
84
85impl<T> TimeUnitSpec for T
86where
87 T: TimeUnitField,
88{
89 fn includes(&self, ordinal: Ordinal) -> bool {
90 self.ordinals().contains(&ordinal)
91 }
92
93 fn count(&self) -> u32 {
94 self.ordinals().len() as u32
95 }
96
97 fn is_all(&self) -> bool {
98 let max_supported_ordinals = Self::inclusive_max() - Self::inclusive_min() + 1;
99 self.ordinals().len() == max_supported_ordinals as usize
100 }
101}
102
103pub trait TimeUnitField
104where
105 Self: Sized,
106{
107 fn from_optional_ordinal_set(ordinal_set: Option<OrdinalSet>) -> Self;
108 fn name() -> Cow<'static, str>;
109 fn inclusive_min() -> Ordinal;
110 fn inclusive_max() -> Ordinal;
111 fn ordinals(&self) -> OrdinalSet;
112
113 fn from_ordinal(ordinal: Ordinal) -> Self {
114 Self::from_ordinal_set(iter::once(ordinal).collect())
115 }
116
117 fn supported_ordinals() -> OrdinalSet {
118 (Self::inclusive_min()..Self::inclusive_max() + 1).collect()
119 }
120
121 fn all() -> Self {
122 Self::from_optional_ordinal_set(None)
123 }
124
125 fn from_ordinal_set(ordinal_set: OrdinalSet) -> Self {
126 Self::from_optional_ordinal_set(Some(ordinal_set))
127 }
128
129 fn ordinal_from_name(name: &str) -> Result<Ordinal, Error> {
130 Err(ErrorKind::Expression(format!(
131 "The '{}' field does not support using names. '{}' \
132 specified.",
133 Self::name(),
134 name
135 ))
136 .into())
137 }
138
139 fn validate_ordinal(ordinal: Ordinal) -> Result<Ordinal, Error> {
140 match ordinal {
142 i if i < Self::inclusive_min() => Err(ErrorKind::Expression(format!(
143 "{} must be greater than or equal to {}. ('{}' \
144 specified.)",
145 Self::name(),
146 Self::inclusive_min(),
147 i
148 ))
149 .into()),
150 i if i > Self::inclusive_max() => Err(ErrorKind::Expression(format!(
151 "{} must be less than {}. ('{}' specified.)",
152 Self::name(),
153 Self::inclusive_max(),
154 i
155 ))
156 .into()),
157 i => Ok(i),
158 }
159 }
160
161 fn ordinals_from_specifier(specifier: &Specifier) -> Result<OrdinalSet, Error> {
162 use self::Specifier::*;
163 match *specifier {
165 All => Ok(Self::supported_ordinals().clone()),
166 Point(ordinal) => Ok((&[ordinal]).iter().cloned().collect()),
167 Range(start, end) => {
168 match (Self::validate_ordinal(start), Self::validate_ordinal(end)) {
169 (Ok(start), Ok(end)) if start <= end => Ok((start..end + 1).collect()),
170 _ => Err(ErrorKind::Expression(format!(
171 "Invalid range for {}: {}-{}",
172 Self::name(),
173 start,
174 end
175 ))
176 .into()),
177 }
178 }
179 NamedRange(ref start_name, ref end_name) => {
180 let start = Self::ordinal_from_name(start_name)?;
181 let end = Self::ordinal_from_name(end_name)?;
182 match (Self::validate_ordinal(start), Self::validate_ordinal(end)) {
183 (Ok(start), Ok(end)) if start <= end => Ok((start..end + 1).collect()),
184 _ => Err(ErrorKind::Expression(format!(
185 "Invalid named range for {}: {}-{}",
186 Self::name(),
187 start_name,
188 end_name
189 ))
190 .into()),
191 }
192 }
193 }
194 }
195
196 fn ordinals_from_root_specifier(root_specifier: &RootSpecifier) -> Result<OrdinalSet, Error> {
197 let ordinals = match root_specifier {
198 RootSpecifier::Specifier(specifier) => Self::ordinals_from_specifier(specifier)?,
199 RootSpecifier::Period(start, step) => {
200 let base_set = match start {
201 Specifier::Point(start) => {
204 let start = Self::validate_ordinal(*start)?;
205 (start..=Self::inclusive_max()).collect()
206 }
207 specifier => Self::ordinals_from_specifier(specifier)?,
208 };
209 if *step == 0 {
210 return Err(ErrorKind::Expression(format!("step cannot be 0")).into());
211 }
212 base_set.into_iter().step_by(*step as usize).collect()
213 }
214 RootSpecifier::NamedPoint(ref name) => (&[Self::ordinal_from_name(name)?])
215 .iter()
216 .cloned()
217 .collect::<OrdinalSet>(),
218 };
219 Ok(ordinals)
220 }
221}