rsonpath/automaton/
state.rs

1//! Definition of [`State`] and DFA-state attributes giving details
2//! about the state's properties.
3use std::{fmt::Display, ops::BitOr};
4
5/// Attributes that may be associated with a DFA's [`State`].
6#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
7#[repr(u8)]
8pub(crate) enum StateAttribute {
9    /// Marks that the [`State`] is accepting.
10    Accepting = 0x01,
11    /// Marks that the [`State`] is rejecting,
12    /// i.e. there is no possible path to any accepting state from it.
13    Rejecting = 0x02,
14    /// Marks that the [`State`] is _unitary_.
15    /// A state is _unitary_ if it contains exactly one labelled transition
16    /// and its fallback transition is [`Rejecting`](`StateAttribute::Rejecting`).
17    Unitary = 0x04,
18    /// Marks that the [`State`] contains some transition
19    /// (labelled or fallback) to an [`Accepting`](`StateAttribute::Accepting`) state.
20    TransitionsToAccepting = 0x08,
21    /// Marks that the [`State`] contains some transition labelled with an array index.
22    HasArrayTransition = 0x10,
23    /// Marks that the [`State`] contains an array-index labelled transition
24    /// to an to an [`Accepting`](`StateAttribute::Accepting`) state.
25    HasArrayTransitionToAccepting = 0x20,
26}
27
28pub(crate) struct StateAttributesBuilder {
29    attrs: StateAttributes,
30}
31
32/// A set of attributes that can be associated with a [`State`].
33#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)]
35pub struct StateAttributes(u8);
36
37impl StateAttributesBuilder {
38    pub(crate) fn new() -> Self {
39        Self {
40            attrs: StateAttributes(0),
41        }
42    }
43
44    pub(crate) fn accepting(self) -> Self {
45        self.set(StateAttribute::Accepting)
46    }
47
48    pub(crate) fn rejecting(self) -> Self {
49        self.set(StateAttribute::Rejecting)
50    }
51
52    pub(crate) fn unitary(self) -> Self {
53        self.set(StateAttribute::Unitary)
54    }
55
56    pub(crate) fn transitions_to_accepting(self) -> Self {
57        self.set(StateAttribute::TransitionsToAccepting)
58    }
59
60    pub(crate) fn has_array_transition(self) -> Self {
61        self.set(StateAttribute::HasArrayTransition)
62    }
63
64    pub(crate) fn has_array_transition_to_accepting(self) -> Self {
65        self.set(StateAttribute::HasArrayTransitionToAccepting)
66    }
67
68    pub(crate) fn build(self) -> StateAttributes {
69        self.attrs
70    }
71
72    fn set(self, attr: StateAttribute) -> Self {
73        Self {
74            attrs: StateAttributes(self.attrs.0 | attr as u8),
75        }
76    }
77}
78
79impl From<StateAttributesBuilder> for StateAttributes {
80    #[inline(always)]
81    fn from(value: StateAttributesBuilder) -> Self {
82        value.build()
83    }
84}
85
86impl BitOr for StateAttributes {
87    type Output = Self;
88
89    #[inline(always)]
90    fn bitor(self, rhs: Self) -> Self::Output {
91        Self(self.0 | rhs.0)
92    }
93}
94
95impl StateAttributes {
96    /// Marks that the [`State`] is accepting.
97    pub const ACCEPTING: Self = Self(StateAttribute::Accepting as u8);
98    /// Set with no attributes.
99    pub const EMPTY: Self = Self(0);
100    /// Marks that the [`State`] is rejecting,
101    /// i.e. there is no possible path to any accepting state from it.
102    pub const REJECTING: Self = Self(StateAttribute::Rejecting as u8);
103    /// Marks that the [`State`] contains some transition
104    /// (labelled or fallback) to an [`Accepting`](`StateAttributes::is_accepting`) state.
105    pub const TRANSITIONS_TO_ACCEPTING: Self = Self(StateAttribute::TransitionsToAccepting as u8);
106    /// Marks that the [`State`] is _unitary_.
107    /// A state is _unitary_ if it contains exactly one labelled transition
108    /// and its fallback transition is [`Rejecting`](`StateAttributes::is_rejecting`).
109    pub const UNITARY: Self = Self(StateAttribute::Unitary as u8);
110    /// Marks that the [`State`] contains some transition labelled with an array index or slice.
111    pub const HAS_ARRAY_TRANSITION: Self = Self(StateAttribute::HasArrayTransition as u8);
112    /// Marks that the [`State`] contains an array index- or slice-labelled transition
113    /// to an to an [`Accepting`](`StateAttributes::is_accepting`) state.
114    pub const HAS_ARRAY_TRANSITION_TO_ACCEPTING: Self = Self(StateAttribute::HasArrayTransitionToAccepting as u8);
115
116    /// Check if the the state is accepting.
117    #[inline(always)]
118    #[must_use]
119    pub fn is_accepting(&self) -> bool {
120        self.is_set(StateAttribute::Accepting)
121    }
122
123    /// Check if the state is rejecting,
124    /// i.e. there is no possible path to any accepting state from it.
125    #[inline(always)]
126    #[must_use]
127    pub fn is_rejecting(&self) -> bool {
128        self.is_set(StateAttribute::Rejecting)
129    }
130
131    /// Marks that the [`State`] contains some transition
132    /// (labelled or fallback) to an [`Accepting`](`StateAttributes::is_accepting`) state.
133    #[inline(always)]
134    #[must_use]
135    pub fn has_transition_to_accepting(&self) -> bool {
136        self.is_set(StateAttribute::TransitionsToAccepting)
137    }
138
139    /// Marks that the [`State`] is _unitary_.
140    /// A state is _unitary_ if it contains exactly one labelled transition
141    /// and its fallback transition is [`Rejecting`](`StateAttributes::is_rejecting`).
142    #[inline(always)]
143    #[must_use]
144    pub fn is_unitary(&self) -> bool {
145        self.is_set(StateAttribute::Unitary)
146    }
147
148    /// Marks that the [`State`] contains some transition labelled with an array index or slice.
149    #[inline(always)]
150    #[must_use]
151    pub fn has_array_transition(&self) -> bool {
152        self.is_set(StateAttribute::HasArrayTransition)
153    }
154
155    /// Marks that the [`State`] contains an array index- or slice- labelled transition
156    /// to an to an [`Accepting`](`StateAttributes::is_accepting`) state.
157    #[inline(always)]
158    #[must_use]
159    pub fn has_array_transition_to_accepting(&self) -> bool {
160        self.is_set(StateAttribute::HasArrayTransitionToAccepting)
161    }
162
163    #[inline(always)]
164    #[must_use]
165    fn is_set(&self, attr: StateAttribute) -> bool {
166        (self.0 & attr as u8) != 0
167    }
168}
169
170/// State of an [`Automaton`](`super::Automaton`). Thin wrapper over a state's identifier.
171#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
172#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
173pub struct State(
174    // Only `pub` for the `automaton` module, since it needs to construct and deconstruct the wrapper.
175    // Everyone outside should *not* know this detail and must not rely on it.
176    // This representation may change at any point in the future.
177    pub(super) u8,
178);
179
180impl Display for State {
181    #[inline]
182    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183        write!(f, "DFA({})", self.0)
184    }
185}