#![allow(incomplete_features)]
#![recursion_limit = "256"]
#![cfg_attr(feature = "nightly", feature(specialization))]
#![deny(missing_docs)]
#![deny(warnings)]
pub mod prelude;
extern crate alloc;
#[cfg(feature="arrayvec")]
extern crate arrayvec;
extern crate byteorder;
#[cfg(feature="parking_lot")]
extern crate parking_lot;
#[cfg(feature="smallvec")]
extern crate smallvec;
#[cfg(feature="parking_lot")]
use parking_lot::{Mutex, MutexGuard,RwLock, RwLockReadGuard};
use std::fs::File;
use std::io::{Read, BufReader, BufWriter};
use std::borrow::Cow;
use std::io::{Write};
use std::sync::atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU64, AtomicU8,
AtomicUsize, Ordering,
};
use self::byteorder::LittleEndian;
use std::collections::BinaryHeap;
use std::collections::VecDeque;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::hash::Hash;
#[allow(unused_imports)]
use std::mem::MaybeUninit;
#[cfg(feature="indexmap")]
extern crate indexmap;
#[cfg(feature="indexmap")]
use indexmap::{IndexMap,IndexSet};
#[cfg(feature="bit-vec")]
extern crate bit_vec;
#[cfg(feature="bzip2")]
extern crate bzip2;
#[cfg(feature="bit-set")]
extern crate bit_set;
#[cfg(feature="rustc-hash")]
extern crate rustc_hash;
extern crate core;
extern crate memoffset;
#[cfg(feature="derive")]
extern crate savefile_derive;
#[derive(Debug)]
#[must_use]
#[non_exhaustive]
pub enum SavefileError {
IncompatibleSchema {
message: String,
},
IOError {
io_error: std::io::Error,
},
InvalidUtf8 {
msg: String,
},
MemoryAllocationLayoutError,
ArrayvecCapacityError {
msg: String,
},
ShortRead,
CryptographyError,
SizeOverflow,
WrongVersion {
msg: String,
},
GeneralError {
msg: String,
},
PoisonedMutex,
CompressionSupportNotCompiledIn,
InvalidChar
}
impl Display for SavefileError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
SavefileError::IncompatibleSchema { message } => {
write!(f,"Incompatible schema: {}", message)
}
SavefileError::IOError { io_error } => {
write!(f,"IO error: {}", io_error)
}
SavefileError::InvalidUtf8 { msg } => {
write!(f,"Invalid UTF-8: {}", msg)
}
SavefileError::MemoryAllocationLayoutError => {
write!(f,"Memory allocation layout error")
}
SavefileError::ArrayvecCapacityError { msg } => {
write!(f,"Arrayvec capacity error: {}",msg)
}
SavefileError::ShortRead => {
write!(f,"Short read")
}
SavefileError::CryptographyError => {
write!(f,"Cryptography error")
}
SavefileError::SizeOverflow => {
write!(f, "Size overflow")
}
SavefileError::WrongVersion { msg } => {
write!(f, "Wrong version: {}", msg)
}
SavefileError::GeneralError { msg } => {
write!(f, "General error: {}", msg)
}
SavefileError::PoisonedMutex => {
write!(f, "Poisoned mutex")
}
SavefileError::CompressionSupportNotCompiledIn => {
write!(f, "Compression support missing - recompile with bzip2 feature enabled.")
}
SavefileError::InvalidChar => {
write!(f, "Invalid char value encountered.")
}
}
}
}
impl std::error::Error for SavefileError {
}
pub struct Serializer<'a, W:Write> {
pub writer: &'a mut W,
pub version: u32,
}
pub struct Deserializer<'a, R: Read> {
reader: &'a mut R,
pub file_version: u32,
pub memory_version: u32,
ephemeral_state: HashMap<TypeId, Box<dyn Any>>,
}
impl<'a, TR: Read> Deserializer<'a, TR> {
pub fn get_state<T: 'static, R: Default + 'static>(&mut self) -> &mut R {
let type_id = TypeId::of::<T>();
let the_any = self
.ephemeral_state
.entry(type_id)
.or_insert_with(|| Box::new(R::default()));
the_any.downcast_mut().unwrap()
}
}
#[derive(Default, Debug)]
pub struct IsReprC(bool);
impl std::ops::BitAnd<IsReprC> for IsReprC {
type Output = IsReprC;
fn bitand(self, rhs: Self) -> Self::Output {
IsReprC(self.0 && rhs.0)
}
}
impl IsReprC {
pub unsafe fn yes() -> IsReprC {
IsReprC(true)
}
pub fn no() -> IsReprC {
IsReprC(false)
}
#[inline(always)]
pub fn is_false(self) -> bool {
!self.0
}
#[inline(always)]
pub fn is_yes(self) -> bool {
self.0
}
}
pub trait ReprC {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC { IsReprC::no()}
}
impl From<std::io::Error> for SavefileError {
fn from(s: std::io::Error) -> SavefileError {
SavefileError::IOError { io_error: s }
}
}
impl<T> From<std::sync::PoisonError<T>> for SavefileError {
fn from(_: std::sync::PoisonError<T>) -> SavefileError {
SavefileError::PoisonedMutex
}
}
impl From<std::string::FromUtf8Error> for SavefileError {
fn from(s: std::string::FromUtf8Error) -> SavefileError {
SavefileError::InvalidUtf8 { msg: s.to_string() }
}
}
#[cfg(feature="arrayvec")]
impl<T> From<arrayvec::CapacityError<T>> for SavefileError {
fn from(s: arrayvec::CapacityError<T>) -> SavefileError {
SavefileError::ArrayvecCapacityError { msg: s.to_string() }
}
}
impl WithSchema for PathBuf {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_string)
}
}
impl Serialize for PathBuf {
fn serialize<'a>(&self, serializer: &mut Serializer<'a,impl Write>) -> Result<(), SavefileError> {
let as_string: String = self.to_string_lossy().to_string();
as_string.serialize(serializer)
}
}
impl ReprC for PathBuf {}
impl Deserialize for PathBuf {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(PathBuf::from(String::deserialize(deserializer)?))
}
}
impl Introspect for PathBuf {
fn introspect_value(&self) -> String {
self.to_string_lossy().to_string()
}
fn introspect_child<'a>(&'a self, _index: usize) -> Option<Box<dyn IntrospectItem<'a>>> {
None
}
}
impl<'a, T: 'a + WithSchema + ToOwned + ?Sized> WithSchema for Cow<'a, T> {
fn schema(version: u32) -> Schema {
T::schema(version)
}
}
impl<'a, T: 'a + ToOwned +?Sized> ReprC for Cow<'a, T> {}
impl<'a, T: 'a + Serialize + ToOwned + ?Sized> Serialize for Cow<'a, T> {
fn serialize<'b>(&self, serializer: &mut Serializer<'b, impl Write>) -> Result<(), SavefileError> {
(**self).serialize(serializer)
}
}
impl<'a, T: 'a + WithSchema + ToOwned + ?Sized> Deserialize for Cow<'a, T>
where
T::Owned: Deserialize,
{
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(Cow::Owned(<T as ToOwned>::Owned::deserialize(deserializer)?))
}
}
impl<'a, T: 'a + Introspect + ToOwned + ?Sized> Introspect for Cow<'a, T> {
fn introspect_value(&self) -> String {
(**self).introspect_value()
}
fn introspect_child<'b>(&'b self, index: usize) -> Option<Box<dyn IntrospectItem<'b> + 'b>> {
(**self).introspect_child(index)
}
fn introspect_len(&self) -> usize {
(**self).introspect_len()
}
}
#[cfg(feature="ring")]
mod crypto {
use std::fs::File;
use std::io::{Error, ErrorKind, Read, Write};
use std::path::Path;
use ring::aead;
use ring::aead::{BoundKey, Nonce, NonceSequence, OpeningKey, SealingKey, UnboundKey, AES_256_GCM};
use ring::error::Unspecified;
extern crate rand;
use byteorder::{LittleEndian, ReadBytesExt};
use byteorder::WriteBytesExt;
use rand::rngs::OsRng;
use rand::RngCore;
use crate::{Deserialize, Deserializer, SavefileError, Serialize, Serializer, WithSchema};
extern crate ring;
#[derive(Debug)]
struct RandomNonceSequence {
data1: u64,
data2: u32,
}
impl RandomNonceSequence {
pub fn new() -> RandomNonceSequence {
RandomNonceSequence {
data1: OsRng.next_u64(),
data2: OsRng.next_u32(),
}
}
pub fn serialize(&self, writer: &mut dyn Write) -> Result<(), SavefileError> {
writer.write_u64::<LittleEndian>(self.data1)?;
writer.write_u32::<LittleEndian>(self.data2)?;
Ok(())
}
pub fn deserialize(reader: &mut dyn Read) -> Result<RandomNonceSequence, SavefileError> {
Ok(RandomNonceSequence {
data1: reader.read_u64::<LittleEndian>()?,
data2: reader.read_u32::<LittleEndian>()?,
})
}
}
impl NonceSequence for RandomNonceSequence {
fn advance(&mut self) -> Result<Nonce, Unspecified> {
self.data2 = self.data2.wrapping_add(1);
if self.data2 == 0 {
self.data1 = self.data1.wrapping_add(1);
}
use std::mem::transmute;
let mut bytes = [0u8; 12];
let bytes1: [u8; 8] = unsafe { transmute(self.data1.to_le()) };
let bytes2: [u8; 4] = unsafe { transmute(self.data2.to_le()) };
for i in 0..8 {
bytes[i] = bytes1[i];
}
for i in 0..4 {
bytes[i + 8] = bytes2[i];
}
Ok(Nonce::assume_unique_for_key(bytes))
}
}
pub struct CryptoWriter<'a> {
writer: &'a mut dyn Write,
buf: Vec<u8>,
sealkey: SealingKey<RandomNonceSequence>,
failed: bool,
}
pub struct CryptoReader<'a> {
reader: &'a mut dyn Read,
buf: Vec<u8>,
offset: usize,
openingkey: OpeningKey<RandomNonceSequence>,
}
impl<'a> CryptoReader<'a> {
pub fn new(reader: &'a mut dyn Read, key_bytes: [u8; 32]) -> Result<CryptoReader<'a>, SavefileError> {
let unboundkey = UnboundKey::new(&AES_256_GCM, &key_bytes).unwrap();
let nonce_sequence = RandomNonceSequence::deserialize(reader)?;
let openingkey = OpeningKey::new(unboundkey, nonce_sequence);
Ok(CryptoReader {
reader,
offset: 0,
buf: Vec::new(),
openingkey,
})
}
}
const CRYPTO_BUFSIZE: usize = 100_000;
impl<'a> Drop for CryptoWriter<'a> {
fn drop(&mut self) {
self.flush().expect("The implicit flush in the Drop of CryptoWriter failed. This causes this panic. If you want to be able to handle this, make sure to call flush() manually. If a manual flush has failed, Drop won't panic.");
}
}
impl<'a> CryptoWriter<'a> {
pub fn new(writer: &'a mut dyn Write, key_bytes: [u8; 32]) -> Result<CryptoWriter<'a>, SavefileError> {
let unboundkey = UnboundKey::new(&AES_256_GCM, &key_bytes).unwrap();
let nonce_sequence = RandomNonceSequence::new();
nonce_sequence.serialize(writer)?;
let sealkey = SealingKey::new(unboundkey, nonce_sequence);
Ok(CryptoWriter {
writer,
buf: Vec::new(),
sealkey,
failed: false,
})
}
pub fn flush_final(mut self) -> Result<(), SavefileError> {
if self.failed {
panic!("Call to failed CryptoWriter");
}
self.flush()?;
Ok(())
}
}
impl<'a> Read for CryptoReader<'a> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
loop {
if buf.len() <= self.buf.len() - self.offset {
buf.clone_from_slice(&self.buf[self.offset..self.offset + buf.len()]);
self.offset += buf.len();
return Ok(buf.len());
}
{
let oldlen = self.buf.len();
let newlen = self.buf.len() - self.offset;
self.buf.copy_within(self.offset..oldlen, 0);
self.buf.resize(newlen, 0);
self.offset = 0;
}
let mut sizebuf = [0; 8];
let mut sizebuf_bytes_read = 0;
loop {
match self.reader.read(&mut sizebuf[sizebuf_bytes_read..]) {
Ok(gotsize) => {
if gotsize == 0 {
if sizebuf_bytes_read == 0 {
let cur_content_size = self.buf.len() - self.offset;
buf[0..cur_content_size]
.clone_from_slice(&self.buf[self.offset..self.offset + cur_content_size]);
self.offset += cur_content_size;
return Ok(cur_content_size);
} else {
return Err(Error::new(ErrorKind::UnexpectedEof, "Unexpected EOF"));
}
} else {
sizebuf_bytes_read += gotsize;
assert!(sizebuf_bytes_read <= 8);
}
}
Err(err) => return Err(err),
}
if sizebuf_bytes_read == 8 {
break;
}
}
use byteorder::ByteOrder;
let curlen = byteorder::LittleEndian::read_u64(&sizebuf) as usize;
if curlen > CRYPTO_BUFSIZE + 16 {
return Err(Error::new(ErrorKind::Other, "Cryptography error"));
}
let orglen = self.buf.len();
self.buf.resize(orglen + curlen, 0);
self.reader.read_exact(&mut self.buf[orglen..orglen + curlen])?;
match self
.openingkey
.open_in_place(aead::Aad::empty(), &mut self.buf[orglen..])
{
Ok(_) => {}
Err(_) => {
return Err(Error::new(ErrorKind::Other, "Cryptography error"));
}
}
self.buf.resize(self.buf.len() - 16, 0);
}
}
}
impl<'a> Write for CryptoWriter<'a> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
if self.failed {
panic!("Call to failed CryptoWriter");
}
self.buf.extend(buf);
if self.buf.len() > CRYPTO_BUFSIZE {
self.flush()?;
}
Ok(buf.len())
}
fn flush(&mut self) -> Result<(), Error> {
self.failed = true;
let mut offset = 0;
let mut tempbuf = Vec::new();
if self.buf.len() > CRYPTO_BUFSIZE {
tempbuf = Vec::<u8>::with_capacity(CRYPTO_BUFSIZE + 16);
}
while self.buf.len() > offset {
let curbuf;
if offset == 0 && self.buf.len() <= CRYPTO_BUFSIZE {
curbuf = &mut self.buf;
} else {
let chunksize = (self.buf.len() - offset).min(CRYPTO_BUFSIZE);
tempbuf.resize(chunksize, 0u8);
tempbuf.clone_from_slice(&self.buf[offset..offset + chunksize]);
curbuf = &mut tempbuf;
}
let expected_final_len = curbuf.len() as u64 + 16;
debug_assert!(expected_final_len <= CRYPTO_BUFSIZE as u64 + 16);
self.writer.write_u64::<LittleEndian>(expected_final_len)?; match self.sealkey.seal_in_place_append_tag(aead::Aad::empty(), curbuf) {
Ok(_) => {}
Err(_) => {
return Err(Error::new(ErrorKind::Other, "Cryptography error"));
}
}
debug_assert!(curbuf.len() == expected_final_len as usize, "The size of the TAG generated by the AES 256 GCM in ring seems to have changed! This is very unexpected. File a bug on the savefile-crate");
self.writer.write_all(&curbuf[..])?;
self.writer.flush()?;
offset += curbuf.len() - 16;
curbuf.resize(curbuf.len() - 16, 0);
}
self.buf.clear();
self.failed = false;
Ok(())
}
}
pub fn save_encrypted_file<T: WithSchema + Serialize, P:AsRef<Path>>(
filepath: P,
version: u32,
data: &T,
password: &str,
) -> Result<(), SavefileError> {
use ring::digest;
let actual = digest::digest(&digest::SHA256, password.as_bytes());
let mut key = [0u8; 32];
let password_hash = actual.as_ref();
assert_eq!(password_hash.len(), key.len(), "A SHA256 sum must be 32 bytes");
key.clone_from_slice(password_hash);
let mut f = File::create(filepath)?;
let mut writer = CryptoWriter::new(&mut f, key)?;
Serializer::<CryptoWriter>::save::<T>(&mut writer, version, data, true)?;
writer.flush()?;
Ok(())
}
pub fn load_encrypted_file<T: WithSchema + Deserialize, P:AsRef<Path>>(
filepath: P,
version: u32,
password: &str,
) -> Result<T, SavefileError> {
use ring::digest;
let actual = digest::digest(&digest::SHA256, password.as_bytes());
let mut key = [0u8; 32];
let password_hash = actual.as_ref();
assert_eq!(password_hash.len(), key.len(), "A SHA256 sum must be 32 bytes");
key.clone_from_slice(password_hash);
let mut f = File::open(filepath)?;
let mut reader = CryptoReader::new(&mut f, key).unwrap();
Deserializer::<CryptoReader>::load::<T>(&mut reader, version)
}
}
#[cfg(feature="ring")]
pub use crypto::{CryptoReader,CryptoWriter, save_encrypted_file, load_encrypted_file};
impl<'a, W:Write+'a> Serializer<'a, W> {
#[inline(always)]
pub fn write_bool(&mut self, v: bool) -> Result<(), SavefileError> {
Ok(self.writer.write_u8(if v { 1 } else { 0 })?)
}
#[inline(always)]
pub fn write_u8(&mut self, v: u8) -> Result<(), SavefileError> {
Ok(self.writer.write_all(&[v])?)
}
#[inline(always)]
pub fn write_i8(&mut self, v: i8) -> Result<(), SavefileError> {
Ok(self.writer.write_i8(v)?)
}
#[inline(always)]
pub fn write_u16(&mut self, v: u16) -> Result<(), SavefileError> {
Ok(self.writer.write_u16::<LittleEndian>(v)?)
}
#[inline(always)]
pub fn write_i16(&mut self, v: i16) -> Result<(), SavefileError> {
Ok(self.writer.write_i16::<LittleEndian>(v)?)
}
#[inline(always)]
pub fn write_u32(&mut self, v: u32) -> Result<(), SavefileError> {
Ok(self.writer.write_u32::<LittleEndian>(v)?)
}
#[inline(always)]
pub fn write_i32(&mut self, v: i32) -> Result<(), SavefileError> {
Ok(self.writer.write_i32::<LittleEndian>(v)?)
}
#[inline(always)]
pub fn write_f32(&mut self, v: f32) -> Result<(), SavefileError> {
Ok(self.writer.write_f32::<LittleEndian>(v)?)
}
#[inline(always)]
pub fn write_f64(&mut self, v: f64) -> Result<(), SavefileError> {
Ok(self.writer.write_f64::<LittleEndian>(v)?)
}
#[inline(always)]
pub fn write_u64(&mut self, v: u64) -> Result<(), SavefileError> {
Ok(self.writer.write_u64::<LittleEndian>(v)?)
}
#[inline(always)]
pub fn write_i64(&mut self, v: i64) -> Result<(), SavefileError> {
Ok(self.writer.write_i64::<LittleEndian>(v)?)
}
#[inline(always)]
pub fn write_u128(&mut self, v: u128) -> Result<(), SavefileError> {
Ok(self.writer.write_u128::<LittleEndian>(v)?)
}
#[inline(always)]
pub fn write_i128(&mut self, v: i128) -> Result<(), SavefileError> {
Ok(self.writer.write_i128::<LittleEndian>(v)?)
}
#[inline(always)]
pub fn write_usize(&mut self, v: usize) -> Result<(), SavefileError> {
Ok(self.writer.write_u64::<LittleEndian>(v as u64)?)
}
#[inline(always)]
pub fn write_isize(&mut self, v: isize) -> Result<(), SavefileError> {
Ok(self.writer.write_i64::<LittleEndian>(v as i64)?)
}
#[inline(always)]
pub fn write_buf(&mut self, v: &[u8]) -> Result<(), SavefileError> {
Ok(self.writer.write_all(v)?)
}
#[inline(always)]
pub fn write_string(&mut self, v: &str) -> Result<(), SavefileError> {
let asb = v.as_bytes();
self.write_usize(asb.len())?;
Ok(self.writer.write_all(asb)?)
}
#[inline(always)]
pub fn write_bytes(&mut self, v: &[u8]) -> Result<(), SavefileError> {
Ok(self.writer.write_all(v)?)
}
#[inline(always)]
#[doc(hidden)]
pub unsafe fn raw_write_region<T, T1:ReprC,T2:ReprC>(&mut self, full: &T, t1: &T1, t2: &T2, version: u32) -> Result<(), SavefileError> {
assert!(T1::repr_c_optimization_safe(version).is_yes());
assert!(T2::repr_c_optimization_safe(version).is_yes());
let base = full as *const T as *const u8;
let totlen = std::mem::size_of::<T>();
let p1 = (t1 as *const T1 as *const u8) as usize;
let p2 = (t2 as *const T2 as *const u8) as usize;
let start = p1 - (base as usize);
let end = (p2 - (base as usize)) + std::mem::size_of::<T2>();
let full_slice = std::slice::from_raw_parts(base, totlen);
Ok(self.writer.write_all(&full_slice[start..end])?)
}
pub fn save<T: WithSchema + Serialize>(
writer: &mut W,
version: u32,
data: &T,
with_compression: bool,
) -> Result<(), SavefileError> {
Ok(Self::save_impl(writer, version, data, true, with_compression)?)
}
pub fn save_noschema<T: WithSchema + Serialize>(
writer: &mut W,
version: u32,
data: &T,
) -> Result<(), SavefileError> {
Ok(Self::save_impl(writer, version, data, false, false)?)
}
fn save_impl<T: WithSchema + Serialize>(
writer: &mut W,
version: u32,
data: &T,
with_schema: bool,
with_compression: bool,
) -> Result<(), SavefileError> {
let header = "savefile\0".to_string().into_bytes();
writer.write_all(&header)?; writer.write_u16::<LittleEndian>(0 )?;
writer.write_u32::<LittleEndian>(version)?;
{
if with_compression {
writer.write_u8(1)?; #[cfg(feature="bzip2")]
{
let mut compressed_writer = bzip2::write::BzEncoder::new(writer, Compression::best());
if with_schema {
let schema = T::schema(version);
let mut schema_serializer = Serializer::<bzip2::write::BzEncoder<W>>::new_raw(&mut compressed_writer);
schema.serialize(&mut schema_serializer)?;
}
let mut serializer = Serializer { writer: &mut compressed_writer, version };
data.serialize(&mut serializer)?;
compressed_writer.flush()?;
return Ok(())
}
#[cfg(not(feature="bzip2"))]
{
return Err(SavefileError::CompressionSupportNotCompiledIn);
}
} else {
writer.write_u8(0)?;
if with_schema {
let schema = T::schema(version);
let mut schema_serializer = Serializer::<W>::new_raw(writer);
schema.serialize(&mut schema_serializer)?;
}
let mut serializer = Serializer { writer, version };
data.serialize(&mut serializer)?;
writer.flush()?;
Ok(())
}
}
}
pub fn new_raw(writer: &mut impl Write) -> Serializer<impl Write> {
Serializer { writer, version: 0 }
}
}
impl<'a, TR:Read> Deserializer<'a, TR> {
pub fn read_bool(&mut self) -> Result<bool, SavefileError> {
Ok(self.reader.read_u8()? == 1)
}
pub fn read_u8(&mut self) -> Result<u8, SavefileError> {
let mut buf = [0u8];
self.reader.read_exact(&mut buf)?;
Ok(buf[0])
}
pub fn read_u16(&mut self) -> Result<u16, SavefileError> {
Ok(self.reader.read_u16::<LittleEndian>()?)
}
pub fn read_u32(&mut self) -> Result<u32, SavefileError> {
Ok(self.reader.read_u32::<LittleEndian>()?)
}
pub fn read_u64(&mut self) -> Result<u64, SavefileError> {
Ok(self.reader.read_u64::<LittleEndian>()?)
}
pub fn read_u128(&mut self) -> Result<u128, SavefileError> {
Ok(self.reader.read_u128::<LittleEndian>()?)
}
pub fn read_i8(&mut self) -> Result<i8, SavefileError> {
Ok(self.reader.read_i8()?)
}
pub fn read_i16(&mut self) -> Result<i16, SavefileError> {
Ok(self.reader.read_i16::<LittleEndian>()?)
}
pub fn read_i32(&mut self) -> Result<i32, SavefileError> {
Ok(self.reader.read_i32::<LittleEndian>()?)
}
pub fn read_i64(&mut self) -> Result<i64, SavefileError> {
Ok(self.reader.read_i64::<LittleEndian>()?)
}
pub fn read_i128(&mut self) -> Result<i128, SavefileError> {
Ok(self.reader.read_i128::<LittleEndian>()?)
}
pub fn read_f32(&mut self) -> Result<f32, SavefileError> {
Ok(self.reader.read_f32::<LittleEndian>()?)
}
pub fn read_f64(&mut self) -> Result<f64, SavefileError> {
Ok(self.reader.read_f64::<LittleEndian>()?)
}
pub fn read_isize(&mut self) -> Result<isize, SavefileError> {
if let Ok(val) = TryFrom::try_from(self.reader.read_i64::<LittleEndian>()? as isize) {
Ok(val)
} else {
Err(SavefileError::SizeOverflow)
}
}
pub fn read_usize(&mut self) -> Result<usize, SavefileError> {
if let Ok(val) = TryFrom::try_from(self.reader.read_u64::<LittleEndian>()? as usize) {
Ok(val)
} else {
Err(SavefileError::SizeOverflow)
}
}
pub fn read_string(&mut self) -> Result<String, SavefileError> {
let l = self.read_usize()?;
#[cfg(feature = "size_sanity_checks")]
{
if l > 1_000_000 {
return Err(SavefileError::GeneralError {
msg: format!("String too large"),
});
}
}
let mut v = Vec::with_capacity(l);
v.resize(l, 0); self.reader.read_exact(&mut v)?;
Ok(String::from_utf8(v)?)
}
pub fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>, SavefileError> {
let mut v = Vec::with_capacity(len);
v.resize(len, 0); self.reader.read_exact(&mut v)?;
Ok(v)
}
pub fn read_bytes_to_buf(&mut self, buf: &mut [u8]) -> Result<(), SavefileError> {
self.reader.read_exact(buf)?;
Ok(())
}
pub fn load<T: WithSchema + Deserialize>(reader: &mut TR, version: u32) -> Result<T, SavefileError> {
Deserializer::<_>::load_impl::<T>(reader, version, true)
}
pub fn load_noschema<T: WithSchema + Deserialize>(reader: &mut TR, version: u32) -> Result<T, SavefileError> {
Deserializer::<TR>::load_impl::<T>(reader, version, false)
}
fn load_impl<T: WithSchema + Deserialize>(
reader: &mut TR,
version: u32,
fetch_schema: bool,
) -> Result<T, SavefileError> {
let mut head: [u8; 9] = [0u8; 9];
reader.read_exact(&mut head)?;
if &head[..] != &("savefile\0".to_string().into_bytes())[..] {
return Err(SavefileError::GeneralError {msg: "File is not in new savefile-format. If you have a file in old format, contact crate author and we'll work something out! It is not the intention that binary compatibility will be broken any more in the future.".into()});
}
let savefile_lib_version = reader.read_u16::<LittleEndian>()?;
if savefile_lib_version != 0 {
return Err(SavefileError::GeneralError {msg: "This file has been created by an earlier, incompatible version of the savefile crate (0.5.0 or before).".into()});
}
let file_ver = reader.read_u32::<LittleEndian>()?;
if file_ver > version {
return Err(SavefileError::WrongVersion {
msg: format!(
"File has later version ({}) than structs in memory ({}).",
file_ver, version
),
});
}
let with_compression = reader.read_u8()? != 0;
if with_compression {
#[cfg(feature="bzip2")]
{
let mut compressed_reader = bzip2::read::BzDecoder::new(reader);
if fetch_schema {
let mut schema_deserializer = Deserializer::<bzip2::read::BzDecoder<TR>>::new_raw(&mut compressed_reader);
let memory_schema = T::schema(file_ver);
let file_schema = Schema::deserialize(&mut schema_deserializer)?;
if let Some(err) = diff_schema(&memory_schema, &file_schema, ".".to_string()) {
return Err(SavefileError::IncompatibleSchema {
message: format!(
"Saved schema differs from in-memory schema for version {}. Error: {}",
file_ver, err
),
});
}
}
let mut deserializer = Deserializer {
reader: &mut compressed_reader,
file_version: file_ver,
memory_version: version,
ephemeral_state: HashMap::new(),
};
Ok(T::deserialize(&mut deserializer)?)
}
#[cfg(not(feature="bzip2"))]
{
return Err(SavefileError::CompressionSupportNotCompiledIn);
}
} else {
if fetch_schema {
let mut schema_deserializer = Deserializer::<TR>::new_raw(reader);
let memory_schema = T::schema(file_ver);
let file_schema = Schema::deserialize(&mut schema_deserializer)?;
if let Some(err) = diff_schema(&memory_schema, &file_schema, ".".to_string()) {
return Err(SavefileError::IncompatibleSchema {
message: format!(
"Saved schema differs from in-memory schema for version {}. Error: {}",
file_ver, err
),
});
}
}
let mut deserializer = Deserializer {
reader,
file_version: file_ver,
memory_version: version,
ephemeral_state: HashMap::new(),
};
Ok(T::deserialize(&mut deserializer)?)
}
}
pub fn new_raw(reader: &mut impl Read) -> Deserializer<impl Read> {
Deserializer {
reader,
file_version: 0,
memory_version: 0,
ephemeral_state: HashMap::new(),
}
}
}
pub fn load<T: WithSchema + Deserialize>(reader: &mut impl Read, version: u32) -> Result<T, SavefileError> {
Deserializer::<_>::load::<T>(reader, version)
}
pub fn load_from_mem<T: WithSchema + Deserialize>(input: &[u8], version: u32) -> Result<T, SavefileError> {
let mut input = input;
Deserializer::load::<T>(&mut input, version)
}
pub fn save<T: WithSchema + Serialize>(writer: &mut impl Write, version: u32, data: &T) -> Result<(), SavefileError> {
Serializer::save::<T>(writer, version, data, false)
}
pub fn save_compressed<T: WithSchema + Serialize>(
writer: &mut impl Write,
version: u32,
data: &T,
) -> Result<(), SavefileError> {
Serializer::save::<T>(writer, version, data, true)
}
pub fn save_to_mem<T: WithSchema + Serialize>(version: u32, data: &T) -> Result<Vec<u8>, SavefileError> {
let mut retval = Vec::new();
Serializer::save::<T>(&mut retval, version, data, false)?;
Ok(retval)
}
pub fn load_noschema<T: WithSchema + Deserialize>(reader: &mut impl Read, version: u32) -> Result<T, SavefileError> {
Deserializer::<_>::load_noschema::<T>(reader, version)
}
pub fn save_noschema<T: WithSchema + Serialize>(
writer: &mut impl Write,
version: u32,
data: &T,
) -> Result<(), SavefileError> {
Serializer::save_noschema::<T>(writer, version, data)
}
pub fn load_file<T: WithSchema + Deserialize,P:AsRef<Path>>(filepath: P, version: u32) -> Result<T, SavefileError> {
let mut f = BufReader::new(File::open(filepath)?);
Deserializer::load::<T>(&mut f, version)
}
pub fn save_file<T: WithSchema + Serialize, P:AsRef<Path>>(filepath: P, version: u32, data: &T) -> Result<(), SavefileError> {
let mut f = BufWriter::new(File::create(filepath)?);
Serializer::save::<T>(&mut f, version, data, false)
}
pub fn load_file_noschema<T: WithSchema + Deserialize, P: AsRef<Path>>(filepath: P, version: u32) -> Result<T, SavefileError> {
let mut f = BufReader::new(File::open(filepath)?);
Deserializer::load_noschema::<T>(&mut f, version)
}
pub fn save_file_noschema<T: WithSchema + Serialize, P:AsRef<Path>>(
filepath: P,
version: u32,
data: &T,
) -> Result<(), SavefileError> {
let mut f = BufWriter::new(File::create(filepath)?);
Serializer::save_noschema::<T>(&mut f, version, data)
}
pub trait WithSchema {
fn schema(version: u32) -> Schema;
}
pub trait Serialize: WithSchema {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError>; }
pub trait IntrospectItem<'a> {
fn key(&self) -> &str;
fn val(&self) -> &dyn Introspect;
}
struct NullIntrospectable {}
static THE_NULL_INTROSPECTABLE: NullIntrospectable = NullIntrospectable{};
impl Introspect for NullIntrospectable {
fn introspect_value(&self) -> String {
String::new()
}
fn introspect_child<'a>(&'a self, _index: usize) -> Option<Box<dyn IntrospectItem<'a> + 'a>> {
None
}
fn introspect_len(&self) -> usize {
0
}
}
impl<'a> IntrospectItem<'a> for String {
fn key(&self) -> &str {
&self
}
fn val(&self) -> &dyn Introspect {
&THE_NULL_INTROSPECTABLE
}
}
pub const MAX_CHILDREN: usize = 10000;
pub trait Introspect {
fn introspect_value(&self) -> String;
fn introspect_child<'a>(&'a self, index: usize) -> Option<Box<dyn IntrospectItem<'a> + 'a>>;
fn introspect_len(&self) -> usize {
for child_index in 0..MAX_CHILDREN {
if self.introspect_child(child_index).is_none() {
return child_index;
}
}
return MAX_CHILDREN;
}
}
pub trait Deserialize: WithSchema + Sized {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError>; }
#[derive(Debug, PartialEq)]
pub struct Field {
pub name: String,
pub value: Box<Schema>,
}
#[derive(Debug, PartialEq)]
pub struct SchemaArray {
pub item_type: Box<Schema>,
pub count: usize,
}
impl SchemaArray {
fn serialized_size(&self) -> Option<usize> {
self.item_type.serialized_size().map(|x| x * self.count)
}
}
#[derive(Debug, PartialEq)]
pub struct SchemaStruct {
pub dbg_name: String,
pub fields: Vec<Field>,
}
fn maybe_add(a: Option<usize>, b: Option<usize>) -> Option<usize> {
if let Some(a) = a {
if let Some(b) = b {
return Some(a + b);
}
}
None
}
impl SchemaStruct {
fn serialized_size(&self) -> Option<usize> {
self.fields
.iter()
.fold(Some(0usize), |prev, x| maybe_add(prev, x.value.serialized_size()))
}
}
#[derive(Debug, PartialEq)]
pub struct Variant {
pub name: String,
pub discriminator: u8,
pub fields: Vec<Field>,
}
impl Variant {
fn serialized_size(&self) -> Option<usize> {
self.fields
.iter()
.fold(Some(0usize), |prev, x| maybe_add(prev, x.value.serialized_size()))
}
}
#[derive(Debug, PartialEq)]
pub struct SchemaEnum {
pub dbg_name: String,
pub variants: Vec<Variant>,
}
fn maybe_max(a: Option<usize>, b: Option<usize>) -> Option<usize> {
if let Some(a) = a {
if let Some(b) = b {
return Some(a.max(b));
}
}
None
}
impl SchemaEnum {
fn serialized_size(&self) -> Option<usize> {
let discr_size = 1usize; self.variants
.iter()
.fold(Some(discr_size), |prev, x| maybe_max(prev, x.serialized_size()))
}
}
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum SchemaPrimitive {
schema_i8,
schema_u8,
schema_i16,
schema_u16,
schema_i32,
schema_u32,
schema_i64,
schema_u64,
schema_string,
schema_f32,
schema_f64,
schema_bool,
schema_canary1,
schema_u128,
schema_i128,
schema_char
}
impl SchemaPrimitive {
fn name(&self) -> &'static str {
match *self {
SchemaPrimitive::schema_i8 => "i8",
SchemaPrimitive::schema_u8 => "u8",
SchemaPrimitive::schema_i16 => "i16",
SchemaPrimitive::schema_u16 => "u16",
SchemaPrimitive::schema_i32 => "i32",
SchemaPrimitive::schema_u32 => "u32",
SchemaPrimitive::schema_i64 => "i64",
SchemaPrimitive::schema_u64 => "u64",
SchemaPrimitive::schema_string => "String",
SchemaPrimitive::schema_f32 => "f32",
SchemaPrimitive::schema_f64 => "f64",
SchemaPrimitive::schema_bool => "bool",
SchemaPrimitive::schema_canary1 => "u32",
SchemaPrimitive::schema_u128 => "u128",
SchemaPrimitive::schema_i128 => "i128",
SchemaPrimitive::schema_char => "char",
}
}
}
impl SchemaPrimitive {
fn serialized_size(&self) -> Option<usize> {
match *self {
SchemaPrimitive::schema_i8 | SchemaPrimitive::schema_u8 => Some(1),
SchemaPrimitive::schema_i16 | SchemaPrimitive::schema_u16 => Some(2),
SchemaPrimitive::schema_i32 | SchemaPrimitive::schema_u32 => Some(4),
SchemaPrimitive::schema_i64 | SchemaPrimitive::schema_u64 => Some(8),
SchemaPrimitive::schema_string => None,
SchemaPrimitive::schema_f32 => Some(4),
SchemaPrimitive::schema_f64 => Some(8),
SchemaPrimitive::schema_bool => Some(1),
SchemaPrimitive::schema_canary1 => Some(4),
SchemaPrimitive::schema_i128|SchemaPrimitive::schema_u128 => Some(16),
SchemaPrimitive::schema_char => {Some(4)}
}
}
}
fn diff_primitive(a: SchemaPrimitive, b: SchemaPrimitive, path: &str) -> Option<String> {
if a != b {
return Some(format!(
"At location [{}]: Application protocol has datatype {}, but disk format has {}",
path,
a.name(),
b.name()
));
}
None
}
#[derive(Debug, PartialEq)]
pub enum Schema {
Struct(SchemaStruct),
Enum(SchemaEnum),
Primitive(SchemaPrimitive),
Vector(Box<Schema>),
Array(SchemaArray),
SchemaOption(Box<Schema>),
Undefined,
ZeroSize,
Custom(String)
}
impl Schema {
pub fn new_tuple1<T1: WithSchema>(version: u32) -> Schema {
Schema::Struct(SchemaStruct {
dbg_name: "1-Tuple".to_string(),
fields: vec![Field {
name: "0".to_string(),
value: Box::new(T1::schema(version)),
}],
})
}
pub fn new_tuple2<T1: WithSchema, T2: WithSchema>(version: u32) -> Schema {
Schema::Struct(SchemaStruct {
dbg_name: "2-Tuple".to_string(),
fields: vec![
Field {
name: "0".to_string(),
value: Box::new(T1::schema(version)),
},
Field {
name: "1".to_string(),
value: Box::new(T2::schema(version)),
},
],
})
}
pub fn new_tuple3<T1: WithSchema, T2: WithSchema, T3: WithSchema>(version: u32) -> Schema {
Schema::Struct(SchemaStruct {
dbg_name: "3-Tuple".to_string(),
fields: vec![
Field {
name: "0".to_string(),
value: Box::new(T1::schema(version)),
},
Field {
name: "1".to_string(),
value: Box::new(T2::schema(version)),
},
Field {
name: "2".to_string(),
value: Box::new(T3::schema(version)),
},
],
})
}
pub fn new_tuple4<T1: WithSchema, T2: WithSchema, T3: WithSchema, T4: WithSchema>(version: u32) -> Schema {
Schema::Struct(SchemaStruct {
dbg_name: "4-Tuple".to_string(),
fields: vec![
Field {
name: "0".to_string(),
value: Box::new(T1::schema(version)),
},
Field {
name: "1".to_string(),
value: Box::new(T2::schema(version)),
},
Field {
name: "2".to_string(),
value: Box::new(T3::schema(version)),
},
Field {
name: "3".to_string(),
value: Box::new(T4::schema(version)),
},
],
})
}
pub fn serialized_size(&self) -> Option<usize> {
match *self {
Schema::Struct(ref schema_struct) => schema_struct.serialized_size(),
Schema::Enum(ref schema_enum) => schema_enum.serialized_size(),
Schema::Primitive(ref schema_primitive) => schema_primitive.serialized_size(),
Schema::Vector(ref _vector) => None,
Schema::Array(ref array) => array.serialized_size(),
Schema::SchemaOption(ref _content) => None,
Schema::Undefined => None,
Schema::ZeroSize => Some(0),
Schema::Custom(_) => None,
}
}
}
fn diff_vector(a: &Schema, b: &Schema, path: String) -> Option<String> {
diff_schema(a, b, path + "/*")
}
fn diff_array(a: &SchemaArray, b: &SchemaArray, path: String) -> Option<String> {
if a.count != b.count {
return Some(format!(
"At location [{}]: In memory array has length {}, but disk format length {}.",
path, a.count, b.count
));
}
diff_schema(&a.item_type, &b.item_type, format!("{}/[{}]", path, a.count))
}
fn diff_option(a: &Schema, b: &Schema, path: String) -> Option<String> {
diff_schema(a, b, path + "/?")
}
fn diff_enum(a: &SchemaEnum, b: &SchemaEnum, path: String) -> Option<String> {
let path = (path + &b.dbg_name).to_string();
if a.variants.len() != b.variants.len() {
return Some(format!(
"At location [{}]: In memory enum has {} variants, but disk format has {} variants.",
path,
a.variants.len(),
b.variants.len()
));
}
for i in 0..a.variants.len() {
if a.variants[i].name != b.variants[i].name {
return Some(format!(
"At location [{}]: Enum variant #{} in memory is called {}, but in disk format it is called {}",
&path, i, a.variants[i].name, b.variants[i].name
));
}
if a.variants[i].discriminator != b.variants[i].discriminator {
return Some(format!(
"At location [{}]: Enum variant #{} in memory has discriminator {}, but in disk format it has {}",
&path, i, a.variants[i].discriminator, b.variants[i].discriminator
));
}
let r = diff_fields(
&a.variants[i].fields,
&b.variants[i].fields,
&(path.to_string() + "/" + &b.variants[i].name).to_string(),
"enum",
"",
"",
);
if let Some(err) = r {
return Some(err);
}
}
None
}
fn diff_struct(a: &SchemaStruct, b: &SchemaStruct, path: String) -> Option<String> {
diff_fields(
&a.fields,
&b.fields,
&(path + "/" + &b.dbg_name).to_string(),
"struct",
&(" (struct ".to_string() + &a.dbg_name + ")"),
&(" (struct ".to_string() + &b.dbg_name + ")"),
)
}
fn diff_fields(
a: &[Field],
b: &[Field],
path: &str,
structuretype: &str,
extra_a: &str,
extra_b: &str,
) -> Option<String> {
if a.len() != b.len() {
return Some(format!(
"At location [{}]: In memory {}{} has {} fields, disk format{} has {} fields.",
path,
structuretype,
extra_a,
a.len(),
extra_b,
b.len()
));
}
for i in 0..a.len() {
let r = diff_schema(
&a[i].value,
&b[i].value,
(path.to_string() + "/" + &b[i].name).to_string(),
);
if let Some(err) = r {
return Some(err);
}
}
None
}
fn diff_schema(a: &Schema, b: &Schema, path: String) -> Option<String> {
let (atype, btype) = match *a {
Schema::Struct(ref xa) => match *b {
Schema::Struct(ref xb) => return diff_struct(xa, xb, path),
Schema::Enum(_) => ("struct", "enum"),
Schema::Primitive(_) => ("struct", "primitive"),
Schema::Vector(_) => ("struct", "vector"),
Schema::SchemaOption(_) => ("struct", "option"),
Schema::Undefined => ("struct", "undefined"),
Schema::ZeroSize => ("struct", "zerosize"),
Schema::Array(_) => ("struct", "array"),
Schema::Custom(_) => ("struct", "custom"),
},
Schema::Enum(ref xa) => match *b {
Schema::Enum(ref xb) => return diff_enum(xa, xb, path),
Schema::Struct(_) => ("enum", "struct"),
Schema::Primitive(_) => ("enum", "primitive"),
Schema::Vector(_) => ("enum", "vector"),
Schema::SchemaOption(_) => ("enum", "option"),
Schema::Undefined => ("enum", "undefined"),
Schema::ZeroSize => ("enum", "zerosize"),
Schema::Array(_) => ("enum", "array"),
Schema::Custom(_) => ("enum", "custom"),
},
Schema::Primitive(ref xa) => match *b {
Schema::Primitive(ref xb) => {
return diff_primitive(*xa, *xb, &path);
}
Schema::Struct(_) => ("primitive", "struct"),
Schema::Enum(_) => ("primitive", "enum"),
Schema::Vector(_) => ("primitive", "vector"),
Schema::SchemaOption(_) => ("primitive", "option"),
Schema::Undefined => ("primitive", "undefined"),
Schema::ZeroSize => ("primitive", "zerosize"),
Schema::Array(_) => ("primitive", "array"),
Schema::Custom(_) => ("primitive", "custom"),
},
Schema::SchemaOption(ref xa) => match *b {
Schema::SchemaOption(ref xb) => {
return diff_option(xa, xb, path);
}
Schema::Struct(_) => ("option", "struct"),
Schema::Enum(_) => ("option", "enum"),
Schema::Primitive(_) => ("option", "primitive"),
Schema::Vector(_) => ("option", "vector"),
Schema::Undefined => ("option", "undefined"),
Schema::ZeroSize => ("option", "zerosize"),
Schema::Array(_) => ("option", "array"),
Schema::Custom(_) => ("option", "custom"),
},
Schema::Vector(ref xa) => match *b {
Schema::Vector(ref xb) => {
return diff_vector(xa, xb, path);
}
Schema::Struct(_) => ("vector", "struct"),
Schema::Enum(_) => ("vector", "enum"),
Schema::Primitive(_) => ("vector", "primitive"),
Schema::SchemaOption(_) => ("vector", "option"),
Schema::Undefined => ("vector", "undefined"),
Schema::ZeroSize => ("vector", "zerosize"),
Schema::Array(_) => ("vector", "array"),
Schema::Custom(_) => ("vector", "custom"),
},
Schema::Undefined => {
return Some(format!("At location [{}]: Undefined schema encountered.", path));
}
Schema::ZeroSize => match *b {
Schema::ZeroSize => {
return None;
}
Schema::Vector(_) => ("zerosize", "vector"),
Schema::Struct(_) => ("zerosize", "struct"),
Schema::Enum(_) => ("zerosize", "enum"),
Schema::SchemaOption(_) => ("zerosize", "option"),
Schema::Primitive(_) => ("zerosize", "primitive"),
Schema::Undefined => ("zerosize", "undefined"),
Schema::Array(_) => ("zerosize", "array"),
Schema::Custom(_) => ("zerosize", "custom"),
},
Schema::Array(ref xa) => match *b {
Schema::Vector(_) => ("array", "vector"),
Schema::Struct(_) => ("array", "struct"),
Schema::Enum(_) => ("array", "enum"),
Schema::Primitive(_) => ("array", "primitive"),
Schema::SchemaOption(_) => ("array", "option"),
Schema::Undefined => ("array", "undefined"),
Schema::ZeroSize => ("array", "zerosize"),
Schema::Array(ref xb) => return diff_array(xa, xb, path),
Schema::Custom(_) => ("array", "custom"),
},
Schema::Custom(ref custom_a) => match b {
Schema::Vector(_) => ("custom", "vector"),
Schema::Struct(_) => ("custom", "struct"),
Schema::Enum(_) => ("custom", "enum"),
Schema::Primitive(_) => ("custom", "primitive"),
Schema::SchemaOption(_) => ("custom", "option"),
Schema::Undefined => ("custom", "undefined"),
Schema::ZeroSize => ("custom", "zerosize"),
Schema::Array(_) => ("custom", "array"),
Schema::Custom(custom_b) => {
if a != b {
return Some(format!(
"At location [{}]: Application protocol has datatype Custom({}), but disk format has Custom({})",
path,
custom_a,
custom_b
));
}
return None;
}
}
};
Some(format!(
"At location [{}]: In memory schema: {}, file schema: {}",
path, atype, btype
))
}
impl WithSchema for Field {
fn schema(_version: u32) -> Schema {
Schema::Undefined
}
}
impl Serialize for Field {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_string(&self.name)?;
self.value.serialize(serializer)
}
}
impl ReprC for Field {}
impl Deserialize for Field {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(Field {
name: deserializer.read_string()?,
value: Box::new(Schema::deserialize(deserializer)?),
})
}
}
impl WithSchema for Variant {
fn schema(_version: u32) -> Schema {
Schema::Undefined
}
}
impl Serialize for Variant {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_string(&self.name)?;
serializer.write_u8(self.discriminator)?;
serializer.write_usize(self.fields.len())?;
for field in &self.fields {
field.serialize(serializer)?;
}
Ok(())
}
}
impl ReprC for Variant {}
impl Deserialize for Variant {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(Variant {
name: deserializer.read_string()?,
discriminator: deserializer.read_u8()?,
fields: {
let l = deserializer.read_usize()?;
let mut ret = Vec::new();
for _ in 0..l {
ret.push(Field {
name: deserializer.read_string()?,
value: Box::new(Schema::deserialize(deserializer)?),
});
}
ret
},
})
}
}
impl Serialize for SchemaArray {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_usize(self.count)?;
self.item_type.serialize(serializer)?;
Ok(())
}
}
impl ReprC for SchemaArray {}
impl Deserialize for SchemaArray {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let count = deserializer.read_usize()?;
let item_type = Box::new(Schema::deserialize(deserializer)?);
Ok(SchemaArray { count, item_type })
}
}
impl WithSchema for SchemaArray {
fn schema(_version: u32) -> Schema {
Schema::Undefined
}
}
impl WithSchema for SchemaStruct {
fn schema(_version: u32) -> Schema {
Schema::Undefined
}
}
impl Serialize for SchemaStruct {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_string(&self.dbg_name)?;
serializer.write_usize(self.fields.len())?;
for field in &self.fields {
field.serialize(serializer)?;
}
Ok(())
}
}
impl ReprC for SchemaStruct {}
impl Deserialize for SchemaStruct {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let dbg_name = deserializer.read_string()?;
let l = deserializer.read_usize()?;
Ok(SchemaStruct {
dbg_name,
fields: {
let mut ret = Vec::new();
for _ in 0..l {
ret.push(Field::deserialize(deserializer)?)
}
ret
},
})
}
}
impl WithSchema for SchemaPrimitive {
fn schema(_version: u32) -> Schema {
Schema::Undefined
}
}
impl Serialize for SchemaPrimitive {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
let discr = match *self {
SchemaPrimitive::schema_i8 => 1,
SchemaPrimitive::schema_u8 => 2,
SchemaPrimitive::schema_i16 => 3,
SchemaPrimitive::schema_u16 => 4,
SchemaPrimitive::schema_i32 => 5,
SchemaPrimitive::schema_u32 => 6,
SchemaPrimitive::schema_i64 => 7,
SchemaPrimitive::schema_u64 => 8,
SchemaPrimitive::schema_string => 9,
SchemaPrimitive::schema_f32 => 10,
SchemaPrimitive::schema_f64 => 11,
SchemaPrimitive::schema_bool => 12,
SchemaPrimitive::schema_canary1 => 13,
SchemaPrimitive::schema_i128 => 14,
SchemaPrimitive::schema_u128 => 15,
SchemaPrimitive::schema_char => 16,
};
serializer.write_u8(discr)
}
}
impl ReprC for SchemaPrimitive {}
impl Deserialize for SchemaPrimitive {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let var = match deserializer.read_u8()? {
1 => SchemaPrimitive::schema_i8,
2 => SchemaPrimitive::schema_u8,
3 => SchemaPrimitive::schema_i16,
4 => SchemaPrimitive::schema_u16,
5 => SchemaPrimitive::schema_i32,
6 => SchemaPrimitive::schema_u32,
7 => SchemaPrimitive::schema_i64,
8 => SchemaPrimitive::schema_u64,
9 => SchemaPrimitive::schema_string,
10 => SchemaPrimitive::schema_f32,
11 => SchemaPrimitive::schema_f64,
12 => SchemaPrimitive::schema_bool,
13 => SchemaPrimitive::schema_canary1,
14 => SchemaPrimitive::schema_i128,
15 => SchemaPrimitive::schema_u128,
16 => SchemaPrimitive::schema_char,
c => {
return Err(SavefileError::GeneralError {
msg: format!("Corrupt schema, type {} encountered. Perhaps data is from future version?", c),
})
}
};
Ok(var)
}
}
impl WithSchema for SchemaEnum {
fn schema(_version: u32) -> Schema {
Schema::Undefined
}
}
impl Serialize for SchemaEnum {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_string(&self.dbg_name)?;
serializer.write_usize(self.variants.len())?;
for var in &self.variants {
var.serialize(serializer)?;
}
Ok(())
}
}
impl ReprC for SchemaEnum {}
impl Deserialize for SchemaEnum {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let dbg_name = deserializer.read_string()?;
let l = deserializer.read_usize()?;
let mut ret = Vec::new();
for _ in 0..l {
ret.push(Variant::deserialize(deserializer)?);
}
Ok(SchemaEnum {
dbg_name,
variants: ret,
})
}
}
impl WithSchema for Schema {
fn schema(_version: u32) -> Schema {
Schema::Undefined
}
}
impl Serialize for Schema {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
match *self {
Schema::Struct(ref schema_struct) => {
serializer.write_u8(1)?;
schema_struct.serialize(serializer)
}
Schema::Enum(ref schema_enum) => {
serializer.write_u8(2)?;
schema_enum.serialize(serializer)
}
Schema::Primitive(ref schema_prim) => {
serializer.write_u8(3)?;
schema_prim.serialize(serializer)
}
Schema::Vector(ref schema_vector) => {
serializer.write_u8(4)?;
schema_vector.serialize(serializer)
}
Schema::Undefined => serializer.write_u8(5),
Schema::ZeroSize => serializer.write_u8(6),
Schema::SchemaOption(ref content) => {
serializer.write_u8(7)?;
content.serialize(serializer)
}
Schema::Array(ref array) => {
serializer.write_u8(8)?;
array.serialize(serializer)
}
Schema::Custom(ref custom) => {
serializer.write_u8(9)?;
custom.serialize(serializer)
}
}
}
}
impl ReprC for Schema {}
impl Deserialize for Schema {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let schema = match deserializer.read_u8()? {
1 => Schema::Struct(SchemaStruct::deserialize(deserializer)?),
2 => Schema::Enum(SchemaEnum::deserialize(deserializer)?),
3 => Schema::Primitive(SchemaPrimitive::deserialize(deserializer)?),
4 => Schema::Vector(Box::new(Schema::deserialize(deserializer)?)),
5 => Schema::Undefined,
6 => Schema::ZeroSize,
7 => Schema::SchemaOption(Box::new(Schema::deserialize(deserializer)?)),
8 => Schema::Array(SchemaArray::deserialize(deserializer)?),
9 => Schema::Custom(String::deserialize(deserializer)?),
c => {
return Err(SavefileError::GeneralError {
msg: format!("Corrupt schema, schema variant {} encountered", c),
})
}
};
Ok(schema)
}
}
impl WithSchema for String {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_string)
}
}
impl Introspect for String {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem>> {
None
}
}
impl Serialize for String {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_string(self)
}
}
impl ReprC for String {}
impl Deserialize for String {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<String, SavefileError> {
deserializer.read_string()
}
}
#[cfg(feature="parking_lot")]
pub struct IntrospectItemMutex<'a, T> {
g: MutexGuard<'a, T>,
}
#[cfg(feature="parking_lot")]
impl<'a, T: Introspect> IntrospectItem<'a> for IntrospectItemMutex<'a, T> {
fn key(&self) -> &str {
"0"
}
fn val(&self) -> &dyn Introspect {
self.g.deref()
}
}
#[cfg(feature="parking_lot")]
impl<T: Introspect> Introspect for Mutex<T> {
fn introspect_value(&self) -> String {
format!("Mutex<{}>", std::any::type_name::<T>())
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if index == 0 {
Some(Box::new(IntrospectItemMutex { g: self.lock() }))
} else {
None
}
}
}
pub struct IntrospectItemStdMutex<'a, T> {
g: std::sync::MutexGuard<'a, T>,
}
impl<'a, T: Introspect> IntrospectItem<'a> for IntrospectItemStdMutex<'a, T> {
fn key(&self) -> &str {
"0"
}
fn val(&self) -> &dyn Introspect {
self.g.deref()
}
}
impl<T: Introspect> Introspect for std::sync::Mutex<T> {
fn introspect_value(&self) -> String {
format!("Mutex<{}>", std::any::type_name::<T>())
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
match self.lock() {
Ok(item) => {
if index == 0 {
Some(Box::new(IntrospectItemStdMutex { g: item }))
} else {
None
}
}
Err(_) => None,
}
}
}
impl<T: WithSchema> WithSchema for std::sync::Mutex<T> {
fn schema(version: u32) -> Schema {
T::schema(version)
}
}
impl<T> ReprC for std::sync::Mutex<T> {}
impl<T: Serialize> Serialize for std::sync::Mutex<T> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
let data = self.lock()?;
data.serialize(serializer)
}
}
impl<T: Deserialize> Deserialize for std::sync::Mutex<T> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<std::sync::Mutex<T>, SavefileError> {
Ok(std::sync::Mutex::new(T::deserialize(deserializer)?))
}
}
#[cfg(feature="parking_lot")]
impl<T: WithSchema> WithSchema for Mutex<T> {
fn schema(version: u32) -> Schema {
T::schema(version)
}
}
#[cfg(feature="parking_lot")]
impl<T> ReprC for Mutex<T> {}
#[cfg(feature="parking_lot")]
impl<T: Serialize> Serialize for Mutex<T> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
let data = self.lock();
data.serialize(serializer)
}
}
#[cfg(feature="parking_lot")]
impl<T: Deserialize> Deserialize for Mutex<T> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Mutex<T>, SavefileError> {
Ok(Mutex::new(T::deserialize(deserializer)?))
}
}
#[cfg(feature="parking_lot")]
pub struct IntrospectItemRwLock<'a, T> {
g: RwLockReadGuard<'a, T>,
}
#[cfg(feature="parking_lot")]
impl<'a, T: Introspect> IntrospectItem<'a> for IntrospectItemRwLock<'a, T> {
fn key(&self) -> &str {
"0"
}
fn val(&self) -> &dyn Introspect {
self.g.deref()
}
}
impl<'a,T:Introspect> Introspect for std::cell::Ref<'a,T> {
fn introspect_value(&self) -> String {
let sub_value = (**self).introspect_value();
format!("Ref({})", sub_value)
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
(**self).introspect_child(index)
}
fn introspect_len(&self) -> usize {
(**self).introspect_len()
}
}
impl<'a,T:Introspect> IntrospectItem<'a> for std::cell::Ref<'a,T> {
fn key(&self) -> &str {
"ref"
}
fn val(&self) -> &dyn Introspect {
&*self
}
}
impl<T: Introspect> Introspect for RefCell<T> {
fn introspect_value(&self) -> String {
let sub_value = self.borrow().introspect_value();
format!("RefCell({})", sub_value)
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if index != 0 {
return None;
}
let rf = self.borrow();
Some(Box::new(rf))
}
fn introspect_len(&self) -> usize {
1
}
}
impl<T: Introspect> Introspect for Rc<T> {
fn introspect_value(&self) -> String {
format!("Rc({})", self.deref().introspect_value())
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
self.deref().introspect_child(index)
}
fn introspect_len(&self) -> usize {
self.deref().introspect_len()
}
}
impl<T: Introspect> Introspect for Arc<T> {
fn introspect_value(&self) -> String {
format!("Arc({})", self.deref().introspect_value())
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
self.deref().introspect_child(index)
}
fn introspect_len(&self) -> usize {
self.deref().introspect_len()
}
}
#[cfg(feature="parking_lot")]
impl<T: Introspect> Introspect for RwLock<T> {
fn introspect_value(&self) -> String {
format!("RwLock<{}>", std::any::type_name::<T>())
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if index == 0 {
Some(Box::new(IntrospectItemRwLock { g: self.read() }))
} else {
None
}
}
fn introspect_len(&self) -> usize {
1
}
}
#[cfg(feature="parking_lot")]
impl<T: WithSchema> WithSchema for RwLock<T> {
fn schema(version: u32) -> Schema {
T::schema(version)
}
}
#[cfg(feature="parking_lot")]
impl<T> ReprC for RwLock<T> {}
#[cfg(feature="parking_lot")]
impl<T: Serialize> Serialize for RwLock<T> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
let data = self.read();
data.serialize(serializer)
}
}
#[cfg(feature="parking_lot")]
impl<T: Deserialize> Deserialize for RwLock<T> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<RwLock<T>, SavefileError> {
Ok(RwLock::new(T::deserialize(deserializer)?))
}
}
pub struct IntrospectItemSimple<'a> {
key: String,
val: &'a dyn Introspect,
}
impl<'a> IntrospectItem<'a> for IntrospectItemSimple<'a> {
fn key(&self) -> &str {
&self.key
}
fn val(&self) -> &dyn Introspect {
self.val
}
}
pub fn introspect_item<'a>(key: String, val: &'a dyn Introspect) -> Box<dyn IntrospectItem<'a> + 'a> {
Box::new(IntrospectItemSimple { key: key, val: val })
}
#[cfg(not(feature = "nightly"))]
impl<K: Introspect + Eq + Hash, V: Introspect, S: ::std::hash::BuildHasher> Introspect for HashMap<K, V, S> {
fn introspect_value(&self) -> String {
format!("HashMap<{},{}>", std::any::type_name::<K>(), std::any::type_name::<V>())
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
let bucket = index / 2;
let off = index % 2;
if let Some((key, val)) = self.iter().skip(bucket).next() {
if off == 0 {
Some(introspect_item(format!("Key #{}", index), key))
} else {
Some(introspect_item(format!("Value #{}", index), val))
}
} else {
None
}
}
fn introspect_len(&self) -> usize {
self.len()
}
}
#[cfg(feature = "nightly")]
impl<K: Introspect + Eq + Hash, V: Introspect, S: ::std::hash::BuildHasher> Introspect for HashMap<K, V, S> {
default fn introspect_value(&self) -> String {
format!("HashMap<{},{}>", std::any::type_name::<K>(), std::any::type_name::<V>())
}
default fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
let bucket = index / 2;
let off = index % 2;
if let Some((key, val)) = self.iter().skip(bucket).next() {
if off == 0 {
Some(introspect_item(format!("Key #{}", index), key))
} else {
Some(introspect_item(format!("Value #{}", index), val))
}
} else {
None
}
}
default fn introspect_len(&self) -> usize {
self.len()
}
}
#[cfg(feature = "nightly")]
impl<K: Introspect + Eq + Hash, V: Introspect, S: ::std::hash::BuildHasher> Introspect for HashMap<K, V, S>
where
K: ToString,
{
fn introspect_value(&self) -> String {
format!("HashMap<{},{}>", std::any::type_name::<K>(), std::any::type_name::<V>())
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if let Some((key, val)) = self.iter().skip(index).next() {
Some(introspect_item(key.to_string(), val))
} else {
None
}
}
fn introspect_len(&self) -> usize {
self.len()
}
}
impl<K: Introspect + Eq + Hash, S: ::std::hash::BuildHasher> Introspect for HashSet<K, S> {
fn introspect_value(&self) -> String {
format!("HashSet<{}>", std::any::type_name::<K>())
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if let Some(key) = self.iter().skip(index).next() {
Some(introspect_item(format!("#{}", index), key))
} else {
None
}
}
fn introspect_len(&self) -> usize {
self.len()
}
}
impl<K: Introspect, V: Introspect> Introspect for BTreeMap<K, V> {
fn introspect_value(&self) -> String {
format!("BTreeMap<{},{}>", std::any::type_name::<K>(), std::any::type_name::<V>())
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
let bucket = index / 2;
let off = index % 2;
if let Some((key, val)) = self.iter().skip(bucket).next() {
if off == 0 {
Some(introspect_item(format!("Key #{}", index), key))
} else {
Some(introspect_item(format!("Value #{}", index), val))
}
} else {
None
}
}
fn introspect_len(&self) -> usize {
self.len()
}
}
impl<K: WithSchema, V: WithSchema> WithSchema for BTreeMap<K, V> {
fn schema(version: u32) -> Schema {
Schema::Vector(Box::new(Schema::Struct(SchemaStruct {
dbg_name: "KeyValuePair".to_string(),
fields: vec![
Field {
name: "key".to_string(),
value: Box::new(K::schema(version)),
},
Field {
name: "value".to_string(),
value: Box::new(V::schema(version)),
},
],
})))
}
}
impl<K, V> ReprC for BTreeMap<K, V> {}
impl<K: Serialize, V: Serialize> Serialize for BTreeMap<K, V> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
self.len().serialize(serializer)?;
for (k, v) in self {
k.serialize(serializer)?;
v.serialize(serializer)?;
}
Ok(())
}
}
impl<K: Deserialize + Ord, V: Deserialize> Deserialize for BTreeMap<K, V> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let mut ret = BTreeMap::new();
let count = <usize as Deserialize>::deserialize(deserializer)?;
for _ in 0..count {
ret.insert(
<_ as Deserialize>::deserialize(deserializer)?,
<_ as Deserialize>::deserialize(deserializer)?,
);
}
Ok(ret)
}
}
impl<K, S: ::std::hash::BuildHasher> ReprC for HashSet<K,S> {}
impl<K:WithSchema, S: ::std::hash::BuildHasher> WithSchema for HashSet<K,S> {
fn schema(version: u32) -> Schema {
Schema::Vector(Box::new(K::schema(version)))
}
}
impl<K:Serialize, S: ::std::hash::BuildHasher> Serialize for HashSet<K,S> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_usize(self.len())?;
for item in self {
item.serialize(serializer)?;
}
Ok(())
}
}
impl<K:Deserialize+Eq+Hash, S: ::std::hash::BuildHasher+Default> Deserialize for HashSet<K,S> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let cnt = deserializer.read_usize()?;
let mut ret = HashSet::with_capacity_and_hasher(cnt, S::default());
for _ in 0..cnt {
ret.insert(<_ as Deserialize>::deserialize(deserializer)?);
}
Ok(ret)
}
}
impl<K: WithSchema + Eq + Hash, V: WithSchema, S: ::std::hash::BuildHasher> WithSchema for HashMap<K, V, S> {
fn schema(version: u32) -> Schema {
Schema::Vector(Box::new(Schema::Struct(SchemaStruct {
dbg_name: "KeyValuePair".to_string(),
fields: vec![
Field {
name: "key".to_string(),
value: Box::new(K::schema(version)),
},
Field {
name: "value".to_string(),
value: Box::new(V::schema(version)),
},
],
})))
}
}
impl<K:Eq + Hash, V, S: ::std::hash::BuildHasher> ReprC for HashMap<K, V, S> {}
impl<K: Serialize + Eq + Hash, V: Serialize, S: ::std::hash::BuildHasher> Serialize for HashMap<K, V, S> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_usize(self.len())?;
for (k, v) in self.iter() {
k.serialize(serializer)?;
v.serialize(serializer)?;
}
Ok(())
}
}
impl<K: Deserialize + Eq + Hash, V: Deserialize, S: ::std::hash::BuildHasher+Default> Deserialize for HashMap<K, V, S> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let l = deserializer.read_usize()?;
let mut ret:Self = HashMap::with_capacity_and_hasher(l, Default::default());
for _ in 0..l {
ret.insert(K::deserialize(deserializer)?, V::deserialize(deserializer)?);
}
Ok(ret)
}
}
#[cfg(feature="indexmap")]
impl<K: WithSchema + Eq + Hash, V: WithSchema, S: ::std::hash::BuildHasher> WithSchema for IndexMap<K, V, S> {
fn schema(version: u32) -> Schema {
Schema::Vector(Box::new(Schema::Struct(SchemaStruct {
dbg_name: "KeyValuePair".to_string(),
fields: vec![
Field {
name: "key".to_string(),
value: Box::new(K::schema(version)),
},
Field {
name: "value".to_string(),
value: Box::new(V::schema(version)),
},
],
})))
}
}
#[cfg(all(not(feature = "nightly"), feature="indexmap"))]
impl<K: Introspect + Eq + Hash, V: Introspect, S: ::std::hash::BuildHasher> Introspect for IndexMap<K, V, S> {
fn introspect_value(&self) -> String {
format!(
"IndexMap<{},{}>",
std::any::type_name::<K>(),
std::any::type_name::<V>()
)
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
let bucket = index / 2;
let off = index % 2;
if let Some((k, v)) = self.get_index(bucket) {
if off == 0 {
Some(introspect_item(format!("Key #{}", bucket), k))
} else {
Some(introspect_item(format!("Value #{}", bucket), v))
}
} else {
None
}
}
fn introspect_len(&self) -> usize {
self.len()
}
}
#[cfg(all(feature = "nightly", feature="indexmap"))]
impl<K: Introspect + Eq + Hash, V: Introspect, S: ::std::hash::BuildHasher> Introspect for IndexMap<K, V, S> {
default fn introspect_value(&self) -> String {
format!(
"IndexMap<{},{}>",
std::any::type_name::<K>(),
std::any::type_name::<V>()
)
}
default fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
let bucket = index / 2;
let off = index % 2;
if let Some((k, v)) = self.get_index(bucket) {
if off == 0 {
Some(introspect_item(format!("Key #{}", bucket), k))
} else {
Some(introspect_item(format!("Value #{}", bucket), v))
}
} else {
None
}
}
default fn introspect_len(&self) -> usize {
self.len()
}
}
#[cfg(all(feature = "nightly", feature="indexmap"))]
impl<K: Introspect + Eq + Hash, V: Introspect, S: ::std::hash::BuildHasher> Introspect for IndexMap<K, V, S>
where
K: ToString,
{
fn introspect_value(&self) -> String {
format!(
"IndexMap<{},{}>",
std::any::type_name::<K>(),
std::any::type_name::<V>()
)
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if let Some((k, v)) = self.get_index(index) {
Some(introspect_item(k.to_string(), v))
} else {
None
}
}
fn introspect_len(&self) -> usize {
self.len()
}
}
#[cfg(feature="indexmap")]
impl<K: Eq + Hash, V, S: ::std::hash::BuildHasher> ReprC for IndexMap<K, V, S> {}
#[cfg(feature="indexmap")]
impl<K: Serialize + Eq + Hash, V: Serialize, S: ::std::hash::BuildHasher> Serialize for IndexMap<K, V, S> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_usize(self.len())?;
for (k, v) in self.iter() {
k.serialize(serializer)?;
v.serialize(serializer)?;
}
Ok(())
}
}
#[cfg(feature="indexmap")]
impl<K: Deserialize + Eq + Hash, V: Deserialize> Deserialize for IndexMap<K, V> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let l = deserializer.read_usize()?;
let mut ret = IndexMap::with_capacity(l);
for _ in 0..l {
ret.insert(K::deserialize(deserializer)?, V::deserialize(deserializer)?);
}
Ok(ret)
}
}
#[cfg(feature="indexmap")]
impl<K: Introspect + Eq + Hash, S: ::std::hash::BuildHasher> Introspect for IndexSet<K, S> {
fn introspect_value(&self) -> String {
format!("IndexSet<{}>", std::any::type_name::<K>())
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if let Some(val) = self.get_index(index) {
Some(introspect_item(format!("#{}", index), val))
} else {
None
}
}
fn introspect_len(&self) -> usize {
self.len()
}
}
#[cfg(feature="indexmap")]
impl<K:Eq + Hash, S: ::std::hash::BuildHasher> ReprC for IndexSet<K, S> {}
#[cfg(feature="indexmap")]
impl<K: WithSchema + Eq + Hash, S: ::std::hash::BuildHasher> WithSchema for IndexSet<K, S> {
fn schema(version: u32) -> Schema {
Schema::Vector(Box::new(Schema::Struct(SchemaStruct {
dbg_name: "Key".to_string(),
fields: vec![Field {
name: "key".to_string(),
value: Box::new(K::schema(version)),
}],
})))
}
}
#[cfg(feature="indexmap")]
impl<K: Serialize + Eq + Hash, S: ::std::hash::BuildHasher> Serialize for IndexSet<K, S> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_usize(self.len())?;
for k in self.iter() {
k.serialize(serializer)?;
}
Ok(())
}
}
#[cfg(feature="indexmap")]
impl<K: Deserialize + Eq + Hash> Deserialize for IndexSet<K> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let l = deserializer.read_usize()?;
let mut ret = IndexSet::with_capacity(l);
for _ in 0..l {
ret.insert(K::deserialize(deserializer)?);
}
Ok(ret)
}
}
#[derive(Debug,Clone,Copy,PartialEq,Eq,PartialOrd,Ord,Hash,Default)]
pub struct Removed<T> {
phantom: std::marker::PhantomData<*const T>,
}
unsafe impl<T> Send for Removed<T> {
}
unsafe impl<T> Sync for Removed<T> {
}
impl<T> Removed<T> {
pub fn new() -> Removed<T> {
Removed {
phantom: std::marker::PhantomData,
}
}
}
impl<T: WithSchema> WithSchema for Removed<T> {
fn schema(version: u32) -> Schema {
<T>::schema(version)
}
}
impl<T: Introspect> Introspect for Removed<T> {
fn introspect_value(&self) -> String {
format!("Removed<{}>", std::any::type_name::<T>())
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl<T> ReprC for Removed<T> {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl<T: WithSchema> Serialize for Removed<T> {
fn serialize(&self, _serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
panic!("Something is wrong with version-specification of fields - there was an attempt to actually serialize a removed field!");
}
}
impl<T: WithSchema + Deserialize> Deserialize for Removed<T> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
T::deserialize(deserializer)?;
Ok(Removed {
phantom: std::marker::PhantomData,
})
}
}
impl<T> Introspect for PhantomData<T> {
fn introspect_value(&self) -> String {
"PhantomData".to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl<T> WithSchema for std::marker::PhantomData<T> {
fn schema(_version: u32) -> Schema {
Schema::ZeroSize
}
}
impl<T> ReprC for std::marker::PhantomData<T> {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl<T> Serialize for std::marker::PhantomData<T> {
fn serialize(&self, _serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
Ok(())
}
}
impl<T> Deserialize for std::marker::PhantomData<T> {
fn deserialize(_deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(std::marker::PhantomData)
}
}
impl<T: Introspect> Introspect for Box<T> {
fn introspect_value(&self) -> String {
self.deref().introspect_value()
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
self.deref().introspect_child(index)
}
fn introspect_len(&self) -> usize {
self.deref().introspect_len()
}
}
impl<T: Introspect> Introspect for Option<T> {
fn introspect_value(&self) -> String {
if let Some(cont) = self {
format!("Some({})", cont.introspect_value())
} else {
"None".to_string()
}
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if let Some(cont) = self {
cont.introspect_child(index)
} else {
None
}
}
fn introspect_len(&self) -> usize {
if let Some(cont) = self {
cont.introspect_len()
} else {
0
}
}
}
impl<T: WithSchema> WithSchema for Option<T> {
fn schema(version: u32) -> Schema {
Schema::SchemaOption(Box::new(T::schema(version)))
}
}
impl<T> ReprC for Option<T> { } impl<T: Serialize> Serialize for Option<T> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
match self {
&Some(ref x) => {
serializer.write_bool(true)?;
x.serialize(serializer)
}
&None => serializer.write_bool(false),
}
}
}
impl<T: Deserialize> Deserialize for Option<T> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let issome = deserializer.read_bool()?;
if issome {
Ok(Some(T::deserialize(deserializer)?))
} else {
Ok(None)
}
}
}
#[cfg(feature="bit-vec")]
#[cfg(target_endian="big")]
compile_error!("savefile bit-vec feature does not support big-endian machines");
#[cfg(feature="bit-vec")]
impl WithSchema for bit_vec::BitVec {
fn schema(version: u32) -> Schema {
Schema::Struct(SchemaStruct {
dbg_name: "BitVec".to_string(),
fields: vec![
Field {
name: "num_bits".to_string(),
value: Box::new(usize::schema(version)),
},
Field {
name: "num_bytes".to_string(),
value: Box::new(usize::schema(version)),
},
Field {
name: "buffer".to_string(),
value: Box::new(Schema::Vector(Box::new(u8::schema(version)))),
},
],
})
}
}
#[cfg(feature="bit-vec")]
impl Introspect for bit_vec::BitVec {
fn introspect_value(&self) -> String {
let mut ret = String::new();
for i in 0..self.len() {
if self[i] {
ret.push('1');
} else {
ret.push('0');
}
}
ret
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
#[cfg(feature="bit-vec")]
impl Serialize for bit_vec::BitVec<u32> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
let l = self.len();
serializer.write_usize(l)?;
let storage = self.storage();
let rawbytes_ptr = storage.as_ptr() as *const u8;
let rawbytes :&[u8] = unsafe{std::slice::from_raw_parts(rawbytes_ptr,4*storage.len())};
serializer.write_usize(rawbytes.len()|(1<<63))?;
serializer.write_bytes(&rawbytes)?;
Ok(())
}
}
#[cfg(feature="bit-vec")]
impl ReprC for bit_vec::BitVec<u32> {}
#[cfg(feature="bit-vec")]
impl Deserialize for bit_vec::BitVec<u32> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let numbits = deserializer.read_usize()?;
let mut numbytes = deserializer.read_usize()?;
if numbytes&(1<<63)!=0 {
numbytes &= !(1<<63);
let mut ret = bit_vec::BitVec::with_capacity(numbytes*8);
unsafe {
let num_words = numbytes/4;
let storage = ret.storage_mut();
storage.resize(num_words, 0);
let storage_ptr = storage.as_ptr() as *mut u8;
let storage_bytes:&mut [u8] = std::slice::from_raw_parts_mut(storage_ptr,4*num_words);
deserializer.read_bytes_to_buf(storage_bytes)?;
ret.set_len(numbits);
}
Ok(ret)
} else {
let bytes = deserializer.read_bytes(numbytes)?;
let mut ret = bit_vec::BitVec::from_bytes(&bytes);
ret.truncate(numbits);
Ok(ret)
}
}
}
#[cfg(feature="bit-set")]
impl WithSchema for bit_set::BitSet {
fn schema(version: u32) -> Schema {
Schema::Struct(SchemaStruct {
dbg_name: "BitSet".to_string(),
fields: vec![
Field {
name: "num_bits".to_string(),
value: Box::new(usize::schema(version)),
},
Field {
name: "num_bytes".to_string(),
value: Box::new(usize::schema(version)),
},
Field {
name: "buffer".to_string(),
value: Box::new(Schema::Vector(Box::new(u8::schema(version)))),
},
],
})
}
}
#[cfg(feature="bit-set")]
impl Introspect for bit_set::BitSet {
fn introspect_value(&self) -> String {
let mut ret = String::new();
for i in 0..self.len() {
if self.contains(i) {
use std::fmt::Write;
write!(&mut ret, "{} ",i).unwrap();
}
}
ret
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
#[cfg(feature="bit-set")]
impl ReprC for bit_set::BitSet<u32> {}
#[cfg(feature="bit-set")]
impl Serialize for bit_set::BitSet<u32> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
let bitset = self.get_ref();
bitset.serialize(serializer)
}
}
#[cfg(feature="bit-set")]
impl Deserialize for bit_set::BitSet<u32> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let bit_vec: bit_vec::BitVec = bit_vec::BitVec::deserialize(deserializer)?;
Ok(bit_set::BitSet::from_bit_vec(bit_vec))
}
}
impl<T: Introspect> Introspect for BinaryHeap<T> {
fn introspect_value(&self) -> String {
"BinaryHeap".to_string()
}
fn introspect_child<'a>(&'a self, index: usize) -> Option<Box<dyn IntrospectItem<'a> + 'a>> {
if index >= self.len() {
return None;
}
return Some(introspect_item(
index.to_string(),
self.iter().skip(index).next().unwrap(),
));
}
fn introspect_len(&self) -> usize {
self.len()
}
}
impl<T> ReprC for BinaryHeap<T> {}
impl<T: WithSchema> WithSchema for BinaryHeap<T> {
fn schema(version: u32) -> Schema {
Schema::Vector(Box::new(T::schema(version)))
}
}
impl<T: Serialize + Ord> Serialize for BinaryHeap<T> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
let l = self.len();
serializer.write_usize(l)?;
for item in self.iter() {
item.serialize(serializer)?
}
Ok(())
}
}
impl<T: Deserialize + Ord> Deserialize for BinaryHeap<T> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let l = deserializer.read_usize()?;
let mut ret = BinaryHeap::with_capacity(l);
for _ in 0..l {
ret.push(T::deserialize(deserializer)?);
}
Ok(ret)
}
}
#[cfg(feature="smallvec")]
impl<T: smallvec::Array> Introspect for smallvec::SmallVec<T>
where
T::Item: Introspect,
{
fn introspect_value(&self) -> String {
format!("SmallVec<{}>", std::any::type_name::<T>())
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if let Some(val) = self.get(index) {
Some(introspect_item(index.to_string(), val))
} else {
None
}
}
fn introspect_len(&self) -> usize {
self.len()
}
}
#[cfg(feature="smallvec")]
impl<T: smallvec::Array> WithSchema for smallvec::SmallVec<T>
where
T::Item: WithSchema,
{
fn schema(version: u32) -> Schema {
Schema::Vector(Box::new(T::Item::schema(version)))
}
}
#[cfg(feature="smallvec")]
impl<T: smallvec::Array> ReprC for smallvec::SmallVec<T>{}
#[cfg(feature="smallvec")]
impl<T: smallvec::Array> Serialize for smallvec::SmallVec<T>
where
T::Item: Serialize,
{
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
let l = self.len();
serializer.write_usize(l)?;
for item in self.iter() {
item.serialize(serializer)?
}
Ok(())
}
}
#[cfg(feature="smallvec")]
impl<T: smallvec::Array> Deserialize for smallvec::SmallVec<T>
where
T::Item: Deserialize,
{
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let l = deserializer.read_usize()?;
let mut ret = Self::with_capacity(l);
for _ in 0..l {
ret.push(T::Item::deserialize(deserializer)?);
}
Ok(ret)
}
}
fn regular_serialize_vec<T: Serialize>(items: &[T], serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
let l = items.len();
serializer.write_usize(l)?;
if std::mem::size_of::<T>() == 0 {
return Ok(());
}
if std::mem::size_of::<T>() < 32 { let chunks = items.chunks_exact((64/std::mem::size_of::<T>()).max(1));
let remainder = chunks.remainder();
for chunk in chunks {
for item in chunk {
item.serialize(serializer)?;
}
}
for item in remainder {
item.serialize(serializer)?;
}
Ok(())
} else {
for item in items {
item.serialize(serializer)?;
}
Ok(())
}
}
impl<T: WithSchema> WithSchema for Box<[T]> {
fn schema(version: u32) -> Schema {
Schema::Vector(Box::new(T::schema(version)))
}
}
impl<T: WithSchema> WithSchema for Arc<[T]> {
fn schema(version: u32) -> Schema {
Schema::Vector(Box::new(T::schema(version)))
}
}
impl<T: Introspect> Introspect for Box<[T]> {
fn introspect_value(&self) -> String {
return "Box[]".to_string();
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if index >= self.len() {
return None;
}
return Some(introspect_item(index.to_string(), &self[index]));
}
fn introspect_len(&self) -> usize {
self.len()
}
}
impl<T: Introspect> Introspect for Arc<[T]> {
fn introspect_value(&self) -> String {
return "Arc[]".to_string();
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if index >= self.len() {
return None;
}
return Some(introspect_item(index.to_string(), &self[index]));
}
fn introspect_len(&self) -> usize {
self.len()
}
}
impl WithSchema for Arc<str> {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_string)
}
}
impl Introspect for Arc<str> {
fn introspect_value(&self) -> String {
self.deref().to_string()
}
fn introspect_child<'a>(&'a self, _index: usize) -> Option<Box<dyn IntrospectItem<'a>>> {
None
}
fn introspect_len(&self) -> usize {
0
}
}
impl Serialize for Arc<str> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_string(&*self)
}
}
impl ReprC for Arc<str> {}
impl Deserialize for Arc<str> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let s = deserializer.read_string()?;
let state = deserializer.get_state::<Arc<str>, HashMap<String, Arc<str>>>();
if let Some(needle) = state.get(&s) {
return Ok(Arc::clone(needle));
}
let arc_ref = state.entry(s.clone()).or_insert(s.into());
Ok(Arc::clone(arc_ref))
}
}
impl<T: Serialize + ReprC> Serialize for Box<[T]> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
unsafe {
if T::repr_c_optimization_safe(serializer.version).is_false() {
regular_serialize_vec(&*self, serializer)
} else {
let l = self.len();
serializer.write_usize(l)?;
serializer.write_buf(std::slice::from_raw_parts(
(*self).as_ptr() as *const u8,
std::mem::size_of::<T>() * l,
))
}
}
}
}
impl<T: ReprC> ReprC for Box<[T]> { }
impl<T: Serialize + ReprC> Serialize for Arc<[T]> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
unsafe {
if T::repr_c_optimization_safe(serializer.version).is_false() {
regular_serialize_vec(&*self, serializer)
} else {
let l = self.len();
serializer.write_usize(l)?;
serializer.write_buf(std::slice::from_raw_parts(
(*self).as_ptr() as *const u8,
std::mem::size_of::<T>() * l,
))
}
}
}
}
impl<T: ReprC> ReprC for Arc<[T]> { }
impl<T: Deserialize+ReprC> Deserialize for Arc<[T]> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(Vec::<T>::deserialize(deserializer)?.into())
}
}
impl<T: Deserialize+ReprC> Deserialize for Box<[T]> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(Vec::<T>::deserialize(deserializer)?.into_boxed_slice())
}
}
impl<T> ReprC for Vec<T> {}
impl<T: WithSchema> WithSchema for Vec<T> {
fn schema(version: u32) -> Schema {
Schema::Vector(Box::new(T::schema(version)))
}
}
impl<T: Introspect> Introspect for Vec<T> {
fn introspect_value(&self) -> String {
return "vec[]".to_string();
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if index >= self.len() {
return None;
}
return Some(introspect_item(index.to_string(), &self[index]));
}
fn introspect_len(&self) -> usize {
self.len()
}
}
impl<T: Serialize + ReprC> Serialize for Vec<T> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
unsafe {
if T::repr_c_optimization_safe(serializer.version).is_false() {
regular_serialize_vec(self, serializer)
} else {
let l = self.len();
serializer.write_usize(l)?;
serializer.write_buf(std::slice::from_raw_parts(
self.as_ptr() as *const u8,
std::mem::size_of::<T>() * l,
))
}
}
}
}
fn regular_deserialize_vec<T: Deserialize>(deserializer: &mut Deserializer<impl Read>) -> Result<Vec<T>, SavefileError> {
let l = deserializer.read_usize()?;
#[cfg(feature = "size_sanity_checks")]
{
if l > 1_000_000 {
return Err(SavefileError::GeneralError {
msg: format!("Too many items in Vec: {}", l),
});
}
}
let mut ret = Vec::with_capacity(l);
for _ in 0..l {
ret.push(T::deserialize(deserializer)?);
}
Ok(ret)
}
impl<T: Deserialize + ReprC> Deserialize for Vec<T> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
if unsafe{T::repr_c_optimization_safe(deserializer.file_version)}.is_false() {
Ok(regular_deserialize_vec(deserializer)?)
} else {
use std::mem;
let align = mem::align_of::<T>();
let elem_size = mem::size_of::<T>();
let num_elems = deserializer.read_usize()?;
if num_elems == 0 {
return Ok(Vec::new());
}
let num_bytes = elem_size * num_elems;
let layout = if let Ok(layout) = std::alloc::Layout::from_size_align(num_bytes, align) {
Ok(layout)
} else {
Err(SavefileError::MemoryAllocationLayoutError)
}?;
let ptr =
if elem_size == 0 {
NonNull::dangling().as_ptr()
} else {
let ptr = unsafe { std::alloc::alloc(layout.clone()) };
if ptr.is_null() {
panic!("Failed to allocate {} bytes of memory", num_bytes);
}
ptr
};
{
let slice = unsafe { std::slice::from_raw_parts_mut(ptr as *mut u8, num_bytes) };
match deserializer.reader.read_exact(slice) {
Ok(()) => Ok(()),
Err(err) => {
unsafe {
std::alloc::dealloc(ptr, layout);
}
Err(err)
}
}?;
}
let ret = unsafe { Vec::from_raw_parts(ptr as *mut T, num_elems, num_elems) };
Ok(ret)
}
}
}
impl<T: Introspect> Introspect for VecDeque<T> {
fn introspect_value(&self) -> String {
format!("VecDeque<{}>", std::any::type_name::<T>())
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if let Some(val) = self.get(index) {
Some(introspect_item(index.to_string(), val))
} else {
None
}
}
fn introspect_len(&self) -> usize {
self.len()
}
}
impl<T: WithSchema> WithSchema for VecDeque<T> {
fn schema(version: u32) -> Schema {
Schema::Vector(Box::new(T::schema(version)))
}
}
impl<T> ReprC for VecDeque<T> {}
impl<T: Serialize> Serialize for VecDeque<T> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
regular_serialize_vecdeque(self, serializer)
}
}
impl<T: Deserialize> Deserialize for VecDeque<T> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(regular_deserialize_vecdeque(deserializer)?)
}
}
fn regular_serialize_vecdeque<T: Serialize>(
item: &VecDeque<T>,
serializer: &mut Serializer<impl Write>,
) -> Result<(), SavefileError> {
let l = item.len();
serializer.write_usize(l)?;
for item in item.iter() {
item.serialize(serializer)?
}
Ok(())
}
fn regular_deserialize_vecdeque<T: Deserialize>(deserializer: &mut Deserializer<impl Read>) -> Result<VecDeque<T>, SavefileError> {
let l = deserializer.read_usize()?;
let mut ret = VecDeque::with_capacity(l);
for _ in 0..l {
ret.push_back(T::deserialize(deserializer)?);
}
Ok(ret)
}
impl ReprC for bool {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
} impl ReprC for u8 {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl ReprC for i8 {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl ReprC for u16 {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl ReprC for i16 {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl ReprC for u32 {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl ReprC for i32 {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl ReprC for u64 {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl ReprC for u128 {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl ReprC for i128 {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl ReprC for i64 {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl ReprC for char {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl ReprC for f32 {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl ReprC for f64 {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl ReprC for usize {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::no()
} }
impl ReprC for isize {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::no()
} }
impl ReprC for () {
unsafe fn repr_c_optimization_safe(_version: u32) -> IsReprC {
IsReprC::yes()
}
}
impl<T: WithSchema, const N: usize> WithSchema for [T; N] {
fn schema(version: u32) -> Schema {
Schema::Array(SchemaArray {
item_type: Box::new(T::schema(version)),
count: N,
})
}
}
impl<T: Introspect, const N: usize> Introspect for [T; N] {
fn introspect_value(&self) -> String {
format!("[{}; {}]", std::any::type_name::<T>(), N)
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if index >= self.len() {
None
} else {
Some(introspect_item(index.to_string(), &self[index]))
}
}
}
impl<T: ReprC, const N: usize> ReprC for [T; N] {
unsafe fn repr_c_optimization_safe(version: u32) -> IsReprC {
T::repr_c_optimization_safe(version)
}
}
impl<T: Serialize + ReprC, const N: usize> Serialize for [T; N] {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
unsafe {
if T::repr_c_optimization_safe(serializer.version).is_false() {
for item in self.iter() {
item.serialize(serializer)?
}
Ok(())
} else {
serializer.write_buf(std::slice::from_raw_parts(
self.as_ptr() as *const u8,
std::mem::size_of::<T>() * N,
))
}
}
}
}
impl<T: Deserialize + ReprC, const N: usize> Deserialize for [T; N] {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
if unsafe{T::repr_c_optimization_safe(deserializer.file_version)}.is_false() {
let mut data: [MaybeUninit<T>; N] = unsafe {
MaybeUninit::uninit().assume_init() };
for idx in 0..N {
data[idx] = MaybeUninit::new(T::deserialize(deserializer)?); }
let ptr = &mut data as *mut _ as *mut [T; N];
let res = unsafe { ptr.read() };
core::mem::forget(data);
Ok(res)
} else {
let mut data: [MaybeUninit<T>; N] = unsafe {
MaybeUninit::uninit().assume_init() };
{
let ptr = data.as_mut_ptr();
let num_bytes: usize = std::mem::size_of::<T>() * N;
let slice: &mut [MaybeUninit<u8>] =
unsafe { std::slice::from_raw_parts_mut(ptr as *mut MaybeUninit<u8>, num_bytes) };
deserializer.reader.read_exact(unsafe { std::mem::transmute(slice) })?;
}
let ptr = &mut data as *mut _ as *mut [T; N];
let res = unsafe { ptr.read() };
core::mem::forget(data);
Ok(res)
}
}
}
impl<T1> ReprC for Range<T1> {}
impl<T1: WithSchema> WithSchema for Range<T1> {
fn schema(version: u32) -> Schema {
Schema::new_tuple2::<T1, T1>(version)
}
}
impl<T1: Serialize> Serialize for Range<T1> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
self.start.serialize(serializer)?;
self.end.serialize(serializer)?;
Ok(())
}
}
impl<T1: Deserialize> Deserialize for Range<T1> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(T1::deserialize(deserializer)?..T1::deserialize(deserializer)?)
}
}
impl<T1: Introspect> Introspect for Range<T1> {
fn introspect_value(&self) -> String {
return "Range".to_string();
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if index == 0 {
return Some(introspect_item("start".to_string(), &self.start));
}
if index == 1 {
return Some(introspect_item("end".to_string(), &self.end));
}
return None;
}
}
impl<T1:ReprC> ReprC for (T1,) {
unsafe fn repr_c_optimization_safe(version: u32) -> IsReprC {
if offset_of_tuple!((T1,),0) == 0 && std::mem::size_of::<T1>() == std::mem::size_of::<(T1, )>() {
T1::repr_c_optimization_safe(version)
} else {
IsReprC::no()
}
}
}
impl<T1:ReprC, T2:ReprC> ReprC for (T1, T2) {
unsafe fn repr_c_optimization_safe(version: u32) -> IsReprC {
if offset_of_tuple!((T1,T2),0) == 0 && std::mem::size_of::<T1>()+std::mem::size_of::<T2>() == std::mem::size_of::<(T1, T2)>() {
T1::repr_c_optimization_safe(version) & T2::repr_c_optimization_safe(version)
} else {
IsReprC::no()
}
}
}
impl<T1:ReprC, T2:ReprC, T3:ReprC> ReprC for (T1, T2, T3) {
unsafe fn repr_c_optimization_safe(version: u32) -> IsReprC {
if offset_of_tuple!((T1,T2,T3),0) == 0 &&
offset_of_tuple!((T1,T2,T3),1) == std::mem::size_of::<T1>() &&
std::mem::size_of::<T1>()+std::mem::size_of::<T2>()+std::mem::size_of::<T3>() == std::mem::size_of::<(T1, T2, T3)>() {
T1::repr_c_optimization_safe(version) & T2::repr_c_optimization_safe(version) & T3::repr_c_optimization_safe(version)
} else {
IsReprC::no()
}
}
}
impl<T1:ReprC, T2:ReprC, T3:ReprC, T4:ReprC> ReprC for (T1, T2, T3, T4) {
unsafe fn repr_c_optimization_safe(version: u32) -> IsReprC {
if offset_of_tuple!((T1,T2,T3,T4),0) == 0 &&
offset_of_tuple!((T1,T2,T3,T4),1) == std::mem::size_of::<T1>() &&
offset_of_tuple!((T1,T2,T3,T4),2) == std::mem::size_of::<T1>() + std::mem::size_of::<T2>() &&
std::mem::size_of::<T1>()+std::mem::size_of::<T2>()+std::mem::size_of::<T3>()+std::mem::size_of::<T4>() == std::mem::size_of::<(T1, T2, T3, T4)>() {
T1::repr_c_optimization_safe(version) & T2::repr_c_optimization_safe(version) & T3::repr_c_optimization_safe(version) & T4::repr_c_optimization_safe(version)
} else {
IsReprC::no()
}
}
}
impl<T1: WithSchema, T2: WithSchema, T3: WithSchema> WithSchema for (T1, T2, T3) {
fn schema(version: u32) -> Schema {
Schema::new_tuple3::<T1, T2, T3>(version)
}
}
impl<T1: Serialize, T2: Serialize, T3: Serialize> Serialize for (T1, T2, T3) {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
self.0.serialize(serializer)?;
self.1.serialize(serializer)?;
self.2.serialize(serializer)
}
}
impl<T1: Deserialize, T2: Deserialize, T3: Deserialize> Deserialize for (T1, T2, T3) {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok((
T1::deserialize(deserializer)?,
T2::deserialize(deserializer)?,
T3::deserialize(deserializer)?,
))
}
}
impl<T1: WithSchema, T2: WithSchema> WithSchema for (T1, T2) {
fn schema(version: u32) -> Schema {
Schema::new_tuple2::<T1, T2>(version)
}
}
impl<T1: Serialize, T2: Serialize> Serialize for (T1, T2) {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
self.0.serialize(serializer)?;
self.1.serialize(serializer)
}
}
impl<T1: Deserialize, T2: Deserialize> Deserialize for (T1, T2) {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok((T1::deserialize(deserializer)?, T2::deserialize(deserializer)?))
}
}
impl<T1: WithSchema> WithSchema for (T1,) {
fn schema(version: u32) -> Schema {
Schema::new_tuple1::<T1>(version)
}
}
impl<T1: Serialize> Serialize for (T1,) {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
self.0.serialize(serializer)
}
}
impl<T1: Deserialize> Deserialize for (T1,) {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok((T1::deserialize(deserializer)?,))
}
}
#[cfg(feature="arrayvec")]
impl<const C:usize> ReprC for arrayvec::ArrayString<C> {}
#[cfg(feature="arrayvec")]
impl<const C:usize> WithSchema for arrayvec::ArrayString<C> {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_string)
}
}
#[cfg(feature="arrayvec")]
impl<const C:usize> Serialize for arrayvec::ArrayString<C> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_string(self.as_str())
}
}
#[cfg(feature="arrayvec")]
impl<const C:usize> Deserialize for arrayvec::ArrayString<C> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let l = deserializer.read_usize()?;
if l > C {
return Err(SavefileError::ArrayvecCapacityError {msg: format!("Deserialized data had length {}, but ArrayString capacity is {}", l,C)});
}
let mut tempbuf = [0u8;C];
deserializer.read_bytes_to_buf(&mut tempbuf[0..l])?;
match std::str::from_utf8(&tempbuf[0..l]) {
Ok(s) => Ok(arrayvec::ArrayString::try_from(s)?),
Err(_err) => Err(SavefileError::InvalidUtf8 {msg:format!("ArrayString<{}> contained invalid UTF8", C)})
}
}
}
#[cfg(feature="arrayvec")]
impl<const C: usize> Introspect for arrayvec::ArrayString<C> {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child<'a>(&'a self, _index: usize) -> Option<Box<dyn IntrospectItem<'a>>> {
None
}
}
#[cfg(feature="arrayvec")]
impl<V: WithSchema, const C: usize> WithSchema for arrayvec::ArrayVec<V,C> {
fn schema(version: u32) -> Schema {
Schema::Vector(Box::new(V::schema(version)))
}
}
#[cfg(feature="arrayvec")]
impl<V: Introspect + 'static, const C: usize> Introspect for arrayvec::ArrayVec<V,C> {
fn introspect_value(&self) -> String {
return "arrayvec[]".to_string();
}
fn introspect_child<'s>(&'s self, index: usize) -> Option<Box<dyn IntrospectItem<'s> + 's>> {
if index >= self.len() {
return None;
}
return Some(Box::new(IntrospectItemSimple {
key: index.to_string(),
val: &self[index],
}));
}
fn introspect_len(&self) -> usize {
self.len()
}
}
#[cfg(feature="arrayvec")]
impl<V:ReprC, const C: usize> ReprC for arrayvec::ArrayVec<V,C> {
unsafe fn repr_c_optimization_safe(version: u32) -> IsReprC {
V::repr_c_optimization_safe(version)
}
}
#[cfg(feature="arrayvec")]
impl<V: Serialize + ReprC, const C:usize> Serialize for arrayvec::ArrayVec<V,C> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
unsafe {
if V::repr_c_optimization_safe(serializer.version).is_false() {
regular_serialize_vec(self, serializer)
} else {
let l = self.len();
serializer.write_usize(l)?;
serializer.write_buf(std::slice::from_raw_parts(
self.as_ptr() as *const u8,
std::mem::size_of::<V>() * l,
))
}
}
}
}
#[cfg(feature="arrayvec")]
impl<V: Deserialize + ReprC, const C: usize > Deserialize for arrayvec::ArrayVec<V,C> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<arrayvec::ArrayVec<V,C>, SavefileError> {
let mut ret = arrayvec::ArrayVec::new();
let l = deserializer.read_usize()?;
if l > ret.capacity() {
return Err(SavefileError::ArrayvecCapacityError {
msg: format!("ArrayVec with capacity {} can't hold {} items", ret.capacity(), l),
});
}
if unsafe{V::repr_c_optimization_safe(deserializer.file_version)}.is_false() {
for _ in 0..l {
ret.push(V::deserialize(deserializer)?);
}
} else {
unsafe {
let bytebuf = std::slice::from_raw_parts_mut(ret.as_mut_ptr() as *mut u8, std::mem::size_of::<V>() * l);
deserializer.reader.read_exact(bytebuf)?; ret.set_len(l);
}
}
Ok(ret)
}
}
use std::ops::{Deref, Range};
impl<T: WithSchema> WithSchema for Box<T> {
fn schema(version: u32) -> Schema {
T::schema(version)
}
}
impl<T> ReprC for Box<T> {}
impl<T: Serialize> Serialize for Box<T> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
self.deref().serialize(serializer)
}
}
impl<T: Deserialize> Deserialize for Box<T> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(Box::new(T::deserialize(deserializer)?))
}
}
use std::rc::Rc;
impl<T> ReprC for Rc<T> {}
impl<T: WithSchema> WithSchema for Rc<T> {
fn schema(version: u32) -> Schema {
T::schema(version)
}
}
impl<T: Serialize> Serialize for Rc<T> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
self.deref().serialize(serializer)
}
}
impl<T: Deserialize> Deserialize for Rc<T> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(Rc::new(T::deserialize(deserializer)?))
}
}
impl<T> ReprC for Arc<T> {}
impl<T: WithSchema> WithSchema for Arc<T> {
fn schema(version: u32) -> Schema {
T::schema(version)
}
}
impl<T: Serialize> Serialize for Arc<T> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
self.deref().serialize(serializer)
}
}
impl<T: Deserialize> Deserialize for Arc<T> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(Arc::new(T::deserialize(deserializer)?))
}
}
#[cfg(feature="bzip2")]
use bzip2::Compression;
use std::any::{Any, TypeId};
use std::cell::Cell;
use std::cell::RefCell;
use std::convert::{TryFrom, TryInto};
use std::fmt::{Debug, Display, Formatter};
use std::marker::PhantomData;
use std::path::{PathBuf, Path};
use std::ptr::NonNull;
use std::sync::Arc;
use byteorder::{ReadBytesExt, WriteBytesExt};
use memoffset::offset_of_tuple;
impl<T> ReprC for RefCell<T> {}
impl<T: WithSchema> WithSchema for RefCell<T> {
fn schema(version: u32) -> Schema {
T::schema(version)
}
}
impl<T: Serialize> Serialize for RefCell<T> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
self.borrow().serialize(serializer)
}
}
impl<T: Deserialize> Deserialize for RefCell<T> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(RefCell::new(T::deserialize(deserializer)?))
}
}
impl<T: ReprC> ReprC for Cell<T> {
unsafe fn repr_c_optimization_safe(version: u32) -> IsReprC {
T::repr_c_optimization_safe(version)
}
}
impl<T: WithSchema> WithSchema for Cell<T> {
fn schema(version: u32) -> Schema {
T::schema(version)
}
}
impl<T: Serialize + Copy> Serialize for Cell<T> {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
let t: T = self.get();
t.serialize(serializer)
}
}
impl<T: Deserialize> Deserialize for Cell<T> {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(Cell::new(T::deserialize(deserializer)?))
}
}
impl WithSchema for () {
fn schema(_version: u32) -> Schema {
Schema::ZeroSize
}
}
impl Serialize for () {
fn serialize(&self, _serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
Ok(())
}
}
impl Introspect for () {
fn introspect_value(&self) -> String {
"()".to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Deserialize for () {
fn deserialize(_deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(())
}
}
impl<T: Introspect> Introspect for (T,) {
fn introspect_value(&self) -> String {
return "1-tuple".to_string();
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if index == 0 {
return Some(introspect_item("0".to_string(), &self.0));
}
return None;
}
}
impl<T1: Introspect, T2: Introspect> Introspect for (T1, T2) {
fn introspect_value(&self) -> String {
return "2-tuple".to_string();
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if index == 0 {
return Some(introspect_item("0".to_string(), &self.0));
}
if index == 1 {
return Some(introspect_item("1".to_string(), &self.1));
}
return None;
}
}
impl<T1: Introspect, T2: Introspect, T3: Introspect> Introspect for (T1, T2, T3) {
fn introspect_value(&self) -> String {
return "3-tuple".to_string();
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if index == 0 {
return Some(introspect_item("0".to_string(), &self.0));
}
if index == 1 {
return Some(introspect_item("1".to_string(), &self.1));
}
if index == 2 {
return Some(introspect_item("2".to_string(), &self.2));
}
return None;
}
}
impl<T1: Introspect, T2: Introspect, T3: Introspect, T4: Introspect> Introspect for (T1, T2, T3, T4) {
fn introspect_value(&self) -> String {
return "4-tuple".to_string();
}
fn introspect_child(&self, index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
if index == 0 {
return Some(introspect_item("0".to_string(), &self.0));
}
if index == 1 {
return Some(introspect_item("1".to_string(), &self.1));
}
if index == 2 {
return Some(introspect_item("2".to_string(), &self.2));
}
if index == 3 {
return Some(introspect_item("3".to_string(), &self.3));
}
return None;
}
}
impl Introspect for AtomicBool {
fn introspect_value(&self) -> String {
self.load(Ordering::SeqCst).to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for AtomicU8 {
fn introspect_value(&self) -> String {
self.load(Ordering::SeqCst).to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for AtomicI8 {
fn introspect_value(&self) -> String {
self.load(Ordering::SeqCst).to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for AtomicU16 {
fn introspect_value(&self) -> String {
self.load(Ordering::SeqCst).to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for AtomicI16 {
fn introspect_value(&self) -> String {
self.load(Ordering::SeqCst).to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for AtomicU32 {
fn introspect_value(&self) -> String {
self.load(Ordering::SeqCst).to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for AtomicI32 {
fn introspect_value(&self) -> String {
self.load(Ordering::SeqCst).to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for AtomicU64 {
fn introspect_value(&self) -> String {
self.load(Ordering::SeqCst).to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for AtomicI64 {
fn introspect_value(&self) -> String {
self.load(Ordering::SeqCst).to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for AtomicUsize {
fn introspect_value(&self) -> String {
self.load(Ordering::SeqCst).to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for AtomicIsize {
fn introspect_value(&self) -> String {
self.load(Ordering::SeqCst).to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl WithSchema for AtomicBool {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_bool)
}
}
impl WithSchema for AtomicU8 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_u8)
}
}
impl WithSchema for AtomicI8 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_i8)
}
}
impl WithSchema for AtomicU16 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_u16)
}
}
impl WithSchema for AtomicI16 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_i16)
}
}
impl WithSchema for AtomicU32 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_u32)
}
}
impl WithSchema for AtomicI32 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_i32)
}
}
impl WithSchema for AtomicU64 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_u64)
}
}
impl WithSchema for AtomicI64 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_i64)
}
}
impl WithSchema for AtomicUsize {
fn schema(_version: u32) -> Schema {
match std::mem::size_of::<usize>() {
4 => Schema::Primitive(SchemaPrimitive::schema_u32),
8 => Schema::Primitive(SchemaPrimitive::schema_u64),
_ => panic!("Size of usize was neither 32 bit nor 64 bit. This is not supported by the savefile crate."),
}
}
}
impl WithSchema for AtomicIsize {
fn schema(_version: u32) -> Schema {
match std::mem::size_of::<isize>() {
4 => Schema::Primitive(SchemaPrimitive::schema_i32),
8 => Schema::Primitive(SchemaPrimitive::schema_i64),
_ => panic!("Size of isize was neither 32 bit nor 64 bit. This is not supported by the savefile crate."),
}
}
}
impl WithSchema for bool {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_bool)
}
}
impl WithSchema for u8 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_u8)
}
}
impl WithSchema for i8 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_i8)
}
}
impl WithSchema for u16 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_u16)
}
}
impl WithSchema for i16 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_i16)
}
}
impl WithSchema for u32 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_u32)
}
}
impl WithSchema for i32 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_i32)
}
}
impl WithSchema for u64 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_u64)
}
}
impl WithSchema for u128 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_u128)
}
}
impl WithSchema for i128 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_i128)
}
}
impl WithSchema for i64 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_i64)
}
}
impl WithSchema for char {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_char)
}
}
impl WithSchema for usize {
fn schema(_version: u32) -> Schema {
match std::mem::size_of::<usize>() {
4 => Schema::Primitive(SchemaPrimitive::schema_u32),
8 => Schema::Primitive(SchemaPrimitive::schema_u64),
_ => panic!("Size of usize was neither 32 bit nor 64 bit. This is not supported by the savefile crate."),
}
}
}
impl WithSchema for isize {
fn schema(_version: u32) -> Schema {
match std::mem::size_of::<isize>() {
4 => Schema::Primitive(SchemaPrimitive::schema_i32),
8 => Schema::Primitive(SchemaPrimitive::schema_i64),
_ => panic!("Size of isize was neither 32 bit nor 64 bit. This is not supported by the savefile crate."),
}
}
}
impl WithSchema for f32 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_f32)
}
}
impl WithSchema for f64 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_f64)
}
}
impl Introspect for bool {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for u8 {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for u16 {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for u32 {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for u64 {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for u128 {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for i8 {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for i16 {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for i32 {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for i64 {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for char {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for i128 {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for f32 {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for f64 {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for usize {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Introspect for isize {
fn introspect_value(&self) -> String {
self.to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Serialize for u8 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_u8(*self)
}
}
impl Deserialize for u8 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_u8()
}
}
impl Serialize for bool {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_bool(*self)
}
}
impl Deserialize for bool {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_bool()
}
}
impl Serialize for f32 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_f32(*self)
}
}
impl Deserialize for f32 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_f32()
}
}
impl Serialize for f64 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_f64(*self)
}
}
impl Deserialize for f64 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_f64()
}
}
impl Serialize for i8 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_i8(*self)
}
}
impl Deserialize for i8 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_i8()
}
}
impl Serialize for u16 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_u16(*self)
}
}
impl Deserialize for u16 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_u16()
}
}
impl Serialize for i16 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_i16(*self)
}
}
impl Deserialize for i16 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_i16()
}
}
impl Serialize for u32 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_u32(*self)
}
}
impl Deserialize for u32 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_u32()
}
}
impl Serialize for i32 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_i32(*self)
}
}
impl Deserialize for i32 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_i32()
}
}
impl Serialize for u64 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_u64(*self)
}
}
impl Deserialize for u64 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_u64()
}
}
impl Serialize for i64 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_i64(*self)
}
}
impl Serialize for char {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_u32((*self).into())
}
}
impl Deserialize for i64 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_i64()
}
}
impl Deserialize for char {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let uc = deserializer.read_u32()?;
match uc.try_into() {
Ok(x) => Ok(x),
Err(_) => Err(SavefileError::InvalidChar)
}
}
}
impl Serialize for u128 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_u128(*self)
}
}
impl Deserialize for u128 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_u128()
}
}
impl Serialize for i128 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_i128(*self)
}
}
impl Deserialize for i128 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_i128()
}
}
impl Serialize for usize {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_usize(*self)
}
}
impl Deserialize for usize {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_usize()
}
}
impl Serialize for isize {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_isize(*self)
}
}
impl Deserialize for isize {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
deserializer.read_isize()
}
}
impl Serialize for AtomicBool {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_bool(self.load(Ordering::SeqCst))
}
}
impl Deserialize for AtomicBool {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(AtomicBool::new(deserializer.read_bool()?))
}
}
impl Serialize for AtomicU8 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_u8(self.load(Ordering::SeqCst))
}
}
impl Deserialize for AtomicU8 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(AtomicU8::new(deserializer.read_u8()?))
}
}
impl Serialize for AtomicI8 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_i8(self.load(Ordering::SeqCst))
}
}
impl Deserialize for AtomicI8 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(AtomicI8::new(deserializer.read_i8()?))
}
}
impl Serialize for AtomicU16 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_u16(self.load(Ordering::SeqCst))
}
}
impl Deserialize for AtomicU16 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(AtomicU16::new(deserializer.read_u16()?))
}
}
impl Serialize for AtomicI16 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_i16(self.load(Ordering::SeqCst))
}
}
impl Deserialize for AtomicI16 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(AtomicI16::new(deserializer.read_i16()?))
}
}
impl Serialize for AtomicU32 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_u32(self.load(Ordering::SeqCst))
}
}
impl Deserialize for AtomicU32 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(AtomicU32::new(deserializer.read_u32()?))
}
}
impl Serialize for AtomicI32 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_i32(self.load(Ordering::SeqCst))
}
}
impl Deserialize for AtomicI32 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(AtomicI32::new(deserializer.read_i32()?))
}
}
impl Serialize for AtomicU64 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_u64(self.load(Ordering::SeqCst))
}
}
impl Deserialize for AtomicU64 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(AtomicU64::new(deserializer.read_u64()?))
}
}
impl Serialize for AtomicI64 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_i64(self.load(Ordering::SeqCst))
}
}
impl Deserialize for AtomicI64 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(AtomicI64::new(deserializer.read_i64()?))
}
}
impl Serialize for AtomicUsize {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_usize(self.load(Ordering::SeqCst))
}
}
impl Deserialize for AtomicUsize {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(AtomicUsize::new(deserializer.read_usize()?))
}
}
impl Serialize for AtomicIsize {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_isize(self.load(Ordering::SeqCst))
}
}
impl Deserialize for AtomicIsize {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
Ok(AtomicIsize::new(deserializer.read_isize()?))
}
}
impl ReprC for AtomicBool{}
impl ReprC for AtomicI8{}
impl ReprC for AtomicU8{}
impl ReprC for AtomicI16{}
impl ReprC for AtomicU16{}
impl ReprC for AtomicI32{}
impl ReprC for AtomicU32{}
impl ReprC for AtomicI64{}
impl ReprC for AtomicU64{}
impl ReprC for AtomicIsize{}
impl ReprC for AtomicUsize{}
#[derive(Clone, Copy, Eq, PartialEq, Default, Debug)]
pub struct Canary1 {}
impl Canary1 {
pub fn new() -> Canary1 {
Canary1 {}
}
}
impl Introspect for Canary1 {
fn introspect_value(&self) -> String {
"Canary1".to_string()
}
fn introspect_child(&self, _index: usize) -> Option<Box<dyn IntrospectItem + '_>> {
None
}
}
impl Deserialize for Canary1 {
fn deserialize(deserializer: &mut Deserializer<impl Read>) -> Result<Self, SavefileError> {
let magic = deserializer.read_u32()?;
if magic != 0x47566843 {
return Err(SavefileError::GeneralError {
msg: format!(
"Encountered bad magic value when deserializing Canary1. Expected {} but got {}",
0x47566843, magic
),
});
}
Ok(Canary1 {})
}
}
impl Serialize for Canary1 {
fn serialize(&self, serializer: &mut Serializer<impl Write>) -> Result<(), SavefileError> {
serializer.write_u32(0x47566843)
}
}
impl ReprC for Canary1 {}
impl WithSchema for Canary1 {
fn schema(_version: u32) -> Schema {
Schema::Primitive(SchemaPrimitive::schema_canary1)
}
}
#[derive(Clone, Debug)]
struct PathElement {
key: String,
key_disambiguator: usize,
max_children: usize,
}
#[derive(Clone, Debug)]
pub struct Introspector {
path: Vec<PathElement>,
child_load_count: usize,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum IntrospectorNavCommand {
ExpandElement(IntrospectedElementKey),
SelectNth {
select_depth: usize,
select_index: usize,
},
Nothing,
Up,
}
#[derive(PartialEq, Eq, Clone)]
pub struct IntrospectedElementKey {
pub depth: usize,
pub key: String,
pub key_disambiguator: usize,
}
impl Default for IntrospectedElementKey {
fn default() -> Self {
IntrospectedElementKey {
depth: 0,
key: "".to_string(),
key_disambiguator: 0,
}
}
}
#[derive(PartialEq, Eq, Clone)]
pub struct IntrospectedElement {
pub key: IntrospectedElementKey,
pub value: String,
pub has_children: bool,
pub selected: bool,
}
impl Debug for IntrospectedElementKey {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(
f,
"Key({} (at depth {}, key disambig {}))",
self.key, self.depth, self.key_disambiguator
)
}
}
impl Debug for IntrospectedElement {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(
f,
"KeyVal({} = {} (at depth {}, key disambig {}))",
self.key.key, self.value, self.key.depth, self.key.key_disambiguator
)
}
}
impl Display for IntrospectedElement {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(f, "{} = {}", self.key.key, self.value)
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum IntrospectionError {
BadDepth,
UnknownKey,
NoChildren,
IndexOutOfRange,
AlreadyAtTop,
}
#[derive(Debug, Clone)]
pub struct IntrospectionFrame {
pub selected: Option<usize>,
pub keyvals: Vec<IntrospectedElement>,
pub limit_reached: bool,
}
#[derive(Debug, Clone)]
pub struct IntrospectionResult {
pub frames: Vec<IntrospectionFrame>,
cached_total_len: usize,
}
impl Display for IntrospectionResult {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
self.format_result_row(f)
}
}
impl IntrospectionResult {
pub fn total_index(&self, index: usize) -> Option<IntrospectedElement> {
let mut cur = 0;
self.total_index_impl(index, 0, &mut cur)
}
fn total_index_impl(&self, index: usize, depth: usize, cur: &mut usize) -> Option<IntrospectedElement> {
if depth >= self.frames.len() {
return None;
}
let frame = &self.frames[depth];
{
let mut offset = 0;
if let Some(selection) = frame.selected {
if index <= *cur + selection {
return Some(frame.keyvals[index - *cur].clone());
}
*cur += selection + 1;
if let Some(result) = self.total_index_impl(index, depth + 1, cur) {
return Some(result);
}
offset = selection + 1;
}
if (index - *cur) + offset < frame.keyvals.len() {
return Some(frame.keyvals[(index - *cur) + offset].clone());
}
*cur += frame.keyvals.len() - offset;
}
return None;
}
pub fn total_len(&self) -> usize {
self.cached_total_len
}
fn format_result_row(self: &IntrospectionResult, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
if self.frames.len() == 0 {
writeln!(f, "Introspectionresult:\n*empty*")?;
return Ok(());
}
let mut idx = 0;
let mut depth = Vec::new();
writeln!(f, "Introspectionresult:")?;
'outer: loop {
let cur_row = &self.frames[depth.len()];
if idx >= cur_row.keyvals.len() {
if let Some(new_idx) = depth.pop() {
idx = new_idx;
continue;
} else {
break;
}
}
while idx < cur_row.keyvals.len() {
let item = &cur_row.keyvals[idx];
let is_selected = Some(idx) == cur_row.selected;
let pad = if is_selected {
"*"
} else {
if item.has_children {
">"
} else {
" "
}
};
writeln!(f, "{:>indent$}{}", pad, item, indent = 1 + 2 * depth.len())?;
idx += 1;
if is_selected && depth.len() + 1 < self.frames.len() {
depth.push(idx);
idx = 0;
continue 'outer;
}
}
}
Ok(())
}
}
impl Display for IntrospectedElementKey {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(f, "{}", self.key)
}
}
struct OuterIntrospectItem<'a> {
key: String,
val: &'a dyn Introspect,
}
impl<'a> IntrospectItem<'a> for OuterIntrospectItem<'a> {
fn key(&self) -> &str {
&self.key
}
fn val(&self) -> &dyn Introspect {
self.val
}
}
impl Introspector {
pub fn new() -> Introspector {
Introspector {
path: vec![],
child_load_count: std::usize::MAX,
}
}
pub fn new_with(child_load_count: usize) -> Introspector {
Introspector {
path: vec![],
child_load_count,
}
}
pub fn num_frames(&self) -> usize {
self.path.len()
}
fn dive<'a>(
&mut self,
depth: usize,
object: &'a dyn Introspect,
navigation_command: IntrospectorNavCommand,
) -> Result<Vec<IntrospectionFrame>, IntrospectionError> {
let mut result_vec = Vec::new();
let mut navigation_command = Some(navigation_command);
let mut cur_path = self.path.get(depth).cloned();
let mut index = 0;
let mut row = IntrospectionFrame {
selected: None,
keyvals: vec![],
limit_reached: false,
};
let mut key_disambig_map = HashMap::new();
let mut do_select_nth = None;
let mut err_if_key_not_found = false;
if let Some(navigation_command) = navigation_command.as_ref() {
match navigation_command {
IntrospectorNavCommand::ExpandElement(elem) => {
if elem.depth > self.path.len() {
return Err(IntrospectionError::BadDepth);
}
if depth == elem.depth {
self.path.drain(depth..);
self.path.push(PathElement {
key: elem.key.clone(),
key_disambiguator: elem.key_disambiguator,
max_children: self.child_load_count,
});
cur_path = self.path.get(depth).cloned();
err_if_key_not_found = true;
}
}
IntrospectorNavCommand::SelectNth {
select_depth,
select_index,
} => {
if depth == *select_depth {
do_select_nth = Some(*select_index);
}
}
IntrospectorNavCommand::Nothing => {}
IntrospectorNavCommand::Up => {}
}
}
loop {
if let Some(child_item) = object.introspect_child(index) {
let key: String = child_item.key().into();
let disambig_counter: &mut usize = key_disambig_map.entry(key.clone()).or_insert(0usize);
let has_children = child_item.val().introspect_child(0).is_some();
row.keyvals.push(IntrospectedElement {
key: IntrospectedElementKey {
depth,
key: key.clone(),
key_disambiguator: *disambig_counter,
},
value: child_item.val().introspect_value(),
has_children,
selected: false,
});
if Some(index) == do_select_nth {
self.path.push(PathElement {
key: key.clone(),
key_disambiguator: *disambig_counter,
max_children: self.child_load_count,
});
do_select_nth = None;
cur_path = self.path.last().cloned();
}
if let Some(cur_path_obj) = &cur_path {
if row.selected.is_none()
&& cur_path_obj.key == key
&& cur_path_obj.key_disambiguator == *disambig_counter
{
row.selected = Some(index);
row.keyvals.last_mut().unwrap().selected = true;
if has_children {
let mut subresult =
self.dive(depth + 1, child_item.val(), navigation_command.take().unwrap())?;
debug_assert_eq!(result_vec.len(), 0);
std::mem::swap(&mut result_vec, &mut subresult);
}
}
}
*disambig_counter += 1;
} else {
break;
}
index += 1;
if index
>= cur_path
.as_ref()
.map(|x| x.max_children)
.unwrap_or(self.child_load_count)
{
row.limit_reached = true;
break;
}
}
if do_select_nth.is_some() {
if index == 0 {
return Err(IntrospectionError::NoChildren);
}
return Err(IntrospectionError::IndexOutOfRange);
}
if err_if_key_not_found && row.selected.is_none() {
self.path.pop().unwrap();
return Err(IntrospectionError::UnknownKey);
}
result_vec.insert(0, row);
Ok(result_vec)
}
pub fn do_introspect<'a>(
&mut self,
object: &'a dyn Introspect,
navigation_command: IntrospectorNavCommand,
) -> Result<IntrospectionResult, IntrospectionError> {
match &navigation_command {
IntrospectorNavCommand::ExpandElement(_) => {}
IntrospectorNavCommand::SelectNth { .. } => {}
IntrospectorNavCommand::Nothing => {}
IntrospectorNavCommand::Up => {
if self.path.len() == 0 {
return Err(IntrospectionError::AlreadyAtTop);
}
self.path.pop();
}
}
let frames = self.dive(0, object, navigation_command)?;
let mut total = 0;
for frame in &frames {
total += frame.keyvals.len();
}
let accum = IntrospectionResult {
frames: frames,
cached_total_len: total,
};
Ok(accum)
}
}