mirror of
https://github.com/neocturne/MinedMap.git
synced 2025-07-10 17:29:06 +02:00
Add documentation comments for all items
This commit is contained in:
parent
ba86dc8c06
commit
05a8056cbf
26 changed files with 576 additions and 42 deletions
|
@ -1,9 +1,12 @@
|
|||
//! Functions for reading and deserializing compressed NBT data
|
||||
|
||||
use std::{fs::File, io::prelude::*, path::Path};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use flate2::read::GzDecoder;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
/// Reads compressed NBT data from a reader and deserializes to a given data structure
|
||||
pub fn from_reader<R, T>(reader: R) -> Result<T>
|
||||
where
|
||||
R: Read,
|
||||
|
@ -18,6 +21,7 @@ where
|
|||
fastnbt::from_bytes(&buf).context("Failed to decode NBT data")
|
||||
}
|
||||
|
||||
/// Reads compressed NBT data from a file and deserializes to a given data structure
|
||||
pub fn from_file<P, T>(path: P) -> Result<T>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
|
|
38
src/io/fs.rs
38
src/io/fs.rs
|
@ -1,3 +1,5 @@
|
|||
//! Helpers and common functions for filesystem access
|
||||
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
io::{BufReader, BufWriter, Read, Write},
|
||||
|
@ -8,15 +10,25 @@ use std::{
|
|||
use anyhow::{Context, Ok, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A file metadata version number
|
||||
///
|
||||
/// Deserialized metadata with non-current version number are considered invalid
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct FileMetaVersion(pub u32);
|
||||
|
||||
/// Metadata stored with generated files to track required incremental updates
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct FileMeta {
|
||||
/// Version of data described by the FileMeta
|
||||
version: FileMetaVersion,
|
||||
/// Timestamp stored with generated data
|
||||
///
|
||||
/// This timestamp is always the time of last modification of the inputs
|
||||
/// that were used to generate the file described by the FileMeta.
|
||||
timestamp: SystemTime,
|
||||
}
|
||||
|
||||
/// Helper for creating suffixed file paths
|
||||
fn suffix_name(path: &Path, suffix: &str) -> PathBuf {
|
||||
let mut file_name = path.file_name().unwrap_or_default().to_os_string();
|
||||
file_name.push(suffix);
|
||||
|
@ -26,24 +38,35 @@ fn suffix_name(path: &Path, suffix: &str) -> PathBuf {
|
|||
ret
|
||||
}
|
||||
|
||||
/// Derives the filename for temporary storage of data during generation
|
||||
fn tmpfile_name(path: &Path) -> PathBuf {
|
||||
suffix_name(path, ".tmp")
|
||||
}
|
||||
|
||||
/// Derives the filename for associated metadata for generated files
|
||||
fn metafile_name(path: &Path) -> PathBuf {
|
||||
suffix_name(path, ".meta")
|
||||
}
|
||||
|
||||
/// Creates a directory including all its parents
|
||||
///
|
||||
/// Wrapper around [fs::create_dir_all] that adds a more descriptive error message
|
||||
pub fn create_dir_all(path: &Path) -> Result<()> {
|
||||
fs::create_dir_all(path)
|
||||
.with_context(|| format!("Failed to create directory {}", path.display(),))
|
||||
}
|
||||
|
||||
/// Renames a file or directory
|
||||
///
|
||||
/// Wrapper around [fs::rename] that adds a more descriptive error message
|
||||
pub fn rename(from: &Path, to: &Path) -> Result<()> {
|
||||
fs::rename(from, to)
|
||||
.with_context(|| format!("Failed to rename {} to {}", from.display(), to.display()))
|
||||
}
|
||||
|
||||
/// Creates a new file
|
||||
///
|
||||
/// The contents of the file are defined by the passed function.
|
||||
pub fn create<T, F>(path: &Path, f: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(&mut BufWriter<File>) -> Result<T>,
|
||||
|
@ -60,6 +83,7 @@ where
|
|||
.with_context(|| format!("Failed to write file {}", path.display()))
|
||||
}
|
||||
|
||||
/// Checks whether the contents of two files are equal
|
||||
pub fn equal(path1: &Path, path2: &Path) -> Result<bool> {
|
||||
let mut file1 = BufReader::new(
|
||||
fs::File::open(path1)
|
||||
|
@ -81,6 +105,12 @@ pub fn equal(path1: &Path, path2: &Path) -> Result<bool> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Creates a new file, temporarily storing its contents in a temporary file
|
||||
///
|
||||
/// Storing the data in a temporary file prevents leaving half-written files
|
||||
/// when the function is interrupted. In addition, the old and new contents of
|
||||
/// the file are compared if a file with the same name already exists, and the
|
||||
/// file timestamp is only updated if the contents have changed.
|
||||
pub fn create_with_tmpfile<T, F>(path: &Path, f: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(&mut BufWriter<File>) -> Result<T>,
|
||||
|
@ -104,6 +134,7 @@ where
|
|||
ret
|
||||
}
|
||||
|
||||
/// Returns the time of last modification for a given file path
|
||||
pub fn modified_timestamp(path: &Path) -> Result<SystemTime> {
|
||||
fs::metadata(path)
|
||||
.and_then(|meta| meta.modified())
|
||||
|
@ -115,6 +146,8 @@ pub fn modified_timestamp(path: &Path) -> Result<SystemTime> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Reads the stored timestamp from file metadata for a file previously written
|
||||
/// using [create_with_timestamp]
|
||||
pub fn read_timestamp(path: &Path, version: FileMetaVersion) -> Option<SystemTime> {
|
||||
let meta_path = metafile_name(path);
|
||||
let mut file = BufReader::new(fs::File::open(meta_path).ok()?);
|
||||
|
@ -127,6 +160,11 @@ pub fn read_timestamp(path: &Path, version: FileMetaVersion) -> Option<SystemTim
|
|||
Some(meta.timestamp)
|
||||
}
|
||||
|
||||
/// Creates a new file, temporarily storing its contents in a temporary file
|
||||
/// like [create_with_tmpfile], and storing a timestamp in a metadata file
|
||||
/// if successful
|
||||
///
|
||||
/// The timestamp can be retrieved later using [read_timestamp].
|
||||
pub fn create_with_timestamp<T, F>(
|
||||
path: &Path,
|
||||
version: FileMetaVersion,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Input/output functions
|
||||
|
||||
pub mod data;
|
||||
pub mod fs;
|
||||
pub mod region;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Functions for reading and deserializing region data
|
||||
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{prelude::*, SeekFrom},
|
||||
|
@ -10,15 +12,24 @@ use serde::de::DeserializeOwned;
|
|||
|
||||
use crate::types::*;
|
||||
|
||||
/// Data block size of region data files
|
||||
///
|
||||
/// After one header block, the region file consists of one or more consecutive blocks
|
||||
/// of data for each populated chunk.
|
||||
const BLOCKSIZE: usize = 4096;
|
||||
|
||||
/// Chunk descriptor extracted from region file header
|
||||
#[derive(Debug)]
|
||||
struct ChunkDesc {
|
||||
/// Offset of data block where the chunk starts
|
||||
offset: u32,
|
||||
/// Number of data block used by the chunk
|
||||
len: u8,
|
||||
/// Coodinates of chunk described by this descriptor
|
||||
coords: ChunkCoords,
|
||||
}
|
||||
|
||||
/// Parses the header of a region data file
|
||||
fn parse_header(header: &ChunkArray<u32>) -> Vec<ChunkDesc> {
|
||||
let mut chunks: Vec<_> = header
|
||||
.iter()
|
||||
|
@ -45,6 +56,7 @@ fn parse_header(header: &ChunkArray<u32>) -> Vec<ChunkDesc> {
|
|||
chunks
|
||||
}
|
||||
|
||||
/// Decompresses chunk data and deserializes to a given data structure
|
||||
fn decode_chunk<T>(buf: &[u8]) -> Result<T>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
|
@ -63,12 +75,18 @@ where
|
|||
fastnbt::from_bytes(&decode_buffer).context("Failed to decode NBT data")
|
||||
}
|
||||
|
||||
/// Wraps a reader used to read a region data file
|
||||
#[derive(Debug)]
|
||||
pub struct Region<R: Read + Seek> {
|
||||
/// The wrapper reader
|
||||
reader: R,
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> Region<R> {
|
||||
/// Iterates over the chunks of the region data
|
||||
///
|
||||
/// The order of iteration is based on the order the chunks appear in the
|
||||
/// data file.
|
||||
pub fn foreach_chunk<T, F>(self, mut f: F) -> Result<()>
|
||||
where
|
||||
R: Read + Seek,
|
||||
|
@ -126,6 +144,7 @@ impl<R: Read + Seek> Region<R> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new [Region] from a reader
|
||||
pub fn from_reader<R>(reader: R) -> Region<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
|
@ -133,6 +152,7 @@ where
|
|||
Region { reader }
|
||||
}
|
||||
|
||||
/// Creates a new [Region] for a file
|
||||
pub fn from_file<P>(path: P) -> Result<Region<File>>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
//! Functions for serializing and deserializing MinedMap data structures efficiently
|
||||
//!
|
||||
//! Data is serialized using Bincode and compressed using zstd.
|
||||
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{Read, Write},
|
||||
|
@ -10,6 +14,9 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||
|
||||
use super::fs;
|
||||
|
||||
/// Serializes data and stores it in a file
|
||||
///
|
||||
/// A timestamp is stored in an assiciated metadata file.
|
||||
pub fn write<T: Serialize>(
|
||||
path: &Path,
|
||||
value: &T,
|
||||
|
@ -29,6 +36,7 @@ pub fn write<T: Serialize>(
|
|||
})
|
||||
}
|
||||
|
||||
/// Reads data from a file and deserializes it
|
||||
pub fn read<T: DeserializeOwned>(path: &Path) -> Result<T> {
|
||||
(|| -> Result<T> {
|
||||
let mut file = File::open(path)?;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue