syntax_parser_generator/handles/
handle.rs

1use std::fmt::{Debug, Formatter};
2use std::hash::Hash;
3
4use derive_where::derive_where;
5
6/// A type that may serve as the internal representation of a [Handle].
7///
8/// A [Handle] is defined by a single field known as its _core_. The core identifies the handled
9/// object, and is an instance of a lightweight type that implements [HandleCore]. It should
10/// be convertible from and to a `usize`, which represents the handled object's serial-number.
11// TODO remove Ord traits from here, create a complete module for ordered handles
12pub trait HandleCore: Clone + Copy + Eq + PartialEq + Hash + Debug + Ord + PartialOrd {
13    /// Get the serial number represented by this [HandleCore].
14    fn into_index(self) -> usize;
15
16    /// Transform a serial number into an identifying [HandleCore].
17    fn from_index(index: usize) -> Self;
18}
19
20/// A lightweight identifier for instances of an arbitrary type `T`.
21#[derive_where(Clone, Copy, PartialEq, Eq, Hash)]
22pub struct Handle<T>
23where
24    T: Handled + ?Sized,
25{
26    /// The internal representation of the identifier.
27    pub core: T::HandleCoreType,
28}
29
30/// A type whose instances may be identified by handles.
31pub trait Handled {
32    /// The type of the internal representation of our handles.
33    type HandleCoreType: HandleCore;
34
35    /// Creates handle associated with an object identified by a certain `serial_number`.
36    fn new_handle(serial_number: usize) -> Handle<Self> {
37        serial_number.into()
38    }
39}
40
41impl<T> Handle<T>
42where
43    T: Handled + ?Sized,
44{
45    pub(super) fn index(&self) -> usize {
46        self.core.into_index()
47    }
48
49    /// Creates a handle different from all handles in a given list of `existing_handles`.
50    ///
51    /// This may serve as "a handle to nothing", a "mock handle".
52    pub fn mock(existing_handles: &Vec<Handle<T>>) -> Handle<T> {
53        let existing_indices: std::collections::HashSet<usize> = existing_handles
54            .iter()
55            .map(|handle| handle.index())
56            .collect();
57
58        let mut index = 0;
59        while existing_indices.contains(&index) {
60            index += 1;
61        }
62
63        index.into()
64    }
65}
66
67impl<T> Debug for Handle<T>
68where
69    T: Handled,
70{
71    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
72        write!(f, "Handle({:?})", self.core.into_index())
73    }
74}
75
76impl<T> From<usize> for Handle<T>
77where
78    T: Handled + ?Sized,
79{
80    /// Converts a serial number of an object to a matching handle.
81    fn from(serial_number: usize) -> Self {
82        Self {
83            core: T::HandleCoreType::from_index(serial_number),
84        }
85    }
86}
87
88impl<T> Into<usize> for Handle<T>
89where
90    T: Handled + ?Sized,
91{
92    /// Converts a handle to the serial number it identifies.
93    fn into(self) -> usize {
94        self.core.into_index()
95    }
96}