From 8bdd6e00e899457598956528a27a26abed13593b Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 10 Nov 2023 13:18:34 +0100 Subject: [PATCH] Add lock_update function for safer multithreading &v = (v, 1).sum might fail if two threads do it at the same time or something, so you can now lock the reference to ensure no other thread messes with your data while you update its value --- mers/src/main.rs | 2 - mers_lib/src/data/defs.rs | 2 +- mers_lib/src/data/reference.rs | 10 ++--- mers_lib/src/program/configs/mod.rs | 4 +- mers_lib/src/program/configs/with_base.rs | 51 ++++++++++++++++++++++- mers_lib/src/program/configs/with_list.rs | 4 +- mers_lib/src/program/run/mod.rs | 8 ++-- mers_lib/src/program/run/variable.rs | 6 +-- 8 files changed, 67 insertions(+), 20 deletions(-) diff --git a/mers/src/main.rs b/mers/src/main.rs index b2a7f43..03b58fb 100755 --- a/mers/src/main.rs +++ b/mers/src/main.rs @@ -92,8 +92,6 @@ fn main() { std::process::exit(36); } }; - #[cfg(debug_assertions)] - dbg!(&return_type); if args.check == Check::Yes { run.run(&mut info_run); } else { diff --git a/mers_lib/src/data/defs.rs b/mers_lib/src/data/defs.rs index 0d5da2a..ba61a6f 100755 --- a/mers_lib/src/data/defs.rs +++ b/mers_lib/src/data/defs.rs @@ -6,7 +6,7 @@ pub fn assign(from: &Data, target: &Data) { .as_any() .downcast_ref::() { - *r.0.lock().unwrap() = from.clone(); + *r.0.write().unwrap() = from.clone(); } else if let (Some(from), Some(target)) = ( from.get() .as_any() diff --git a/mers_lib/src/data/reference.rs b/mers_lib/src/data/reference.rs index 09e8670..e9dad41 100755 --- a/mers_lib/src/data/reference.rs +++ b/mers_lib/src/data/reference.rs @@ -1,18 +1,18 @@ use std::{ any::Any, fmt::Display, - sync::{Arc, Mutex}, + sync::{Arc, RwLock}, }; use super::{Data, MersData, MersType, Type}; #[derive(Debug, Clone)] -pub struct Reference(pub Arc>); +pub struct Reference(pub Arc>); impl MersData for Reference { fn is_eq(&self, other: &dyn MersData) -> bool { if let Some(other) = other.as_any().downcast_ref::() { - *other.0.lock().unwrap() == *self.0.lock().unwrap() + *other.0.write().unwrap() == *self.0.write().unwrap() } else { false } @@ -21,7 +21,7 @@ impl MersData for Reference { Box::new(Clone::clone(self)) } fn as_type(&self) -> Type { - Type::new(ReferenceT(self.0.lock().unwrap().get().as_type())) + Type::new(ReferenceT(self.0.write().unwrap().get().as_type())) } fn as_any(&self) -> &dyn Any { self @@ -69,7 +69,7 @@ impl MersType for ReferenceT { impl Display for Reference { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "&{}", self.0.lock().unwrap().get()) + write!(f, "&{}", self.0.write().unwrap().get()) } } impl Display for ReferenceT { diff --git a/mers_lib/src/program/configs/mod.rs b/mers_lib/src/program/configs/mod.rs index a0b1f40..1ebf805 100755 --- a/mers_lib/src/program/configs/mod.rs +++ b/mers_lib/src/program/configs/mod.rs @@ -1,4 +1,4 @@ -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, RwLock}; use crate::{ data::{Data, Type}, @@ -69,7 +69,7 @@ impl Config { pub fn add_var(mut self, name: String, val: Data) -> Self { let t = val.get().as_type(); self.info_parsed.scopes[0].init_var(name, (0, self.globals)); - self.info_run.scopes[0].init_var(self.globals, Arc::new(Mutex::new(val))); + self.info_run.scopes[0].init_var(self.globals, Arc::new(RwLock::new(val))); self.info_check.scopes[0].init_var(self.globals, t); self.globals += 1; self diff --git a/mers_lib/src/program/configs/with_base.rs b/mers_lib/src/program/configs/with_base.rs index 2f086ad..c8345ec 100755 --- a/mers_lib/src/program/configs/with_base.rs +++ b/mers_lib/src/program/configs/with_base.rs @@ -19,6 +19,7 @@ impl Config { /// `len: fn` gets the length of strings or tuples /// `sleep: fn` sleeps for n seconds (pauses the current thread) /// `panic: fn` exits the program with the given exit code + /// `lock_update: fn` locks the value of a reference so you can exclusively modify it: &var.lock_update(v -> (v, 1).sum) pub fn with_base(self) -> Self { self.add_var("try".to_string(), Data::new(data::function::Function { info: Arc::new(Info::neverused()), @@ -112,6 +113,54 @@ impl Config { unreachable!("try: no function found") }) })) + .add_var("lock_update".to_string(), Data::new(data::function::Function { + info: Arc::new(Info::neverused()), + info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + out: Arc::new(|a, _i| { + for t in a.types.iter() { + if let Some(t) = t.as_any().downcast_ref::() { + if t.0.len() == 2 { + let arg_ref = &t.0[0]; + if let Some(arg) = arg_ref.dereference() { + let func = &t.0[1]; + for func_t in func.types.iter() { + if let Some(f) = func_t.as_any().downcast_ref::() { + match (f.0)(&arg) { + Ok(out) => { + if !out.is_included_in(&arg) { + return Err(format!("Function returns a value of type {out}, which isn't included in the type of the reference, {arg}.").into()); + } + }, + Err(e) => return Err(CheckError::new().msg(format!("Invalid argument type {arg} for function")).err(e)), + } + } else { + return Err(format!("Arguments must be (reference, function)").into()); + } + } + } else { + return Err(format!("Arguments must be (reference, function), but {arg_ref} isn't a reference").into()); + } + } else { + return Err(format!("Can't call lock_update on tuple type {t} with length != 2, which is part of the argument type {a}.").into()); + } + } else { + return Err(format!("Can't call lock_update on non-tuple type {t}, which is part of the argument type {a}.").into()); + } + } + Ok(Type::empty_tuple()) + }), + run: Arc::new(|a, _i| { + let a = a.get(); + let a = a.as_any().downcast_ref::().unwrap(); + let arg_ref = a.0[0].get(); + let arg_ref = arg_ref.as_any().downcast_ref::().unwrap(); + let mut arg = arg_ref.0.write().unwrap(); + let func = a.0[1].get(); + let func = func.as_any().downcast_ref::().unwrap(); + *arg = func.run(arg.clone()); + Data::empty_tuple() + }) + })) .add_var("sleep".to_string(), Data::new(data::function::Function { info: Arc::new(Info::neverused()), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), @@ -268,7 +317,7 @@ impl Config { .as_any() .downcast_ref::() { - r.0.lock().unwrap().clone() + r.0.write().unwrap().clone() } else { unreachable!("called deref on non-reference") } diff --git a/mers_lib/src/program/configs/with_list.rs b/mers_lib/src/program/configs/with_list.rs index 1d98bd5..0e75ed6 100755 --- a/mers_lib/src/program/configs/with_list.rs +++ b/mers_lib/src/program/configs/with_list.rs @@ -53,7 +53,7 @@ impl Config { .downcast_ref::() .unwrap() .0 - .lock() + .write() .unwrap() .get_mut() .mut_any() @@ -118,7 +118,7 @@ impl Config { .downcast_ref::() .unwrap() .0 - .lock() + .write() .unwrap() .get_mut() .mut_any() diff --git a/mers_lib/src/program/run/mod.rs b/mers_lib/src/program/run/mod.rs index 8118d5e..e82c894 100755 --- a/mers_lib/src/program/run/mod.rs +++ b/mers_lib/src/program/run/mod.rs @@ -1,6 +1,6 @@ use std::{ fmt::{Debug, Display}, - sync::{Arc, Mutex}, + sync::{Arc, RwLock}, }; use colored::Colorize; @@ -240,7 +240,7 @@ pub type CheckInfo = info::Info; #[derive(Default, Clone, Debug)] pub struct Local { - vars: Vec>>, + vars: Vec>>, } #[derive(Default, Clone, Debug)] pub struct CheckLocal { @@ -248,9 +248,9 @@ pub struct CheckLocal { } impl info::Local for Local { type VariableIdentifier = usize; - type VariableData = Arc>; + type VariableData = Arc>; fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) { - let nothing = Arc::new(Mutex::new(Data::new(data::bool::Bool(false)))); + let nothing = Arc::new(RwLock::new(Data::new(data::bool::Bool(false)))); while self.vars.len() <= id { self.vars.push(Arc::clone(¬hing)); } diff --git a/mers_lib/src/program/run/variable.rs b/mers_lib/src/program/run/variable.rs index 3f4454d..2917087 100755 --- a/mers_lib/src/program/run/variable.rs +++ b/mers_lib/src/program/run/variable.rs @@ -1,4 +1,4 @@ -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, RwLock}; use crate::data::{self, Data, Type}; @@ -40,7 +40,7 @@ impl MersStatement for Variable { } fn run_custom(&self, info: &mut super::Info) -> Data { if self.is_init { - let nothing = Arc::new(Mutex::new(Data::new(data::bool::Bool(false)))); + let nothing = Arc::new(RwLock::new(Data::new(data::bool::Bool(false)))); while info.scopes[self.var.0].vars.len() <= self.var.1 { info.scopes[self.var.0].vars.push(Arc::clone(¬hing)); } @@ -52,7 +52,7 @@ impl MersStatement for Variable { ))) } else { info.scopes[self.var.0].vars[self.var.1] - .lock() + .write() .unwrap() .clone() }