eule 0.5.0

Async generic serialization crate with a minimal interface.
Documentation
use serde::{Serialize, Deserialize};
use std::path::PathBuf;
use directories::ProjectDirs;
use anyhow::{Result, Context};
use tokio::{fs, fs::OpenOptions, io::{self, AsyncReadExt, AsyncWriteExt}, sync::Mutex};
use std::sync::Arc;

pub struct Serder
{
	path: PathBuf,
}
impl Serder
{
	pub async fn new(package_name: String) -> Result<Serder>
	{
		let dirs = ProjectDirs::from("","", &package_name).context(r"Error finding data_dir: https://crates.io/crates/directories")?;
		let data_dir = dirs.data_dir();
		fs::create_dir_all(data_dir).await?;
		Ok(Serder { path: data_dir.into() })
	}
	pub async fn deserialize_or_default<T>(&self, filename: String) -> io::Result<T>
	where
		T: Default + for<'de> Deserialize<'de>
	{
		let filepath = self.path.join(filename);
		let mut file = OpenOptions::new().read(true).write(true).create(true).open(filepath).await?;

		let mut buf = Vec::new();	
		let size = file.read_to_end(&mut buf).await?;

		let output: T = match size
		{
			0 => Default::default(),
			1.. => serde_json::from_slice(&buf)?,
		};

		Ok(output)
	}
		pub async fn deserialize_or_value<T>(&self, filename: String, value: T) -> io::Result<T>
	where
		T: for<'de> Deserialize<'de>
	{
		let filepath = self.path.join(filename);
		let mut file = OpenOptions::new().read(true).write(true).create(true).open(filepath).await?;

		let mut buf = Vec::new();	
		let size = file.read_to_end(&mut buf).await?;

		let output: T = match size
		{
			0 => value,
			1.. => serde_json::from_slice(&buf)?,
		};

		Ok(output)
	}
	pub async fn deserialize_or_err<T>(&self, filename: String) -> Result<T>
	where
		T: for<'de> Deserialize<'de>
	{
		let buf = self.read_file(filename).await?;
	
		let output = match buf.len()
		{
			0 => None,
			1.. => Some(serde_json::from_slice(&buf)?),
		}.context("File empty.")?;
		Ok(output)
	}
	pub async fn serialize_and_save<T>(&self, filename: String, data: T) -> io::Result<()>
	where
		T: Serialize
	{
		let filepath = self.path.join(filename);
		let mut file = OpenOptions::new().truncate(true).write(true).create(true).open(filepath).await?;
		let serialized_data = serde_json::to_string(&data)?;
		file.write_all(serialized_data.as_bytes()).await?;
		Ok(())
	}
	pub async fn serialize_arc_and_save<T>(&self, filename: String, data: Arc<T>) -> io::Result<()>
	where
		T: Serialize
	{
		let filepath = self.path.join(filename);
		let mut file = OpenOptions::new().truncate(true).write(true).create(true).open(filepath).await?;
		let serialized_data = serde_json::to_string(data.as_ref())?;
		file.write_all(serialized_data.as_bytes()).await?;
		Ok(())
	}
	pub async fn serialize_arc_mutex_and_save<T>(&self, filename: String, data: Arc<Mutex<T>>) -> io::Result<()>
	where
		T: Serialize
	{
		let filepath = self.path.join(filename);
		let mut file = OpenOptions::new().truncate(true).write(true).create(true).open(filepath).await?;
		let locked_data = data.lock().await;
		let serialized_data = serde_json::to_string(&*locked_data)?;
		file.write_all(serialized_data.as_bytes()).await?;
		Ok(())
	}
	async fn read_file(&self, filename: String) -> Result<Vec<u8>>
	{
		let filepath = self.path.join(filename);
		let mut file = OpenOptions::new().read(true).write(true).create(true).open(filepath).await?;

		let mut buf = Vec::new();	
		file.read_to_end(&mut buf).await?;

		Ok(buf)
	}
}

#[cfg(test)]
mod tests
{
	use std::collections::HashMap;
	use super::*;
	#[derive(Clone, Serialize, Deserialize, Eq, PartialEq, Hash)] 
	pub struct T<A, B, C>
	{
		data: E<A, B, C>,
	}
	#[derive(Clone, Serialize, Deserialize, Eq, PartialEq, Hash)] 
	pub enum E<A, B, C>
	{
		A {v: Option<A>},
		B {v: Option<B>},
		C {v: Option<C>},
	}
	#[derive(Clone, Serialize, Deserialize, Eq, PartialEq, Hash)] 
	pub enum EA
	{
		AA, AB, AC
	}
	#[derive(Clone, Serialize, Deserialize, Eq, PartialEq, Hash)] 
	pub enum EB
	{
		BA, BB, BC
	}
	#[derive(Clone, Serialize, Deserialize, Eq, PartialEq, Hash)] 
	pub enum EC
	{
		CA, CB, CC
	}
	#[tokio::test]
	async fn default_or_value() -> Result<()>
	{
		let se = Serder::new("eule_test".to_string()).await?;
		let mut hm: HashMap<String, E<EA, EB, EC>> = HashMap::new();
		hm.insert("B".to_string(), E::B{v: Some(EB::BC)});
		let data: HashMap<String, E<EA, EB, EC>> = se.deserialize_or_value("in_no_err.json".to_string(), hm).await?;
		se.serialize_and_save("out_no_err.json".to_string(), data).await?;

		Ok(())
	}
	#[tokio::test]
	async fn default_or_value_arc_mutex() -> Result<()>
	{
		let se = Serder::new("eule_test".to_string()).await?;
		let mut hm: HashMap<String, E<EA, EB, EC>> = HashMap::new();
		hm.insert("B".to_string(), E::B{v: Some(EB::BC)});
		let data: HashMap<String, E<EA, EB, EC>> = se.deserialize_or_value("in_arc_mutex.json".to_string(), hm).await?;
		let data_arc_mutex = Arc::new(Mutex::new(&data));
		se.serialize_arc_mutex_and_save("out_arc_mutex.json".to_string(), Arc::clone(&data_arc_mutex)).await?;

		Ok(())
	}
}