use core::fmt; use std::convert::Infallible; use std::str::FromStr; use chrono::{DateTime, Utc}; use serde::{de::Visitor, Deserialize}; use sha1_smol::Digest; #[derive(Deserialize, Debug)] pub struct LatestVersions { pub release: String, pub snapshot: String } #[derive(Debug, Clone)] pub enum VersionType { Snapshot, Release, OldBeta, OldAlpha, Other(String) } impl FromStr for VersionType { type Err = Infallible; fn from_str(s: &str) -> Result { match s { "snapshot" => Ok(Self::Snapshot), "release" => Ok(Self::Release), "old_beta" => Ok(Self::OldBeta), "old_alpha" => Ok(Self::OldAlpha), _ => Ok(Self::Other(s.to_owned())) } } } impl VersionType { pub fn to_str(&self) -> &str { match self { Self::Snapshot => "snapshot", Self::Release => "release", Self::OldBeta => "old_beta", Self::OldAlpha => "old_alpha", Self::Other(s) => s } } } struct VersionTypeVisitor; impl Visitor<'_> for VersionTypeVisitor { type Value = VersionType; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a Minecraft release type") } fn visit_str(self, v: &str) -> Result where E: serde::de::Error, { Ok(VersionType::from_str(v).unwrap(/* infallible */)) } } impl<'de> Deserialize<'de> for VersionType { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { deserializer.deserialize_string(VersionTypeVisitor) } } // https://piston-meta.mojang.com/mc/game/version_manifest_v2.json #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct VersionManifestVersion { pub id: String, #[serde(rename = "type")] pub version_type: VersionType, pub url: String, pub time: DateTime, pub release_time: DateTime, pub sha1: Digest, pub compliance_level: u32 } #[derive(Deserialize, Debug)] pub struct VersionManifest { pub latest: LatestVersions, pub versions: Vec }