use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::num::NonZeroUsize;
use crate::DirectoryEntry;
#[non_exhaustive]
pub enum WalkDepthLimit {
Unlimited,
Limited {
max_depth: usize,
},
}
impl WalkDepthLimit {
#[must_use]
pub fn maximum_depth(&self) -> Option<usize> {
match self {
Self::Unlimited => None,
Self::Limited { max_depth } => Some(*max_depth),
}
}
}
impl Clone for WalkDepthLimit {
fn clone(&self) -> Self {
match self {
Self::Unlimited => Self::Unlimited,
Self::Limited { max_depth } => Self::Limited {
max_depth: *max_depth,
},
}
}
}
impl fmt::Debug for WalkDepthLimit {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Unlimited => formatter.write_str("Unlimited"),
Self::Limited { max_depth } => formatter
.debug_struct("Limited")
.field("max_depth", max_depth)
.finish(),
}
}
}
impl fmt::Display for WalkDepthLimit {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Unlimited => formatter.write_str("unlimited depth"),
Self::Limited { max_depth } => {
write!(formatter, "maximum depth: {max_depth}")
}
}
}
}
impl PartialEq for WalkDepthLimit {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Unlimited, Self::Unlimited) => true,
(
Self::Limited {
max_depth: left,
},
Self::Limited {
max_depth: right,
},
) => left == right,
_ => false,
}
}
}
impl Eq for WalkDepthLimit {}
impl PartialOrd for WalkDepthLimit {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for WalkDepthLimit {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(
Self::Limited {
max_depth: left,
},
Self::Limited {
max_depth: right,
},
) => left.cmp(right),
(Self::Limited { .. }, Self::Unlimited) => Ordering::Less,
(Self::Unlimited, Self::Limited { .. }) => Ordering::Greater,
(Self::Unlimited, Self::Unlimited) => Ordering::Equal,
}
}
}
impl Hash for WalkDepthLimit {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
match self {
Self::Limited { max_depth } => {
0_u8.hash(state);
max_depth.hash(state);
}
Self::Unlimited => {
1_u8.hash(state);
}
}
}
}
#[non_exhaustive]
pub struct WalkOptions {
pub depth_limit: WalkDepthLimit,
}
impl WalkOptions {
#[must_use]
pub fn new(depth_limit: WalkDepthLimit) -> Self {
Self { depth_limit }
}
}
impl Clone for WalkOptions {
fn clone(&self) -> Self {
Self::new(self.depth_limit.clone())
}
}
impl fmt::Debug for WalkOptions {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("WalkOptions")
.field("depth_limit", &self.depth_limit)
.finish()
}
}
impl fmt::Display for WalkOptions {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "depth limit: {}", self.depth_limit)
}
}
impl PartialEq for WalkOptions {
fn eq(&self, other: &Self) -> bool {
self.depth_limit == other.depth_limit
}
}
impl Eq for WalkOptions {}
impl PartialOrd for WalkOptions {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for WalkOptions {
fn cmp(&self, other: &Self) -> Ordering {
self.depth_limit.cmp(&other.depth_limit)
}
}
impl Hash for WalkOptions {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.depth_limit.hash(state);
}
}
#[non_exhaustive]
pub struct WalkEntry<L> {
pub entry: DirectoryEntry<L>,
pub depth: NonZeroUsize,
}
impl<L> WalkEntry<L> {
#[must_use]
pub fn new(entry: DirectoryEntry<L>, depth: NonZeroUsize) -> Self {
Self { entry, depth }
}
#[must_use]
pub fn into_parts(self) -> (DirectoryEntry<L>, NonZeroUsize) {
(self.entry, self.depth)
}
}
impl<L> Clone for WalkEntry<L>
where
L: Clone,
{
fn clone(&self) -> Self {
Self::new(self.entry.clone(), self.depth)
}
}
impl<L> fmt::Debug for WalkEntry<L>
where
L: fmt::Debug,
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("WalkEntry")
.field("entry", &self.entry)
.field("depth", &self.depth)
.finish()
}
}
impl<L> fmt::Display for WalkEntry<L>
where
L: fmt::Debug,
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{:?} at depth {}", self.entry, self.depth)
}
}
impl<L> PartialEq for WalkEntry<L>
where
L: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.entry == other.entry && self.depth == other.depth
}
}
impl<L> Eq for WalkEntry<L> where L: Eq {}
impl<L> PartialOrd for WalkEntry<L>
where
L: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match self.entry.partial_cmp(&other.entry)? {
Ordering::Equal => self.depth.partial_cmp(&other.depth),
ordering => Some(ordering),
}
}
}
impl<L> Ord for WalkEntry<L>
where
L: Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
self.entry
.cmp(&other.entry)
.then_with(|| self.depth.cmp(&other.depth))
}
}
impl<L> Hash for WalkEntry<L>
where
L: Hash,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.entry.hash(state);
self.depth.hash(state);
}
}