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 filter_concept_names = generate::event_filter_concept_names(api);
78 let identification_names = generate::identification_concept_names(api, &filter_concept_names);
79 let identification_signatures = generate::identification_signatures(api, &identification_names);
80 let mut concept_names = generate::generatable_concept_names(api, &filter_concept_names);
81 concept_names.extend(identification_names.iter().cloned());
82 let union_registry = generate::collect_literal_unions(api);
83 let known = generate::KnownTypes {
84 classes: &class_names,
85 concepts: &concept_names,
86 identifications: &identification_names,
87 identification_signatures: &identification_signatures,
88 unions: union_registry.names(),
89 union_registry: &union_registry,
90 };
91 let event_filters = generate::generate_event_filters(api);
92 let concepts = {
93 let mut structs = generate::generate_concepts(api, &known, &filter_concept_names);
94 let ids = generate::generate_identifications(api, &known).to_string();
95 structs.push_str(&ids);
96 structs
97 };
98
99 GeneratedApi {
100 application_version: api.application_version.clone(),
101 api_version: api.api_version,
102 events: generate::generate_events(api),
103 event_map: generate::generate_event_map(&mappings),
104 event_lookup: generate::generate_event_lookup(&mappings),
105 event_filter_lookup: generate::generate_event_filter_lookup(&mappings),
106 event_module_lookup: generate::generate_event_module_lookup(&mappings),
107 event_filters,
108 event_data: generate::generate_event_data(api, &known),
109 defines: generate::generate_defines(&api.defines),
110 classes: generate::generate_classes(api, &known),
111 globals: generate::generate_globals(api, &known),
112 concepts,
113 unions: generate::generate_unions(&union_registry),
114 debug_types: generate::generate_debug_types(api, &known),
115 attribute_setters: generate::generate_attribute_setter_lookup(api),
116 }
117}
118
119pub fn generate_from_json(json: &str) -> Result<GeneratedApi, serde_json::Error> {
120 let api = parse_runtime_api(json)?;
121 Ok(generate_runtime_api(&api))
122}
123
124pub fn bundled_runtime_api_json() -> &'static str {
125 include_str!("../api/runtime-api.json")
126}
127
128pub fn generate_from_bundled_api() -> Result<GeneratedApi, serde_json::Error> {
129 generate_from_json(bundled_runtime_api_json())
130}
131
132pub fn parse_prototype_api(json: &str) -> Result<PrototypeApi, serde_json::Error> {
133 serde_json::from_str(json)
134}
135
136pub fn bundled_prototype_api_json() -> &'static str {
137 include_str!("../api/prototype-api.json")
138}
139
140pub fn generate_prototypes_from_bundled() -> Result<String, String> {
141 let api = parse_prototype_api(bundled_prototype_api_json()).map_err(|e| e.to_string())?;
142 generate::generate_prototypes(&api)
143}
144
145pub fn generate_prototype_type_map_from_bundled() -> Result<String, String> {
146 let api = parse_prototype_api(bundled_prototype_api_json()).map_err(|e| e.to_string())?;
147 generate::generate_prototype_type_map(&api)
148}
149
150pub fn write_generated_prototypes(output_dir: &Path, source: &str) -> std::io::Result<()> {
151 std::fs::create_dir_all(output_dir)?;
152 write_module(output_dir, "prototypes_gen.rs", source)
153}
154
155pub fn write_generated_api(output_dir: &Path, generated: &GeneratedApi) -> std::io::Result<()> {
156 std::fs::create_dir_all(output_dir)?;
157
158 write_module(
159 output_dir,
160 "mod.rs",
161 &format!(
162 "// Generated from Factorio runtime API v{} (format v{}).\n\
163 #[allow(unused, clippy::all, clippy::pedantic, clippy::nursery)]\n\n\
164 pub mod classes;\n\
165 pub mod concepts;\n\
166 pub mod debug_types;\n\
167 pub mod defines;\n\
168 pub mod event_data;\n\
169 pub mod event_filters;\n\
170 pub mod events;\n\
171 pub mod globals;\n\
172 pub mod map;\n\
173 pub mod unions;\n",
174 generated.application_version, generated.api_version
175 ),
176 )?;
177 write_module(output_dir, "events.rs", &generated.events)?;
178 write_module(output_dir, "map.rs", &generated.event_map)?;
179 write_module(output_dir, "event_filters.rs", &generated.event_filters)?;
180 write_module(output_dir, "event_data.rs", &generated.event_data)?;
181 write_module(output_dir, "defines.rs", &generated.defines)?;
182 write_module(output_dir, "classes.rs", &generated.classes)?;
183 write_module(output_dir, "globals.rs", &generated.globals)?;
184 write_module(output_dir, "concepts.rs", &generated.concepts)?;
185 write_module(output_dir, "unions.rs", &generated.unions)?;
186 write_module(output_dir, "debug_types.rs", &generated.debug_types)?;
187
188 Ok(())
189}
190
191pub fn write_macro_event_lookup(
192 output_dir: &Path,
193 generated: &GeneratedApi,
194) -> std::io::Result<()> {
195 std::fs::create_dir_all(output_dir)?;
196 write_module(output_dir, "event_lookup.rs", &generated.event_lookup)?;
197 write_module(
198 output_dir,
199 "event_filter_lookup.rs",
200 &generated.event_filter_lookup,
201 )?;
202 write_module(
203 output_dir,
204 "event_module_lookup.rs",
205 &generated.event_module_lookup,
206 )
207}
208
209fn write_module(output_dir: &Path, file_name: &str, contents: &str) -> std::io::Result<()> {
210 let path = output_dir.join(file_name);
211 std::fs::write(path, contents)
212}