eule 0.5.6

Async generic serialization crate with a minimal interface.
Documentation
use std::{path::PathBuf, sync::Arc};
use serde::{Serialize, Deserialize};
use directories::ProjectDirs;
use anyhow::{Result, Context};
use tokio::{fs, fs::OpenOptions, io::{AsyncReadExt, AsyncWriteExt}, sync::Mutex};
use ron::extensions::Extensions;
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) -> anyhow::Result<T>
	where
		T: Default + for<'de> Deserialize<'de>
	{
		let buf = self.read_file(filename).await?;
		println!("buf: {}", String::from_utf8(buf.clone())?);
		let output = match buf.len()
		{
			0 =>
			{
				println!("0");
				Default::default()
			},
			1.. =>
			{
				//let a: T = ron::de::from_bytes(&buf)?;
				println!("1");
				ron::de::from_bytes(&buf).unwrap_or_default()
			},
		};

		Ok(output)
	}
	pub async fn deserialize_or_value<T>(&self, filename: String, value: T) -> anyhow::Result<T>
	where
		T: for<'de> Deserialize<'de>
	{
		let buf = self.read_file(filename).await?;
		let output = match buf.len()
		{
			0 => value,
			1.. => ron::de::from_bytes(&buf).unwrap_or(value),
		};

		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(ron::de::from_bytes(&buf)?),
		}.context("File empty.")?;
		Ok(output)
	}
	pub async fn serialize_and_save<T>(&self, filename: String, data: T) -> anyhow::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 = pretty_ser(data)?;
		file.write_all(serialized_data.as_bytes()).await?;
		Ok(())
	}
	pub async fn serialize_arc_and_save<T>(&self, filename: String, data: Arc<T>) -> anyhow::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 = pretty_ser(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>>) -> anyhow::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 = pretty_ser(&*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)
	}
}
fn pretty_ser<T>(data: T) -> anyhow::Result<String>
	where
		T: Serialize
	{
		let ext = Extensions::default().union(Extensions::IMPLICIT_SOME).union(Extensions::UNWRAP_NEWTYPES).union(Extensions::UNWRAP_VARIANT_NEWTYPES);
		let config = ron::ser::PrettyConfig::default().indentor("\t".to_string()).struct_names(true).separate_tuple_members(true).extensions(ext);
		Ok(ron::ser::to_string_pretty(&data, config)?)
	}

#[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 deserialize_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.ron".to_string(), hm).await?;
		se.serialize_and_save("out_no_err.ron".to_string(), data).await?;

		Ok(())
	}
	#[tokio::test]
	async fn deserialize_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.ron".to_string(), hm).await?;
		let data_arc_mutex = Arc::new(Mutex::new(&data));
		se.serialize_arc_mutex_and_save("out_arc_mutex.ron".to_string(), Arc::clone(&data_arc_mutex)).await?;
		Ok(())
	}
	#[tokio::test]
	async fn serialize_arc_mutex_and_save() -> 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_arc_mutex = Arc::new(Mutex::new(&hm));
		se.serialize_arc_mutex_and_save("out_arc_mutex_save.ron".to_string(), Arc::clone(&data_arc_mutex)).await?;
		Ok(())
	}
}