1use crate::error::TzError;
4use crate::timezone::{LeapSecond, Transition};
5
6use core::cmp::Ordering;
7
8pub(crate) const fn cmp(a: i64, b: i64) -> Ordering {
10 if a < b {
11 Ordering::Less
12 } else if a == b {
13 Ordering::Equal
14 } else {
15 Ordering::Greater
16 }
17}
18
19pub(crate) const fn min(a: i64, b: i64) -> i64 {
21 match cmp(a, b) {
22 Ordering::Less | Ordering::Equal => a,
23 Ordering::Greater => b,
24 }
25}
26
27macro_rules! impl_try_into_integer {
29 ($from_type:ty, $to_type:ty, $value:expr) => {{
30 let min = <$to_type>::MIN as $from_type;
31 let max = <$to_type>::MAX as $from_type;
32
33 if min <= $value && $value <= max {
34 Ok($value as $to_type)
35 } else {
36 Err(TzError::OutOfRange)
37 }
38 }};
39}
40
41pub(crate) const fn try_into_i32(value: i64) -> Result<i32, TzError> {
43 impl_try_into_integer!(i64, i32, value)
44}
45
46pub(crate) const fn try_into_i64(value: i128) -> Result<i64, TzError> {
48 impl_try_into_integer!(i128, i64, value)
49}
50
51macro_rules! impl_binary_search {
53 ($slice:expr, $f:expr, $x:expr) => {{
54 let mut size = $slice.len();
55 let mut left = 0;
56 let mut right = size;
57 while left < right {
58 let mid = left + size / 2;
59
60 let v = $f(&$slice[mid]);
61 if v < $x {
62 left = mid + 1;
63 } else if v > $x {
64 right = mid;
65 } else {
66 return Ok(mid);
67 }
68
69 size = right - left;
70 }
71 Err(left)
72 }};
73}
74
75const fn copied(x: &i64) -> i64 {
77 *x
78}
79
80pub(crate) const fn binary_search_i64(slice: &[i64], x: i64) -> Result<usize, usize> {
82 impl_binary_search!(slice, copied, x)
83}
84
85pub(crate) const fn binary_search_transitions(slice: &[Transition], x: i64) -> Result<usize, usize> {
87 impl_binary_search!(slice, Transition::unix_leap_time, x)
88}
89
90pub(crate) const fn binary_search_leap_seconds(slice: &[LeapSecond], x: i64) -> Result<usize, usize> {
92 impl_binary_search!(slice, LeapSecond::unix_leap_time, x)
93}