Enforce thread safety to allow for multithread interpreter

This commit is contained in:
NGnius (Graham) 2022-12-24 10:24:59 -05:00
parent 8910d9df18
commit 13ac120ebc
15 changed files with 475 additions and 413 deletions

688
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -8,17 +8,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom",
"once_cell",
"version_check",
]
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.18" version = "0.7.18"
@ -57,6 +46,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base64"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
@ -345,18 +340,6 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fallible-streaming-iterator"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.24" version = "1.0.24"
@ -397,30 +380,12 @@ dependencies = [
"wasi 0.11.0+wasi-snapshot-preview1", "wasi 0.11.0+wasi-snapshot-preview1",
] ]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"ahash",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.12.1" version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
[[package]]
name = "hashlink"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
dependencies = [
"hashbrown 0.11.2",
]
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.3.3" version = "0.3.3"
@ -452,7 +417,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown 0.12.1", "hashbrown",
] ]
[[package]] [[package]]
@ -496,17 +461,6 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "libsqlite3-sys"
version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cafc7c74096c336d9d27145f7ebd4f4b6f95ba16aa5a282387267e6925cb58"
dependencies = [
"cc",
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.17" version = "0.4.17"
@ -516,6 +470,15 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "m3u8-rs"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50fe05791a7f418b59d6cddebdc293d77c9c1f652adbff855c071d4507cd883b"
dependencies = [
"nom",
]
[[package]] [[package]]
name = "maplit" name = "maplit"
version = "1.0.2" version = "1.0.2"
@ -546,6 +509,12 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.5.3" version = "0.5.3"
@ -570,13 +539,15 @@ dependencies = [
name = "muss-interpreter" name = "muss-interpreter"
version = "0.9.0" version = "0.9.0"
dependencies = [ dependencies = [
"base64",
"bliss-audio-symphonia", "bliss-audio-symphonia",
"dirs", "dirs",
"m3u8-rs",
"mpd", "mpd",
"rand", "rand",
"regex", "regex",
"rusqlite",
"shellexpand", "shellexpand",
"sqlparser",
"symphonia", "symphonia",
"unidecode", "unidecode",
] ]
@ -641,6 +612,16 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "nom"
version = "7.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]] [[package]]
name = "num-bigint" name = "num-bigint"
version = "0.4.3" version = "0.4.3"
@ -760,12 +741,6 @@ dependencies = [
"sha-1", "sha-1",
] ]
[[package]]
name = "pkg-config"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.16" version = "0.2.16"
@ -926,21 +901,6 @@ dependencies = [
"opaque-debug 0.3.0", "opaque-debug 0.3.0",
] ]
[[package]]
name = "rusqlite"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ba4d3462c8b2e4d7f4fcfcf2b296dc6b65404fbbc7b63daa37fd485c149daf7"
dependencies = [
"bitflags",
"fallible-iterator",
"fallible-streaming-iterator",
"hashlink",
"libsqlite3-sys",
"memchr",
"smallvec",
]
[[package]] [[package]]
name = "rustc-serialize" name = "rustc-serialize"
version = "0.3.24" version = "0.3.24"
@ -989,10 +949,13 @@ dependencies = [
] ]
[[package]] [[package]]
name = "smallvec" name = "sqlparser"
version = "1.8.1" version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" checksum = "0beb13adabbdda01b63d595f38c8bfd19a361e697fd94ce0098a634077bc5b25"
dependencies = [
"log",
]
[[package]] [[package]]
name = "strength_reduce" name = "strength_reduce"
@ -1281,12 +1244,6 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc" checksum = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"

View file

@ -16,7 +16,7 @@ use crate::Item;
const INNER_VARIABLE_NAME: &str = "[inner variable]"; const INNER_VARIABLE_NAME: &str = "[inner variable]";
pub trait FilterPredicate: Clone + Debug + Display { pub trait FilterPredicate: Clone + Debug + Display + Send {
fn matches(&mut self, item: &Item, ctx: &mut Context) -> Result<bool, RuntimeMsg>; fn matches(&mut self, item: &Item, ctx: &mut Context) -> Result<bool, RuntimeMsg>;
fn is_complete(&self) -> bool; fn is_complete(&self) -> bool;
@ -24,7 +24,7 @@ pub trait FilterPredicate: Clone + Debug + Display {
fn reset(&mut self) -> Result<(), RuntimeMsg>; fn reset(&mut self) -> Result<(), RuntimeMsg>;
} }
pub trait FilterFactory<P: FilterPredicate + 'static> { pub trait FilterFactory<P: FilterPredicate + 'static>: Send + Sync {
fn is_filter(&self, tokens: &VecDeque<&Token>) -> bool; fn is_filter(&self, tokens: &VecDeque<&Token>) -> bool;
fn build_filter( fn build_filter(

View file

@ -8,7 +8,7 @@ use crate::lang::SyntaxError;
use crate::lang::{BoxedOpFactory, Op}; use crate::lang::{BoxedOpFactory, Op};
use crate::tokens::Token; use crate::tokens::Token;
pub trait FunctionFactory<O: Op + 'static> { pub trait FunctionFactory<O: Op + 'static>: Send + Sync {
fn is_function(&self, name: &str) -> bool; fn is_function(&self, name: &str) -> bool;
fn build_function_params( fn build_function_params(

View file

@ -8,11 +8,11 @@ use crate::Item;
pub struct GeneratorOp { pub struct GeneratorOp {
context: Option<Context>, context: Option<Context>,
generator: Box<dyn FnMut(&mut Context) -> Option<Result<Item, RuntimeMsg>>>, generator: Box<dyn (FnMut(&mut Context) -> Option<Result<Item, RuntimeMsg>>) + Send>,
} }
impl GeneratorOp { impl GeneratorOp {
pub fn new<F: FnMut(&mut Context) -> Option<Result<Item, RuntimeMsg>> + 'static>(generator_fn: F) -> Self { pub fn new<F: (FnMut(&mut Context) -> Option<Result<Item, RuntimeMsg>>) + Send + 'static>(generator_fn: F) -> Self {
Self { Self {
context: None, context: None,
generator: Box::new(generator_fn), generator: Box::new(generator_fn),

View file

@ -17,11 +17,11 @@ use crate::Context;
const ITEM_VARIABLE_NAME: &str = "item"; const ITEM_VARIABLE_NAME: &str = "item";
pub trait ItemOp: Debug + Display { pub trait ItemOp: Debug + Display + Send + Sync {
fn execute(&self, context: &mut Context) -> Result<Type, RuntimeMsg>; fn execute(&self, context: &mut Context) -> Result<Type, RuntimeMsg>;
} }
pub trait ItemOpFactory<T: Deref<Target = dyn ItemOp> + 'static> { pub trait ItemOpFactory<T: Deref<Target = dyn ItemOp> + 'static>: Send + Sync {
fn is_item_op(&self, tokens: &VecDeque<Token>) -> bool; fn is_item_op(&self, tokens: &VecDeque<Token>) -> bool;
fn build_item_op( fn build_item_op(

View file

@ -48,7 +48,7 @@ pub trait OpFactory<T: Op + 'static> {
} }
} }
pub trait BoxedOpFactory { pub trait BoxedOpFactory: Send {
fn build_op_boxed( fn build_op_boxed(
&self, &self,
tokens: &mut VecDeque<Token>, tokens: &mut VecDeque<Token>,
@ -60,7 +60,7 @@ pub trait BoxedOpFactory {
pub type IteratorItem = Result<Item, RuntimeError>; pub type IteratorItem = Result<Item, RuntimeError>;
pub trait Op: Iterator<Item = IteratorItem> + Debug + Display { pub trait Op: Iterator<Item = IteratorItem> + Debug + Display + Send {
fn enter(&mut self, ctx: Context); fn enter(&mut self, ctx: Context);
fn escape(&mut self) -> Context; fn escape(&mut self) -> Context;

View file

@ -12,7 +12,7 @@ use crate::Context;
const SORTER_ITEM_CACHE_SIZE: usize = 8; const SORTER_ITEM_CACHE_SIZE: usize = 8;
pub trait Sorter: Clone + Debug + Display { pub trait Sorter: Clone + Debug + Display + Send + Sync {
fn sort( fn sort(
&mut self, &mut self,
iterator: &mut dyn Op, iterator: &mut dyn Op,
@ -22,7 +22,7 @@ pub trait Sorter: Clone + Debug + Display {
fn reset(&mut self) {} fn reset(&mut self) {}
} }
pub trait SorterFactory<S: Sorter + 'static> { pub trait SorterFactory<S: Sorter + 'static>: Send + Sync {
fn is_sorter(&self, tokens: &VecDeque<&Token>) -> bool; fn is_sorter(&self, tokens: &VecDeque<&Token>) -> bool;
fn build_sorter( fn build_sorter(

View file

@ -1,6 +1,7 @@
use core::ops::Deref; use core::ops::Deref;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt::{Debug, Display, Error, Formatter}; use std::fmt::{Debug, Display, Error, Formatter};
use std::sync::Mutex;
use crate::lang::utility::{assert_name, check_name}; use crate::lang::utility::{assert_name, check_name};
use crate::lang::LanguageDictionary; use crate::lang::LanguageDictionary;
@ -12,7 +13,7 @@ use crate::Context;
#[derive(Debug)] #[derive(Debug)]
pub struct IterItemOp { pub struct IterItemOp {
inner: Box<dyn Op>, inner: Mutex<Box<dyn Op>>,
} }
impl Deref for IterItemOp { impl Deref for IterItemOp {
@ -24,13 +25,19 @@ impl Deref for IterItemOp {
impl Display for IterItemOp { impl Display for IterItemOp {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "iter {}", self.inner) match self.inner.lock() {
Ok(inner) => write!(f, "iter {}", inner),
Err(e) => write!(f, "iter !?!? (e:{})", e)
}
} }
} }
impl ItemOp for IterItemOp { impl ItemOp for IterItemOp {
fn execute(&self, _context: &mut Context) -> Result<Type, RuntimeMsg> { fn execute(&self, _context: &mut Context) -> Result<Type, RuntimeMsg> {
Ok(Type::Op(self.inner.dup())) match self.inner.lock() {
Ok(inner) => Ok(Type::Op(inner.dup())),
Err(e) => Err(RuntimeMsg(format!("IterItemOp lock failed: {}", e)))
}
} }
} }
@ -49,6 +56,6 @@ impl ItemOpFactory<IterItemOp> for IterItemOpFactory {
) -> Result<IterItemOp, SyntaxError> { ) -> Result<IterItemOp, SyntaxError> {
assert_name("iter", tokens)?; assert_name("iter", tokens)?;
let inner_op = dict.try_build_statement(tokens)?; let inner_op = dict.try_build_statement(tokens)?;
Ok(IterItemOp { inner: inner_op }) Ok(IterItemOp { inner: Mutex::new(inner_op) })
} }
} }

View file

@ -329,7 +329,7 @@ impl Iterator for FileIter {
} }
} }
pub trait FilesystemQuerier: Debug { pub trait FilesystemQuerier: Debug + Send {
fn raw( fn raw(
&mut self, &mut self,
folder: Option<&str>, folder: Option<&str>,
@ -369,7 +369,7 @@ pub struct FilesystemExecutor {}
impl FilesystemExecutor { impl FilesystemExecutor {
#[cfg(feature = "collections")] #[cfg(feature = "collections")]
fn read_m3u8<P: AsRef<Path> + 'static>(&self, path: P) -> Result<GeneratorOp, RuntimeMsg> { fn read_m3u8<P: AsRef<Path> + Send + 'static>(&self, path: P) -> Result<GeneratorOp, RuntimeMsg> {
let mut file = std::fs::File::open(&path).map_err(|e| RuntimeMsg(format!("Path read error: {}", e)))?; let mut file = std::fs::File::open(&path).map_err(|e| RuntimeMsg(format!("Path read error: {}", e)))?;
let mut file_bytes = Vec::new(); let mut file_bytes = Vec::new();
file.read_to_end(&mut file_bytes).map_err(|e| RuntimeMsg(format!("File read error: {}", e)))?; file.read_to_end(&mut file_bytes).map_err(|e| RuntimeMsg(format!("File read error: {}", e)))?;

View file

@ -11,7 +11,7 @@ use crate::lang::TypePrimitive;
use crate::Item; use crate::Item;
/// Music Player Daemon interface for interacting with it's database /// Music Player Daemon interface for interacting with it's database
pub trait MpdQuerier: Debug { pub trait MpdQuerier: Debug + Send {
fn connect(&mut self, addr: SocketAddr) -> Result<(), RuntimeMsg>; fn connect(&mut self, addr: SocketAddr) -> Result<(), RuntimeMsg>;
fn search(&mut self, params: Vec<(&str, String)>) -> Result<VecDeque<Item>, RuntimeMsg>; fn search(&mut self, params: Vec<(&str, String)>) -> Result<VecDeque<Item>, RuntimeMsg>;

View file

@ -23,7 +23,7 @@ use crate::Item;
const PATH_FIELD: &str = "filename"; const PATH_FIELD: &str = "filename";
pub trait MusicAnalyzer: Debug { pub trait MusicAnalyzer: Debug + Send {
fn prepare_distance(&mut self, from: &Item, to: &Item) -> Result<(), RuntimeMsg>; fn prepare_distance(&mut self, from: &Item, to: &Item) -> Result<(), RuntimeMsg>;
fn prepare_item(&mut self, item: &Item) -> Result<(), RuntimeMsg>; fn prepare_item(&mut self, item: &Item) -> Result<(), RuntimeMsg>;

View file

@ -18,7 +18,7 @@ use crate::Item;
pub type QueryResult = Result<Box<dyn Op>, RuntimeMsg>; pub type QueryResult = Result<Box<dyn Op>, RuntimeMsg>;
/// SQL querying functionality, loosely de-coupled from any specific SQL dialect (excluding raw call) /// SQL querying functionality, loosely de-coupled from any specific SQL dialect (excluding raw call)
pub trait DatabaseQuerier: Debug { pub trait DatabaseQuerier: Debug + Send {
/// raw SQL call, assumed (but not guaranteed) to retrieved music items /// raw SQL call, assumed (but not guaranteed) to retrieved music items
fn raw(&mut self, query: &str) -> QueryResult; fn raw(&mut self, query: &str) -> QueryResult;

View file

@ -31,7 +31,7 @@ impl Type {
} }
} }
pub trait VariableStorer: Debug { pub trait VariableStorer: Debug + Send {
fn get(&self, name: &str) -> Result<&'_ Type, RuntimeMsg> { fn get(&self, name: &str) -> Result<&'_ Type, RuntimeMsg> {
match self.get_opt(name) { match self.get_opt(name) {
Some(item) => Ok(item), Some(item) => Ok(item),

View file

@ -113,15 +113,27 @@ fn pretty_print_item(item: &Item, terminal: &mut Term, args: &CliArgs, verbose:
fields.sort(); fields.sort();
for field in fields { for field in fields {
if field != "title" { if field != "title" {
let field_str = item.field(field).unwrap_or(&TypePrimitive::Empty).as_str();
let max_len = terminal.size().1 as usize - (args.prompt.len() + field.len() + 8);
if field_str.len() >= max_len {
writeln!(
terminal,
" {}: `{}[...]`",
field,
&field_str[..max_len-5]
)
.expect(TERMINAL_WRITE_ERROR);
} else {
writeln!( writeln!(
terminal, terminal,
" {}: `{}`", " {}: `{}`",
field, field,
item.field(field).unwrap_or(&TypePrimitive::Empty).as_str() field_str
) )
.expect(TERMINAL_WRITE_ERROR); .expect(TERMINAL_WRITE_ERROR);
} }
} }
}
} else { } else {
writeln!( writeln!(
terminal, terminal,