#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use crate::{error::Error, secure::get_key_store};
pub mod error;
pub mod secure;
#[cfg_attr(async_api, async_trait::async_trait)]
pub trait GlobalByteBox<const SECURE: bool>: Serialize + for<'de> Deserialize<'de> {
fn path() -> PathBuf;
fn save(&self) -> Result<(), Error> {
let path = Self::path();
let bytes = self.encode()?;
std::fs::write(&path, bytes)?;
Ok(())
}
#[cfg(async_api)]
async fn save_async(&self) -> Result<(), Error> {
let path = Self::path();
let bytes = self.encode()?;
#[cfg(feature = "async-fs")]
async_fs::write(&path, bytes).await?;
#[cfg(feature = "tokio")]
tokio::fs::write(&path, bytes).await?;
Ok(())
}
fn load() -> Result<Self, Error>
where
Self: Sized,
{
let path = Self::path();
let bytes = std::fs::read(&path)?;
Self::decode(&bytes)
}
#[cfg(async_api)]
async fn load_async() -> Result<Self, Error>
where
Self: Sized,
{
let path = Self::path();
#[cfg(feature = "async-fs")]
let bytes: Vec<u8> = async_fs::read(&path).await?;
#[cfg(feature = "tokio")]
let bytes: Vec<u8> = tokio::fs::read(&path).await?;
Self::decode(&bytes)
}
fn encode(&self) -> Result<Vec<u8>, Error> {
if SECURE {
let name = format!("{}", Self::path().display());
let bytes = bitcode::serialize(self)?;
let key = get_key_store().get_key_or_generate(&name)?;
secure::encrypt(&bytes, key)
} else {
Ok(bitcode::serialize(self)?)
}
}
fn decode(bytes: &[u8]) -> Result<Self, Error> {
if SECURE {
let name = Self::path().to_string_lossy().to_string();
let key = get_key_store().get_key_or_generate(&name)?;
let decrypted = secure::decrypt(bytes.to_vec(), key)?;
Ok(bitcode::deserialize(&decrypted)?)
} else {
Ok(bitcode::deserialize(bytes)?)
}
}
fn delete() -> Result<(), Error> {
std::fs::remove_file(Self::path())?;
Ok(())
}
#[cfg(async_api)]
async fn delete_async(&self) -> Result<(), Error> {
#[cfg(feature = "async-fs")]
async_fs::remove_file(Self::path()).await?;
#[cfg(feature = "tokio")]
tokio::fs::remove_file(Self::path()).await?;
Ok(())
}
}
#[cfg_attr(async_api, async_trait::async_trait)]
pub trait ByteBox<const SECURE: bool>: Serialize + for<'de> Deserialize<'de> {
fn path(&self) -> PathBuf;
fn save(&self) -> Result<(), Error> {
let path = self.path();
let bytes = self.encode()?;
std::fs::write(&path, bytes)?;
Ok(())
}
fn load(&mut self) -> Result<(), Error> {
let path = self.path();
let bytes = std::fs::read(&path)?;
*self = self.decode(&bytes)?;
Ok(())
}
#[cfg(async_api)]
async fn load_async(&mut self) -> Result<(), Error> {
let path = self.path();
#[cfg(feature = "async-fs")]
let bytes: Vec<u8> = async_fs::read(&path).await?;
#[cfg(feature = "tokio")]
let bytes: Vec<u8> = tokio::fs::read(&path).await?;
*self = self.decode(&bytes)?;
Ok(())
}
fn encode(&self) -> Result<Vec<u8>, Error> {
if SECURE {
let name = format!("{}", self.path().display());
let bytes = bitcode::serialize(self)?;
let key = get_key_store().get_key_or_generate(&name)?;
secure::encrypt(&bytes, key)
} else {
Ok(bitcode::serialize(self)?)
}
}
fn decode(&self, bytes: &[u8]) -> Result<Self, Error> {
if SECURE {
let name = format!("{}", self.path().display());
let key = get_key_store().get_key_or_generate(&name)?;
let decrypted = secure::decrypt(bytes.to_vec(), key)?;
Ok(bitcode::deserialize(&decrypted)?)
} else {
Ok(bitcode::deserialize(bytes)?)
}
}
fn delete(&self) -> Result<(), Error> {
std::fs::remove_file(self.path())?;
Ok(())
}
#[cfg(async_api)]
async fn save_async(&self) -> Result<(), Error> {
let path = self.path();
let bytes = self.encode()?;
#[cfg(feature = "async-fs")]
async_fs::write(&path, bytes).await?;
#[cfg(feature = "tokio")]
tokio::fs::write(&path, bytes).await?;
Ok(())
}
#[cfg(async_api)]
async fn delete_async(&self) -> Result<(), Error> {
#[cfg(feature = "async-fs")]
async_fs::remove_file(self.path()).await?;
#[cfg(feature = "tokio")]
tokio::fs::remove_file(self.path()).await?;
Ok(())
}
}