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