Skip to main content

factorio_ir/
stage.rs

1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2pub enum Stage {
3    Settings,
4    SettingsUpdates,
5    SettingsFinalFixes,
6    Data,
7    DataUpdates,
8    DataFinalFixes,
9    Control,
10    Shared,
11}
12
13impl Stage {
14    /// Stages that emit a Factorio root entry file with side-effect entry functions
15    /// (`settings*.lua` / `data*.lua`). Control uses event registration instead.
16    pub const SIDE_EFFECT_STAGES: [Self; 6] = [
17        Self::Settings,
18        Self::SettingsUpdates,
19        Self::SettingsFinalFixes,
20        Self::Data,
21        Self::DataUpdates,
22        Self::DataFinalFixes,
23    ];
24
25    /// Infer a stage from a dotted module name (e.g. `"control.on_built_entity"`).
26    ///
27    /// Longer phase names are matched before shorter ones so
28    /// `settings_updates` does not fall through to `settings`.
29    #[must_use]
30    pub fn from_module_name(module_name: &str) -> Option<Self> {
31        const PREFIXES: &[(&str, Stage)] = &[
32            ("settings_final_fixes", Stage::SettingsFinalFixes),
33            ("settings_updates", Stage::SettingsUpdates),
34            ("settings", Stage::Settings),
35            ("data_final_fixes", Stage::DataFinalFixes),
36            ("data_updates", Stage::DataUpdates),
37            ("data", Stage::Data),
38            ("control", Stage::Control),
39            ("shared", Stage::Shared),
40        ];
41
42        for &(prefix, stage) in PREFIXES {
43            if module_name == prefix
44                || module_name
45                    .strip_prefix(prefix)
46                    .is_some_and(|rest| rest.starts_with('.'))
47            {
48                return Some(stage);
49            }
50        }
51        None
52    }
53
54    /// The canonical root module name for this stage.
55    #[must_use]
56    pub const fn default_module_name(self) -> &'static str {
57        match self {
58            Self::Settings => "settings",
59            Self::SettingsUpdates => "settings_updates",
60            Self::SettingsFinalFixes => "settings_final_fixes",
61            Self::Data => "data",
62            Self::DataUpdates => "data_updates",
63            Self::DataFinalFixes => "data_final_fixes",
64            Self::Control => "control",
65            Self::Shared => "shared",
66        }
67    }
68
69    /// The Factorio entry-point file name for this stage, if any.
70    ///
71    /// `Shared` modules have no entry file - they are required by other stages.
72    #[must_use]
73    pub const fn entry_file_name(self) -> Option<&'static str> {
74        match self {
75            Self::Settings => Some("settings.lua"),
76            Self::SettingsUpdates => Some("settings-updates.lua"),
77            Self::SettingsFinalFixes => Some("settings-final-fixes.lua"),
78            Self::Data => Some("data.lua"),
79            Self::DataUpdates => Some("data-updates.lua"),
80            Self::DataFinalFixes => Some("data-final-fixes.lua"),
81            Self::Control => Some("control.lua"),
82            Self::Shared => None,
83        }
84    }
85
86    /// Whether public functions/structs in this stage are load-time entry points.
87    #[must_use]
88    pub const fn has_side_effect_entry(self) -> bool {
89        matches!(
90            self,
91            Self::Settings
92                | Self::SettingsUpdates
93                | Self::SettingsFinalFixes
94                | Self::Data
95                | Self::DataUpdates
96                | Self::DataFinalFixes
97        )
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::Stage;
104
105    #[test]
106    fn matches_phase_module_names_before_base() {
107        assert_eq!(
108            Stage::from_module_name("settings_updates"),
109            Some(Stage::SettingsUpdates)
110        );
111        assert_eq!(
112            Stage::from_module_name("settings_updates.extra"),
113            Some(Stage::SettingsUpdates)
114        );
115        assert_eq!(
116            Stage::from_module_name("settings_final_fixes"),
117            Some(Stage::SettingsFinalFixes)
118        );
119        assert_eq!(Stage::from_module_name("settings"), Some(Stage::Settings));
120        assert_eq!(
121            Stage::from_module_name("data_updates"),
122            Some(Stage::DataUpdates)
123        );
124        assert_eq!(
125            Stage::from_module_name("data_final_fixes.foo"),
126            Some(Stage::DataFinalFixes)
127        );
128        assert_eq!(Stage::from_module_name("data"), Some(Stage::Data));
129    }
130
131    #[test]
132    fn entry_file_names_match_factorio_layout() {
133        assert_eq!(Stage::Settings.entry_file_name(), Some("settings.lua"));
134        assert_eq!(
135            Stage::SettingsUpdates.entry_file_name(),
136            Some("settings-updates.lua")
137        );
138        assert_eq!(
139            Stage::SettingsFinalFixes.entry_file_name(),
140            Some("settings-final-fixes.lua")
141        );
142        assert_eq!(Stage::Data.entry_file_name(), Some("data.lua"));
143        assert_eq!(
144            Stage::DataUpdates.entry_file_name(),
145            Some("data-updates.lua")
146        );
147        assert_eq!(
148            Stage::DataFinalFixes.entry_file_name(),
149            Some("data-final-fixes.lua")
150        );
151    }
152}