rsonpath/
depth.rs

1//! Overflow-safe utilities for tracking JSON document depth.
2use super::error::DepthError;
3use std::{
4    fmt::Display,
5    ops::{Add, Deref, Sub},
6};
7
8/// Overflow-safe thin wrapper for a [`u8`] depth counter.
9#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub struct Depth(u8);
11
12impl Depth {
13    /// Depth of 0.
14    pub const ZERO: Self = Self(0);
15
16    /// Depth of 1.
17    pub const ONE: Self = Self(1);
18
19    /// Add `1` to the depth, or raise an error if the maximum
20    /// supported value is reached.
21    pub fn increment(&mut self) -> Result<(), DepthError> {
22        *self = (*self + 1)?;
23        Ok(())
24    }
25
26    /// Subtract `1` from the depth, or raise an error if the depth
27    /// is zero.
28    pub fn decrement(&mut self) -> Result<(), DepthError> {
29        *self = (*self - 1)?;
30        Ok(())
31    }
32}
33
34macro_rules! impl_add {
35    ($t:ty) => {
36        impl Add<u8> for $t {
37            type Output = Result<Depth, DepthError>;
38
39            #[inline]
40            fn add(self, rhs: u8) -> Self::Output {
41                self.0
42                    .checked_add(rhs)
43                    .ok_or(DepthError::AboveLimit(u8::MAX as usize))
44                    .map(Depth)
45            }
46        }
47    };
48}
49
50macro_rules! impl_sub {
51    ($t:ty) => {
52        impl Sub<u8> for $t {
53            type Output = Result<Depth, DepthError>;
54
55            #[inline]
56            fn sub(self, rhs: u8) -> Self::Output {
57                self.0.checked_sub(rhs).ok_or(DepthError::BelowZero).map(Depth)
58            }
59        }
60    };
61}
62
63impl_add!(Depth);
64impl_add!(&Depth);
65impl_add!(&mut Depth);
66
67impl_sub!(Depth);
68impl_sub!(&Depth);
69impl_sub!(&mut Depth);
70
71impl Display for Depth {
72    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73        self.0.fmt(f)
74    }
75}
76
77impl Deref for Depth {
78    type Target = u8;
79
80    fn deref(&self) -> &Self::Target {
81        &self.0
82    }
83}