tz/utils/
const_fns.rs

1//! Some useful constant functions.
2
3use crate::error::OutOfRangeError;
4use crate::timezone::{LeapSecond, Transition};
5
6use core::cmp::Ordering;
7
8/// Compare two values
9#[cfg_attr(feature = "const", const_fn::const_fn)]
10pub fn cmp(a: i64, b: i64) -> Ordering {
11    if a < b {
12        Ordering::Less
13    } else if a == b {
14        Ordering::Equal
15    } else {
16        Ordering::Greater
17    }
18}
19
20/// Returns the minimum of two values
21#[cfg_attr(feature = "const", const_fn::const_fn)]
22pub fn min(a: i64, b: i64) -> i64 {
23    match cmp(a, b) {
24        Ordering::Less | Ordering::Equal => a,
25        Ordering::Greater => b,
26    }
27}
28
29/// Macro for implementing integer conversion
30macro_rules! impl_try_into_integer {
31    ($from_type:ty, $to_type:ty, $value:expr) => {{
32        let min = <$to_type>::MIN as $from_type;
33        let max = <$to_type>::MAX as $from_type;
34
35        if min <= $value && $value <= max {
36            Ok($value as $to_type)
37        } else {
38            Err(OutOfRangeError("out of range integer conversion"))
39        }
40    }};
41}
42
43/// Convert a `i64` value to a `i32` value
44#[cfg_attr(feature = "const", const_fn::const_fn)]
45pub fn try_into_i32(value: i64) -> Result<i32, OutOfRangeError> {
46    impl_try_into_integer!(i64, i32, value)
47}
48
49/// Convert a `i128` value to a `i64` value
50#[cfg_attr(feature = "const", const_fn::const_fn)]
51pub fn try_into_i64(value: i128) -> Result<i64, OutOfRangeError> {
52    impl_try_into_integer!(i128, i64, value)
53}
54
55/// Macro for implementing binary search
56macro_rules! impl_binary_search {
57    ($slice:expr, $f:expr, $x:expr) => {{
58        let mut size = $slice.len();
59        let mut left = 0;
60        let mut right = size;
61        while left < right {
62            let mid = left + size / 2;
63
64            let v = $f(&$slice[mid]);
65            if v < $x {
66                left = mid + 1;
67            } else if v > $x {
68                right = mid;
69            } else {
70                return Ok(mid);
71            }
72
73            size = right - left;
74        }
75        Err(left)
76    }};
77}
78
79/// Copy the input value
80#[cfg_attr(feature = "const", const_fn::const_fn)]
81fn copied(x: &i64) -> i64 {
82    *x
83}
84
85/// Binary searches a sorted `i64` slice for the given element
86#[cfg_attr(feature = "const", const_fn::const_fn)]
87pub fn binary_search_i64(slice: &[i64], x: i64) -> Result<usize, usize> {
88    impl_binary_search!(slice, copied, x)
89}
90
91/// Binary searches a sorted `Transition` slice for the given element
92#[cfg_attr(feature = "const", const_fn::const_fn)]
93pub fn binary_search_transitions(slice: &[Transition], x: i64) -> Result<usize, usize> {
94    impl_binary_search!(slice, Transition::unix_leap_time, x)
95}
96
97/// Binary searches a sorted `LeapSecond` slice for the given element
98#[cfg_attr(feature = "const", const_fn::const_fn)]
99pub fn binary_search_leap_seconds(slice: &[LeapSecond], x: i64) -> Result<usize, usize> {
100    impl_binary_search!(slice, LeapSecond::unix_leap_time, x)
101}
102
103/// Macro for panicking in a const context
104macro_rules! const_panic {
105    () => {{
106        #[allow(unconditional_panic)]
107        let panic = [][0];
108        panic
109    }};
110}
111pub(crate) use const_panic;