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"
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]]
name = "aho-corasick"
version = "0.7.18"
@ -57,6 +46,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base64"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "bitflags"
version = "1.3.2"
@ -345,18 +340,6 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "flate2"
version = "1.0.24"
@ -397,30 +380,12 @@ dependencies = [
"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]]
name = "hashbrown"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "heck"
version = "0.3.3"
@ -452,7 +417,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [
"autocfg",
"hashbrown 0.12.1",
"hashbrown",
]
[[package]]
@ -496,17 +461,6 @@ dependencies = [
"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]]
name = "log"
version = "0.4.17"
@ -516,6 +470,15 @@ dependencies = [
"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]]
name = "maplit"
version = "1.0.2"
@ -546,6 +509,12 @@ dependencies = [
"autocfg",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.5.3"
@ -570,13 +539,15 @@ dependencies = [
name = "muss-interpreter"
version = "0.9.0"
dependencies = [
"base64",
"bliss-audio-symphonia",
"dirs",
"m3u8-rs",
"mpd",
"rand",
"regex",
"rusqlite",
"shellexpand",
"sqlparser",
"symphonia",
"unidecode",
]
@ -641,6 +612,16 @@ dependencies = [
"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]]
name = "num-bigint"
version = "0.4.3"
@ -760,12 +741,6 @@ dependencies = [
"sha-1",
]
[[package]]
name = "pkg-config"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]]
name = "ppv-lite86"
version = "0.2.16"
@ -926,21 +901,6 @@ dependencies = [
"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]]
name = "rustc-serialize"
version = "0.3.24"
@ -989,10 +949,13 @@ dependencies = [
]
[[package]]
name = "smallvec"
version = "1.8.1"
name = "sqlparser"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2"
checksum = "0beb13adabbdda01b63d595f38c8bfd19a361e697fd94ce0098a634077bc5b25"
dependencies = [
"log",
]
[[package]]
name = "strength_reduce"
@ -1281,12 +1244,6 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.4"

View file

@ -16,7 +16,7 @@ use crate::Item;
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 is_complete(&self) -> bool;
@ -24,7 +24,7 @@ pub trait FilterPredicate: Clone + Debug + Display {
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 build_filter(

View file

@ -8,7 +8,7 @@ use crate::lang::SyntaxError;
use crate::lang::{BoxedOpFactory, Op};
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 build_function_params(

View file

@ -8,11 +8,11 @@ use crate::Item;
pub struct GeneratorOp {
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 {
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 {
context: None,
generator: Box::new(generator_fn),

View file

@ -17,11 +17,11 @@ use crate::Context;
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>;
}
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 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(
&self,
tokens: &mut VecDeque<Token>,
@ -60,7 +60,7 @@ pub trait BoxedOpFactory {
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 escape(&mut self) -> Context;

View file

@ -12,7 +12,7 @@ use crate::Context;
const SORTER_ITEM_CACHE_SIZE: usize = 8;
pub trait Sorter: Clone + Debug + Display {
pub trait Sorter: Clone + Debug + Display + Send + Sync {
fn sort(
&mut self,
iterator: &mut dyn Op,
@ -22,7 +22,7 @@ pub trait Sorter: Clone + Debug + Display {
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 build_sorter(

View file

@ -1,6 +1,7 @@
use core::ops::Deref;
use std::collections::VecDeque;
use std::fmt::{Debug, Display, Error, Formatter};
use std::sync::Mutex;
use crate::lang::utility::{assert_name, check_name};
use crate::lang::LanguageDictionary;
@ -12,7 +13,7 @@ use crate::Context;
#[derive(Debug)]
pub struct IterItemOp {
inner: Box<dyn Op>,
inner: Mutex<Box<dyn Op>>,
}
impl Deref for IterItemOp {
@ -24,13 +25,19 @@ impl Deref for IterItemOp {
impl Display for IterItemOp {
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 {
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> {
assert_name("iter", 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(
&mut self,
folder: Option<&str>,
@ -369,7 +369,7 @@ pub struct FilesystemExecutor {}
impl FilesystemExecutor {
#[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_bytes = Vec::new();
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;
/// 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 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";
pub trait MusicAnalyzer: Debug {
pub trait MusicAnalyzer: Debug + Send {
fn prepare_distance(&mut self, from: &Item, to: &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>;
/// 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
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> {
match self.get_opt(name) {
Some(item) => Ok(item),

View file

@ -113,15 +113,27 @@ fn pretty_print_item(item: &Item, terminal: &mut Term, args: &CliArgs, verbose:
fields.sort();
for field in fields {
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!(
terminal,
" {}: `{}`",
field,
item.field(field).unwrap_or(&TypePrimitive::Empty).as_str()
field_str
)
.expect(TERMINAL_WRITE_ERROR);
}
}
}
} else {
writeln!(
terminal,