use std::fmt::{Display, Formatter};
use serde::{Deserialize, Serialize};
use crate::modules::ship::{
ShipCockpitModule, ShipDecal, ShipHardpointModule, ShipInternalModule, ShipNameplate,
ShipPaintJob, ShipVoicepack,
};
use crate::modules::ship::models::ship_module::ship_bobble::ShipBobble;
use crate::modules::ship::models::ship_module::ship_engine_color::ShipEngineColor;
use crate::modules::ship::models::ship_module::ship_kit_module::ShipKitModule;
use crate::modules::ship::models::ship_module::ship_string_lights::ShipStringLights;
use crate::modules::ship::models::ship_module::ship_weapon_color::ShipWeaponColor;
pub mod module_class;
pub mod ship_bobble;
pub mod ship_cockpit_module;
pub mod ship_decal;
pub mod ship_engine_color;
pub mod ship_hardpoint_module;
pub mod ship_internal_module;
pub mod ship_kit_module;
pub mod ship_nameplate;
pub mod ship_paint_job;
pub mod ship_string_lights;
pub mod ship_voicepack;
pub mod ship_weapon_color;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub enum ShipModule {
#[serde(
alias = "modularcargobaydoor",
alias = "modularcargobaydoorfdl",
alias = "$modularcargobaydoor_name;"
)]
CargoBayDoor,
#[serde(alias = "hpt_shipdatalinkscanner")]
DataLinkScanner,
#[serde(alias = "int_codexscanner")]
CodexScanner,
#[serde(alias = "int_stellarbodydiscoveryscanner_standard")]
DiscoverScanner,
#[serde(untagged)]
Internal(ShipInternalModule),
#[serde(untagged)]
Hardpoint(ShipHardpointModule),
#[serde(untagged)]
Cockpit(ShipCockpitModule),
#[serde(untagged)]
PaintJob(ShipPaintJob),
#[serde(untagged)]
Decal(ShipDecal),
#[serde(untagged)]
VoicePack(ShipVoicepack),
#[serde(untagged)]
Nameplate(ShipNameplate),
#[serde(untagged)]
EngineColor(ShipEngineColor),
#[serde(untagged)]
WeaponColor(ShipWeaponColor),
#[serde(untagged)]
ShipKitModule(ShipKitModule),
#[serde(untagged)]
Bobble(ShipBobble),
#[serde(untagged)]
StringLights(ShipStringLights),
#[cfg(not(feature = "strict"))]
#[serde(untagged)]
Unknown(String),
}
impl ShipModule {
pub fn is_hardpoint_module(&self) -> bool {
matches!(self, ShipModule::Hardpoint(_))
}
pub fn is_full_sized_hardpoint_module(&self) -> bool {
let ShipModule::Hardpoint(hardpoint) = self else {
return false;
};
hardpoint.is_full_sized_module()
}
pub fn is_utility_module(&self) -> bool {
let ShipModule::Hardpoint(hardpoint) = self else {
return false;
};
hardpoint.is_utility_module()
}
pub fn is_internal_module(&self) -> bool {
matches!(self, ShipModule::Hardpoint(_))
}
pub fn is_core_internal(&self) -> bool {
let ShipModule::Internal(internal) = self else {
return false;
};
internal.is_core_internal()
}
pub fn is_optional_internal(&self) -> bool {
let ShipModule::Internal(internal) = self else {
return false;
};
internal.is_optional_internal()
}
pub fn is_powerplay_module(&self) -> bool {
match self {
ShipModule::Internal(internal) => internal.is_powerplay_module(),
ShipModule::Hardpoint(hardpoint) => hardpoint.is_powerplay_module(),
_ => false,
}
}
pub fn is_guardian_module(&self) -> bool {
match self {
ShipModule::Internal(internal) => internal.is_guardian_module(),
ShipModule::Hardpoint(hardpoint) => hardpoint.is_guardian_module(),
_ => false,
}
}
pub fn is_cosmetic(&self) -> bool {
matches!(
self,
ShipModule::PaintJob(_)
| ShipModule::Decal(_)
| ShipModule::VoicePack(_)
| ShipModule::Nameplate(_)
| ShipModule::EngineColor(_)
| ShipModule::WeaponColor(_)
| ShipModule::ShipKitModule(_)
| ShipModule::Bobble(_)
| ShipModule::StringLights(_)
)
}
}
impl Display for ShipModule {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ShipModule::CargoBayDoor => write!(f, "Cargo Hatch"),
ShipModule::DataLinkScanner => write!(f, "Data Link Scanner"),
ShipModule::CodexScanner => write!(f, "Codex Scanner"),
ShipModule::DiscoverScanner => write!(f, "Discovery Scanner"),
ShipModule::Internal(internal_module) => internal_module.fmt(f),
ShipModule::Hardpoint(hardpoint_module) => hardpoint_module.fmt(f),
ShipModule::Cockpit(_) => write!(f, "Cockpit"),
ShipModule::PaintJob(_) => write!(f, "Paint job"),
ShipModule::Decal(_) => write!(f, "Decal"),
ShipModule::VoicePack(_) => write!(f, "Voicepack"),
ShipModule::Nameplate(_) => write!(f, "Nameplate"),
ShipModule::EngineColor(_) => write!(f, "Engine Color"),
ShipModule::WeaponColor(_) => write!(f, "Weapon Color"),
ShipModule::Bobble(_) => write!(f, "Bobble"),
ShipModule::StringLights(_) => write!(f, "String Lights"),
ShipModule::ShipKitModule(module) => write!(f, "Skip kit module: {}", module.name),
#[cfg(not(feature = "strict"))]
ShipModule::Unknown(unknown) => write!(f, "Unknown module: {}", unknown),
}
}
}
#[cfg(test)]
mod tests {
use serde_json::Value;
use crate::modules::ship::ShipModule;
#[test]
fn modules_are_parsed_correctly() {
let test_cases = include_str!("zz_ship_module_test_cases.txt").lines();
let mut count = 0;
for line in test_cases {
let result = serde_json::from_value::<ShipModule>(Value::String(line.to_string()));
count += 1;
if result.is_err() {
dbg!(&line);
dbg!(&result);
}
assert!(result.is_ok());
}
assert!(count > 1000);
}
}