1use color_eyre::eyre::ContextCompat;
2
3pub const BUILD_MODE_ENV: &str = "CONFIGURATION";
4pub const IOS_ARCHS_ENV: &str = "IOS_ARCHS";
5pub const ANDROID_ARCHS_ENV: &str = "ANDROID_ARCHS";
6pub const FLUTTER_ARCHS_ENV: &str = "FLUTTER_ARCHS";
7pub const REACT_NATIVE_ARCHS_ENV: &str = "REACT_NATIVE_ARCHS";
8
9pub const IOS_BINDINGS_DIR: &str = "MoproiOSBindings";
10pub const IOS_SWIFT_FILE: &str = "mopro.swift";
11pub const IOS_XCFRAMEWORKS_DIR: &str = "MoproBindings.xcframework";
12
13pub const ANDROID_BINDINGS_DIR: &str = "MoproAndroidBindings";
14pub const ANDROID_JNILIBS_DIR: &str = "jniLibs";
15pub const ANDROID_UNIFFI_DIR: &str = "uniffi";
16pub const ANDROID_PACKAGE_NAME: &str = "mopro";
17pub const ANDROID_KT_FILE: &str = "mopro.kt";
18
19pub const WEB_BINDINGS_DIR: &str = "MoproWasmBindings";
20
21pub const ARCH_X86_64: &str = "x86_64";
22pub const ARCH_ARM_64: &str = "aarch64";
23pub const ARCH_I686: &str = "x86";
24pub const ARCH_ARM_V7_ABI: &str = "armeabi-v7a";
25pub const ARCH_ARM_64_V8: &str = "arm64-v8a";
26
27pub const FLUTTER_BINDINGS_DIR: &str = "mopro_flutter_bindings";
28pub const REACT_NATIVE_BINDINGS_DIR: &str = "MoproReactNativeBindings";
29
30#[derive(Debug, Copy, Clone, PartialEq, Eq)]
31pub enum Mode {
32 Debug,
33 Release,
34}
35
36struct ModeInfo {
37 mode: Mode,
38 str: &'static str,
39}
40
41const MODES: [ModeInfo; 2] = [
42 ModeInfo {
43 mode: Mode::Debug,
44 str: "debug",
45 },
46 ModeInfo {
47 mode: Mode::Release,
48 str: "release",
49 },
50];
51
52impl Mode {
53 pub fn as_str(&self) -> &'static str {
54 MODES
55 .iter()
56 .find(|info| info.mode == *self)
57 .map(|info| info.str)
58 .expect("Unsupported Mode, only support 'release' and 'debug'")
59 }
60
61 pub fn parse_from_str(s: &str) -> Self {
62 MODES
63 .iter()
64 .find(|info| info.str.to_lowercase() == s.to_lowercase())
65 .map(|info| info.mode)
66 .expect("Unsupported Mode String, only support 'release' and 'debug'")
67 }
68
69 pub fn from_idx(idx: usize) -> Self {
70 MODES[idx].mode
71 }
72
73 pub fn idx(s: &str) -> Option<usize> {
74 MODES
75 .iter()
76 .enumerate()
77 .find(|(_, m)| m.str == s)
78 .map(|(i, _)| i)
79 }
80
81 pub fn all_strings() -> Vec<&'static str> {
82 MODES.iter().map(|info| info.str).collect()
83 }
84}
85
86pub trait Arch {
91 fn platform() -> Box<dyn Platform>;
92 fn as_str(&self) -> &'static str;
93 fn parse_from_str<S: AsRef<str>>(s: S) -> Self;
94 fn all_strings() -> Vec<&'static str>;
95 fn all_display_strings() -> Vec<(String, String)>;
96 fn env_var_name() -> &'static str;
97}
98
99#[derive(Debug, Copy, Clone, PartialEq, Eq)]
101pub enum IosArch {
102 Aarch64Apple,
103 Aarch64AppleSim,
104 X8664Apple,
105}
106
107struct IosArchInfo {
108 #[allow(dead_code)] arch: IosArch,
110 str: &'static str,
111 description: &'static str,
112}
113
114const IOS_ARCHS: [IosArchInfo; 3] = [
115 IosArchInfo {
116 arch: IosArch::Aarch64Apple,
117 str: "aarch64-apple-ios",
118 description: "64-bit iOS devices (iPhone/iPad)",
119 },
120 IosArchInfo {
121 arch: IosArch::Aarch64AppleSim,
122 str: "aarch64-apple-ios-sim",
123 description: "ARM64 iOS simulator on Apple Silicon Macs",
124 },
125 IosArchInfo {
126 arch: IosArch::X8664Apple,
127 str: "x86_64-apple-ios",
128 description: "x86_64 iOS simulator on Intel Macs",
129 },
130];
131
132impl Arch for IosArch {
133 fn platform() -> Box<dyn Platform> {
134 Box::new(IosPlatform)
135 }
136
137 fn as_str(&self) -> &'static str {
138 IOS_ARCHS
139 .iter()
140 .find(|info| info.arch == *self)
141 .map(|info| info.str)
142 .expect("Unsupported iOS Arch")
143 }
144
145 fn parse_from_str<S: AsRef<str>>(s: S) -> Self {
146 IOS_ARCHS
147 .iter()
148 .find(|info| info.str.to_lowercase() == s.as_ref().to_lowercase())
149 .map(|info| info.arch)
150 .context(format!("Unsupported iOS Arch '{}'", s.as_ref()))
151 .unwrap()
152 }
153
154 fn all_strings() -> Vec<&'static str> {
155 IOS_ARCHS.iter().map(|info| info.str).collect()
156 }
157
158 fn all_display_strings() -> Vec<(String, String)> {
159 IOS_ARCHS
160 .iter()
161 .map(|info| (info.str.to_string(), info.description.to_string()))
162 .collect()
163 }
164
165 fn env_var_name() -> &'static str {
166 IOS_ARCHS_ENV
167 }
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq)]
171pub enum AndroidArch {
172 X8664Linux,
173 I686Linux,
174 Armv7LinuxAbi,
175 Aarch64Linux,
176}
177
178struct AndroidArchInfo {
179 arch: AndroidArch,
180 str: &'static str,
181 description: &'static str,
182}
183
184const ANDROID_ARCHS: [AndroidArchInfo; 4] = [
185 AndroidArchInfo {
186 arch: AndroidArch::X8664Linux,
187 str: "x86_64-linux-android",
188 description: "64-bit Android emulators (x86_64 architecture)",
189 },
190 AndroidArchInfo {
191 arch: AndroidArch::I686Linux,
192 str: "i686-linux-android",
193 description: "32-bit Android emulators (x86 architecture, legacy)",
194 },
195 AndroidArchInfo {
196 arch: AndroidArch::Armv7LinuxAbi,
197 str: "armv7-linux-androideabi",
198 description: "32-bit ARM devices (older Android smartphones/tablets)",
199 },
200 AndroidArchInfo {
201 arch: AndroidArch::Aarch64Linux,
202 str: "aarch64-linux-android",
203 description: "64-bit ARM devices (modern Android smartphones/tablets)",
204 },
205];
206
207impl Arch for AndroidArch {
208 fn platform() -> Box<dyn Platform> {
209 Box::new(AndroidPlatform)
210 }
211
212 fn as_str(&self) -> &'static str {
213 ANDROID_ARCHS
214 .iter()
215 .find(|info| info.arch == *self)
216 .map(|info| info.str)
217 .expect("Unsupported Android Arch")
218 }
219
220 fn parse_from_str<S: AsRef<str>>(s: S) -> Self {
221 ANDROID_ARCHS
222 .iter()
223 .find(|info| info.str.to_lowercase() == s.as_ref().to_lowercase())
224 .map(|info| info.arch)
225 .context(format!("Unsupported Android Arch '{}'", s.as_ref()))
226 .unwrap()
227 }
228
229 fn all_strings() -> Vec<&'static str> {
230 ANDROID_ARCHS.iter().map(|info| info.str).collect()
231 }
232
233 fn all_display_strings() -> Vec<(String, String)> {
234 ANDROID_ARCHS
235 .iter()
236 .map(|info| (info.str.to_string(), info.description.to_string()))
237 .collect()
238 }
239
240 fn env_var_name() -> &'static str {
241 ANDROID_ARCHS_ENV
242 }
243}
244
245pub struct WebArch;
246
247impl Arch for WebArch {
248 fn platform() -> Box<dyn Platform> {
249 Box::new(WebPlatform)
250 }
251
252 fn as_str(&self) -> &'static str {
253 "wasm32-unknown-unknown"
254 }
255
256 fn parse_from_str<S: AsRef<str>>(_s: S) -> Self {
257 WebArch
258 }
259
260 fn all_strings() -> Vec<&'static str> {
261 vec!["wasm32-unknown-unknown"]
262 }
263
264 fn all_display_strings() -> Vec<(String, String)> {
265 vec![(
266 "wasm32-unknown-unknown".to_string(),
267 "WebAssembly".to_string(),
268 )]
269 }
270
271 fn env_var_name() -> &'static str {
272 "WEB_ARCHS"
273 }
274}
275
276#[derive(Debug, Clone, Copy, PartialEq, Eq)]
278
279pub enum FlutterArch {
280 Aarch64Apple,
281 Aarch64AppleSim,
282 X8664Apple,
283 X8664Linux,
284 I686Linux,
285 Armv7LinuxAbi,
286 Aarch64Linux,
287}
288struct FlutterArchInfo {
289 arch: FlutterArch,
290 str: &'static str,
291 description: &'static str,
292}
293
294const FLUTTER_ARCHS: [FlutterArchInfo; 7] = [
295 FlutterArchInfo {
296 arch: FlutterArch::Aarch64Apple,
297 str: "aarch64-apple-ios",
298 description: "64-bit iOS devices (iPhone/iPad)",
299 },
300 FlutterArchInfo {
301 arch: FlutterArch::Aarch64AppleSim,
302 str: "aarch64-apple-ios-sim",
303 description: "ARM64 iOS simulator on Apple Silicon Macs",
304 },
305 FlutterArchInfo {
306 arch: FlutterArch::X8664Apple,
307 str: "x86_64-apple-ios",
308 description: "x86_64 iOS simulator on Intel Macs",
309 },
310 FlutterArchInfo {
311 arch: FlutterArch::X8664Linux,
312 str: "x86_64-linux-android",
313 description: "64-bit Android emulators (x86_64 architecture)",
314 },
315 FlutterArchInfo {
316 arch: FlutterArch::I686Linux,
317 str: "i686-linux-android",
318 description: "32-bit Android emulators (x86 architecture, legacy)",
319 },
320 FlutterArchInfo {
321 arch: FlutterArch::Armv7LinuxAbi,
322 str: "armv7-linux-androideabi",
323 description: "32-bit ARM devices (older Android smartphones/tablets)",
324 },
325 FlutterArchInfo {
326 arch: FlutterArch::Aarch64Linux,
327 str: "aarch64-linux-android",
328 description: "64-bit ARM devices (modern Android smartphones/tablets)",
329 },
330];
331
332impl Arch for FlutterArch {
333 fn platform() -> Box<dyn Platform> {
334 Box::new(FlutterPlatform)
335 }
336
337 fn as_str(&self) -> &'static str {
338 FLUTTER_ARCHS
339 .iter()
340 .find(|info| info.arch == *self)
341 .map(|info| info.str)
342 .expect("Unsupported iOS Arch")
343 }
344
345 fn parse_from_str<S: AsRef<str>>(s: S) -> Self {
346 FLUTTER_ARCHS
347 .iter()
348 .find(|info| info.str.to_lowercase() == s.as_ref().to_lowercase())
349 .map(|info| info.arch)
350 .context(format!("Unsupported iOS Arch '{}'", s.as_ref()))
351 .unwrap()
352 }
353
354 fn all_strings() -> Vec<&'static str> {
355 FLUTTER_ARCHS.iter().map(|info| info.str).collect()
356 }
357
358 fn all_display_strings() -> Vec<(String, String)> {
359 FLUTTER_ARCHS
360 .iter()
361 .map(|info| (info.str.to_string(), info.description.to_string()))
362 .collect()
363 }
364
365 fn env_var_name() -> &'static str {
366 FLUTTER_ARCHS_ENV
367 }
368}
369
370#[derive(Debug, Clone, Copy, PartialEq, Eq)]
372
373pub enum ReactNativeArch {
374 Aarch64Apple,
375 Aarch64AppleSim,
376 X8664Apple,
377 X8664Linux,
378 I686Linux,
379 Armv7LinuxAbi,
380 Aarch64Linux,
381}
382struct ReactNativeArchInfo {
383 arch: ReactNativeArch,
384 str: &'static str,
385 description: &'static str,
386}
387
388const REACT_NATIVE_ARCHS: [ReactNativeArchInfo; 7] = [
389 ReactNativeArchInfo {
390 arch: ReactNativeArch::Aarch64Apple,
391 str: "aarch64-apple-ios",
392 description: "64-bit iOS devices (iPhone/iPad)",
393 },
394 ReactNativeArchInfo {
395 arch: ReactNativeArch::Aarch64AppleSim,
396 str: "aarch64-apple-ios-sim",
397 description: "ARM64 iOS simulator on Apple Silicon Macs",
398 },
399 ReactNativeArchInfo {
400 arch: ReactNativeArch::X8664Apple,
401 str: "x86_64-apple-ios",
402 description: "x86_64 iOS simulator on Intel Macs",
403 },
404 ReactNativeArchInfo {
405 arch: ReactNativeArch::X8664Linux,
406 str: "x86_64-linux-android",
407 description: "64-bit Android emulators (x86_64 architecture)",
408 },
409 ReactNativeArchInfo {
410 arch: ReactNativeArch::I686Linux,
411 str: "i686-linux-android",
412 description: "32-bit Android emulators (x86 architecture, legacy)",
413 },
414 ReactNativeArchInfo {
415 arch: ReactNativeArch::Armv7LinuxAbi,
416 str: "armv7-linux-androideabi",
417 description: "32-bit ARM devices (older Android smartphones/tablets)",
418 },
419 ReactNativeArchInfo {
420 arch: ReactNativeArch::Aarch64Linux,
421 str: "aarch64-linux-android",
422 description: "64-bit ARM devices (modern Android smartphones/tablets)",
423 },
424];
425
426impl Arch for ReactNativeArch {
427 fn platform() -> Box<dyn Platform> {
428 Box::new(ReactNativePlatform)
429 }
430
431 fn as_str(&self) -> &'static str {
432 REACT_NATIVE_ARCHS
433 .iter()
434 .find(|info| info.arch == *self)
435 .map(|info| info.str)
436 .expect("Unsupported React Native Arch")
437 }
438
439 fn parse_from_str<S: AsRef<str>>(s: S) -> Self {
440 REACT_NATIVE_ARCHS
441 .iter()
442 .find(|info| info.str.to_lowercase() == s.as_ref().to_lowercase())
443 .map(|info| info.arch)
444 .context(format!("Unsupported React Native Arch '{}'", s.as_ref()))
445 .unwrap()
446 }
447
448 fn all_strings() -> Vec<&'static str> {
449 REACT_NATIVE_ARCHS.iter().map(|info| info.str).collect()
450 }
451
452 fn all_display_strings() -> Vec<(String, String)> {
453 REACT_NATIVE_ARCHS
454 .iter()
455 .map(|info| (info.str.to_string(), info.description.to_string()))
456 .collect()
457 }
458
459 fn env_var_name() -> &'static str {
460 REACT_NATIVE_ARCHS_ENV
461 }
462}
463
464pub trait Platform {
469 fn identifier() -> &'static str
470 where
471 Self: Sized;
472}
473
474pub trait PlatformBuilder: Platform {
475 type Arch: Arch;
476 type Params: Default;
477
478 fn build(
479 mode: Mode,
480 project_dir: &std::path::Path,
481 target_arch: Vec<Self::Arch>,
482 params: Self::Params,
483 ) -> anyhow::Result<std::path::PathBuf>;
484}
485
486pub struct IosPlatform;
487
488impl Platform for IosPlatform {
489 fn identifier() -> &'static str {
490 "iOS Bindings Builder"
491 }
492}
493
494pub struct AndroidPlatform;
495
496impl Platform for AndroidPlatform {
497 fn identifier() -> &'static str {
498 "Android Bindings Builder"
499 }
500}
501
502pub struct WebPlatform;
503
504impl Platform for WebPlatform {
505 fn identifier() -> &'static str {
506 "Web Bindings Builder"
507 }
508}
509
510pub struct FlutterPlatform;
511
512impl Platform for FlutterPlatform {
513 fn identifier() -> &'static str {
514 "Flutter Bindings Builder"
515 }
516}
517
518pub struct ReactNativePlatform;
519
520impl Platform for ReactNativePlatform {
521 fn identifier() -> &'static str {
522 "React Native Bindings Builder"
523 }
524}