mirror of
https://github.com/neocturne/MinedMap.git
synced 2025-07-01 13:29:06 +02:00
treewide: update to bincode 2
Consistently use bincode's Encode/Decode to avoid issues with incompatible serde features. Support for storing some temporary files as JSON is removed. The size of the "processed" directory is reduced by ~8% with the new default encoding of bincode 2. Performance is more or less unaffected.
This commit is contained in:
parent
404ad74235
commit
53a0f24600
16 changed files with 133 additions and 81 deletions
|
@ -3,13 +3,15 @@
|
|||
use std::{
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
fmt::Debug,
|
||||
hash::Hash,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use bincode::{Decode, Encode};
|
||||
use clap::ValueEnum;
|
||||
use regex::{Regex, RegexSet};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
io::fs::FileMetaVersion,
|
||||
|
@ -24,7 +26,7 @@ use crate::{
|
|||
///
|
||||
/// Increase when the generation of processed regions from region data changes
|
||||
/// (usually because of updated resource data)
|
||||
pub const REGION_FILE_META_VERSION: FileMetaVersion = FileMetaVersion(5);
|
||||
pub const REGION_FILE_META_VERSION: FileMetaVersion = FileMetaVersion(6);
|
||||
|
||||
/// MinedMap map tile data version number
|
||||
///
|
||||
|
@ -46,7 +48,7 @@ pub const MIPMAP_FILE_META_VERSION: FileMetaVersion = FileMetaVersion(0);
|
|||
/// MinedMap processed entity data version number
|
||||
///
|
||||
/// Increase when entity collection changes bacause of code changes.
|
||||
pub const ENTITIES_FILE_META_VERSION: FileMetaVersion = FileMetaVersion(1);
|
||||
pub const ENTITIES_FILE_META_VERSION: FileMetaVersion = FileMetaVersion(2);
|
||||
|
||||
/// Coordinate pair of a generated tile
|
||||
///
|
||||
|
@ -85,7 +87,7 @@ impl TileCoordMap {
|
|||
}
|
||||
|
||||
/// Data structure for storing chunk data between processing and rendering steps
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Encode, Decode)]
|
||||
pub struct ProcessedChunk {
|
||||
/// Block type data
|
||||
pub blocks: Box<layer::BlockArray>,
|
||||
|
@ -96,7 +98,7 @@ pub struct ProcessedChunk {
|
|||
}
|
||||
|
||||
/// Data structure for storing region data between processing and rendering steps
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
#[derive(Debug, Default, Encode, Decode)]
|
||||
pub struct ProcessedRegion {
|
||||
/// List of biomes used in the region
|
||||
///
|
||||
|
@ -107,7 +109,7 @@ pub struct ProcessedRegion {
|
|||
}
|
||||
|
||||
/// Data structure for storing entity data between processing and collection steps
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
#[derive(Debug, Default, Encode, Decode)]
|
||||
pub struct ProcessedEntities {
|
||||
/// List of block entities
|
||||
pub block_entities: Vec<BlockEntity>,
|
||||
|
|
|
@ -78,23 +78,22 @@ impl<'a> EntityCollector<'a> {
|
|||
let mut output = ProcessedEntities::default();
|
||||
|
||||
for source_path in sources {
|
||||
let mut source: ProcessedEntities =
|
||||
match storage::read_file(source_path.as_ref(), storage::Format::Json) {
|
||||
Ok(source) => source,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"Failed to read entity data file {}: {:?}",
|
||||
source_path.as_ref().display(),
|
||||
err,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let mut source: ProcessedEntities = match storage::read_file(source_path.as_ref()) {
|
||||
Ok(source) => source,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"Failed to read entity data file {}: {:?}",
|
||||
source_path.as_ref().display(),
|
||||
err,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
output.block_entities.append(&mut source.block_entities);
|
||||
}
|
||||
|
||||
storage::write(file, &output, storage::Format::Json).context("Failed to write entity data")
|
||||
storage::write(file, &output).context("Failed to write entity data")
|
||||
}
|
||||
|
||||
/// Runs the mipmap generation
|
||||
|
|
|
@ -179,9 +179,8 @@ impl<'a> MetadataWriter<'a> {
|
|||
|
||||
/// Generates [Entities] data from collected entity lists
|
||||
fn entities(&self) -> Result<Entities> {
|
||||
let data: ProcessedEntities =
|
||||
storage::read_file(&self.config.entities_path_final, storage::Format::Json)
|
||||
.context("Failed to read entity data file")?;
|
||||
let data: ProcessedEntities = storage::read_file(&self.config.entities_path_final)
|
||||
.context("Failed to read entity data file")?;
|
||||
|
||||
let ret = Entities {
|
||||
signs: data
|
||||
|
|
|
@ -168,7 +168,6 @@ impl<'a> SingleRegionProcessor<'a> {
|
|||
storage::write_file(
|
||||
&self.output_path,
|
||||
&self.processed_region,
|
||||
storage::Format::Bincode,
|
||||
REGION_FILE_META_VERSION,
|
||||
self.input_timestamp,
|
||||
)
|
||||
|
@ -207,7 +206,6 @@ impl<'a> SingleRegionProcessor<'a> {
|
|||
storage::write_file(
|
||||
&self.entities_path,
|
||||
&self.entities,
|
||||
storage::Format::Json,
|
||||
ENTITIES_FILE_META_VERSION,
|
||||
self.input_timestamp,
|
||||
)
|
||||
|
|
|
@ -105,8 +105,7 @@ impl<'a> TileRenderer<'a> {
|
|||
|
||||
region_loader
|
||||
.get_or_try_init(|| async {
|
||||
storage::read_file(&processed_path, storage::Format::Bincode)
|
||||
.context("Failed to load processed region data")
|
||||
storage::read_file(&processed_path).context("Failed to load processed region data")
|
||||
})
|
||||
.await
|
||||
.cloned()
|
||||
|
|
|
@ -10,28 +10,16 @@ use std::{
|
|||
};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use bincode::{Decode, Encode};
|
||||
|
||||
use super::fs;
|
||||
|
||||
/// Storage format
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Format {
|
||||
/// Encode as Bincode
|
||||
///
|
||||
/// Bincode is more efficient than JSON, but cannot handle many of
|
||||
/// serde's features like flatten, conditional skipping, ...
|
||||
Bincode,
|
||||
/// Encode as JSON
|
||||
Json,
|
||||
}
|
||||
/// Bincode configuration
|
||||
const BINCODE_CONFIG: bincode::config::Configuration = bincode::config::standard();
|
||||
|
||||
/// Serializes data and writes it to a writer
|
||||
pub fn write<W: Write, T: Serialize>(writer: &mut W, value: &T, format: Format) -> Result<()> {
|
||||
let data = match format {
|
||||
Format::Bincode => bincode::serialize(value)?,
|
||||
Format::Json => serde_json::to_vec(value)?,
|
||||
};
|
||||
pub fn write<W: Write, T: Encode>(writer: &mut W, value: &T) -> Result<()> {
|
||||
let data = bincode::encode_to_vec(value, BINCODE_CONFIG)?;
|
||||
let len = u32::try_from(data.len())?;
|
||||
let compressed = zstd::bulk::compress(&data, 1)?;
|
||||
drop(data);
|
||||
|
@ -45,18 +33,21 @@ pub fn write<W: Write, T: Serialize>(writer: &mut W, value: &T, format: Format)
|
|||
/// Serializes data and stores it in a file
|
||||
///
|
||||
/// A timestamp is stored in an assiciated metadata file.
|
||||
pub fn write_file<T: Serialize>(
|
||||
pub fn write_file<T: Encode>(
|
||||
path: &Path,
|
||||
value: &T,
|
||||
format: Format,
|
||||
version: fs::FileMetaVersion,
|
||||
timestamp: SystemTime,
|
||||
) -> Result<()> {
|
||||
fs::create_with_timestamp(path, version, timestamp, |file| write(file, value, format))
|
||||
fs::create_with_timestamp(path, version, timestamp, |file| write(file, value))
|
||||
}
|
||||
|
||||
/// Reads data from a reader and deserializes it
|
||||
pub fn read<R: Read, T: DeserializeOwned>(reader: &mut R, format: Format) -> Result<T> {
|
||||
pub fn read<R, T>(reader: &mut R) -> Result<T>
|
||||
where
|
||||
R: Read,
|
||||
T: Decode<()>,
|
||||
{
|
||||
let mut len_buf = [0u8; 4];
|
||||
reader.read_exact(&mut len_buf)?;
|
||||
let len = usize::try_from(u32::from_be_bytes(len_buf))?;
|
||||
|
@ -66,18 +57,17 @@ pub fn read<R: Read, T: DeserializeOwned>(reader: &mut R, format: Format) -> Res
|
|||
let data = zstd::bulk::decompress(&compressed, len)?;
|
||||
drop(compressed);
|
||||
|
||||
let value = match format {
|
||||
Format::Bincode => bincode::deserialize(&data)?,
|
||||
Format::Json => serde_json::from_slice(&data)?,
|
||||
};
|
||||
Ok(value)
|
||||
Ok(bincode::decode_from_slice(&data, BINCODE_CONFIG)?.0)
|
||||
}
|
||||
|
||||
/// Reads data from a file and deserializes it
|
||||
pub fn read_file<T: DeserializeOwned>(path: &Path, format: Format) -> Result<T> {
|
||||
pub fn read_file<T>(path: &Path) -> Result<T>
|
||||
where
|
||||
T: Decode<()>,
|
||||
{
|
||||
(|| -> Result<T> {
|
||||
let mut file = File::open(path)?;
|
||||
read(&mut file, format)
|
||||
read(&mut file)
|
||||
})()
|
||||
.with_context(|| format!("Failed to read file {}", path.display()))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
//! Processing of block entity data
|
||||
|
||||
use bincode::{Decode, Encode};
|
||||
use minedmap_resource::{BlockFlag, BlockType};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Serialize;
|
||||
|
||||
use super::{
|
||||
de,
|
||||
|
@ -9,7 +10,7 @@ use super::{
|
|||
};
|
||||
|
||||
/// Kind of sign block
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum SignKind {
|
||||
/// Standing sign
|
||||
|
@ -23,7 +24,7 @@ pub enum SignKind {
|
|||
}
|
||||
|
||||
/// Processed sign data
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, Serialize)]
|
||||
pub struct Sign {
|
||||
/// The kind of the sign
|
||||
pub kind: SignKind,
|
||||
|
@ -54,7 +55,7 @@ impl Sign {
|
|||
}
|
||||
|
||||
/// Data for different kinds of [BlockEntity]
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, Serialize)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum BlockEntityData {
|
||||
/// A sign block
|
||||
|
@ -62,7 +63,7 @@ pub enum BlockEntityData {
|
|||
}
|
||||
|
||||
/// A processed block entity
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, Serialize)]
|
||||
pub struct BlockEntity {
|
||||
/// Global X coordinate
|
||||
pub x: i32,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use std::{collections::VecDeque, fmt::Display};
|
||||
|
||||
use bincode::{Decode, Encode};
|
||||
use minedmap_resource::Color;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
@ -12,7 +13,9 @@ use serde::{Deserialize, Serialize};
|
|||
/// is handled by [DeserializedText].
|
||||
///
|
||||
/// Formatting that is not set in a node is inherited from the parent.
|
||||
#[derive(Debug, Serialize, Deserialize, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(
|
||||
Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Encode, Decode,
|
||||
)]
|
||||
pub struct FormattedText {
|
||||
#[serde(default)]
|
||||
/// Text content
|
||||
|
@ -84,7 +87,7 @@ impl From<String> for FormattedTextTree {
|
|||
}
|
||||
|
||||
/// List of [FormattedText]
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Encode, Decode)]
|
||||
pub struct FormattedTextList(pub Vec<FormattedText>);
|
||||
|
||||
impl FormattedTextList {
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
use std::num::NonZeroU16;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use bincode::{Decode, Encode};
|
||||
use indexmap::IndexSet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::chunk::{Chunk, SectionIterItem};
|
||||
use crate::{
|
||||
|
@ -13,7 +13,7 @@ use crate::{
|
|||
};
|
||||
|
||||
/// Height (Y coordinate) of a block
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)]
|
||||
pub struct BlockHeight(pub i32);
|
||||
|
||||
impl BlockHeight {
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
use std::fmt::Display;
|
||||
|
||||
use bincode::{Decode, Encode};
|
||||
use minedmap_resource::Color;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Serialize;
|
||||
|
||||
use super::{
|
||||
de,
|
||||
|
@ -104,7 +105,7 @@ impl BlockEntitySignExt for de::BlockEntitySign {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, Default, Serialize, PartialEq, Eq, PartialOrd, Ord, Encode, Decode)]
|
||||
/// Deserialized and linearized sign text
|
||||
pub struct SignText(pub Vec<FormattedTextList>);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue