Skip to main content

syntree/
index.rs

1//! Types that can be used to refer to indexes in a [Span][crate::Span].
2
3use core::cmp;
4use core::fmt;
5
6use crate::flavor::Flavor;
7
8mod sealed {
9    pub trait Sealed {}
10
11    impl Sealed for u32 {}
12    impl Sealed for usize {}
13    impl Sealed for crate::empty::Empty {}
14}
15
16/// A type that can be used when referring to an index in a tree.
17///
18/// An index is a valid single component of a [Span][crate::Span], valid indexes
19/// are types such as `u32` and `usize`, but also [`Empty`][crate::Empty] in
20/// case indexing is not required.
21///
22/// See [Builder::new_with][crate::Builder::new_with].
23pub trait Index: Sized + Copy + cmp::Ord + cmp::Eq + self::sealed::Sealed {
24    #[doc(hidden)]
25    const EMPTY: Self;
26
27    #[doc(hidden)]
28    type Length: Length;
29
30    #[doc(hidden)]
31    fn is_empty(&self) -> bool;
32
33    #[doc(hidden)]
34    fn as_usize(self) -> usize;
35
36    #[doc(hidden)]
37    fn checked_add_len(self, other: Self::Length) -> Option<Self>;
38
39    #[doc(hidden)]
40    fn len_to(self, other: Self) -> Self::Length;
41
42    #[doc(hidden)]
43    fn from_usize(value: usize) -> Option<Self>;
44}
45
46#[doc(hidden)]
47pub trait Length: Copy + self::sealed::Sealed {
48    #[doc(hidden)]
49    const EMPTY: Self;
50
51    #[doc(hidden)]
52    fn is_empty(&self) -> bool;
53}
54
55impl Length for usize {
56    const EMPTY: Self = 0;
57
58    #[inline]
59    fn is_empty(&self) -> bool {
60        *self == 0
61    }
62}
63
64/// Ensure u32 is smaller or equal to usize.
65const _: () = assert!(core::mem::size_of::<u32>() <= core::mem::size_of::<usize>());
66
67impl Index for u32 {
68    const EMPTY: Self = 0;
69
70    type Length = usize;
71
72    #[inline]
73    fn is_empty(&self) -> bool {
74        *self == 0
75    }
76
77    #[inline]
78    fn as_usize(self) -> usize {
79        self as usize
80    }
81
82    #[inline]
83    fn checked_add_len(self, other: Self::Length) -> Option<Self> {
84        u32::checked_add(self, u32::try_from(other).ok()?)
85    }
86
87    #[inline]
88    fn len_to(self, other: Self) -> Self::Length {
89        other.saturating_sub(self) as usize
90    }
91
92    #[inline]
93    fn from_usize(value: usize) -> Option<Self> {
94        u32::try_from(value).ok()
95    }
96}
97
98impl Index for usize {
99    const EMPTY: Self = 0;
100
101    type Length = usize;
102
103    #[inline]
104    fn is_empty(&self) -> bool {
105        *self == 0
106    }
107
108    #[inline]
109    fn as_usize(self) -> usize {
110        self
111    }
112
113    #[inline]
114    fn checked_add_len(self, other: Self::Length) -> Option<Self> {
115        usize::checked_add(self, other)
116    }
117
118    #[inline]
119    fn len_to(self, other: Self) -> Self::Length {
120        other.saturating_sub(self)
121    }
122
123    #[inline]
124    fn from_usize(value: usize) -> Option<Self> {
125        Some(value)
126    }
127}
128
129/// A single span index entry for the given [Flavor] `F`.
130#[doc(hidden)]
131pub struct TreeIndex<F>
132where
133    F: ?Sized + Flavor,
134{
135    pub(crate) index: F::Index,
136    pub(crate) id: F::Pointer,
137}
138
139// Implemented by hand since deriving would require `F` itself to implement the
140// traits, which flavors are not required to.
141impl<F> Clone for TreeIndex<F>
142where
143    F: ?Sized + Flavor,
144{
145    #[inline]
146    fn clone(&self) -> Self {
147        *self
148    }
149}
150
151impl<F> Copy for TreeIndex<F> where F: ?Sized + Flavor {}
152
153impl<F> fmt::Debug for TreeIndex<F>
154where
155    F: ?Sized + Flavor<Index: fmt::Debug>,
156{
157    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158        f.debug_struct("TreeIndex")
159            .field("index", &self.index)
160            .field("id", &self.id)
161            .finish()
162    }
163}