1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//---------------------------------------------------------------------------------------------------- Use
use anyhow::{anyhow,bail};
use std::path::PathBuf;
use crate::common;
use bincode2::config::*;
use crate::header::*;
use std::io::{Seek};
//use log::{info,error,warn,trace,debug};
//use serde::{Serialize,Deserialize};
use std::io::{
	Read,Write,
	BufReader,BufWriter,
};
use once_cell::sync::Lazy;

//---------------------------------------------------------------------------------------------------- Bincode
static ENCODING_OPTIONS: Lazy<Configuration> = Lazy::new(bincode2::config::standard);

crate::common::impl_macro_binary!(Bincode2, "bin");

/// [`Bincode2`](https://docs.rs/bincode/2.0.0-rc.3) (`2.x.x-rc.x`) (binary) file format
///
/// ## `2.x.x-rc.x`
/// [`bincode 2.0.0`](https://docs.rs/bincode/2.0.0-rc.3) (currently not stable) brings big performance improvements.
///
/// It also no longer requires `serde`, having it's own `Encode` and `Decode` traits.
///
/// This means your type must implement these as well, e.g:
/// ```rust,ignore
/// use bincode::{Encode, Decode};
///
/// #[derive(Encode, Decode)]
/// struct State;
/// ```
///
/// To implement `bincode 2.x.x`'s new traits, add it to `Cargo.toml`:
/// ```txt
/// bincode = "2.0.0-rc.3"
/// ```
/// and add `#[derive(Encode, Decode)]` to your types, like you would with `serde`.
///
/// ## Encoding
/// The encoding option used is:
/// ```txt
/// bincode::config::standard()
/// ```
///
/// File extension is `.bin`.
///
/// ## Safety
/// When manually implementing, you are **promising** that the `PATH`'s manually specified are correct.
pub unsafe trait Bincode2: bincode2::Encode + bincode2::Decode {
	#[doc(hidden)]
	#[inline(always)]
	/// Internal function. Most efficient `from_file()` impl.
	fn __from_file() -> Result <Self, anyhow::Error> {
		let path = Self::absolute_path()?;
		let mut file = std::fs::File::open(path)?;
		Self::from_reader(&mut file)
	}

	#[inline(always)]
	/// Create [`Self`] from bytes.
	fn from_bytes(bytes: &[u8]) -> Result<Self, anyhow::Error> {
		ensure_header!(bytes);

		match bincode2::decode_from_slice(&bytes[25..], *ENCODING_OPTIONS) {
			Ok((s, _))  => Ok(s),
			Err(e) => Err(e)?,
		}
	}

	#[inline(always)]
	/// Convert [`Self`] to bytes.
	fn to_bytes(&self) -> Result<Vec<u8>, anyhow::Error> {
		let mut vec = match bincode2::encode_to_vec(self, *ENCODING_OPTIONS) {
			Ok(v)  => v,
			Err(e) => Err(e)?,
		};

		header_return!(vec)
	}

	#[inline(always)]
	/// Create [`Self`] directly from reader `R`.
	fn from_reader<R>(reader: &mut R) -> Result<Self, anyhow::Error>
		where
			R: Read,
	{
		let mut bytes = [0_u8; 25];
		let mut reader = BufReader::new(reader);
		reader.read_exact(&mut bytes)?;
		ensure_header!(bytes);
		Ok(bincode2::decode_from_std_read(&mut reader, *ENCODING_OPTIONS)?)
	}

	#[inline(always)]
	/// Convert [`Self`] directly to the given [`slice`].
	///
	/// The amount of bytes written is returned on success.
	///
	/// ## Error
	/// The slice must be at least `25` bytes in length to holder the header
	/// bytes and must be large enough to hold the resulting serialized bytes.
	fn to_slice(&self, slice: &mut [u8]) -> Result<usize, anyhow::Error> {
		let len = slice.len();
		if len < 25 {
			bail!("input slice length less than 25: {len}");
		}
		slice[..25].copy_from_slice(&Self::full_header());
		Ok(bincode2::encode_into_slice(self, &mut slice[25..], *ENCODING_OPTIONS)?)
	}

	#[inline(always)]
	/// Convert [`Self`] to directly to the writer `W` without intermediate bytes.
	///
	/// The amount of bytes written is returned on success.
	fn to_writer<W>(&self, writer: &mut W) -> Result<usize, anyhow::Error>
		where
			W: Write,
	{
		let mut writer = BufWriter::new(writer);
		writer.write_all(&Self::full_header())?;
		Ok(bincode2::encode_into_std_write(self, &mut writer, *ENCODING_OPTIONS)?)
	}

	impl_header!();
	common::impl_binary!("bincode2");
}

//---------------------------------------------------------------------------------------------------- TESTS
//#[cfg(test)]
//mod tests {
//}