use std::fmt::Display; use chrono::NaiveDateTime; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Version { pub major: u16, pub minor: u8, pub build: u8, } impl Display for Version { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}.{:0>2}.{:0>2}", self.major, self.minor, self.build) } } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct IcfInnerData { pub id: String, pub version: Version, pub required_system_version: Version, pub datetime: NaiveDateTime, #[serde(default = "default_is_prerelease")] pub is_prerelease: bool, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct IcfOptionData { #[serde(skip, default = "empty_string")] pub app_id: String, pub option_id: String, #[serde(skip, default = "empty_version")] pub required_system_version: Version, pub datetime: NaiveDateTime, #[serde(default = "default_is_prerelease")] pub is_prerelease: bool, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct IcfPatchData { #[serde(skip, default = "empty_string")] pub id: String, pub sequence_number: u8, pub source_version: Version, pub source_datetime: NaiveDateTime, pub source_required_system_version: Version, pub target_version: Version, pub target_datetime: NaiveDateTime, pub target_required_system_version: Version, #[serde(default = "default_is_prerelease")] pub is_prerelease: bool, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "type")] pub enum IcfData { System(IcfInnerData), App(IcfInnerData), Patch(IcfPatchData), Option(IcfOptionData), } impl IcfData { pub fn is_prerelease(&self) -> bool { match self { IcfData::System(s) => s.is_prerelease, IcfData::App(a) => a.is_prerelease, IcfData::Option(o) => o.is_prerelease, IcfData::Patch(p) => p.is_prerelease, } } pub fn filename(&self) -> String { match self { IcfData::System(data) => format!( "{}_{:04}.{:02}.{:02}_{}_0.pack", data.id, data.version.major, data.version.minor, data.version.build, data.datetime.format("%Y%m%d%H%M%S") ), IcfData::App(data) => format!( "{}_{}_{}_0.app", data.id, data.version, data.datetime.format("%Y%m%d%H%M%S") ), IcfData::Option(data) => format!( "{}_{}_{}_0.opt", data.app_id, data.option_id, data.datetime.format("%Y%m%d%H%M%S") ), IcfData::Patch(data) => format!( "{}_{}_{}_{}_{}.app", data.id, data.target_version, data.target_datetime.format("%Y%m%d%H%M%S"), data.sequence_number, data.source_version, ), } } } fn empty_string() -> String { String::new() } fn empty_version() -> Version { Version { major: 0, minor: 0, build: 0 } } fn default_is_prerelease() -> bool { false }