Enforce thread safety to allow for multithread interpreter
This commit is contained in:
parent
8910d9df18
commit
13ac120ebc
15 changed files with 475 additions and 413 deletions
688
Cargo.lock
generated
688
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
125
interpreter/fuzz/Cargo.lock
generated
125
interpreter/fuzz/Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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) })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)))?;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
26
src/repl.rs
26
src/repl.rs
|
@ -113,13 +113,25 @@ fn pretty_print_item(item: &Item, terminal: &mut Term, args: &CliArgs, verbose:
|
|||
fields.sort();
|
||||
for field in fields {
|
||||
if field != "title" {
|
||||
writeln!(
|
||||
terminal,
|
||||
" {}: `{}`",
|
||||
field,
|
||||
item.field(field).unwrap_or(&TypePrimitive::Empty).as_str()
|
||||
)
|
||||
.expect(TERMINAL_WRITE_ERROR);
|
||||
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,
|
||||
field_str
|
||||
)
|
||||
.expect(TERMINAL_WRITE_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue