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
use pns::{FireChanges, State, Tid};
use rfd::FileDialog;

use std::{collections::BTreeMap, path::PathBuf};

/// Indicates if some transition is callable.
#[derive(Default, Copy, Clone)]
pub struct CallableState {
    /// The transition is callable forward.
    pub forward: bool,
    /// The transition is callable backwards.
    pub backwards: bool,
}

pub struct StateInfo {
    pub state_path: Option<PathBuf>,
    pub changes: bool,
    pub callables: BTreeMap<Tid, CallableState>,
}

impl StateInfo {
    pub fn update_state(&mut self, state: &mut State) {
        let FireChanges { added, removed } = state.changed_transitions();

        for added in added {
            unsafe { self.callables.get_mut(&added).unwrap_unchecked() }.forward = true;
        }
        for removed in removed {
            unsafe { self.callables.get_mut(&removed).unwrap_unchecked() }.forward = false;
        }

        let FireChanges { added, removed } = state.changed_transitions_backwards();

        for added in added {
            unsafe { self.callables.get_mut(&added).unwrap_unchecked() }.backwards = true;
        }
        for removed in removed {
            unsafe { self.callables.get_mut(&removed).unwrap_unchecked() }.backwards = false;
        }
    }

    pub fn file_dialog(&self) -> FileDialog {
        let dialog = FileDialog::new().add_filter("Petri net interactive files", &["pns"]);

        if let Some(path) = &self.state_path {
            dialog.set_directory(path)
        } else if let Ok(path) = std::env::current_dir() {
            dialog.set_directory(path)
        } else {
            dialog
        }
    }
}