total_space/
configurations.rs

1use crate::messages::*;
2use crate::utilities::*;
3
4// BEGIN MAYBE TESTED
5
6/// An indicator that something is invalid.
7#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
8pub enum Invalid<MessageId: IndexLike> {
9    Configuration(&'static str),
10    Agent(usize, &'static str),
11    Message(MessageId, &'static str),
12}
13
14// END MAYBE TESTED
15
16impl<MessageId: IndexLike> Default for Invalid<MessageId> {
17    fn default() -> Self {
18        Invalid::Configuration("you should not be seeing this")
19    }
20}
21
22// BEGIN MAYBE TESTED
23
24/// A complete system configuration.
25///
26/// We will have a *lot* of these, so keeping their size down and avoiding heap memory as much as
27/// possible is critical. The maximal sizes were chosen so that the configuration plus its memoized
28/// identifier will fit together inside exactly one cache lines, which should make this more
29/// cache-friendly when placed inside a hash table.
30#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
31pub struct Configuration<
32    StateId: IndexLike,
33    MessageId: IndexLike,
34    InvalidId: IndexLike,
35    const MAX_AGENTS: usize,
36    const MAX_MESSAGES: usize,
37> {
38    /// The state of each agent.
39    pub state_ids: [StateId; MAX_AGENTS],
40
41    /// The number of messages sent by each agent.
42    pub message_counts: [MessageIndex; MAX_AGENTS],
43
44    /// The messages sent by each agent.
45    pub message_ids: [MessageId; MAX_MESSAGES],
46
47    /// The invalid condition, if any.
48    pub invalid_id: InvalidId,
49}
50
51// END MAYBE TESTED
52
53impl<
54        StateId: IndexLike,
55        MessageId: IndexLike,
56        InvalidId: IndexLike,
57        const MAX_AGENTS: usize,
58        const MAX_MESSAGES: usize,
59    > Default for Configuration<StateId, MessageId, InvalidId, MAX_AGENTS, MAX_MESSAGES>
60{
61    fn default() -> Self {
62        Configuration {
63            state_ids: [StateId::invalid(); MAX_AGENTS],
64            message_counts: [MessageIndex::invalid(); MAX_AGENTS],
65            message_ids: [MessageId::invalid(); MAX_MESSAGES],
66            invalid_id: InvalidId::invalid(),
67        }
68    }
69}
70
71impl<
72        StateId: IndexLike,
73        MessageId: IndexLike,
74        InvalidId: IndexLike,
75        const MAX_AGENTS: usize,
76        const MAX_MESSAGES: usize,
77    > Configuration<StateId, MessageId, InvalidId, MAX_AGENTS, MAX_MESSAGES>
78{
79    /// Remove a message from the configuration.
80    pub(crate) fn remove_message(&mut self, source: usize, mut message_index: usize) {
81        debug_assert!(self.message_counts[source].to_usize() > 0);
82        debug_assert!(self.message_ids[message_index].is_valid());
83
84        self.message_counts[source].decr();
85
86        loop {
87            let next_message_index = message_index + 1;
88            let next_message_id = if next_message_index < MAX_MESSAGES {
89                self.message_ids[next_message_index]
90            } else {
91                MessageId::invalid() // NOT TESTED
92            };
93            self.message_ids[message_index] = next_message_id;
94            if !next_message_id.is_valid() {
95                return;
96            }
97            message_index = next_message_index;
98        }
99    }
100
101    /// Add a message to the configuration.
102    pub(crate) fn add_message(&mut self, source_index: usize, message_id: MessageId) {
103        debug_assert!(source_index != usize::max_value());
104        debug_assert!(self.message_counts[source_index] < MessageIndex::invalid());
105
106        assert!(
107            !self.message_ids[MAX_MESSAGES - 1].is_valid(),
108            "too many in-flight messages, must be at most {}",
109            MAX_MESSAGES
110        );
111
112        self.message_counts[source_index].incr();
113        self.message_ids[MAX_MESSAGES - 1] = message_id;
114        self.message_ids.sort();
115    }
116
117    /// Change the state of an agent in the configuration.
118    pub(crate) fn change_state(&mut self, agent_index: usize, state_id: StateId) {
119        self.state_ids[agent_index] = state_id;
120    }
121}