use core::fmt;
use serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{self, MapAccess, SeqAccess, Visitor},
ser::SerializeStruct,
};
use time::Duration;
#[derive(Debug, Deserialize, Clone, PartialEq, Eq, Hash, Default)]
#[serde(rename_all = "PascalCase")]
pub struct WorldManifest {
#[serde(rename = "GenPassResults")]
pub generator_passes: Vec<GeneratorPass>,
#[serde(deserialize_with = "non_empty_str")]
pub version: Option<String>,
#[serde(deserialize_with = "non_empty_str", rename = "GitSHA")]
pub git_sha: Option<String>,
}
fn non_empty_str<'de, D: Deserializer<'de>>(d: D) -> Result<Option<String>, D::Error> {
use serde::Deserialize;
let o: Option<String> = Option::deserialize(d)?;
Ok(o.filter(|s| !s.is_empty()))
}
impl Serialize for WorldManifest {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut world_manifest = serializer.serialize_struct("WorldManifest", 4)?;
world_manifest.serialize_field("GenPassResults", &self.generator_passes)?;
world_manifest.serialize_field("Version", &self.version)?;
world_manifest.serialize_field("GitSHA", &self.git_sha.as_deref().unwrap_or_default())?;
world_manifest.serialize_field(
"FinalHash",
&self.generator_passes.last().and_then(|x| match x.result {
GeneratorPassResult::Result {
duration: _,
random: _,
hash,
} => hash,
GeneratorPassResult::Skipped => None,
}),
)?;
world_manifest.end()
}
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash)]
#[serde(rename_all = "PascalCase")]
pub struct GeneratorPass {
pub name: String,
#[serde(flatten)]
pub result: GeneratorPassResult,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GeneratorPassResult {
Skipped,
Result {
duration: Duration,
random: i32,
hash: Option<u32>,
},
}
impl Serialize for GeneratorPassResult {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut duration = Duration::ZERO;
let mut random = 0;
let mut hash = None;
let mut is_skipped = true;
match *self {
GeneratorPassResult::Result {
duration: d,
random: r,
hash: h,
} => {
duration = d;
random = r;
hash = h;
is_skipped = false;
}
GeneratorPassResult::Skipped => {}
}
let mut gen_pass_result = serializer.serialize_struct("GenPassResults", 5)?;
gen_pass_result.serialize_field(
"DurationMs",
&(duration
.whole_milliseconds()
.clamp(i32::MIN as i128, i32::MAX as i128) as i32),
)?;
gen_pass_result.serialize_field("RandNext", &random)?;
gen_pass_result.serialize_field("Hash", &hash)?;
gen_pass_result.serialize_field("Skipped", &is_skipped)?;
gen_pass_result.end()
}
}
impl<'de> Deserialize<'de> for GeneratorPassResult {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "PascalCase")]
enum Field {
DurationMs,
RandNext,
Hash,
Skipped,
}
struct GeneratorPassResultVisitor;
impl<'de> Visitor<'de> for GeneratorPassResultVisitor {
type Value = GeneratorPassResult;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct GeneratorPassResult")
}
fn visit_seq<V>(self, mut seq: V) -> Result<GeneratorPassResult, V::Error>
where
V: SeqAccess<'de>,
{
let duration_ms = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let random = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
let hash = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(2, &self))?;
let is_skipped = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(3, &self))?;
if is_skipped {
return Ok(GeneratorPassResult::Skipped);
}
Ok(GeneratorPassResult::Result {
duration: Duration::milliseconds(duration_ms),
random,
hash,
})
}
fn visit_map<V>(self, mut map: V) -> Result<GeneratorPassResult, V::Error>
where
V: MapAccess<'de>,
{
let mut duration_ms: Option<i64> = None;
let mut random: Option<i32> = None;
let mut hash: Option<Option<u32>> = None;
let mut is_skipped: Option<bool> = None;
while let Some(key) = map.next_key()? {
match key {
Field::DurationMs => {
if duration_ms.is_some() {
return Err(de::Error::duplicate_field("DurationMs"));
}
duration_ms = Some(map.next_value()?);
}
Field::RandNext => {
if random.is_some() {
return Err(de::Error::duplicate_field("RandNext"));
}
random = Some(map.next_value()?);
}
Field::Hash => {
if hash.is_some() {
return Err(de::Error::duplicate_field("Hash"));
}
hash = Some(map.next_value()?);
}
Field::Skipped => {
if is_skipped.is_some() {
return Err(de::Error::duplicate_field("Skipped"));
}
is_skipped = Some(map.next_value()?)
}
}
}
if is_skipped.ok_or_else(|| de::Error::missing_field("Skipped"))? {
return Ok(GeneratorPassResult::Skipped);
}
let duration_ms =
duration_ms.ok_or_else(|| de::Error::missing_field("DurationMs"))?;
let random = random.ok_or_else(|| de::Error::missing_field("RandNext"))?;
let hash = hash.ok_or_else(|| de::Error::missing_field("Hash"))?;
Ok(GeneratorPassResult::Result {
duration: Duration::milliseconds(duration_ms),
random,
hash,
})
}
}
const FIELDS: &[&str] = &["DurationMs", "RandNext", "Hash", "Skipped"];
deserializer.deserialize_struct("GeneratorPassResult", FIELDS, GeneratorPassResultVisitor)
}
}