use std::collections::Bound;
use std::ops::RangeBounds;
struct WrappedRange {
lower_bound: i64,
upper_bound: Option<i64>,
}
pub fn wrapped<T>(signed_range: impl RangeBounds<T>) -> impl SignedRange
where
T: Copy + Into<i64>,
{
let lower_bound = lower_bound(signed_range.start_bound().map(|v| (*v).into())).unwrap_or(0);
let upper_bound = upper_bound(signed_range.end_bound().map(|v| (*v).into()));
WrappedRange {
lower_bound,
upper_bound,
}
}
fn lower_bound(bound: Bound<i64>) -> Option<i64> {
match bound {
Bound::Included(n) => Some(n),
Bound::Excluded(n) => Some(n + 1),
Bound::Unbounded => None,
}
}
fn upper_bound(bound: Bound<i64>) -> Option<i64> {
match bound {
Bound::Included(n) => Some(n + 1),
Bound::Excluded(n) => Some(n),
Bound::Unbounded => None,
}
}
mod sealed {
pub trait SealedRange {}
}
pub trait SignedRange: sealed::SealedRange {
#[doc(hidden)]
fn signed(&self) -> (i64, Option<i64>);
}
impl sealed::SealedRange for WrappedRange {}
impl SignedRange for WrappedRange {
fn signed(&self) -> (i64, Option<i64>) {
(self.lower_bound, self.upper_bound)
}
}
impl<R> sealed::SealedRange for R where R: RangeBounds<usize> {}
impl<R> SignedRange for R
where
R: RangeBounds<usize>,
{
fn signed(&self) -> (i64, Option<i64>) {
let lower_bound = lower_bound(self.start_bound().map(|v| *v as i64)).unwrap_or(0);
let upper_bound = upper_bound(self.end_bound().map(|v| *v as i64));
(lower_bound, upper_bound)
}
}
pub(crate) fn to_godot_range_fromto(range: impl SignedRange) -> (i64, i64) {
match range.signed() {
(from, Some(to)) => {
crate::sys::strict_assert!(from <= to, "range: start ({from}) > end ({to})");
(from, to)
}
(from, None) => (from, 0),
}
}
pub(crate) fn to_godot_range_fromlen(range: impl SignedRange, unbounded: i64) -> (i64, i64) {
match range.signed() {
(from, Some(to)) => {
crate::sys::strict_assert!(from <= to, "range: start ({from}) > end ({to})");
(from, to - from)
}
(from, None) => (from, unbounded),
}
}