use super::*;
pub trait Offset: Sized + Copy + Clone + Deref<Target = u32> + From<u32> {
type Quantum: Quantum;
fn to_absolute(
&self,
topo: &Topology,
power: u8,
) -> <<Self as Offset>::Quantum as Quantum>::Absolute;
fn to_quantum(&self, power: u8) -> Self::Quantum;
fn from_absolute_rounded(loc: Loc, topo: &Topology, power: u8) -> Self;
}
#[derive(
Copy,
Clone,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
derive_more::Add,
derive_more::Sub,
derive_more::Mul,
derive_more::Div,
derive_more::Deref,
derive_more::DerefMut,
derive_more::From,
derive_more::Into,
serde::Serialize,
serde::Deserialize,
)]
#[serde(transparent)]
pub struct SpaceOffset(pub u32);
#[derive(
Copy,
Clone,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
derive_more::Add,
derive_more::Sub,
derive_more::Mul,
derive_more::Div,
derive_more::Deref,
derive_more::DerefMut,
derive_more::From,
derive_more::Into,
serde::Serialize,
serde::Deserialize,
)]
#[serde(transparent)]
pub struct TimeOffset(pub u32);
impl Offset for SpaceOffset {
type Quantum = SpaceQuantum;
fn to_absolute(&self, topo: &Topology, power: u8) -> Loc {
self.wrapping_mul(topo.space.quantum)
.wrapping_mul(pow2(power))
.into()
}
fn to_quantum(&self, power: u8) -> Self::Quantum {
self.wrapping_mul(pow2(power)).into()
}
fn from_absolute_rounded(loc: Loc, topo: &Topology, power: u8) -> Self {
(loc.as_u32() / topo.space.quantum / pow2(power)).into()
}
}
impl Offset for TimeOffset {
type Quantum = TimeQuantum;
fn to_absolute(&self, topo: &Topology, power: u8) -> Timestamp {
Timestamp::from_micros(
self.wrapping_mul(topo.time.quantum)
.wrapping_mul(pow2(power)) as i64,
)
}
fn to_quantum(&self, power: u8) -> Self::Quantum {
self.wrapping_mul(pow2(power)).into()
}
fn from_absolute_rounded(loc: Loc, topo: &Topology, power: u8) -> Self {
(loc.as_u32() / topo.time.quantum / pow2(power)).into()
}
}
#[derive(
Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize,
)]
pub struct Segment<O: Offset> {
pub power: u8,
pub offset: O,
}
impl<O: Offset> Segment<O> {
pub fn new<OO: Into<O>>(power: u8, offset: OO) -> Self {
Self {
power,
offset: offset.into(),
}
}
pub fn num_quanta(&self) -> u64 {
2u64.pow(self.power.into())
}
pub fn absolute_length(&self, topo: &Topology) -> u64 {
let q = O::Quantum::dimension(topo).quantum as u64;
self.num_quanta() * q
}
pub fn quantum_bounds(&self, topo: &Topology) -> (O::Quantum, O::Quantum) {
let n = self.num_quanta();
let a = (n * u64::from(*self.offset)) as u32;
(
O::Quantum::from(a).normalized(topo),
O::Quantum::from(a.wrapping_add(n as u32).wrapping_sub(1)).normalized(topo),
)
}
pub fn contains_quantum(&self, topo: &Topology, coord: O::Quantum) -> bool {
let (lo, hi) = self.quantum_bounds(topo);
let coord = coord.normalized(topo);
if lo <= hi {
lo <= coord && coord <= hi
} else {
lo <= coord || coord <= hi
}
}
pub fn bisect(&self) -> Option<[Self; 2]> {
if self.power == 0 {
None
} else {
let power = self.power - 1;
Some([
Segment::new(power, O::from(self.offset.wrapping_mul(2))),
Segment::new(power, O::from(self.offset.wrapping_mul(2).wrapping_add(1))),
])
}
}
}
impl SpaceSegment {
pub fn loc_bounds(&self, topo: &Topology) -> (Loc, Loc) {
let (a, b): (u32, u32) = bounds(&topo.space, self.power, self.offset, 1);
(Loc::from(a), Loc::from(b))
}
}
impl TimeSegment {
pub fn timestamp_bounds(&self, topo: &Topology) -> (Timestamp, Timestamp) {
let (a, b): (i64, i64) = bounds64(&topo.time, self.power, self.offset, 1);
let o = topo.time_origin.as_micros();
(Timestamp::from_micros(a + o), Timestamp::from_micros(b + o))
}
}
pub type SpaceSegment = Segment<SpaceOffset>;
pub type TimeSegment = Segment<TimeOffset>;
pub(super) fn bounds<N: From<u32>>(
dim: &Dimension,
power: u8,
offset: SpaceOffset,
count: u32,
) -> (N, N) {
debug_assert_ne!(dim.quantum, 0);
debug_assert_ne!(count, 0);
let q = dim.quantum.wrapping_mul(pow2(power));
let start = offset.wrapping_mul(q);
let len = count.wrapping_mul(q);
(start.into(), start.wrapping_add(len).wrapping_sub(1).into())
}
pub(super) fn bounds64<N: From<i64>>(
dim: &Dimension,
power: u8,
offset: TimeOffset,
count: u32,
) -> (N, N) {
debug_assert_ne!(dim.quantum, 0);
debug_assert_ne!(count, 0);
let q = dim.quantum as i64 * 2i64.pow(power.into());
let start = (*offset as i64).wrapping_mul(q);
let len = (count as i64).wrapping_mul(q);
(start.into(), start.wrapping_add(len).wrapping_sub(1).into())
}