Skip to main content

syntree/
pointer.rs

1//! Pointer-related types and traits.
2
3use core::fmt;
4use core::hash;
5
6mod sealed {
7    pub trait Sealed {}
8}
9
10/// A pointer type that is derived from the pointer [Width].
11pub trait Pointer: Sized + Copy + hash::Hash + Eq + fmt::Debug + self::sealed::Sealed {
12    /// Construct a pointer without checking that `value` is in bounds.
13    ///
14    /// # Safety
15    ///
16    /// The `value` must be in bounds for the pointer type, that is
17    /// [`Pointer::new(value)`][Pointer::new] must return `Some`.
18    #[doc(hidden)]
19    unsafe fn new_unchecked(value: usize) -> Self;
20
21    /// Safe constructor for the pointer.
22    ///
23    /// Returns [`None`] if the value provided is out of bounds for the pointer type.
24    ///
25    /// # Examples
26    ///
27    /// ```
28    /// use syntree::pointer::{Pointer, PointerU32};
29    ///
30    /// let v = PointerU32::new(0).ok_or("out of bounds")?;
31    /// assert_eq!(v.get(), 0);
32    /// let v = PointerU32::new(42).ok_or("out of bounds")?;
33    /// assert_eq!(v.get(), 42);
34    /// # Ok::<_, Box<dyn core::error::Error>>(())
35    /// ```
36    fn new(value: usize) -> Option<Self>;
37
38    /// Get the index of a pointer.
39    ///
40    /// # Examples
41    ///
42    /// ```
43    /// use syntree::pointer::{Pointer, PointerU32};
44    ///
45    /// let v = PointerU32::new(0).ok_or("out of bounds")?;
46    /// assert_eq!(v.get(), 0);
47    /// let v = PointerU32::new(42).ok_or("out of bounds")?;
48    /// assert_eq!(v.get(), 42);
49    /// # Ok::<_, Box<dyn core::error::Error>>(())
50    /// ```
51    fn get(self) -> usize;
52}
53
54/// A pointer width that can be used to reference other nodes.
55///
56/// This is determined by a primitive unsigned types such as `u32` or `usize`.
57pub trait Width: self::sealed::Sealed {
58    /// The pointer type associated with a specific width.
59    ///
60    /// # Examples
61    ///
62    /// ```
63    /// use syntree::pointer::Width;
64    ///
65    /// let tree = syntree::tree! {
66    ///     "root1",
67    ///     "root2",
68    /// };
69    ///
70    /// let root1: <usize as Width>::Pointer = tree.first().ok_or("missing root")?.id();
71    /// let root2: <usize as Width>::Pointer = tree.last().ok_or("missing root")?.id();
72    ///
73    /// assert_ne!(root1, root2);
74    ///
75    /// # Ok::<_, Box<dyn core::error::Error>>(())
76    /// ```
77    type Pointer: Pointer;
78}
79
80macro_rules! implement {
81    ($ty:ident, $non_zero:ident, $e:ident) => {
82        impl Width for $ty {
83            type Pointer = $e;
84        }
85
86        use core::num::$non_zero;
87
88        impl self::sealed::Sealed for $ty {}
89        impl self::sealed::Sealed for $e {}
90
91        #[doc = concat!(" [`Pointer`] implementation for `", stringify!($ty), "`.")]
92        #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
93        #[repr(transparent)]
94        pub struct $e($non_zero);
95
96        impl $e {
97            #[doc = concat!(" Safe constructor for the pointer.")]
98            ///
99            #[doc = concat!(" Returns [`None`] if the value provided is out of bounds for the pointer type.")]
100            ///
101            /// # Examples
102            ///
103            /// ```
104            /// use syntree::pointer::Pointer;
105            #[doc = concat!("use syntree::pointer::", stringify!($e), ";")]
106            ///
107            #[doc = concat!(" let v = ", stringify!($e), "::new(0).ok_or(\"out of bounds\")?;")]
108            /// assert_eq!(v.get(), 0);
109            #[doc = concat!(" let v = ", stringify!($e), "::new(42).ok_or(\"out of bounds\")?;")]
110            /// assert_eq!(v.get(), 42);
111            /// # Ok::<_, Box<dyn core::error::Error>>(())
112            /// ```
113            #[inline]
114            pub fn new(value: usize) -> Option<Self> {
115                let value = <$ty>::try_from(value).ok()?;
116                $non_zero::new(value.wrapping_add(1)).map(Self)
117            }
118
119            #[doc = concat!(" Get the index of a pointer.")]
120            ///
121            /// # Examples
122            ///
123            /// ```
124            /// use syntree::pointer::Pointer;
125            #[doc = concat!("use syntree::pointer::", stringify!($e), ";")]
126            ///
127            #[doc = concat!(" let v = ", stringify!($e), "::new(0).ok_or(\"out of bounds\")?;")]
128            /// assert_eq!(v.get(), 0);
129            #[doc = concat!(" let v = ", stringify!($e), "::new(42).ok_or(\"out of bounds\")?;")]
130            /// assert_eq!(v.get(), 42);
131            /// # Ok::<_, Box<dyn core::error::Error>>(())
132            /// ```
133            #[inline]
134            pub fn get(self) -> usize {
135                self.0.get().wrapping_sub(1) as usize
136            }
137        }
138
139        #[doc = concat!(" Pointer used for `", stringify!($ty), "` type.")]
140        ///
141        /// ```
142        /// use syntree::pointer::Pointer;
143        #[doc = concat!("use syntree::pointer::", stringify!($e), ";")]
144        ///
145        #[doc = concat!(" let v = ", stringify!($e), "::new(0).ok_or(\"out of bounds\")?;")]
146        /// assert_eq!(v.get(), 0);
147        #[doc = concat!(" let v = ", stringify!($e), "::new(42).ok_or(\"out of bounds\")?;")]
148        /// assert_eq!(v.get(), 42);
149        /// # Ok::<_, Box<dyn core::error::Error>>(())
150        /// ```
151        impl crate::pointer::Pointer for $e {
152            #[inline]
153            unsafe fn new_unchecked(value: usize) -> Self {
154                let value = value as $ty;
155                Self($non_zero::new_unchecked(value.wrapping_add(1)))
156            }
157
158            #[inline]
159            fn new(value: usize) -> Option<Self> {
160                $e::new(value)
161            }
162
163            #[inline]
164            fn get(self) -> usize {
165                $e::get(self)
166            }
167        }
168
169        /// Construct a default value.
170        ///
171        /// ```
172        /// use syntree::pointer::Pointer;
173        #[doc = concat!("use syntree::pointer::", stringify!($e), ";")]
174        ///
175        #[doc = concat!(" let v = ", stringify!($e), "::default();")]
176        /// assert_eq!(v.get(), 0);
177        /// ```
178        impl Default for $e {
179            #[inline]
180            fn default() -> Self {
181                Self($non_zero::MIN)
182            }
183        }
184
185        impl fmt::Debug for $e {
186            #[inline]
187            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188                self.get().fmt(f)
189            }
190        }
191    };
192}
193
194implement!(usize, NonZeroUsize, PointerUsize);
195implement!(u8, NonZeroU8, PointerU8);
196implement!(u16, NonZeroU16, PointerU16);
197implement!(u32, NonZeroU32, PointerU32);
198implement!(u64, NonZeroU64, PointerU64);
199implement!(u128, NonZeroU128, PointerU128);