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)
    }
}