use core::cmp::Ordering;
use core::fmt::Debug;
use core::hash::Hash;
#[cfg(feature = "dev")]
use arbitrary::{Arbitrary, size_hint};
use order_theory::{GreatestElement, LeastElement, SuccessorExceptForGreatest};
use crate::prelude::*;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Range3d<const MCL: usize, const MCC: usize, const MPL: usize, S> {
subspaces: SubspaceRange<S>,
paths: PathRange<MCL, MCC, MPL>,
times: TimeRange,
}
#[cfg(feature = "dev")]
impl<'a, const MCL: usize, const MCC: usize, const MPL: usize, S> Arbitrary<'a>
for Range3d<MCL, MCC, MPL, S>
where
S: PartialOrd + Arbitrary<'a>,
{
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
let subspaces = SubspaceRange::<S>::arbitrary(u)?;
let paths = PathRange::<MCL, MCC, MPL>::arbitrary(u)?;
let times = TimeRange::arbitrary(u)?;
Ok(Self {
subspaces,
paths,
times,
})
}
fn try_size_hint(
depth: usize,
) -> arbitrary::Result<(usize, Option<usize>), arbitrary::MaxRecursionReached> {
Ok(size_hint::and_all(&[
SubspaceRange::<S>::try_size_hint(depth)?,
PathRange::<MCL, MCC, MPL>::try_size_hint(depth)?,
TimeRange::try_size_hint(depth)?,
]))
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, S> Range3d<MCL, MCC, MPL, S> {
pub fn new<SR, PR, TR>(subspaces: SR, paths: PR, times: TR) -> Self
where
SR: Into<SubspaceRange<S>>,
PR: Into<PathRange<MCL, MCC, MPL>>,
TR: Into<TimeRange>,
{
Self {
subspaces: subspaces.into(),
paths: paths.into(),
times: times.into(),
}
}
pub fn subspaces(&self) -> &SubspaceRange<S> {
&self.subspaces
}
pub fn paths(&self) -> &PathRange<MCL, MCC, MPL> {
&self.paths
}
pub fn times(&self) -> &TimeRange {
&self.times
}
pub fn set_subspaces<SR>(&mut self, new_range: SR)
where
SR: Into<SubspaceRange<S>>,
{
self.subspaces = new_range.into();
}
pub fn set_paths<PR>(&mut self, new_range: PR)
where
PR: Into<PathRange<MCL, MCC, MPL>>,
{
self.paths = new_range.into();
}
pub fn set_times<TR>(&mut self, new_range: TR)
where
TR: Into<TimeRange>,
{
self.times = new_range.into();
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, S> Grouping<MCL, MCC, MPL, S>
for Range3d<MCL, MCC, MPL, S>
where
S: PartialOrd,
{
fn wdm_includes<Coord>(&self, coord: &Coord) -> bool
where
Coord: Coordinatelike<MCL, MCC, MPL, S> + ?Sized,
{
self.times().includes_value(&coord.wdm_timestamp())
&& self.subspaces().includes_value(coord.wdm_subspace_id())
&& self.paths().includes_value(coord.wdm_path())
}
fn wdm_intersection(&self, other: &Self) -> Result<Self, EmptyGrouping>
where
S: Clone,
{
Ok(Self {
subspaces: self
.subspaces()
.intersection_willow_range(other.subspaces())?,
paths: self.paths().intersection_willow_range(other.paths())?,
times: self.times().intersection_willow_range(other.times())?,
})
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, S> PartialOrd<Self>
for Range3d<MCL, MCC, MPL, S>
where
S: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let cmp_subspaces = self.subspaces().partial_cmp(other.subspaces())?;
let cmp_paths = self.paths().partial_cmp(other.paths())?;
let cmp_times = self.times().partial_cmp(other.times())?;
if cmp_subspaces == Ordering::Equal
&& cmp_paths == Ordering::Equal
&& cmp_times == Ordering::Equal
{
Some(Ordering::Equal)
} else if cmp_subspaces.is_le() && cmp_paths.is_le() && cmp_times.is_le() {
return Some(Ordering::Less);
} else if cmp_subspaces.is_ge() && cmp_paths.is_ge() && cmp_times.is_ge() {
return Some(Ordering::Greater);
} else {
return None;
}
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, S> GreatestElement
for Range3d<MCL, MCC, MPL, S>
where
S: LeastElement,
{
fn greatest() -> Self {
Self::new(SubspaceRange::full(), PathRange::full(), TimeRange::full())
}
fn is_greatest(&self) -> bool {
self.times().is_full() && self.subspaces().is_full() && self.paths().is_full()
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, S> From<Area<MCL, MCC, MPL, S>>
for Range3d<MCL, MCC, MPL, S>
where
S: Clone + SuccessorExceptForGreatest + LeastElement,
{
fn from(value: Area<MCL, MCC, MPL, S>) -> Self {
let subspaces = match value.subspace() {
None => WillowRange::full(),
Some(s) => WillowRange::singleton(s.clone()),
};
let paths = match value.path().greater_but_not_prefixed() {
Some(succ) => WillowRange::new_closed(value.path().clone(), succ),
None => WillowRange::new_open(value.path().clone()),
};
Self::new(subspaces, paths, *value.times())
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, S> Range3d<MCL, MCC, MPL, S>
where
S: Clone + SuccessorExceptForGreatest,
{
pub fn singleton<Coord>(coord: &Coord) -> Self
where
Coord: Coordinatelike<MCL, MCC, MPL, S>,
{
Self::new(
SubspaceRange::singleton(coord.wdm_subspace_id().clone()),
PathRange::singleton(coord.wdm_path().clone()),
TimeRange::singleton(coord.wdm_timestamp()),
)
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, S> Range3d<MCL, MCC, MPL, S>
where
S: LeastElement,
{
pub fn full() -> Self {
Self::greatest()
}
pub fn is_full(&self) -> bool {
self.is_greatest()
}
}