diff --git a/hel/Cargo.toml b/hel/Cargo.toml index 177232f..efe70fb 100644 --- a/hel/Cargo.toml +++ b/hel/Cargo.toml @@ -22,6 +22,7 @@ base64 = "0.20.0" shlex = "1.1.0" shellexpand = "3.0.0" scopeguard = "1.1.0" +parking_lot = { version = "0.12.1", features = ["deadlock_detection"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] chrono = "0.4.23" diff --git a/hel/src/commands.rs b/hel/src/commands.rs index d26984b..29f3421 100644 --- a/hel/src/commands.rs +++ b/hel/src/commands.rs @@ -11,14 +11,14 @@ use crate::password::fix_password_recursion; use crate::password::{Name, Password, PasswordRef}; use crate::repl::LKEval; use crate::structs::{LKOut, Radix, CORRECT_FILE, DUMP_FILE}; -use crate::utils::{call_cmd_with_input, get_cmd_args_from_command, get_copy_command_from_env, rnd}; use crate::utils::editor::password; +use crate::utils::{call_cmd_with_input, get_cmd_args_from_command, get_copy_command_from_env, rnd}; impl<'a> LKEval<'a> { pub fn get_password(&self, name: &String) -> Option { - match self.state.borrow().ls.get(name) { + match self.state.lock().borrow().ls.get(name) { Some(pwd) => Some(pwd.clone()), - None => match self.state.borrow().db.get(name) { + None => match self.state.lock().borrow().db.get(name) { Some(pwd) => Some(pwd.clone()), None => None, }, @@ -34,15 +34,15 @@ impl<'a> LKEval<'a> { None => (), } } - let parent = match &pwd.borrow().parent { - Some(p) => p.borrow().name.to_string(), + let parent = match &pwd.lock().borrow().parent { + Some(p) => p.lock().borrow().name.to_string(), None => "/".to_string(), }; - let secret = match self.state.borrow().secrets.get(&parent) { + let secret = match self.state.lock().borrow().secrets.get(&parent) { Some(p) => Some(p.clone()), None => None, }; - match (pwd.borrow().parent.clone(), secret) { + match (pwd.lock().borrow().parent.clone(), secret) { (_, Some(s)) => Some(s.to_string()), (None, None) => { if read { @@ -50,7 +50,7 @@ impl<'a> LKEval<'a> { Ok(password) => { let name = "/".to_string(); self.cmd_correct(&out, &name, true, Some(password.clone())); - self.state.borrow_mut().secrets.insert(name, password.clone()); + self.state.lock().borrow_mut().secrets.insert(name, password.clone()); Some(password) } Err(_) => None, @@ -61,22 +61,22 @@ impl<'a> LKEval<'a> { } (Some(pn), None) => { let password = if read { - (self.read_password)(format!("Password for {}: ", pn.borrow().name)).ok() + (self.read_password)(format!("Password for {}: ", pn.lock().borrow().name)).ok() } else { None }; if password.is_some() && password.as_ref().unwrap().len() > 0 { - let name = pn.borrow().name.to_string(); + let name = pn.lock().borrow().name.to_string(); self.cmd_correct(&out, &name, true, Some(password.as_ref().unwrap().clone())); - self.state.borrow_mut().secrets.insert(name, password.as_ref().unwrap().clone()); + self.state.lock().borrow_mut().secrets.insert(name, password.as_ref().unwrap().clone()); password } else { match self.read_master(&out, pn.clone(), read) { Some(master) => { - let password = pn.borrow().encode(master.as_str()); - let name = pn.borrow().name.to_string(); + let password = pn.lock().borrow().encode(master.as_str()); + let name = pn.lock().borrow().name.to_string(); self.cmd_correct(&out, &name, true, Some(password.to_string())); - self.state.borrow_mut().secrets.insert(name, password.clone()); + self.state.lock().borrow_mut().secrets.insert(name, password.clone()); Some(password) } None => None, @@ -87,15 +87,15 @@ impl<'a> LKEval<'a> { } pub fn cmd_add(&self, out: &LKOut, name: &PasswordRef) { - let state = &mut self.state.borrow_mut(); + let state_cell = self.state.lock(); + let mut state = state_cell.borrow_mut(); let mut fix = false; { - let db = &mut state.db; - let pwname = &name.borrow().name.to_string(); - if db.get(pwname).is_some() { + let pwname = &name.lock().borrow().name.to_string(); + if state.db.get(pwname).is_some() { out.e(format!("error: password {} already exist", pwname)); } else { - db.insert(pwname.to_string(), name.clone()); + state.db.insert(pwname.to_string(), name.clone()); fix = true; } } @@ -105,9 +105,12 @@ impl<'a> LKEval<'a> { } pub fn cmd_leave(&self, out: &LKOut, name: &Name) { - let pwd = match self.state.borrow().ls.get(name) { + let pwd = match self.state.lock().borrow().ls.get(name) { Some(pwd) => pwd.clone(), - None => { out.e(format!("error: {} not found", name)); return; } + None => { + out.e(format!("error: {} not found", name)); + return; + } }; self.cmd_add(&out, &pwd); } @@ -116,11 +119,11 @@ impl<'a> LKEval<'a> { match self.get_password(name) { Some(pwd) => { if folder == "/" { - pwd.borrow_mut().parent = None + pwd.lock().borrow_mut().parent = None } else { match self.get_password(folder) { Some(fld) => { - pwd.borrow_mut().parent = Some(fld.clone()); + pwd.lock().borrow_mut().parent = Some(fld.clone()); fix_password_recursion(pwd.clone()); } None => out.e(format!("error: folder {} not found", folder)), @@ -134,18 +137,15 @@ impl<'a> LKEval<'a> { pub fn cmd_pass(&self, out: &LKOut, name: &String) { match self.get_password(name) { Some(p) => { - let pwd = (self.read_password)(format!("Password for {}: ", p.borrow().name)).unwrap(); - self.cmd_correct(&out, &p.borrow().name, true, Some(pwd.clone())); - self.state.borrow_mut().secrets.insert(p.borrow().name.to_string(), pwd); + let pwd = (self.read_password)(format!("Password for {}: ", p.lock().borrow().name)).unwrap(); + self.cmd_correct(&out, &p.lock().borrow().name, true, Some(pwd.clone())); + self.state.lock().borrow_mut().secrets.insert(p.lock().borrow().name.to_string(), pwd); } None => { if name == "/" { let pwd = (self.read_password)("Master: ".to_string()).unwrap(); self.cmd_correct(&out, &"/".to_string(), true, Some(pwd.clone())); - self.state - .borrow_mut() - .secrets - .insert("/".to_string(), pwd); + self.state.lock().borrow_mut().secrets.insert("/".to_string(), pwd); } else { out.e(format!("error: password with name {} not found", name)); } @@ -156,7 +156,7 @@ impl<'a> LKEval<'a> { pub fn cmd_comment(&self, out: &LKOut, name: &String, comment: &Option) { match self.get_password(name) { Some(pwd) => { - pwd.borrow_mut().comment = match comment { + pwd.lock().borrow_mut().comment = match comment { Some(c) => Some(c.to_string()), None => None, } @@ -167,8 +167,8 @@ impl<'a> LKEval<'a> { pub fn cmd_enc(&self, out: &LKOut, name: &String) -> Option<(String, String)> { let root_folder = "/".to_string(); - let (name, pass) = if name == "/" && self.state.borrow().secrets.contains_key(&root_folder) { - (root_folder.to_string(), self.state.borrow().secrets.get(&root_folder).unwrap().to_string()) + let (name, pass) = if name == "/" && self.state.lock().borrow().secrets.contains_key(&root_folder) { + (root_folder.to_string(), self.state.lock().borrow().secrets.get(&root_folder).unwrap().to_string()) } else { let pwd = match self.get_password(name) { Some(p) => p.clone(), @@ -177,12 +177,12 @@ impl<'a> LKEval<'a> { return None; } }; - let name = pwd.borrow().name.to_string(); - if self.state.borrow().secrets.contains_key(&name) { - (name.clone(), self.state.borrow().secrets.get(&name).unwrap().to_string()) + let name = pwd.lock().borrow().name.to_string(); + if self.state.lock().borrow().secrets.contains_key(&name) { + (name.clone(), self.state.lock().borrow().secrets.get(&name).unwrap().to_string()) } else { match self.read_master(&out, pwd.clone(), true) { - Some(sec) => (name.clone(), pwd.borrow().encode(sec.as_str())), + Some(sec) => (name.clone(), pwd.lock().borrow().encode(sec.as_str())), None => { out.e(format!("error: master for {} not found", name)); return None; @@ -253,7 +253,9 @@ impl<'a> LKEval<'a> { for cmd in cmd_list { let print = LKEval::new(cmd, self.state.clone(), password).eval(); print.out.copy(&out); - if print.quit { return true; } + if print.quit { + return true; + } } } Err(e) => { @@ -273,9 +275,9 @@ impl<'a> LKEval<'a> { let file = fs::File::create(script)?; let mut writer = BufWriter::new(file); let mut vals = data.values().map(|v| v.clone()).collect::>(); - vals.sort_by(|a, b| a.borrow().name.cmp(&b.borrow().name)); + vals.sort_by(|a, b| a.lock().borrow().name.cmp(&b.lock().borrow().name)); for pwd in vals { - writeln!(writer, "add {}", pwd.borrow().to_string())? + writeln!(writer, "add {}", pwd.lock().borrow().to_string())? } Ok(()) } @@ -289,10 +291,11 @@ impl<'a> LKEval<'a> { }; let data = self .state + .lock() .borrow() .db .values() - .map(|v| format!("add {}", v.borrow().to_string())) + .map(|v| format!("add {}", v.lock().borrow().to_string())) .collect::>() .join("\n"); let output = match call_cmd_with_input(&cmd, &args, data.as_str()) { @@ -309,13 +312,13 @@ impl<'a> LKEval<'a> { out.o(format!("Passwords saved to command {}", cmd)); } } else if script.trim() == "-" { - let mut vals = (&self.state.borrow().db).values().map(|v| v.clone()).collect::>(); - vals.sort_by(|a, b| a.borrow().name.cmp(&b.borrow().name)); + let mut vals = (&self.state.lock().borrow().db).values().map(|v| v.clone()).collect::>(); + vals.sort_by(|a, b| a.lock().borrow().name.cmp(&b.lock().borrow().name)); for pwd in vals { - out.o(format!("add {}", pwd.borrow().to_string())) - }; + out.o(format!("add {}", pwd.lock().borrow().to_string())) + } } else { - match save_dump(&self.state.borrow().db, &script) { + match save_dump(&self.state.lock().borrow().db, &script) { Ok(()) => out.o(format!("Passwords saved to file {}", script)), Err(e) => out.e(format!("error: failed to dump passswords to {}: {}", script, e.to_string())), }; @@ -334,24 +337,26 @@ impl<'a> LKEval<'a> { } }; let mut tmp: Vec = vec![]; - for (_, name) in &self.state.borrow().db { - if re.find(&name.borrow().to_string()).is_some() { + for (_, name) in &self.state.lock().borrow().db { + if re.find(&name.lock().borrow().to_string()).is_some() { tmp.push(name.clone()); - } else if re.find(&name.borrow().name).is_some() { + } else if re.find(&name.lock().borrow().name).is_some() { tmp.push(name.clone()); - } else if name.borrow().comment.is_some() && re.find(&name.borrow().comment.as_ref().unwrap()).is_some() { + } else if name.lock().borrow().comment.is_some() + && re.find(&name.lock().borrow().comment.as_ref().unwrap()).is_some() + { tmp.push(name.clone()); } } - tmp.sort_by(|a,b| a.borrow().name.cmp(&b.borrow().name)); + tmp.sort_by(|a, b| a.lock().borrow().name.cmp(&b.lock().borrow().name)); tmp.sort_by(sort_by); - self.state.borrow_mut().ls.clear(); + self.state.lock().borrow_mut().ls.clear(); let mut counter = 1; for pwd in tmp { let key = Radix::new(counter, 36).unwrap().to_string(); counter += 1; - self.state.borrow_mut().ls.insert(key.clone(), pwd.clone()); - out.o(format!("{:>3} {}", key, pwd.borrow().to_string())); + self.state.lock().borrow_mut().ls.insert(key.clone(), pwd.clone()); + out.o(format!("{:>3} {}", key, pwd.lock().borrow().to_string())); } } @@ -435,42 +440,42 @@ impl<'a> LKEval<'a> { static ref RE: Regex = Regex::new(r"^.+?(G+|X+)$").unwrap(); } let num: usize = (*num).try_into().unwrap(); - let pwd = name.borrow(); + let pwd = name.lock(); let mut genpwds: Vec = Vec::new(); - match RE.captures(pwd.name.as_ref()) { + match RE.captures(pwd.borrow().name.as_ref()) { Some(caps) => { let gen = &caps[1]; if gen.starts_with("G") { - let name = pwd.name.trim_end_matches('G'); + let name = pwd.borrow().name.trim_end_matches('G').to_string(); for num in 1..10_u32.pow(gen.len().try_into().unwrap()) { - let npwd = Password::from_password(&pwd); - npwd.borrow_mut().name = format!("{}{}", name, num).to_string(); + let npwd = Password::from_password_ref(&pwd.borrow()); + npwd.lock().borrow_mut().name = format!("{}{}", name, num).to_string(); genpwds.push(npwd); } } else { - let name = pwd.name.trim_end_matches('X'); + let name = pwd.borrow().name.trim_end_matches('X').to_string(); let num = rnd::range(1, 10_u32.pow(gen.len().try_into().unwrap())); - let npwd = Password::from_password(&pwd); - npwd.borrow_mut().name = format!("{}{}", name, num).to_string(); + let npwd = Password::from_password_ref(&pwd.borrow()); + npwd.lock().borrow_mut().name = format!("{}{}", name, num).to_string(); genpwds.push(npwd); } } None => { - let npwd = Password::from_password(&pwd); + let npwd = Password::from_password_ref(&pwd.borrow()); genpwds.push(npwd); } } - self.state.borrow_mut().ls.clear(); + self.state.lock().borrow_mut().ls.clear(); let mut counter = 1; let mut lspwds: Vec<(PasswordRef, String)> = Vec::new(); for num in 0..genpwds.len() { let pwd = genpwds[num].clone(); let key = Radix::new(counter, 36).unwrap().to_string(); counter += 1; - self.state.borrow_mut().ls.insert(key.to_string(), pwd.clone()); + self.state.lock().borrow_mut().ls.insert(key.to_string(), pwd.clone()); lspwds.push((pwd, key)); } - self.state.borrow().fix_hierarchy(); + self.state.lock().borrow().fix_hierarchy(); let mut err = match &out.err { Some(e) => Some(e.clone()), None => None, @@ -479,8 +484,8 @@ impl<'a> LKEval<'a> { for (pwd, key) in lspwds { let pass = match self.cmd_enc(&LKOut::from_lkout(None, err), &key) { Some((name, pass)) => { - if name != pwd.borrow().name { - panic!("INTERNAL_ERROR: wrong name found: {} != {}", name, pwd.borrow().name); + if name != pwd.lock().borrow().name { + panic!("INTERNAL_ERROR: wrong name found: {} != {}", name, pwd.lock().borrow().name); }; pass } @@ -493,15 +498,15 @@ impl<'a> LKEval<'a> { encpwds.push((pwd.clone(), pass)); } encpwds.sort_by(|a, b| b.1.len().cmp(&a.1.len())); - self.state.borrow_mut().ls.clear(); + self.state.lock().borrow_mut().ls.clear(); let mut counter = 1; out.o(format!("{:>3} {:>36} {:>4} {}", "", "Password", "Len", "Name")); for num in (encpwds.len() - min(genpwds.len(), num))..encpwds.len() { let (pwd, pass) = (encpwds[num].0.clone(), encpwds[num].1.to_string()); let key = Radix::new(counter, 36).unwrap().to_string(); counter += 1; - self.state.borrow_mut().ls.insert(key.clone(), pwd.clone()); - out.o(format!("{:>3} {:>36} {:>4} {}", key, pass, pass.len(), pwd.borrow().to_string())); + self.state.lock().borrow_mut().ls.insert(key.clone(), pwd.clone()); + out.o(format!("{:>3} {:>36} {:>4} {}", key, pass, pass.len(), pwd.lock().borrow().to_string())); } } } diff --git a/hel/src/lib.rs b/hel/src/lib.rs index f9c8565..119fb98 100644 --- a/hel/src/lib.rs +++ b/hel/src/lib.rs @@ -12,4 +12,3 @@ pub mod repl; pub mod skey; pub mod structs; pub mod utils; - diff --git a/hel/src/lk.rs b/hel/src/lk.rs index aae9bad..d1a10ab 100644 --- a/hel/src/lk.rs +++ b/hel/src/lk.rs @@ -1,8 +1,13 @@ use crate::password::{fix_password_recursion, Name, PasswordRef}; +use parking_lot::ReentrantMutex; use regex::{Captures, Regex}; +use std::cell::RefCell; use std::collections::HashMap; +use std::sync::Arc; -#[derive(PartialEq, Debug)] +pub type LKRef = Arc>>; + +#[derive(Debug)] pub struct LK { pub db: HashMap, pub ls: HashMap, @@ -24,7 +29,7 @@ impl LK { } for db in vec![&self.db, &self.ls] { for (_, name) in db { - let comment = name.borrow().comment.clone(); + let comment = name.lock().borrow().comment.clone(); match comment { Some(comment) => { let mut changed = false; @@ -33,7 +38,7 @@ impl LK { let folder = c[1].to_string(); match self.db.get(&folder) { Some(entry) => { - name.borrow_mut().parent = Some(entry.clone()); + name.lock().borrow_mut().parent = Some(entry.clone()); changed = true; } None => (), @@ -43,7 +48,7 @@ impl LK { .trim() .to_string(); if changed && new != comment { - name.borrow_mut().comment = if new.len() > 0 { Some(new) } else { None } + name.lock().borrow_mut().comment = if new.len() > 0 { Some(new) } else { None } } } None => (), @@ -53,3 +58,22 @@ impl LK { } } } + +impl PartialEq for LK { + fn eq(&self, other: &Self) -> bool { + if self.db.len() != other.db.len() || self.ls.len() != other.ls.len() || self.secrets != other.secrets { + return false; + } + for (k, v) in &self.db { + if !other.db.contains_key(k) || *other.db[k].lock() != *v.lock() { + return false; + } + } + for (k, v) in &self.ls { + if !other.ls.contains_key(k) || *other.ls[k].lock() != *v.lock() { + return false; + } + } + true + } +} diff --git a/hel/src/parser.rs b/hel/src/parser.rs index b197516..a891fda 100644 --- a/hel/src/parser.rs +++ b/hel/src/parser.rs @@ -3,7 +3,6 @@ extern crate peg; use crate::password::Password; use crate::structs::{Command, LKErr, Mode}; use crate::utils::date::Date; -use std::{cell::RefCell, rc::Rc}; peg::parser! { pub grammar command_parser() for str { @@ -89,10 +88,10 @@ peg::parser! { rule source_cmd() -> Command<'input> = "source" _ s:$(([' '..='~'])+) { Command::Source(s.to_string()) } rule ls_cmd() -> Command<'input> = "ls" f:comment()? { Command::Ls(f.unwrap_or(".".to_string())) } rule ld_cmd() -> Command<'input> = "ld" f:comment()? { Command::Ld(f.unwrap_or(".".to_string())) } - rule add_cmd() -> Command<'input> = "add" _ name:name() { Command::Add(Rc::new(RefCell::new(name))) } + rule add_cmd() -> Command<'input> = "add" _ name:name() { Command::Add(Password::from_password(name)) } rule leave_cmd() -> Command<'input> = "leave" _ name:word() { Command::Leave(name.to_string()) } rule gen_cmd() -> Command<'input> = "gen" n:num()? _ name:name() { - Command::Gen(match n { Some(n) => n, None => 10_u32 }, Rc::new(RefCell::new(name))) + Command::Gen(match n { Some(n) => n, None => 10_u32 }, Password::from_password(name)) } rule error_cmd() -> Command<'input> = "error" _ e:$(([' '..='~'])+) { Command::Error(LKErr::Error(e)) } rule mv_cmd() -> Command<'input> = "mv" _ name:word() _ folder:word() { Command::Mv(name, folder) } @@ -119,7 +118,7 @@ add t2 C 99 2022-12-14 add t3 C 99 2022-12-14"### ), Ok(vec![ - Command::Add(Rc::new(RefCell::new(Password { + Command::Add(Password::from_password(Password { parent: None, prefix: None, name: "t1".to_string(), @@ -128,8 +127,8 @@ add t3 C 99 2022-12-14"### seq: 99, date: Date::new(2022, 12, 14), comment: None - }))), - Command::Add(Rc::new(RefCell::new(Password { + })), + Command::Add(Password::from_password(Password { parent: None, prefix: None, name: "t2".to_string(), @@ -138,8 +137,8 @@ add t3 C 99 2022-12-14"### seq: 99, date: Date::new(2022, 12, 14), comment: None - }))), - Command::Add(Rc::new(RefCell::new(Password { + })), + Command::Add(Password::from_password(Password { parent: None, prefix: None, name: "t3".to_string(), @@ -148,7 +147,7 @@ add t3 C 99 2022-12-14"### seq: 99, date: Date::new(2022, 12, 14), comment: None - }))) + })) ]) ); assert_eq!( @@ -159,7 +158,7 @@ add t3 C 99 2022-12-14 "### ), Ok(vec![ - Command::Add(Rc::new(RefCell::new(Password { + Command::Add(Password::from_password(Password { parent: None, prefix: None, name: "t1".to_string(), @@ -168,8 +167,8 @@ add t3 C 99 2022-12-14 seq: 99, date: Date::new(2022, 12, 14), comment: None - }))), - Command::Add(Rc::new(RefCell::new(Password { + })), + Command::Add(Password::from_password(Password { parent: None, prefix: None, name: "t2".to_string(), @@ -178,8 +177,8 @@ add t3 C 99 2022-12-14 seq: 99, date: Date::new(2022, 12, 14), comment: None - }))), - Command::Add(Rc::new(RefCell::new(Password { + })), + Command::Add(Password::from_password(Password { parent: None, prefix: None, name: "t3".to_string(), @@ -188,7 +187,7 @@ add t3 C 99 2022-12-14 seq: 99, date: Date::new(2022, 12, 14), comment: None - }))), + })), Command::Noop ]) ); @@ -201,7 +200,7 @@ add t3 C 99 2022-12-14 "### ), Ok(vec![ - Command::Add(Rc::new(RefCell::new(Password { + Command::Add(Password::from_password(Password { parent: None, prefix: None, name: "t1".to_string(), @@ -210,8 +209,8 @@ add t3 C 99 2022-12-14 seq: 99, date: Date::new(2022, 12, 14), comment: None - }))), - Command::Add(Rc::new(RefCell::new(Password { + })), + Command::Add(Password::from_password(Password { parent: None, prefix: None, name: "t2".to_string(), @@ -220,8 +219,8 @@ add t3 C 99 2022-12-14 seq: 99, date: Date::new(2022, 12, 14), comment: None - }))), - Command::Add(Rc::new(RefCell::new(Password { + })), + Command::Add(Password::from_password(Password { parent: None, prefix: None, name: "t3".to_string(), @@ -230,7 +229,7 @@ add t3 C 99 2022-12-14 seq: 99, date: Date::new(2022, 12, 14), comment: None - }))), + })), Command::Noop, Command::Noop ]) diff --git a/hel/src/password.rs b/hel/src/password.rs index 9a7376f..f56e2ea 100644 --- a/hel/src/password.rs +++ b/hel/src/password.rs @@ -1,17 +1,19 @@ use crate::skey::SKey; use crate::structs::Mode; use crate::utils::date::Date; -use std::{cell::RefCell, rc::Rc}; +use parking_lot::ReentrantMutex; +use std::cell::RefCell; +use std::sync::Arc; pub type Name = String; pub type Prefix = Option; pub type Comment = Option; -pub type PasswordRef = Rc>; +pub type PasswordRef = Arc>>; pub type Parent = Option; pub type Length = Option; pub type Seq = u32; -#[derive(PartialEq, Debug)] +#[derive(Debug)] pub struct Password { pub parent: Parent, pub prefix: Prefix, @@ -45,8 +47,8 @@ impl Password { } } - pub fn from_password(password: &Password) -> PasswordRef { - Rc::new(RefCell::new(Self { + pub fn from_password_ref(password: &Password) -> PasswordRef { + Arc::new(ReentrantMutex::new(RefCell::new(Self { parent: password.parent.clone(), prefix: password.prefix.clone(), name: password.name.clone(), @@ -55,7 +57,11 @@ impl Password { seq: password.seq, date: password.date.clone(), comment: password.comment.clone(), - })) + }))) + } + + pub fn from_password(password: Password) -> PasswordRef { + Arc::new(ReentrantMutex::new(RefCell::new(password))) } pub fn encode(&self, secret: &str) -> String { @@ -109,13 +115,28 @@ impl std::string::ToString for Password { None => "".to_string(), }; let parent = match &self.parent { - Some(s) => format!(" ^{}", s.borrow().name), + Some(s) => format!(" ^{}", s.lock().borrow().name), None => "".to_string(), }; format!("{:>6}{} {}{} {} {}{}{}", prefix, self.name, length, self.mode, self.seq, self.date, comment, parent) } } +impl PartialEq for Password { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + && match (&self.parent, &other.parent) { + (Some(s), Some(o)) => *s.lock() == *o.lock(), + (None, None) => true, + _ => false, + } + && self.prefix == other.prefix + && self.length == other.length + && self.mode == other.mode + && self.seq == other.seq + } +} + fn camel_case(words: [&str; 6]) -> String { let mut camel_case_string = String::new(); @@ -128,34 +149,34 @@ fn camel_case(words: [&str; 6]) -> String { camel_case_string } -pub fn fix_password_recursion(entry: Rc>) { +pub fn fix_password_recursion(entry: PasswordRef) { let mut t1 = entry.clone(); let mut t2 = entry; - let mut t3: Option>> = None; + let mut t3: Option = None; loop { - t2 = match &t2.clone().borrow().parent { + t2 = match &t2.clone().lock().borrow().parent { Some(o) => o.clone(), None => break, }; - if std::ptr::eq(&*t1.borrow(), &*t2.borrow()) { + if std::ptr::eq(&*t1.lock().borrow(), &*t2.lock().borrow()) { t3 = Some(t2.clone()); break; } - t1 = match &t1.clone().borrow().parent { + t1 = match &t1.clone().lock().borrow().parent { Some(o) => o.clone(), None => break, }; - t2 = match &t2.clone().borrow().parent { + t2 = match &t2.clone().lock().borrow().parent { Some(o) => o.clone(), None => break, }; - if std::ptr::eq(&*t1.borrow(), &*t2.borrow()) { + if std::ptr::eq(&*t1.lock().borrow(), &*t2.lock().borrow()) { t3 = Some(t2.clone()); break; } } match t3 { - Some(o) => o.borrow_mut().parent = None, + Some(o) => o.lock().borrow_mut().parent = None, None => (), } } @@ -166,7 +187,7 @@ mod tests { #[test] fn exec_recursion_test() { - let p1 = Rc::new(RefCell::new(Password::new( + let p1 = Password::from_password(Password::new( None, "p1".to_string(), None, @@ -174,13 +195,15 @@ mod tests { 99, Date::new(2022, 12, 3), None, - ))); + )); - p1.borrow_mut().parent = Some(p1.clone()); + { + p1.lock().borrow_mut().parent = Some(p1.clone()); + }; fix_password_recursion(p1.clone()); - assert_eq!(p1.borrow().parent, None); + assert_eq!(p1.lock().borrow().parent.is_none(), true); - let p2 = Rc::new(RefCell::new(Password::new( + let p2 = Password::from_password(Password::new( None, "p2".to_string(), None, @@ -188,9 +211,9 @@ mod tests { 99, Date::new(2022, 12, 3), None, - ))); - p2.borrow_mut().parent = Some(p1.clone()); - let p3 = Rc::new(RefCell::new(Password::new( + )); + p2.lock().borrow_mut().parent = Some(p1.clone()); + let p3 = Password::from_password(Password::new( None, "p3".to_string(), None, @@ -198,9 +221,9 @@ mod tests { 99, Date::new(2022, 12, 3), None, - ))); - p3.borrow_mut().parent = Some(p2.clone()); - let p4 = Rc::new(RefCell::new(Password::new( + )); + p3.lock().borrow_mut().parent = Some(p2.clone()); + let p4 = Password::from_password(Password::new( None, "p4".to_string(), None, @@ -208,9 +231,9 @@ mod tests { 99, Date::new(2022, 12, 3), None, - ))); - p4.borrow_mut().parent = Some(p3.clone()); - let p5 = Rc::new(RefCell::new(Password::new( + )); + p4.lock().borrow_mut().parent = Some(p3.clone()); + let p5 = Password::from_password(Password::new( None, "p5".to_string(), None, @@ -218,12 +241,12 @@ mod tests { 99, Date::new(2022, 12, 3), None, - ))); - p5.borrow_mut().parent = Some(p4.clone()); + )); + p5.lock().borrow_mut().parent = Some(p4.clone()); - p1.borrow_mut().parent = Some(p3.clone()); + p1.lock().borrow_mut().parent = Some(p3.clone()); fix_password_recursion(p5.clone()); - assert_eq!(p3.borrow().parent, None); + assert_eq!(p3.lock().borrow().parent.is_none(), true); } #[test] diff --git a/hel/src/repl.rs b/hel/src/repl.rs index b23acbc..399a872 100644 --- a/hel/src/repl.rs +++ b/hel/src/repl.rs @@ -1,15 +1,13 @@ -use std::{cell::RefCell, rc::Rc}; - -use crate::lk::LK; +use crate::lk::LKRef; use crate::parser::command_parser; use crate::structs::{Command, LKErr, LKOut, HISTORY_FILE}; -use crate::utils::editor::{ Editor, password }; +use crate::utils::editor::{password, Editor}; #[derive(Debug)] pub struct LKRead { pub rl: Editor, pub prompt: String, - pub state: Rc>, + pub state: LKRef, pub cmd: String, pub read_password: fn(String) -> std::io::Result, } @@ -17,19 +15,19 @@ pub struct LKRead { #[derive(Debug)] pub struct LKEval<'a> { pub cmd: Command<'a>, - pub state: Rc>, + pub state: LKRef, pub read_password: fn(String) -> std::io::Result, } -#[derive(Debug, PartialEq)] +#[derive(Debug)] pub struct LKPrint { pub out: LKOut, pub quit: bool, - pub state: Rc>, + pub state: LKRef, } impl LKRead { - pub fn new(rl: Editor, prompt: String, state: Rc>) -> Self { + pub fn new(rl: Editor, prompt: String, state: LKRef) -> Self { Self { rl, prompt, @@ -77,7 +75,7 @@ impl LKRead { } impl<'a> LKEval<'a> { - pub fn new(cmd: Command<'a>, state: Rc>, read_password: fn(String) -> std::io::Result) -> Self { + pub fn new(cmd: Command<'a>, state: LKRef, read_password: fn(String) -> std::io::Result) -> Self { Self { cmd, state, @@ -94,25 +92,33 @@ impl<'a> LKEval<'a> { out.e("Bye!".to_string()); quit = true; } - Command::Ls(filter) => self.cmd_ls(&out, filter.to_string(), |a,b| a.borrow().name.cmp(&b.borrow().name)), - Command::Ld(filter) => self.cmd_ls(&out, filter.to_string(), |a,b| a.borrow().date.cmp(&b.borrow().date)), + Command::Ls(filter) => { + self.cmd_ls(&out, filter.to_string(), |a, b| a.lock().borrow().name.cmp(&b.lock().borrow().name)) + } + Command::Ld(filter) => { + self.cmd_ls(&out, filter.to_string(), |a, b| a.lock().borrow().date.cmp(&b.lock().borrow().date)) + } Command::Add(name) => self.cmd_add(&out, &name), Command::Leave(name) => self.cmd_leave(&out, &name), Command::Comment(name, comment) => self.cmd_comment(&out, &name, &comment), Command::Rm(name) => match self.get_password(name) { Some(pwd) => { - self.state.borrow_mut().db.remove(&pwd.borrow().name); - out.o(format!("removed {}", pwd.borrow().name)); + self.state.lock().borrow_mut().db.remove(&pwd.lock().borrow().name); + out.o(format!("removed {}", pwd.lock().borrow().name)); } None => out.e(format!("error: password {} not found", name)), }, - Command::Enc(name) => { self.cmd_enc(&out, name); } + Command::Enc(name) => { + self.cmd_enc(&out, name); + } Command::Gen(num, name) => self.cmd_gen(&out, &num, &name), Command::PasteBuffer(command) => self.cmd_pb(&out, command), - Command::Source(script) => { quit = self.cmd_source(&out, script); } + Command::Source(script) => { + quit = self.cmd_source(&out, script); + } Command::Dump(script) => self.cmd_dump(&out, script), Command::Pass(name) => self.cmd_pass(&out, &name), - Command::UnPass(name) => match self.state.borrow_mut().secrets.remove(name) { + Command::UnPass(name) => match self.state.lock().borrow_mut().secrets.remove(name) { Some(_) => out.o(format!("Removed saved password for {}", name)), None => out.e(format!("error: saved password for {} not found", name)), }, @@ -136,7 +142,7 @@ impl<'a> LKEval<'a> { } impl LKPrint { - pub fn new(out: LKOut, quit: bool, state: Rc>) -> Self { + pub fn new(out: LKOut, quit: bool, state: LKRef) -> Self { Self { out, quit, state } } @@ -147,16 +153,26 @@ impl LKPrint { } } +impl PartialEq for LKPrint { + fn eq(&self, other: &Self) -> bool { + self.out == other.out && self.quit == other.quit && *self.state.lock() == *other.state.lock() + } +} + #[cfg(test)] mod tests { use super::*; + use crate::lk::LK; use crate::password::Password; use crate::structs::Mode; - use std::collections::HashMap; use crate::utils::date::Date; + use parking_lot::ReentrantMutex; + use std::cell::RefCell; + use std::collections::HashMap; + use std::sync::Arc; impl<'a> LKEval<'a> { - pub fn news(cmd: Command<'a>, state: Rc>) -> Self { + pub fn news(cmd: Command<'a>, state: LKRef) -> Self { Self { cmd, state, @@ -169,12 +185,12 @@ mod tests { #[test] fn exec_cmds_basic() { - let lk = Rc::new(RefCell::new(LK::new())); + let lk = Arc::new(ReentrantMutex::new(RefCell::new(LK::new()))); assert_eq!( LKEval::news(Command::Ls(".".to_string()), lk.clone()).eval(), LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone()) ); - let pwd1 = Rc::new(RefCell::new(Password { + let pwd1 = Password::from_password(Password { name: "t1".to_string(), prefix: None, length: None, @@ -183,12 +199,25 @@ mod tests { date: Date::new(2022, 12, 30), comment: Some("comment".to_string()), parent: None, - })); - assert_eq!(LKEval::news(Command::Add(pwd1.clone()), lk.clone()).eval().state.borrow().db, { - let mut db = HashMap::new(); - db.insert(pwd1.borrow().name.to_string(), pwd1.clone()); - db }); + assert_eq!( + LKEval::news(Command::Add(pwd1.clone()), lk.clone()) + .eval() + .state + .lock() + .borrow() + .db + .iter() + .map(|x| (x.0.to_string(), x.1.lock().borrow().to_string())) + .collect::>(), + { + let mut db = HashMap::new(); + db.insert(pwd1.lock().borrow().name.to_string(), pwd1.clone()); + db.into_iter() + .map(|x| (x.0.to_string(), x.1.lock().borrow().to_string())) + .collect::>() + } + ); assert_eq!( LKEval::news(Command::Ls(".".to_string()), lk.clone()).eval(), LKPrint::new( @@ -201,7 +230,7 @@ mod tests { LKEval::news(Command::Quit, lk.clone()).eval(), LKPrint::new(LKOut::from_vecs(vec![], vec!["Bye!".to_string()]), true, lk.clone()) ); - let pwd2 = Rc::new(RefCell::new(Password { + let pwd2 = Password::from_password(Password { name: "t2".to_string(), prefix: None, length: None, @@ -210,18 +239,32 @@ mod tests { date: Date::new(2022, 12, 31), comment: Some("bli blup".to_string()), parent: None, - })); - assert_eq!(LKEval::news(Command::Add(pwd2.clone()), lk.clone()).eval().state.borrow().db, { - let mut db = HashMap::new(); - db.insert(pwd1.borrow().name.to_string(), pwd1.clone()); - db.insert(pwd2.borrow().name.to_string(), pwd2.clone()); - db }); + assert_eq!( + LKEval::news(Command::Add(pwd2.clone()), lk.clone()) + .eval() + .state + .lock() + .borrow() + .db + .iter() + .map(|x| (x.0.to_string(), x.1.lock().borrow().to_string())) + .collect::>(), + { + let mut db = HashMap::new(); + db.insert(pwd1.lock().borrow().name.to_string(), pwd1.clone()); + db.insert(pwd2.lock().borrow().name.to_string(), pwd2.clone()); + db.into_iter().map(|x| (x.0, x.1.lock().borrow().to_string())).collect::>() + } + ); assert_eq!( LKEval::news(Command::Ls(".".to_string()), lk.clone()).eval(), LKPrint::new( LKOut::from_vecs( - vec![" 1 t1 R 99 2022-12-30 comment".to_string(), " 2 t2 R 99 2022-12-31 bli blup".to_string()], + vec![ + " 1 t1 R 99 2022-12-30 comment".to_string(), + " 2 t2 R 99 2022-12-31 bli blup".to_string() + ], vec![] ), false, @@ -244,8 +287,8 @@ mod tests { #[test] fn read_pwd_test() { - let lk = Rc::new(RefCell::new(LK::new())); - let t1 = Rc::new(RefCell::new(Password::new( + let lk = Arc::new(ReentrantMutex::new(RefCell::new(LK::new()))); + let t1 = Password::from_password(Password::new( None, "t1".to_string(), None, @@ -253,8 +296,8 @@ mod tests { 99, Date::new(2022, 12, 30), None, - ))); - let t2 = Rc::new(RefCell::new(Password::new( + )); + let t2 = Password::from_password(Password::new( None, "t2".to_string(), None, @@ -262,8 +305,8 @@ mod tests { 99, Date::new(2022, 12, 30), None, - ))); - let t3 = Rc::new(RefCell::new(Password::new( + )); + let t3 = Password::from_password(Password::new( None, "t3".to_string(), None, @@ -271,19 +314,23 @@ mod tests { 99, Date::new(2022, 12, 30), None, - ))); + )); + println!("POINT 1"); assert_eq!( LKEval::news(Command::Add(t1.clone()), lk.clone()).eval(), LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone()) ); + println!("POINT 2"); assert_eq!( LKEval::news(Command::Add(t2.clone()), lk.clone()).eval(), LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone()) ); + println!("POINT 3"); assert_eq!( LKEval::news(Command::Add(t3.clone()), lk.clone()).eval(), LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone()) ); + println!("POINT 4"); assert_eq!( LKEval::news(Command::Mv("t3".to_string(), "t2".to_string()), lk.clone()).eval(), LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone()) diff --git a/hel/src/structs.rs b/hel/src/structs.rs index b6cbfc0..1ea56d7 100644 --- a/hel/src/structs.rs +++ b/hel/src/structs.rs @@ -1,13 +1,16 @@ use crate::password::{Comment, Name, PasswordRef}; +use parking_lot::Mutex; +use parking_lot::ReentrantMutex; +use std::cell::RefCell; use std::fmt; use std::path::Path; -use std::{cell::RefCell, rc::Rc}; +use std::sync::Arc; use crate::lk::LK; use crate::parser::command_parser; use crate::repl::{LKEval, LKRead}; +use crate::utils::editor::{password, Editor}; use crate::utils::home; -use crate::utils::editor::{ Editor, password }; lazy_static! { pub static ref HISTORY_FILE: Box = { @@ -54,7 +57,7 @@ pub enum LKErr<'a> { ParseError(peg::error::ParseError), } -#[derive(PartialEq, Debug)] +#[derive(Debug)] pub enum Command<'a> { Add(PasswordRef), Leave(Name), @@ -78,6 +81,34 @@ pub enum Command<'a> { Quit, } +impl<'a> PartialEq for Command<'a> { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Command::Add(s), Command::Add(o)) => *s.lock() == *o.lock(), + (Command::Leave(s), Command::Leave(o)) => s == o, + (Command::Ls(s), Command::Ls(o)) => s == o, + (Command::Ld(s), Command::Ld(o)) => s == o, + (Command::Mv(a, b), Command::Mv(x, y)) => a == x && b == y, + (Command::Rm(s), Command::Rm(o)) => s == o, + (Command::Enc(s), Command::Enc(o)) => s == o, + (Command::Gen(a, b), Command::Gen(x, y)) => a == x && *b.lock() == *y.lock(), + (Command::Pass(s), Command::Pass(o)) => s == o, + (Command::UnPass(s), Command::UnPass(o)) => s == o, + (Command::Correct(s), Command::Correct(o)) => s == o, + (Command::Uncorrect(s), Command::Uncorrect(o)) => s == o, + (Command::PasteBuffer(s), Command::PasteBuffer(o)) => s == o, + (Command::Source(s), Command::Source(o)) => s == o, + (Command::Dump(s), Command::Dump(o)) => s == o, + (Command::Comment(a, b), Command::Comment(x, y)) => a == x && b == y, + (Command::Error(s), Command::Error(o)) => s == o, + (Command::Noop, Command::Noop) => true, + (Command::Help, Command::Help) => true, + (Command::Quit, Command::Quit) => true, + _ => false, + } + } +} + #[derive(PartialEq, Debug, Clone)] pub enum Mode { Regular, @@ -114,21 +145,21 @@ impl std::fmt::Display for Mode { } } -#[derive(PartialEq, Debug)] +#[derive(Debug)] pub struct LKOut { - pub out: Option>>>, - pub err: Option>>>, + pub out: Option>>>, + pub err: Option>>>, } impl LKOut { pub fn new() -> Self { Self { - out: Some(Rc::new(RefCell::new(vec![]))), - err: Some(Rc::new(RefCell::new(vec![]))), + out: Some(Arc::new(Mutex::new(vec![]))), + err: Some(Arc::new(Mutex::new(vec![]))), } } - pub fn from_lkout(out: Option>>>, err: Option>>>) -> Self { + pub fn from_lkout(out: Option>>>, err: Option>>>) -> Self { let o = match out { Some(v) => Some(v.clone()), None => None, @@ -143,8 +174,8 @@ impl LKOut { #[allow(dead_code)] pub fn from_vecs(out: Vec, err: Vec) -> Self { Self { - out: Some(Rc::new(RefCell::new(out))), - err: Some(Rc::new(RefCell::new(err))), + out: Some(Arc::new(Mutex::new(out))), + err: Some(Arc::new(Mutex::new(err))), } } @@ -152,7 +183,7 @@ impl LKOut { if !self.out.is_some() { return; } - for line in self.out.as_ref().unwrap().borrow().iter() { + for line in self.out.as_ref().unwrap().lock().iter() { out.o(line.to_string()) } } @@ -161,7 +192,7 @@ impl LKOut { if !self.err.is_some() { return; } - for line in self.err.as_ref().unwrap().borrow().iter() { + for line in self.err.as_ref().unwrap().lock().iter() { out.e(line.to_string()) } } @@ -170,7 +201,7 @@ impl LKOut { if !self.out.is_some() { return; } - for line in self.out.as_ref().unwrap().borrow().iter() { + for line in self.out.as_ref().unwrap().lock().iter() { println!("{}", line); } } @@ -179,7 +210,7 @@ impl LKOut { if !self.err.is_some() { return; } - for line in self.err.as_ref().unwrap().borrow().iter() { + for line in self.err.as_ref().unwrap().lock().iter() { eprintln!("{}", line); } } @@ -191,7 +222,7 @@ impl LKOut { pub fn data(&self) -> String { if self.out.is_some() { - self.out.as_ref().unwrap().borrow().join("\n") + self.out.as_ref().unwrap().lock().join("\n") } else { "".to_string() } @@ -202,16 +233,30 @@ impl LKOut { } pub fn o(&self, line: String) { if self.out.is_some() { - self.out.as_ref().unwrap().borrow_mut().push(line); + self.out.as_ref().unwrap().lock().push(line); } } pub fn e(&self, line: String) { if self.err.is_some() { - self.err.as_ref().unwrap().borrow_mut().push(line); + self.err.as_ref().unwrap().lock().push(line); } } } +impl PartialEq for LKOut { + fn eq(&self, other: &Self) -> bool { + (match (&self.out, &other.out) { + (Some(a), Some(b)) => *a.lock() == *b.lock(), + (None, None) => true, + _ => false, + } && match (&self.err, &other.err) { + (Some(a), Some(b)) => *a.lock() == *b.lock(), + (None, None) => true, + _ => false, + }) + } +} + pub struct Radix { x: i32, radix: u32, @@ -263,13 +308,15 @@ impl fmt::Display for Radix { } pub fn init() -> Option { - let lk = Rc::new(RefCell::new(LK::new())); + let lk = Arc::new(ReentrantMutex::new(RefCell::new(LK::new()))); match std::fs::read_to_string(INIT_FILE.to_str().unwrap()) { Ok(script) => match command_parser::script(&script) { Ok(cmd_list) => { for cmd in cmd_list { - if !LKEval::new(cmd, lk.clone(), password).eval().print() { return None; } + if !LKEval::new(cmd, lk.clone(), password).eval().print() { + return None; + } } } Err(err) => { @@ -349,9 +396,9 @@ mod tests { let lkread = init().unwrap(); assert_eq!(lkread.prompt, "test> "); - assert_eq!(lkread.state.borrow().db.contains_key("t1"), true); + assert_eq!(lkread.state.lock().borrow().db.contains_key("t1"), true); - let t1 = Rc::new(RefCell::new(Password::new( + let t1 = Password::from_password(Password::new( None, "t1".to_string(), None, @@ -359,8 +406,8 @@ mod tests { 99, Date::new(2022, 10, 10), None, - ))); - let t2 = Rc::new(RefCell::new(Password::new( + )); + let t2 = Password::from_password(Password::new( None, "t2".to_string(), None, @@ -368,9 +415,9 @@ mod tests { 99, Date::new(2022, 10, 10), Some("test".to_string()), - ))); - t2.borrow_mut().parent = Some(t1.clone()); - let t3 = Rc::new(RefCell::new(Password::new( + )); + t2.lock().borrow_mut().parent = Some(t1.clone()); + let t3 = Password::from_password(Password::new( None, "t3".to_string(), None, @@ -378,15 +425,13 @@ mod tests { 99, Date::new(2022, 10, 10), Some("aoeu".to_string()), - ))); - t3.borrow_mut().parent = Some(t2.clone()); - assert_eq!(*lkread.state.borrow().db.get("t1").unwrap().borrow(), *t1.borrow()); - assert_eq!(*lkread.state.borrow().db.get("t2").unwrap().borrow(), *t2.borrow()); - assert_eq!(*lkread.state.borrow().db.get("t3").unwrap().borrow(), *t3.borrow()); + )); + t3.lock().borrow_mut().parent = Some(t2.clone()); + assert_eq!(*lkread.state.lock().borrow().db.get("t1").unwrap().lock(), *t1.lock()); + assert_eq!(*lkread.state.lock().borrow().db.get("t2").unwrap().lock(), *t2.lock()); + assert_eq!(*lkread.state.lock().borrow().db.get("t3").unwrap().lock(), *t3.lock()); - LKEval::new(command_parser::cmd("save").unwrap(), lkread.state.clone(), password) - .eval() - .print(); + LKEval::new(command_parser::cmd("save").unwrap(), lkread.state.clone(), password).eval().print(); assert_eq!( std::fs::read_to_string("test_dump").expect("read"), "add t1 R 99 2022-10-10\nadd t2 R 99 2022-10-10 test ^t1\nadd t3 R 99 2022-10-10 aoeu ^t2\n".to_string() @@ -412,7 +457,7 @@ mod tests { ] ) ); - lkread.state.borrow_mut().secrets.clear(); + lkread.state.lock().borrow_mut().secrets.clear(); let pr = LKEval::new(command_parser::cmd("pb enc t3").unwrap(), lkread.state.clone(), |v| { if v == "/" { Ok("a".to_string()) diff --git a/hel/src/utils.rs b/hel/src/utils.rs index 144382c..6a32349 100644 --- a/hel/src/utils.rs +++ b/hel/src/utils.rs @@ -11,12 +11,14 @@ pub mod date { #[derive(PartialEq, Debug, Clone, Copy)] pub struct Date { - date: NaiveDate + date: NaiveDate, } impl Date { pub fn new(year: i32, month: u32, day: u32) -> Self { - Self { date: NaiveDate::from_ymd_opt(year, month, day).unwrap() } + Self { + date: NaiveDate::from_ymd_opt(year, month, day).unwrap(), + } } pub fn try_new(year: i32, month: u32, day: u32) -> Result { @@ -27,7 +29,9 @@ pub mod date { } pub fn now() -> Self { - Self { date: Local::now().naive_local().date() } + Self { + date: Local::now().naive_local().date(), + } } pub fn cmp(&self, other: &Self) -> core::cmp::Ordering { @@ -95,7 +99,9 @@ pub mod editor { impl Editor { pub fn new() -> Self { - Self { editor: rustyline::Editor::<()>::new().unwrap() } + Self { + editor: rustyline::Editor::<()>::new().unwrap(), + } } pub fn clear_history(&mut self) { diff --git a/helwasm/Cargo.toml b/helwasm/Cargo.toml index 67b19fd..50dbe43 100644 --- a/helwasm/Cargo.toml +++ b/helwasm/Cargo.toml @@ -13,6 +13,7 @@ crate-type = ["cdylib"] [dependencies] hel = { version = "0.1.0", path = "../hel" } +lazy_static = "1.4.0" wasm-bindgen = "0.2.83" [dependencies.web-sys] diff --git a/helwasm/index.html b/helwasm/index.html index 2e46921..5073fde 100644 --- a/helwasm/index.html +++ b/helwasm/index.html @@ -1,7 +1,6 @@ - @@ -76,7 +75,9 @@
-