use std::num::NonZeroUsize;
use crate::query::DepthVariance;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct DepthMin(pub NonZeroUsize);
impl DepthMin {
pub fn from_min_or_unbounded(min: usize) -> DepthBehavior {
use DepthBehavior::{Min, Unbounded};
DepthMin::try_from(min).map(Min).unwrap_or(Unbounded)
}
pub(crate) fn min_at_pivot(self, pivot: usize) -> usize {
self.0.get().saturating_sub(pivot)
}
}
impl From<NonZeroUsize> for DepthMin {
fn from(min: NonZeroUsize) -> Self {
DepthMin(min)
}
}
impl From<DepthMin> for NonZeroUsize {
fn from(min: DepthMin) -> Self {
min.0
}
}
impl TryFrom<usize> for DepthMin {
type Error = ();
fn try_from(min: usize) -> Result<Self, Self::Error> {
NonZeroUsize::new(min).map(DepthMin).ok_or(())
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct DepthMax(pub usize);
impl DepthMax {
pub(crate) fn max_at_pivot(self, pivot: usize) -> usize {
self.0.saturating_sub(pivot)
}
}
impl From<usize> for DepthMax {
fn from(max: usize) -> Self {
DepthMax(max)
}
}
impl From<DepthMax> for usize {
fn from(max: DepthMax) -> Self {
max.0
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct DepthMinMax {
pub min: NonZeroUsize,
pub extent: usize,
}
impl DepthMinMax {
pub fn from_depths_or_max(p: usize, q: usize) -> DepthBehavior {
use DepthBehavior::{Max, MinMax};
let [min, max] = crate::minmax(p, q);
let extent = max - min;
NonZeroUsize::new(min)
.map(|min| DepthMinMax { min, extent })
.map_or_else(|| Max(DepthMax(max)), MinMax)
}
pub(crate) fn min_max_at_pivot(self, pivot: usize) -> (usize, usize) {
(
self.min.get().saturating_sub(pivot),
self.max().get().saturating_sub(pivot),
)
}
pub fn max(&self) -> NonZeroUsize {
self.min.saturating_add(self.extent)
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum DepthBehavior {
#[default]
Unbounded,
Min(DepthMin),
Max(DepthMax),
MinMax(DepthMinMax),
}
impl DepthBehavior {
pub fn bounded(min: impl Into<Option<usize>>, max: impl Into<Option<usize>>) -> Option<Self> {
use DepthBehavior::{Max, Min, MinMax};
match (min.into(), max.into()) {
(Some(min), None) => NonZeroUsize::new(min).map(DepthMin).map(Min),
(None, Some(max)) => Some(Max(DepthMax(max))),
(Some(min), Some(max)) if min <= max => NonZeroUsize::new(min)
.map(|min| DepthMinMax {
min,
extent: max - min.get(),
})
.map(MinMax),
_ => None,
}
}
pub fn bounded_at_depth_variance(
min: impl Into<Option<usize>>,
max: impl Into<Option<usize>>,
depth: DepthVariance,
) -> Option<Self> {
let lower = match depth {
DepthVariance::Invariant(depth) => depth,
DepthVariance::Variant(bounds) => bounds.lower().bounded().map_or(0, usize::from),
};
let translation = move |depth: Option<usize>| -> Result<Option<usize>, ()> {
depth
.map(|depth| depth.checked_add(lower).ok_or(()))
.transpose()
};
DepthBehavior::bounded(translation(min.into()).ok()?, translation(max.into()).ok()?)
}
}
impl From<DepthMax> for DepthBehavior {
fn from(max: DepthMax) -> Self {
DepthBehavior::Max(max)
}
}
impl From<DepthMin> for DepthBehavior {
fn from(min: DepthMin) -> Self {
DepthBehavior::Min(min)
}
}
impl From<DepthMinMax> for DepthBehavior {
fn from(minmax: DepthMinMax) -> Self {
DepthBehavior::MinMax(minmax)
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum LinkBehavior {
#[default]
ReadFile,
ReadTarget,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct WalkBehavior {
pub depth: DepthBehavior,
pub link: LinkBehavior,
}
impl From<()> for WalkBehavior {
fn from(_: ()) -> Self {
Default::default()
}
}
impl From<DepthBehavior> for WalkBehavior {
fn from(depth: DepthBehavior) -> Self {
WalkBehavior {
depth,
..Default::default()
}
}
}
impl From<DepthMax> for WalkBehavior {
fn from(max: DepthMax) -> Self {
DepthBehavior::from(max).into()
}
}
impl From<DepthMin> for WalkBehavior {
fn from(min: DepthMin) -> Self {
DepthBehavior::from(min).into()
}
}
impl From<DepthMinMax> for WalkBehavior {
fn from(minmax: DepthMinMax) -> Self {
DepthBehavior::from(minmax).into()
}
}
impl From<LinkBehavior> for WalkBehavior {
fn from(link: LinkBehavior) -> Self {
WalkBehavior {
link,
..Default::default()
}
}
}