ACCOUNT CREATION AND LOGIN

This commit is contained in:
2026-02-16 23:56:07 -05:00
parent 79da5e1146
commit 61e9c2ac5c
17 changed files with 2322 additions and 326 deletions

View File

@@ -1,50 +1,103 @@
use std::{
fs::{self, File},
io::Write,
path::Path,
path::PathBuf,
};
use directories_next::ProjectDirs;
#[derive(Clone)]
pub struct DataDir {
dirs: ProjectDirs,
}
impl Default for DataDir {
fn default() -> Self {
Self {
dirs: ProjectDirs::from("", "", "openworm").unwrap(),
}
}
}
pub trait DataRsc: bitcode::Encode + bitcode::DecodeOwned + Default {
fn path() -> &'static str;
pub path: PathBuf,
}
impl DataDir {
pub fn get(&self) -> &Path {
self.dirs.data_local_dir()
}
pub fn load<T: DataRsc>(&self) -> T {
let path = self.get().join(T::path());
match fs::read(path) {
Ok(bytes) => match bitcode::decode(&bytes) {
Ok(data) => data,
Err(_) => todo!(),
},
Err(_) => T::default(),
pub fn new(dir: Option<&str>) -> Self {
let dirs = ProjectDirs::from("", "", "openworm").unwrap();
let mut path = dirs.data_local_dir().to_path_buf();
if let Some(dir) = dir {
path = path.join(dir);
}
Self { path }
}
}
pub trait DataRsc: serde::Serialize + Default {
fn name() -> &'static str;
fn path() -> String {
Self::name().to_string() + ".ron"
}
fn parse_version(text: &str, version: u32) -> Result<Self, String>;
fn version() -> u32;
}
pub struct DataGuard<T: DataRsc> {
path: PathBuf,
val: T,
}
impl DataDir {
pub fn load<T: DataRsc>(&self) -> DataGuard<T> {
let path = self.path.join(T::path());
let invalid = |info: &str| {
println!("warning: invalid config @ {path:?}: {info}");
DataGuard {
path: path.clone(),
val: T::default(),
}
};
match fs::read_to_string(&path) {
Ok(text) => {
let mut lines = text.lines();
let Some(first) = lines.next() else {
return invalid("empty file");
};
let version_str: String = first
.chars()
.skip_while(|c| *c != 'v')
.skip(1)
.take_while(|c| !c.is_whitespace())
.collect();
let Ok(version): Result<u32, _> = version_str.parse() else {
return invalid("invalid version");
};
let text: String = lines.collect();
match T::parse_version(&text, version) {
Ok(val) => DataGuard { path, val },
Err(e) => invalid(&e),
}
}
Err(_) => DataGuard {
path,
val: T::default(),
},
}
}
}
impl<T: DataRsc> std::ops::Deref for DataGuard<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.val
}
}
impl<T: DataRsc> std::ops::DerefMut for DataGuard<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.val
}
}
impl<T: DataRsc> Drop for DataGuard<T> {
fn drop(&mut self) {
let dir = self.path.parent().unwrap();
fs::create_dir_all(dir).unwrap();
let mut file = File::create(dir.join(T::path())).unwrap();
let ron = ron::to_string(&self.val).unwrap();
let data = format!("// v{}\n{}\n", T::version(), ron);
if let Err(e) = file.write_all(data.as_bytes()) {
println!("Failed to write config @ {:?}: {e}", self.path);
}
}
pub fn save<T: DataRsc>(&self, data: &T) {
let dir = self.get();
fs::create_dir_all(dir).unwrap();
let mut file = File::create(dir.join(T::path())).unwrap();
// TODO: used to use encode_into_std_write from bincode here
let data = bitcode::encode(data);
file.write_all(&data).unwrap();
}
}