use std::sync::OnceLock;
use miniz_oxide::inflate::{
TINFLStatus,
core::{
DecompressorOxide, decompress, inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF,
},
};
use serde::de::DeserializeOwned;
pub fn decompress_blob(blob: &[u8]) -> Vec<u8> {
let (len, compressed) = blob.split_at(4);
let len = u32::from_le_bytes(len.try_into().unwrap()) as usize;
let mut data = vec![0u8; len];
let (status, _, written) = decompress(
&mut DecompressorOxide::default(),
compressed,
&mut data,
0,
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF,
);
assert!(status == TINFLStatus::Done && written == len, "Failed to decompress data");
data
}
pub fn load<T: DeserializeOwned>(compressed: &[u8]) -> T {
postcard::from_bytes(&decompress_blob(compressed)).unwrap()
}
pub struct LazyData<T> {
compressed: &'static [u8],
cell: OnceLock<T>,
}
impl<T: DeserializeOwned> LazyData<T> {
pub const fn new(compressed: &'static [u8]) -> Self {
Self { compressed, cell: OnceLock::new() }
}
pub fn get(&self) -> &T {
self.cell.get_or_init(|| load(self.compressed))
}
}
pub struct LazyBlob {
compressed: &'static [u8],
cell: OnceLock<Vec<u8>>,
}
impl LazyBlob {
pub const fn new(compressed: &'static [u8]) -> Self {
Self { compressed, cell: OnceLock::new() }
}
pub fn get(&self) -> &[u8] {
self.cell.get_or_init(|| decompress_blob(self.compressed))
}
}