total_space/
agents.rs

1use crate::memoize::*;
2use crate::reactions::*;
3use crate::utilities::*;
4
5use std::cell::RefCell;
6use std::marker::PhantomData;
7use std::rc::Rc;
8
9/// Specify the number of agent instances to use.
10pub enum Instances {
11    /// Always have just a single instance.
12    Singleton,
13
14    /// Use a specific number of instances.
15    Count(usize),
16}
17
18/// A trait partially describing some agent instances of the same type.
19pub trait AgentInstances<StateId: IndexLike, Payload: DataLike>: Name {
20    /// Return the previous agent type in the chain, if any.
21    fn prev_agent_type(&self) -> Option<Rc<dyn AgentType<StateId, Payload>>>;
22
23    /// The index of the first agent of this type.
24    fn first_index(&self) -> usize;
25
26    /// The next index after the last agent of this type.
27    fn next_index(&self) -> usize;
28
29    /// Whether this type only has a single instance.
30    ///
31    /// If true, the count will always be 1.
32    fn is_singleton(&self) -> bool;
33
34    /// The number of agents of this type that will be used in the system.
35    fn instances_count(&self) -> usize;
36
37    /// The order of the agent (for sequence diagrams).
38    fn instance_order(&self, instance: usize) -> usize;
39
40    /// Display the state.
41    ///
42    /// The format of the display must be either `<state-name>` if the state is a simple enum, or
43    /// `<state-name>(<state-data>)` if the state contains additional data. The `Debug` of the state
44    /// might be acceptable as-is, but typically it is better to get rid or shorten the explicit
45    /// field names, and/or format their values in a more compact form.
46    fn display_state(&self, state_id: StateId) -> Rc<String>;
47
48    /// Convert the full state identifier to the terse state identifier.
49    fn terse_id(&self, state_id: StateId) -> StateId;
50
51    /// Return the name of the terse state (just the state name).
52    fn display_terse(&self, name_id: StateId) -> String;
53}
54
55/// A trait fully describing some agent instances of the same type.
56pub trait AgentType<StateId: IndexLike, Payload: DataLike>:
57    AgentInstances<StateId, Payload>
58{
59    /// Return the actions that may be taken by an agent instance with some state when receiving a
60    /// payload.
61    fn reaction(
62        &self,
63        instance: usize,
64        state_ids: &[StateId],
65        payload: &Payload,
66    ) -> Reaction<StateId, Payload>;
67
68    /// Return the actions that may be taken by an agent with some state when time passes.
69    fn activity(&self, instance: usize, state_ids: &[StateId]) -> Activity<Payload>;
70
71    /// Whether any agent in the state is deferring messages.
72    fn state_is_deferring(&self, instance: usize, state_ids: &[StateId]) -> bool;
73
74    /// Return a reason that a state is invalid (unless it is valid).
75    fn state_invalid_because(&self, instance: usize, state_ids: &[StateId])
76        -> Option<&'static str>;
77
78    /// The maximal number of messages sent by an agent which may be in-flight when it is in the
79    /// state.
80    fn state_max_in_flight_messages(&self, instance: usize, state_ids: &[StateId])
81        -> Option<usize>;
82
83    /// The total number of states seen so far.
84    fn states_count(&self) -> usize;
85
86    /// Compute mapping from full states to terse states (name only).
87    fn compute_terse(&self);
88}
89
90/// Allow access to state of parts.
91pub trait PartType<State: DataLike, StateId: IndexLike> {
92    /// Access the part state by the state identifier.
93    fn part_state_by_id(&self, state_id: StateId) -> State;
94
95    /// The index of the first agent of this type.
96    fn part_first_index(&self) -> usize;
97
98    /// The number of agent instances of this type.
99    fn parts_count(&self) -> usize;
100}
101
102// BEGIN MAYBE TESTED
103
104/// The data we need to implement an agent type.
105///
106/// This should be placed in a `Singleton` to allow the agent states to get services from it.
107pub struct AgentTypeData<State: DataLike, StateId: IndexLike, Payload: DataLike> {
108    /// Memoization of the agent states.
109    states: RefCell<Memoize<State, StateId>>,
110
111    /// The index of the first agent of this type.
112    first_index: usize,
113
114    /// The name of the agent type.
115    name: &'static str,
116
117    /// Whether this type only has a single instance.
118    is_singleton: bool,
119
120    /// The display string of each state.
121    label_of_state: RefCell<Vec<Rc<String>>>,
122
123    /// Convert a full state identifier to a terse state identifier.
124    terse_of_state: RefCell<Vec<StateId>>,
125
126    /// The names of the terse states (state names only).
127    name_of_terse: RefCell<Vec<String>>,
128
129    /// The order of each instance (for sequence diagrams).
130    order_of_instances: Vec<usize>,
131
132    /// The previous agent type in the chain.
133    prev_agent_type: Option<Rc<dyn AgentType<StateId, Payload>>>,
134
135    /// Trick the compiler into thinking we have a field of type Payload.
136    _payload: PhantomData<Payload>,
137}
138
139/// The data we need to implement an container agent type.
140///
141/// This should be placed in a `Singleton` to allow the agent states to get services from it.
142pub struct ContainerOf1TypeData<
143    State: DataLike,
144    Part: DataLike,
145    StateId: IndexLike,
146    Payload: DataLike,
147    const MAX_PARTS: usize,
148> {
149    /// The basic agent type data.
150    agent_type_data: AgentTypeData<State, StateId, Payload>,
151
152    /// Access part states (for a container).
153    part_type: Rc<dyn PartType<Part, StateId>>,
154}
155
156/// The data we need to implement an container agent type.
157///
158/// This should be placed in a `Singleton` to allow the agent states to get services from it.
159pub struct ContainerOf2TypeData<
160    State: DataLike,
161    Part1: DataLike,
162    Part2: DataLike,
163    StateId: IndexLike,
164    Payload: DataLike,
165    const MAX_PARTS: usize,
166> {
167    /// The basic agent type data.
168    agent_type_data: AgentTypeData<State, StateId, Payload>,
169
170    /// Access first parts states (for a container).
171    part1_type: Rc<dyn PartType<Part1, StateId>>,
172
173    /// Access second parts states (for a container).
174    part2_type: Rc<dyn PartType<Part2, StateId>>,
175}
176
177// END MAYBE TESTED
178
179impl<State: DataLike, StateId: IndexLike, Payload: DataLike>
180    AgentTypeData<State, StateId, Payload>
181{
182    /// Create new agent type data with the specified name and number of instances.
183    pub fn new(
184        name: &'static str,
185        instances: Instances,
186        prev_agent_type: Option<Rc<dyn AgentType<StateId, Payload>>>,
187    ) -> Self {
188        let (is_singleton, count) = match instances {
189            Instances::Singleton => (true, 1),
190            Instances::Count(amount) => {
191                assert!(
192                    amount > 0,
193                    "zero instances specified for agent type {}",
194                    name
195                );
196                (false, amount)
197            }
198        };
199
200        let default_state: State = Default::default();
201        let mut states = Memoize::new(StateId::invalid().to_usize());
202        states.store(default_state);
203        let label_of_state = RefCell::new(vec![]);
204        label_of_state
205            .borrow_mut()
206            .push(Rc::new(format!("{}", default_state)));
207
208        let order_of_instances = vec![0; count];
209
210        Self {
211            name,
212            order_of_instances,
213            is_singleton,
214            label_of_state,
215            terse_of_state: RefCell::new(vec![]),
216            name_of_terse: RefCell::new(vec![]),
217            states: RefCell::new(states),
218            first_index: prev_agent_type
219                .clone()
220                .map_or(0, |agent_type| agent_type.next_index()),
221            prev_agent_type,
222            _payload: PhantomData,
223        }
224    }
225
226    // BEGIN NOT TESTED
227
228    /// Set the horizontal order of an instance of the agent in a sequence diagram.
229    pub fn set_order(&mut self, instance: usize, order: usize) {
230        assert!(
231            instance < self.instances_count(),
232            "instance: {} count: {}",
233            instance,
234            self.instances_count()
235        );
236        self.order_of_instances[instance] = order;
237    }
238
239    // END NOT TESTED
240
241    /// Compute mapping between full and terse state identifiers.
242    fn impl_compute_terse(&self) {
243        let mut terse_of_state = self.terse_of_state.borrow_mut();
244        let mut name_of_terse = self.name_of_terse.borrow_mut();
245
246        assert!(terse_of_state.is_empty());
247        assert!(name_of_terse.is_empty());
248
249        let states = self.states.borrow();
250        terse_of_state.reserve(states.len());
251        name_of_terse.reserve(states.len());
252
253        for state_id in 0..states.len() {
254            let state = states.get(StateId::from_usize(state_id));
255            let state_name = state.name();
256            if let Some(terse_id) = name_of_terse
257                .iter()
258                .position(|terse_name| terse_name == &state_name)
259            {
260                terse_of_state.push(StateId::from_usize(terse_id));
261            } else {
262                terse_of_state.push(StateId::from_usize(name_of_terse.len()));
263                name_of_terse.push(state_name);
264            }
265        }
266
267        name_of_terse.shrink_to_fit();
268    }
269
270    /// Access the actual state by its identifier.
271    pub fn get_state(&self, state_id: StateId) -> State {
272        self.states.borrow().get(state_id)
273    }
274}
275
276impl<
277        State: DataLike,
278        Part: DataLike,
279        StateId: IndexLike,
280        Payload: DataLike,
281        const MAX_PARTS: usize,
282    > ContainerOf1TypeData<State, Part, StateId, Payload, MAX_PARTS>
283{
284    /// Create new agent type data with the specified name and number of instances.
285    pub fn new(
286        name: &'static str,
287        instances: Instances,
288        part_type: Rc<dyn PartType<Part, StateId>>,
289        prev_type: Rc<dyn AgentType<StateId, Payload>>,
290    ) -> Self {
291        Self {
292            agent_type_data: AgentTypeData::new(name, instances, Some(prev_type)),
293            part_type,
294        }
295    }
296}
297
298// BEGIN NOT TESTED
299impl<
300        State: DataLike,
301        Part1: DataLike,
302        Part2: DataLike,
303        StateId: IndexLike,
304        Payload: DataLike,
305        const MAX_PARTS: usize,
306    > ContainerOf2TypeData<State, Part1, Part2, StateId, Payload, MAX_PARTS>
307{
308    /// Create new agent type data with the specified name and number of instances.
309    pub fn new(
310        name: &'static str,
311        instances: Instances,
312        part1_type: Rc<dyn PartType<Part1, StateId>>,
313        part2_type: Rc<dyn PartType<Part2, StateId>>,
314        prev_type: Rc<dyn AgentType<StateId, Payload>>,
315    ) -> Self {
316        Self {
317            agent_type_data: AgentTypeData::new(name, instances, Some(prev_type)),
318            part1_type,
319            part2_type,
320        }
321    }
322}
323// END NOT TESTED
324
325impl<State: DataLike, StateId: IndexLike, Payload: DataLike> PartType<State, StateId>
326    for AgentTypeData<State, StateId, Payload>
327{
328    fn part_state_by_id(&self, state_id: StateId) -> State {
329        self.states.borrow().get(state_id)
330    }
331
332    fn part_first_index(&self) -> usize {
333        self.first_index
334    }
335
336    fn parts_count(&self) -> usize {
337        self.instances_count()
338    }
339}
340
341/// A trait for a single agent state.
342pub trait AgentState<State: DataLike, Payload: DataLike> {
343    /// Return the actions that may be taken by an agent instance with this state when receiving a
344    /// payload.
345    fn reaction(&self, instance: usize, payload: &Payload) -> Reaction<State, Payload>;
346
347    /// Return the actions that may be taken by an agent with some state when time passes.
348    fn activity(&self, _instance: usize) -> Activity<Payload> {
349        Activity::Passive
350    }
351
352    /// Whether any agent in this state is deferring messages.
353    fn is_deferring(&self, _instance: usize) -> bool {
354        false
355    }
356
357    /// If this object is invalid, return why.
358    fn invalid_because(&self, _instance: usize) -> Option<&'static str> {
359        None
360    }
361
362    /// The maximal number of messages sent by this agent which may be in-flight when it is in this
363    /// state.
364    fn max_in_flight_messages(&self, _instance: usize) -> Option<usize> {
365        None
366    }
367}
368
369/// A trait for a container agent state.
370pub trait ContainerOf1State<State: DataLike, Part: DataLike, Payload: DataLike> {
371    /// Return the actions that may be taken by an agent instance with this state when receiving a
372    /// payload.
373    fn reaction(
374        &self,
375        instance: usize,
376        payload: &Payload,
377        parts: &[Part],
378    ) -> Reaction<State, Payload>;
379
380    /// Return the actions that may be taken by an agent with some state when time passes.
381    fn activity(&self, _instance: usize, _parts: &[Part]) -> Activity<Payload> {
382        Activity::Passive
383    }
384
385    /// Whether any agent in this state is deferring messages.
386    fn is_deferring(&self, _instance: usize, _parts: &[Part]) -> bool {
387        false
388    }
389
390    // BEGIN NOT TESTED
391
392    /// If this object is invalid, return why.
393    fn invalid_because(&self, _instance: usize, _parts: &[Part]) -> Option<&'static str> {
394        None
395    }
396
397    // END NOT TESTED
398
399    /// The maximal number of messages sent by this agent which may be in-flight when it is in this
400    /// state.
401    fn max_in_flight_messages(&self, _instance: usize, _parts: &[Part]) -> Option<usize> {
402        None
403    }
404}
405
406// BEGIN NOT TESTED
407
408/// A trait for a container agent state.
409pub trait ContainerOf2State<State: DataLike, Part1: DataLike, Part2: DataLike, Payload: DataLike> {
410    /// Return the actions that may be taken by an agent instance with this state when receiving a
411    /// payload.
412    fn reaction(
413        &self,
414        instance: usize,
415        payload: &Payload,
416        parts1: &[Part1],
417        parts2: &[Part2],
418    ) -> Reaction<State, Payload>;
419
420    /// Return the actions that may be taken by an agent with some state when time passes.
421    fn activity(
422        &self,
423        _instance: usize,
424        _parts1: &[Part1],
425        _parts2: &[Part2],
426    ) -> Activity<Payload> {
427        Activity::Passive
428    }
429
430    /// Whether any agent in this state is deferring messages.
431    fn is_deferring(&self, _instance: usize, _parts1: &[Part1], _parts2: &[Part2]) -> bool {
432        false
433    }
434
435    /// If this object is invalid, return why.
436    fn invalid_because(
437        &self,
438        _instance: usize,
439        _parts1: &[Part1],
440        _parts2: &[Part2],
441    ) -> Option<&'static str> {
442        None
443    }
444
445    /// The maximal number of messages sent by this agent which may be in-flight when it is in this
446    /// state.
447    fn max_in_flight_messages(
448        &self,
449        _instance: usize,
450        _parts1: &[Part1],
451        _parts2: &[Part2],
452    ) -> Option<usize> {
453        None
454    }
455}
456
457// END NOT TESTED
458
459impl<State: DataLike, StateId: IndexLike, Payload: DataLike>
460    AgentTypeData<State, StateId, Payload>
461{
462    fn translate_reaction(
463        &self,
464        reaction: &Reaction<State, Payload>,
465    ) -> Reaction<StateId, Payload> {
466        match reaction {
467            Reaction::Unexpected => Reaction::Unexpected,
468            Reaction::Ignore => Reaction::Ignore,
469            Reaction::Defer => Reaction::Defer,
470            Reaction::Do1(action) => Reaction::Do1(self.translate_action(action)),
471            Reaction::Do1Of(actions) => Reaction::Do1Of(self.translate_actions(&actions)), // NOT TESTED
472        }
473    }
474
475    fn translate_action(&self, action: &Action<State, Payload>) -> Action<StateId, Payload> {
476        match *action {
477            Action::Defer => Action::Defer,
478
479            Action::Ignore => Action::Ignore, // NOT TESTED
480            Action::Change(state) => Action::Change(self.translate_state(state)),
481
482            Action::Send1(emit) => Action::Send1(emit),
483            Action::ChangeAndSend1(state, emit) => {
484                Action::ChangeAndSend1(self.translate_state(state), emit)
485            }
486
487            Action::Sends(emits) => Action::Sends(emits), // NOT TESTED
488            Action::ChangeAndSends(state, emits) => {
489                Action::ChangeAndSends(self.translate_state(state), emits)
490            }
491        }
492    }
493
494    // BEGIN NOT TESTED
495
496    fn translate_actions(
497        &self,
498        actions: &[Option<Action<State, Payload>>; MAX_COUNT],
499    ) -> [Option<Action<StateId, Payload>>; MAX_COUNT] {
500        let mut translated_actions: [Option<Action<StateId, Payload>>; MAX_COUNT] =
501            [None; MAX_COUNT];
502        for (maybe_action, maybe_translated) in actions.iter().zip(translated_actions.iter_mut()) {
503            *maybe_translated = maybe_action
504                .as_ref()
505                .map(|action| self.translate_action(action));
506        }
507        translated_actions
508    }
509
510    // END NOT TESTED
511
512    fn translate_state(&self, state: State) -> StateId {
513        let stored = self.states.borrow_mut().store(state);
514        if stored.is_new {
515            debug_assert!(self.label_of_state.borrow().len() == stored.id.to_usize());
516            self.label_of_state
517                .borrow_mut()
518                .push(Rc::new(format!("{}", state)));
519        }
520        stored.id
521    }
522}
523
524impl<State: DataLike, StateId: IndexLike, Payload: DataLike> Name
525    for AgentTypeData<State, StateId, Payload>
526{
527    fn name(&self) -> String {
528        self.name.to_string()
529    }
530}
531
532impl<
533        State: DataLike,
534        Part: DataLike,
535        StateId: IndexLike,
536        Payload: DataLike,
537        const MAX_PARTS: usize,
538    > Name for ContainerOf1TypeData<State, Part, StateId, Payload, MAX_PARTS>
539{
540    fn name(&self) -> String {
541        self.agent_type_data.name()
542    }
543}
544
545// BEGIN NOT TESTED
546impl<
547        State: DataLike,
548        Part1: DataLike,
549        Part2: DataLike,
550        StateId: IndexLike,
551        Payload: DataLike,
552        const MAX_PARTS: usize,
553    > Name for ContainerOf2TypeData<State, Part1, Part2, StateId, Payload, MAX_PARTS>
554{
555    fn name(&self) -> String {
556        self.agent_type_data.name()
557    }
558}
559// END NOT TESTED
560
561impl<State: DataLike, StateId: IndexLike, Payload: DataLike> AgentInstances<StateId, Payload>
562    for AgentTypeData<State, StateId, Payload>
563{
564    fn prev_agent_type(&self) -> Option<Rc<dyn AgentType<StateId, Payload>>> {
565        self.prev_agent_type.clone()
566    }
567
568    fn first_index(&self) -> usize {
569        self.first_index
570    }
571
572    fn next_index(&self) -> usize {
573        self.first_index + self.instances_count()
574    }
575
576    fn is_singleton(&self) -> bool {
577        self.is_singleton
578    }
579
580    fn instances_count(&self) -> usize {
581        self.order_of_instances.len()
582    }
583
584    fn instance_order(&self, instance: usize) -> usize {
585        self.order_of_instances[instance]
586    }
587
588    fn display_state(&self, state_id: StateId) -> Rc<String> {
589        self.label_of_state.borrow()[state_id.to_usize()].clone()
590    }
591
592    fn terse_id(&self, state_id: StateId) -> StateId {
593        self.terse_of_state.borrow()[state_id.to_usize()]
594    }
595
596    fn display_terse(&self, terse_id: StateId) -> String {
597        self.name_of_terse.borrow()[terse_id.to_usize()].clone()
598    }
599}
600
601impl<
602        State: DataLike + ContainerOf1State<State, Part, Payload>,
603        Part: DataLike + AgentState<Part, Payload>,
604        StateId: IndexLike,
605        Payload: DataLike,
606        const MAX_PARTS: usize,
607    > AgentInstances<StateId, Payload>
608    for ContainerOf1TypeData<State, Part, StateId, Payload, MAX_PARTS>
609{
610    fn prev_agent_type(&self) -> Option<Rc<dyn AgentType<StateId, Payload>>> {
611        self.agent_type_data.prev_agent_type.clone()
612    }
613
614    fn first_index(&self) -> usize {
615        self.agent_type_data.first_index()
616    }
617
618    fn next_index(&self) -> usize {
619        self.agent_type_data.next_index()
620    }
621
622    fn is_singleton(&self) -> bool {
623        self.agent_type_data.is_singleton()
624    }
625
626    fn instances_count(&self) -> usize {
627        self.agent_type_data.instances_count()
628    }
629
630    fn instance_order(&self, instance: usize) -> usize {
631        self.agent_type_data.instance_order(instance)
632    }
633
634    fn display_state(&self, state_id: StateId) -> Rc<String> {
635        self.agent_type_data.display_state(state_id)
636    }
637
638    // BEGIN NOT TESTED
639    fn terse_id(&self, state_id: StateId) -> StateId {
640        self.agent_type_data.terse_id(state_id)
641    }
642
643    fn display_terse(&self, terse_id: StateId) -> String {
644        self.agent_type_data.display_terse(terse_id)
645    }
646    // END NOT TESTED
647}
648
649// BEGIN NOT TESTED
650impl<
651        State: DataLike + ContainerOf2State<State, Part1, Part2, Payload>,
652        Part1: DataLike + AgentState<Part1, Payload>,
653        Part2: DataLike + AgentState<Part2, Payload>,
654        StateId: IndexLike,
655        Payload: DataLike,
656        const MAX_PARTS: usize,
657    > AgentInstances<StateId, Payload>
658    for ContainerOf2TypeData<State, Part1, Part2, StateId, Payload, MAX_PARTS>
659{
660    fn prev_agent_type(&self) -> Option<Rc<dyn AgentType<StateId, Payload>>> {
661        self.agent_type_data.prev_agent_type.clone()
662    }
663
664    fn first_index(&self) -> usize {
665        self.agent_type_data.first_index()
666    }
667
668    fn next_index(&self) -> usize {
669        self.agent_type_data.next_index()
670    }
671
672    fn is_singleton(&self) -> bool {
673        self.agent_type_data.is_singleton()
674    }
675
676    fn instances_count(&self) -> usize {
677        self.agent_type_data.instances_count()
678    }
679
680    fn instance_order(&self, instance: usize) -> usize {
681        self.agent_type_data.instance_order(instance)
682    }
683
684    fn display_state(&self, state_id: StateId) -> Rc<String> {
685        self.agent_type_data.display_state(state_id)
686    }
687
688    fn terse_id(&self, state_id: StateId) -> StateId {
689        self.agent_type_data.terse_id(state_id)
690    }
691
692    fn display_terse(&self, terse_id: StateId) -> String {
693        self.agent_type_data.display_terse(terse_id)
694    }
695}
696// END NOT TESTED
697
698impl<State: DataLike + AgentState<State, Payload>, StateId: IndexLike, Payload: DataLike>
699    AgentType<StateId, Payload> for AgentTypeData<State, StateId, Payload>
700{
701    fn reaction(
702        &self,
703        instance: usize,
704        state_ids: &[StateId],
705        payload: &Payload,
706    ) -> Reaction<StateId, Payload> {
707        debug_assert!(
708            instance < self.instances_count(),
709            "instance: {} count: {}",
710            instance,
711            self.instances_count() // NOT TESTED
712        );
713        let state = self
714            .states
715            .borrow()
716            .get(state_ids[self.first_index + instance]);
717        let reaction = state.reaction(instance, payload);
718        self.translate_reaction(&reaction)
719    }
720
721    fn activity(&self, instance: usize, state_ids: &[StateId]) -> Activity<Payload> {
722        debug_assert!(
723            instance < self.instances_count(),
724            "instance: {} count: {}",
725            instance,
726            self.instances_count() // NOT TESTED
727        );
728        self.states
729            .borrow()
730            .get(state_ids[self.first_index + instance])
731            .activity(instance)
732    }
733
734    fn state_is_deferring(&self, instance: usize, state_ids: &[StateId]) -> bool {
735        debug_assert!(
736            instance < self.instances_count(),
737            "instance: {} count: {}",
738            instance,
739            self.instances_count() // NOT TESTED
740        );
741        self.states
742            .borrow()
743            .get(state_ids[self.first_index + instance])
744            .is_deferring(instance)
745    }
746
747    fn state_invalid_because(
748        &self,
749        instance: usize,
750        state_ids: &[StateId],
751    ) -> Option<&'static str> {
752        debug_assert!(
753            instance < self.instances_count(),
754            "instance: {} count: {}",
755            instance,
756            self.instances_count() // NOT TESTED
757        );
758        self.states
759            .borrow()
760            .get(state_ids[self.first_index + instance])
761            .invalid_because(instance)
762    }
763
764    fn state_max_in_flight_messages(
765        &self,
766        instance: usize,
767        state_ids: &[StateId],
768    ) -> Option<usize> {
769        debug_assert!(
770            instance < self.instances_count(),
771            "instance: {} count: {}",
772            instance,
773            self.instances_count() // NOT TESTED
774        );
775        self.states
776            .borrow()
777            .get(state_ids[self.first_index + instance])
778            .max_in_flight_messages(instance)
779    }
780
781    fn states_count(&self) -> usize {
782        self.states.borrow().len()
783    }
784
785    fn compute_terse(&self) {
786        self.impl_compute_terse();
787    }
788}
789
790impl<
791        State: DataLike + ContainerOf1State<State, Part, Payload>,
792        Part: DataLike + AgentState<Part, Payload>,
793        StateId: IndexLike,
794        Payload: DataLike,
795        const MAX_PARTS: usize,
796    > ContainerOf1TypeData<State, Part, StateId, Payload, MAX_PARTS>
797{
798    fn collect_parts(&self, state_ids: &[StateId]) -> [Part; MAX_PARTS] {
799        let mut parts = [Part::default(); MAX_PARTS];
800        let part_first_index = self.part_type.part_first_index();
801        (0..self.part_type.parts_count()).for_each(|part_instance| {
802            let state_id = state_ids[part_first_index + part_instance];
803            parts[part_instance] = self.part_type.part_state_by_id(state_id);
804        });
805
806        parts
807    }
808
809    // BEGIN NOT TESTED
810
811    /// Set the horizontal order of an instance of the agent in a sequence diagram.
812    pub fn set_order(&mut self, instance: usize, order: usize) {
813        self.agent_type_data.set_order(instance, order);
814    }
815
816    // END NOT TESTED
817}
818
819// BEGIN NOT TESTED
820impl<
821        State: DataLike + ContainerOf2State<State, Part1, Part2, Payload>,
822        Part1: DataLike + AgentState<Part1, Payload>,
823        Part2: DataLike + AgentState<Part2, Payload>,
824        StateId: IndexLike,
825        Payload: DataLike,
826        const MAX_PARTS: usize,
827    > ContainerOf2TypeData<State, Part1, Part2, StateId, Payload, MAX_PARTS>
828{
829    fn collect_parts(&self, state_ids: &[StateId]) -> ([Part1; MAX_PARTS], [Part2; MAX_PARTS]) {
830        let mut parts1 = [Part1::default(); MAX_PARTS];
831        let part1_first_index = self.part1_type.part_first_index();
832        (0..self.part1_type.parts_count()).for_each(|part1_instance| {
833            let state_id = state_ids[part1_first_index + part1_instance];
834            parts1[part1_instance] = self.part1_type.part_state_by_id(state_id);
835        });
836
837        let mut parts2 = [Part2::default(); MAX_PARTS];
838        let part2_first_index = self.part2_type.part_first_index();
839        (0..self.part2_type.parts_count()).for_each(|part2_instance| {
840            let state_id = state_ids[part2_first_index + part2_instance];
841            parts2[part2_instance] = self.part2_type.part_state_by_id(state_id);
842        });
843
844        (parts1, parts2)
845    }
846
847    /// Set the horizontal order of an instance of the agent in a sequence diagram.
848    pub fn set_order(&mut self, instance: usize, order: usize) {
849        self.agent_type_data.set_order(instance, order);
850    }
851}
852// END NOT TESTED
853
854impl<
855        State: DataLike + ContainerOf1State<State, Part, Payload>,
856        Part: DataLike + AgentState<Part, Payload>,
857        StateId: IndexLike,
858        Payload: DataLike,
859        const MAX_PARTS: usize,
860    > AgentType<StateId, Payload>
861    for ContainerOf1TypeData<State, Part, StateId, Payload, MAX_PARTS>
862{
863    fn reaction(
864        &self,
865        instance: usize,
866        state_ids: &[StateId],
867        payload: &Payload,
868    ) -> Reaction<StateId, Payload> {
869        debug_assert!(
870            instance < self.instances_count(),
871            "instance: {} count: {}",
872            instance,
873            self.instances_count() // NOT TESTED
874        );
875
876        let all_parts = self.collect_parts(state_ids);
877        let parts = &all_parts[..self.part_type.parts_count()];
878
879        let reaction = self
880            .agent_type_data
881            .states
882            .borrow()
883            .get(state_ids[self.agent_type_data.first_index + instance])
884            .reaction(instance, payload, parts);
885        self.agent_type_data.translate_reaction(&reaction)
886    }
887
888    fn activity(&self, instance: usize, state_ids: &[StateId]) -> Activity<Payload> {
889        debug_assert!(
890            instance < self.instances_count(),
891            "instance: {} count: {}",
892            instance,
893            self.instances_count() // NOT TESTED
894        );
895
896        let all_parts = self.collect_parts(state_ids);
897        let parts = &all_parts[..self.part_type.parts_count()];
898
899        self.agent_type_data
900            .states
901            .borrow()
902            .get(state_ids[self.agent_type_data.first_index + instance])
903            .activity(instance, parts)
904    }
905
906    fn state_is_deferring(&self, instance: usize, state_ids: &[StateId]) -> bool {
907        debug_assert!(
908            instance < self.instances_count(),
909            "instance: {} count: {}",
910            instance,
911            self.instances_count() // NOT TESTED
912        );
913
914        let all_parts = self.collect_parts(state_ids);
915        let parts = &all_parts[..self.part_type.parts_count()];
916
917        self.agent_type_data
918            .states
919            .borrow()
920            .get(state_ids[self.agent_type_data.first_index + instance])
921            .is_deferring(instance, parts)
922    }
923
924    // BEGIN NOT TESTED
925    fn state_invalid_because(
926        &self,
927        instance: usize,
928        state_ids: &[StateId],
929    ) -> Option<&'static str> {
930        debug_assert!(
931            instance < self.instances_count(),
932            "instance: {} count: {}",
933            instance,
934            self.instances_count()
935        );
936
937        let all_parts = self.collect_parts(state_ids);
938        let parts = &all_parts[..self.part_type.parts_count()];
939
940        self.agent_type_data
941            .states
942            .borrow()
943            .get(state_ids[self.agent_type_data.first_index + instance])
944            .invalid_because(instance, parts)
945    }
946    // END NOT TESTED
947
948    fn state_max_in_flight_messages(
949        &self,
950        instance: usize,
951        state_ids: &[StateId],
952    ) -> Option<usize> {
953        debug_assert!(
954            instance < self.instances_count(),
955            "instance: {} count: {}",
956            instance,
957            self.instances_count() // NOT TESTED
958        );
959
960        let all_parts = self.collect_parts(state_ids);
961        let parts = &all_parts[..self.part_type.parts_count()];
962
963        self.agent_type_data
964            .states
965            .borrow()
966            .get(state_ids[self.agent_type_data.first_index + instance])
967            .max_in_flight_messages(instance, parts)
968    }
969
970    // BEGIN NOT TESTED
971    fn states_count(&self) -> usize {
972        self.agent_type_data.states.borrow().len()
973    }
974    // END NOT TESTED
975
976    fn compute_terse(&self) {
977        self.agent_type_data.impl_compute_terse();
978    }
979}
980
981// BEGIN NOT TESTED
982impl<
983        State: DataLike + ContainerOf2State<State, Part1, Part2, Payload>,
984        Part1: DataLike + AgentState<Part1, Payload>,
985        Part2: DataLike + AgentState<Part2, Payload>,
986        StateId: IndexLike,
987        Payload: DataLike,
988        const MAX_PARTS: usize,
989    > AgentType<StateId, Payload>
990    for ContainerOf2TypeData<State, Part1, Part2, StateId, Payload, MAX_PARTS>
991{
992    fn reaction(
993        &self,
994        instance: usize,
995        state_ids: &[StateId],
996        payload: &Payload,
997    ) -> Reaction<StateId, Payload> {
998        debug_assert!(
999            instance < self.instances_count(),
1000            "instance: {} count: {}",
1001            instance,
1002            self.instances_count()
1003        );
1004
1005        let (all_parts1, all_parts2) = self.collect_parts(state_ids);
1006        let parts1 = &all_parts1[..self.part1_type.parts_count()];
1007        let parts2 = &all_parts2[..self.part2_type.parts_count()];
1008
1009        let reaction = self
1010            .agent_type_data
1011            .states
1012            .borrow()
1013            .get(state_ids[self.agent_type_data.first_index + instance])
1014            .reaction(instance, payload, parts1, parts2);
1015        self.agent_type_data.translate_reaction(&reaction)
1016    }
1017
1018    fn activity(&self, instance: usize, state_ids: &[StateId]) -> Activity<Payload> {
1019        debug_assert!(
1020            instance < self.instances_count(),
1021            "instance: {} count: {}",
1022            instance,
1023            self.instances_count()
1024        );
1025
1026        let (all_parts1, all_parts2) = self.collect_parts(state_ids);
1027        let parts1 = &all_parts1[..self.part1_type.parts_count()];
1028        let parts2 = &all_parts2[..self.part2_type.parts_count()];
1029
1030        self.agent_type_data
1031            .states
1032            .borrow()
1033            .get(state_ids[self.agent_type_data.first_index + instance])
1034            .activity(instance, parts1, parts2)
1035    }
1036
1037    fn state_is_deferring(&self, instance: usize, state_ids: &[StateId]) -> bool {
1038        debug_assert!(
1039            instance < self.instances_count(),
1040            "instance: {} count: {}",
1041            instance,
1042            self.instances_count()
1043        );
1044
1045        let (all_parts1, all_parts2) = self.collect_parts(state_ids);
1046        let parts1 = &all_parts1[..self.part1_type.parts_count()];
1047        let parts2 = &all_parts2[..self.part2_type.parts_count()];
1048
1049        self.agent_type_data
1050            .states
1051            .borrow()
1052            .get(state_ids[self.agent_type_data.first_index + instance])
1053            .is_deferring(instance, parts1, parts2)
1054    }
1055
1056    fn state_invalid_because(
1057        &self,
1058        instance: usize,
1059        state_ids: &[StateId],
1060    ) -> Option<&'static str> {
1061        debug_assert!(
1062            instance < self.instances_count(),
1063            "instance: {} count: {}",
1064            instance,
1065            self.instances_count()
1066        );
1067
1068        let (all_parts1, all_parts2) = self.collect_parts(state_ids);
1069        let parts1 = &all_parts1[..self.part1_type.parts_count()];
1070        let parts2 = &all_parts2[..self.part2_type.parts_count()];
1071
1072        self.agent_type_data
1073            .states
1074            .borrow()
1075            .get(state_ids[self.agent_type_data.first_index + instance])
1076            .invalid_because(instance, parts1, parts2)
1077    }
1078
1079    fn state_max_in_flight_messages(
1080        &self,
1081        instance: usize,
1082        state_ids: &[StateId],
1083    ) -> Option<usize> {
1084        debug_assert!(
1085            instance < self.instances_count(),
1086            "instance: {} count: {}",
1087            instance,
1088            self.instances_count()
1089        );
1090
1091        let (all_parts1, all_parts2) = self.collect_parts(state_ids);
1092        let parts1 = &all_parts1[..self.part1_type.parts_count()];
1093        let parts2 = &all_parts2[..self.part2_type.parts_count()];
1094
1095        self.agent_type_data
1096            .states
1097            .borrow()
1098            .get(state_ids[self.agent_type_data.first_index + instance])
1099            .max_in_flight_messages(instance, parts1, parts2)
1100    }
1101
1102    fn states_count(&self) -> usize {
1103        self.agent_type_data.states.borrow().len()
1104    }
1105
1106    fn compute_terse(&self) {
1107        self.agent_type_data.impl_compute_terse();
1108    }
1109}
1110// END NOT TESTED
1111
1112// BEGIN MAYBE TESTED
1113
1114/// A macro for implementing some `IndexLike` type.
1115///
1116/// This should be concerted to a derive macro.
1117#[macro_export]
1118macro_rules! index_type {
1119    ($name:ident, $type:ident) => {
1120        #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone, Debug)]
1121        pub struct $name($type);
1122
1123        impl total_space::IndexLike for $name {
1124            fn from_usize(value: usize) -> Self {
1125                $name($type::from_usize(value).unwrap())
1126            }
1127
1128            fn to_usize(&self) -> usize {
1129                let $name(value) = self;
1130                $type::to_usize(value).unwrap()
1131            }
1132
1133            fn invalid() -> Self {
1134                $name($type::max_value())
1135            }
1136        }
1137
1138        impl Display for $name {
1139            fn fmt(&self, formatter: &mut Formatter<'_>) -> FormatterResult {
1140                write!(formatter, "{}", self.to_usize())
1141            }
1142        }
1143    };
1144}