Skip to main content

factorio_api_gen/
lib.rs

1#![allow(
2    clippy::missing_errors_doc,
3    clippy::missing_panics_doc,
4    clippy::module_name_repetitions,
5    clippy::must_use_candidate,
6    clippy::too_many_lines,
7    clippy::cognitive_complexity,
8    clippy::doc_markdown,
9    clippy::unnested_or_patterns,
10    clippy::option_if_let_else,
11    clippy::map_unwrap_or,
12    clippy::needless_pass_by_value,
13    clippy::use_self,
14    clippy::similar_names,
15    clippy::single_match_else,
16    clippy::match_same_arms,
17    clippy::items_after_statements,
18    clippy::struct_field_names,
19    clippy::if_not_else,
20    clippy::from_iter_instead_of_collect,
21    clippy::manual_string_new,
22    clippy::wildcard_imports,
23    clippy::enum_glob_use,
24    clippy::unused_self,
25    clippy::trivially_copy_pass_by_ref,
26    clippy::as_conversions,
27    clippy::indexing_slicing,
28    clippy::integer_division,
29    clippy::arithmetic_side_effects,
30    clippy::missing_const_for_fn,
31    clippy::implicit_hasher,
32    clippy::semicolon_if_nothing_returned,
33    clippy::redundant_closure_for_method_calls,
34    clippy::unnecessary_wraps,
35    clippy::return_self_not_must_use,
36    clippy::pub_use,
37    clippy::module_inception,
38    clippy::redundant_pub_crate
39)]
40
41mod generate;
42mod schema;
43mod schema_prototype;
44
45use std::path::Path;
46
47pub use generate::PROTOTYPE_RICH_OVERRIDES;
48pub use schema::RuntimeApi;
49pub use schema_prototype::PrototypeApi;
50
51pub struct GeneratedApi {
52    pub application_version: String,
53    pub api_version: u32,
54    pub events: String,
55    pub event_map: String,
56    pub event_lookup: String,
57    pub event_filter_lookup: String,
58    pub event_module_lookup: String,
59    pub event_filters: String,
60    pub event_data: String,
61    pub defines: String,
62    pub classes: String,
63    pub globals: String,
64    pub concepts: String,
65    pub unions: String,
66    pub debug_types: String,
67    pub attribute_setters: String,
68}
69
70pub fn parse_runtime_api(json: &str) -> Result<RuntimeApi, serde_json::Error> {
71    serde_json::from_str(json)
72}
73
74pub fn generate_runtime_api(api: &RuntimeApi) -> GeneratedApi {
75    let mappings = generate::collect_event_mappings(api);
76    let class_names = generate::class_names(api);
77    let mut filter_concept_names = generate::event_filter_concept_names(api);
78    filter_concept_names.extend(generate::prototype_filter_concept_names(api));
79    let identification_names = generate::identification_concept_names(api, &filter_concept_names);
80    let identification_signatures = generate::identification_signatures(api, &identification_names);
81    let mut concept_names = generate::generatable_concept_names(api, &filter_concept_names);
82    concept_names.extend(identification_names.iter().cloned());
83    let flag_sets = generate::flag_set_concept_names(api);
84    let union_registry = generate::collect_literal_unions(api);
85    let known = generate::KnownTypes {
86        classes: &class_names,
87        concepts: &concept_names,
88        identifications: &identification_names,
89        identification_signatures: &identification_signatures,
90        unions: union_registry.names(),
91        union_registry: &union_registry,
92        flag_sets: &flag_sets,
93    };
94    let event_filters = generate::generate_event_filters(api);
95    let concepts = {
96        let mut structs = generate::generate_concepts(api, &known, &filter_concept_names);
97        let ids = generate::generate_identifications(api, &known).to_string();
98        structs.push_str(&ids);
99        structs
100    };
101
102    GeneratedApi {
103        application_version: api.application_version.clone(),
104        api_version: api.api_version,
105        events: generate::generate_events(api),
106        event_map: generate::generate_event_map(&mappings),
107        event_lookup: generate::generate_event_lookup(&mappings),
108        event_filter_lookup: generate::generate_event_filter_lookup(&mappings),
109        event_module_lookup: generate::generate_event_module_lookup(&mappings),
110        event_filters,
111        event_data: generate::generate_event_data(api, &known),
112        defines: generate::generate_defines(&api.defines),
113        classes: generate::generate_classes(api, &known),
114        globals: generate::generate_globals(api, &known),
115        concepts,
116        unions: generate::generate_unions(&union_registry),
117        debug_types: generate::generate_debug_types(api, &known),
118        attribute_setters: generate::generate_attribute_setter_lookup(api),
119    }
120}
121
122pub fn generate_from_json(json: &str) -> Result<GeneratedApi, serde_json::Error> {
123    let api = parse_runtime_api(json)?;
124    Ok(generate_runtime_api(&api))
125}
126
127pub fn bundled_runtime_api_json() -> &'static str {
128    include_str!("../api/runtime-api.json")
129}
130
131pub fn generate_from_bundled_api() -> Result<GeneratedApi, serde_json::Error> {
132    generate_from_json(bundled_runtime_api_json())
133}
134
135pub fn parse_prototype_api(json: &str) -> Result<PrototypeApi, serde_json::Error> {
136    serde_json::from_str(json)
137}
138
139pub fn bundled_prototype_api_json() -> &'static str {
140    include_str!("../api/prototype-api.json")
141}
142
143pub fn generate_prototypes_from_bundled() -> Result<String, String> {
144    let api = parse_prototype_api(bundled_prototype_api_json()).map_err(|e| e.to_string())?;
145    generate::generate_prototypes(&api)
146}
147
148pub fn generate_prototype_type_map_from_bundled() -> Result<String, String> {
149    let api = parse_prototype_api(bundled_prototype_api_json()).map_err(|e| e.to_string())?;
150    generate::generate_prototype_type_map(&api)
151}
152
153pub fn write_generated_prototypes(output_dir: &Path, source: &str) -> std::io::Result<()> {
154    std::fs::create_dir_all(output_dir)?;
155    write_module(output_dir, "prototypes_gen.rs", source)
156}
157
158pub fn write_generated_api(output_dir: &Path, generated: &GeneratedApi) -> std::io::Result<()> {
159    std::fs::create_dir_all(output_dir)?;
160
161    write_module(
162        output_dir,
163        "mod.rs",
164        &format!(
165            "// Generated from Factorio runtime API v{} (format v{}).\n\
166             #[allow(unused, clippy::all, clippy::pedantic, clippy::nursery)]\n\n\
167             pub mod classes;\n\
168             pub mod concepts;\n\
169             pub mod debug_types;\n\
170             pub mod defines;\n\
171             pub mod event_data;\n\
172             pub mod event_filters;\n\
173             pub mod events;\n\
174             pub mod globals;\n\
175             pub mod map;\n\
176             pub mod unions;\n",
177            generated.application_version, generated.api_version
178        ),
179    )?;
180    write_module(output_dir, "events.rs", &generated.events)?;
181    write_module(output_dir, "map.rs", &generated.event_map)?;
182    write_module(output_dir, "event_filters.rs", &generated.event_filters)?;
183    write_module(output_dir, "event_data.rs", &generated.event_data)?;
184    write_module(output_dir, "defines.rs", &generated.defines)?;
185    write_module(output_dir, "classes.rs", &generated.classes)?;
186    write_module(output_dir, "globals.rs", &generated.globals)?;
187    write_module(output_dir, "concepts.rs", &generated.concepts)?;
188    write_module(output_dir, "unions.rs", &generated.unions)?;
189    write_module(output_dir, "debug_types.rs", &generated.debug_types)?;
190
191    Ok(())
192}
193
194pub fn write_macro_event_lookup(
195    output_dir: &Path,
196    generated: &GeneratedApi,
197) -> std::io::Result<()> {
198    std::fs::create_dir_all(output_dir)?;
199    write_module(output_dir, "event_lookup.rs", &generated.event_lookup)?;
200    write_module(
201        output_dir,
202        "event_filter_lookup.rs",
203        &generated.event_filter_lookup,
204    )?;
205    write_module(
206        output_dir,
207        "event_module_lookup.rs",
208        &generated.event_module_lookup,
209    )
210}
211
212fn write_module(output_dir: &Path, file_name: &str, contents: &str) -> std::io::Result<()> {
213    let path = output_dir.join(file_name);
214    std::fs::write(path, contents)
215}