Fix clippy warnings & errors
This commit is contained in:
parent
2bec331700
commit
2b6c47f166
52 changed files with 305 additions and 304 deletions
|
@ -1,4 +1,4 @@
|
||||||
use mps_interpreter::MpsFaye;
|
use muss_interpreter::Interpreter;
|
||||||
//use mps_interpreter::MpsRunner;
|
//use mps_interpreter::MpsRunner;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufReader, Read, Seek};
|
use std::io::{BufReader, Read, Seek};
|
||||||
|
@ -35,12 +35,12 @@ fn faye_benchmark(c: &mut Criterion) {
|
||||||
let mut buf = Vec::with_capacity(1024 * 1024);
|
let mut buf = Vec::with_capacity(1024 * 1024);
|
||||||
reader.read_to_end(&mut buf).unwrap();
|
reader.read_to_end(&mut buf).unwrap();
|
||||||
drop(buf);
|
drop(buf);
|
||||||
c.bench_function("mps-faye lots_of_empty.mps", |b| {
|
c.bench_function("muss-faye lots_of_empty.mps", |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
//let f = File::open("benches/lots_of_empty.mps").unwrap();
|
//let f = File::open("benches/lots_of_empty.mps").unwrap();
|
||||||
//let mut reader = BufReader::new(f);
|
//let mut reader = BufReader::new(f);
|
||||||
reader.rewind().unwrap();
|
reader.rewind().unwrap();
|
||||||
let mps = MpsFaye::with_stream(&mut reader);
|
let mps = Interpreter::with_stream(&mut reader);
|
||||||
for item in mps {
|
for item in mps {
|
||||||
match item {
|
match item {
|
||||||
Err(e) => panic!("{}", e),
|
Err(e) => panic!("{}", e),
|
||||||
|
|
11
interpreter/fuzz/Cargo.lock
generated
11
interpreter/fuzz/Cargo.lock
generated
|
@ -83,7 +83,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bliss-audio-symphonia"
|
name = "bliss-audio-symphonia"
|
||||||
version = "0.4.6"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bliss-audio-aubio-rs",
|
"bliss-audio-aubio-rs",
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
|
@ -96,6 +96,7 @@ dependencies = [
|
||||||
"noisy_float",
|
"noisy_float",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
"rcue",
|
||||||
"ripemd160",
|
"ripemd160",
|
||||||
"rustfft",
|
"rustfft",
|
||||||
"strum",
|
"strum",
|
||||||
|
@ -567,7 +568,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "muss-interpreter"
|
name = "muss-interpreter"
|
||||||
version = "0.8.0"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bliss-audio-symphonia",
|
"bliss-audio-symphonia",
|
||||||
"dirs",
|
"dirs",
|
||||||
|
@ -871,6 +872,12 @@ dependencies = [
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rcue"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fca1481d62f18158646de2ec552dd63f8bdc5be6448389b192ba95c939df997e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.13"
|
version = "0.2.13"
|
||||||
|
|
|
@ -48,7 +48,6 @@ where
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let next_item = self.interpreter.next();
|
let next_item = self.interpreter.next();
|
||||||
let transmuted_next = (self.transmuter)(&mut self.interpreter, next_item);
|
(self.transmuter)(&mut self.interpreter, next_item)
|
||||||
transmuted_next
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn empty_callback<'a, T: TokenReader>(
|
fn empty_callback<T: TokenReader>(
|
||||||
_s: &mut Interpreter<'a, T>,
|
_s: &mut Interpreter<'_, T>,
|
||||||
_d: InterpreterEvent,
|
_d: InterpreterEvent,
|
||||||
) -> Result<(), InterpreterError> {
|
) -> Result<(), InterpreterError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -23,26 +23,26 @@ pub(crate) fn standard_vocab(vocabulary: &mut LanguageDictionary) {
|
||||||
// iter blocks
|
// iter blocks
|
||||||
.add(
|
.add(
|
||||||
crate::lang::ItemBlockFactory::new()
|
crate::lang::ItemBlockFactory::new()
|
||||||
.add(crate::lang::vocabulary::item_ops::ConstantItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::ConstantItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::VariableAssignItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::VariableAssignItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::FieldAssignItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::FieldAssignItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::FileItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::FileItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::VariableDeclareItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::VariableDeclareItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::InterpolateStringItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::InterpolateStringItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::BranchItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::BranchItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::IterItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::IterItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::ConstructorItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::ConstructorItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::EmptyItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::EmptyItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::RemoveItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::RemoveItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::VariableRetrieveItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::VariableRetrieveItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::NegateItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::NegateItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::NotItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::NotItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::CompareItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::CompareItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::AddItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::AddItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::SubtractItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::SubtractItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::OrItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::OrItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::AndItemOpFactory)
|
.push(crate::lang::vocabulary::item_ops::AndItemOpFactory)
|
||||||
.add(crate::lang::vocabulary::item_ops::BracketsItemOpFactory),
|
.push(crate::lang::vocabulary::item_ops::BracketsItemOpFactory),
|
||||||
)
|
)
|
||||||
// functions and misc
|
// functions and misc
|
||||||
// functions don't enforce bracket coherence
|
// functions don't enforce bracket coherence
|
||||||
|
|
|
@ -45,6 +45,10 @@ impl Item {
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.fields.len()
|
self.fields.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.fields.is_empty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Item {
|
impl Display for Item {
|
||||||
|
|
|
@ -53,6 +53,7 @@ impl LanguageDictionary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::derivable_impls)]
|
||||||
impl Default for LanguageDictionary {
|
impl Default for LanguageDictionary {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -227,7 +227,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterStatement<P> {
|
||||||
let matches_result = self.predicate.matches(&item, &mut ctx);
|
let matches_result = self.predicate.matches(&item, &mut ctx);
|
||||||
let matches = match matches_result {
|
let matches = match matches_result {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
maybe_result = Some(Err(e.with(RuntimeOp(fake.clone()))));
|
maybe_result = Some(Err(e.with(RuntimeOp(fake))));
|
||||||
self.context = Some(ctx);
|
self.context = Some(ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -245,7 +245,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterStatement<P> {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
//self.context = Some(op.escape());
|
//self.context = Some(op.escape());
|
||||||
maybe_result =
|
maybe_result =
|
||||||
Some(Err(e.with(RuntimeOp(fake.clone()))));
|
Some(Err(e.with(RuntimeOp(fake))));
|
||||||
self.context = Some(ctx);
|
self.context = Some(ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -269,7 +269,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterStatement<P> {
|
||||||
Err(e) => match maybe_result {
|
Err(e) => match maybe_result {
|
||||||
Some(Ok(_)) => {
|
Some(Ok(_)) => {
|
||||||
maybe_result = Some(Err(
|
maybe_result = Some(Err(
|
||||||
e.with(RuntimeOp(fake.clone()))
|
e.with(RuntimeOp(fake))
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Some(Err(e2)) => maybe_result = Some(Err(e2)), // already failing, do not replace error,
|
Some(Err(e2)) => maybe_result = Some(Err(e2)), // already failing, do not replace error,
|
||||||
|
@ -286,7 +286,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterStatement<P> {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
//self.context = Some(op.escape());
|
//self.context = Some(op.escape());
|
||||||
maybe_result =
|
maybe_result =
|
||||||
Some(Err(e.with(RuntimeOp(fake.clone()))));
|
Some(Err(e.with(RuntimeOp(fake))));
|
||||||
self.context = Some(ctx);
|
self.context = Some(ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -332,7 +332,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterStatement<P> {
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.is_failing = true; // this is unrecoverable and reproducible, so it shouldn't be tried again (to prevent error spam)
|
self.is_failing = true; // this is unrecoverable and reproducible, so it shouldn't be tried again (to prevent error spam)
|
||||||
return Some(Err(e.with(RuntimeOp(fake.clone()))))
|
return Some(Err(e.with(RuntimeOp(fake))))
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let mut maybe_result = None;
|
let mut maybe_result = None;
|
||||||
|
@ -434,7 +434,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterStatement<P> {
|
||||||
.variables
|
.variables
|
||||||
.declare(variable_name, Type::Op(variable))
|
.declare(variable_name, Type::Op(variable))
|
||||||
{
|
{
|
||||||
Err(e) => Some(Err(e.with(RuntimeOp(fake.clone())))),
|
Err(e) => Some(Err(e.with(RuntimeOp(fake)))),
|
||||||
Ok(_) => maybe_result,
|
Ok(_) => maybe_result,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -479,6 +479,7 @@ impl<P: FilterPredicate + 'static, F: FilterFactory<P> + 'static>
|
||||||
impl<P: FilterPredicate + 'static, F: FilterFactory<P> + 'static> BoxedOpFactory
|
impl<P: FilterPredicate + 'static, F: FilterFactory<P> + 'static> BoxedOpFactory
|
||||||
for FilterStatementFactory<P, F>
|
for FilterStatementFactory<P, F>
|
||||||
{
|
{
|
||||||
|
#[allow(clippy::unnecessary_unwrap)]
|
||||||
fn is_op_boxed(&self, tokens: &VecDeque<Token>) -> bool {
|
fn is_op_boxed(&self, tokens: &VecDeque<Token>) -> bool {
|
||||||
let tokens_len = tokens.len();
|
let tokens_len = tokens.len();
|
||||||
if is_correct_format(tokens) {
|
if is_correct_format(tokens) {
|
||||||
|
@ -524,8 +525,7 @@ impl<P: FilterPredicate + 'static, F: FilterFactory<P> + 'static> BoxedOpFactory
|
||||||
dict: &LanguageDictionary,
|
dict: &LanguageDictionary,
|
||||||
) -> Result<Box<dyn Op>, SyntaxError> {
|
) -> Result<Box<dyn Op>, SyntaxError> {
|
||||||
let start_of_op = last_dot_before_open_bracket(tokens);
|
let start_of_op = last_dot_before_open_bracket(tokens);
|
||||||
let op;
|
let op = if start_of_op == 1 && tokens[0].is_name() {
|
||||||
if start_of_op == 1 && tokens[0].is_name() {
|
|
||||||
// variable_name.(predicate)
|
// variable_name.(predicate)
|
||||||
let variable_name = assert_token(
|
let variable_name = assert_token(
|
||||||
|t| match t {
|
|t| match t {
|
||||||
|
@ -535,15 +535,15 @@ impl<P: FilterPredicate + 'static, F: FilterFactory<P> + 'static> BoxedOpFactory
|
||||||
Token::Name("variable_name".into()),
|
Token::Name("variable_name".into()),
|
||||||
tokens,
|
tokens,
|
||||||
)?;
|
)?;
|
||||||
op = VariableOrOp::Variable(variable_name);
|
VariableOrOp::Variable(variable_name)
|
||||||
} else {
|
} else {
|
||||||
// <some other op>.(predicate)
|
// <some other op>.(predicate)
|
||||||
//let mut new_tokens = tokens.range(0..start_of_op).map(|x| x.to_owned()).collect();
|
//let mut new_tokens = tokens.range(0..start_of_op).map(|x| x.to_owned()).collect();
|
||||||
let end_tokens = tokens.split_off(start_of_op); // don't parse filter in inner statement
|
let end_tokens = tokens.split_off(start_of_op); // don't parse filter in inner statement
|
||||||
let inner_op = dict.try_build_statement(tokens)?;
|
let inner_op = dict.try_build_statement(tokens)?;
|
||||||
tokens.extend(end_tokens);
|
tokens.extend(end_tokens);
|
||||||
op = VariableOrOp::Op(inner_op.into());
|
VariableOrOp::Op(inner_op.into())
|
||||||
}
|
};
|
||||||
assert_token_raw(Token::Dot, tokens)?;
|
assert_token_raw(Token::Dot, tokens)?;
|
||||||
assert_token_raw(Token::OpenBracket, tokens)?;
|
assert_token_raw(Token::OpenBracket, tokens)?;
|
||||||
if !tokens.is_empty() && check_name("if", &tokens[0]) {
|
if !tokens.is_empty() && check_name("if", &tokens[0]) {
|
||||||
|
|
|
@ -190,7 +190,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterReplaceStatement<P> {
|
||||||
Ok(x) => {
|
Ok(x) => {
|
||||||
return Some(Err(RuntimeError {
|
return Some(Err(RuntimeError {
|
||||||
line: 0,
|
line: 0,
|
||||||
op: fake.clone(),
|
op: fake,
|
||||||
msg: format!(
|
msg: format!(
|
||||||
"Expected operation/iterable type in variable {}, got {}",
|
"Expected operation/iterable type in variable {}, got {}",
|
||||||
&variable_name, x
|
&variable_name, x
|
||||||
|
@ -203,15 +203,14 @@ impl<P: FilterPredicate + 'static> Iterator for FilterReplaceStatement<P> {
|
||||||
variable.enter(ctx);
|
variable.enter(ctx);
|
||||||
let item = variable.next();
|
let item = variable.next();
|
||||||
self.context = Some(variable.escape());
|
self.context = Some(variable.escape());
|
||||||
match self
|
if let Err(e) = self
|
||||||
.context
|
.context
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.variables
|
.variables
|
||||||
.declare(variable_name, Type::Op(variable))
|
.declare(variable_name, Type::Op(variable))
|
||||||
{
|
{
|
||||||
Err(e) => return Some(Err(e.with(RuntimeOp(fake)))),
|
return Some(Err(e.with(RuntimeOp(fake))));
|
||||||
Ok(_) => {}
|
|
||||||
}
|
}
|
||||||
item
|
item
|
||||||
}
|
}
|
||||||
|
@ -242,9 +241,8 @@ impl<P: FilterPredicate + 'static> Iterator for FilterReplaceStatement<P> {
|
||||||
// invoke inner op
|
// invoke inner op
|
||||||
real_op.enter(self.context.take().unwrap());
|
real_op.enter(self.context.take().unwrap());
|
||||||
if real_op.is_resetable() {
|
if real_op.is_resetable() {
|
||||||
match real_op.reset() {
|
if let Err(e) = real_op.reset() {
|
||||||
Err(e) => return Some(Err(e)),
|
return Some(Err(e));
|
||||||
Ok(_) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for item in real_op.by_ref() {
|
for item in real_op.by_ref() {
|
||||||
|
@ -287,9 +285,8 @@ impl<P: FilterPredicate + 'static> Iterator for FilterReplaceStatement<P> {
|
||||||
// invoke inner operation
|
// invoke inner operation
|
||||||
real_op.enter(self.context.take().unwrap());
|
real_op.enter(self.context.take().unwrap());
|
||||||
if real_op.is_resetable() {
|
if real_op.is_resetable() {
|
||||||
match real_op.reset() {
|
if let Err(e) = real_op.reset() {
|
||||||
Err(e) => return Some(Err(e)),
|
return Some(Err(e));
|
||||||
Ok(_) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for item in real_op.by_ref() {
|
for item in real_op.by_ref() {
|
||||||
|
@ -319,7 +316,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterReplaceStatement<P> {
|
||||||
Some(Ok(item))
|
Some(Ok(item))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => Some(Err(e.with(RuntimeOp(fake.clone())))),
|
Err(e) => Some(Err(e.with(RuntimeOp(fake)))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Err(e)) => Some(Err(e)),
|
Some(Err(e)) => Some(Err(e)),
|
||||||
|
@ -347,12 +344,11 @@ fn declare_or_replace_item(
|
||||||
single: SingleItem,
|
single: SingleItem,
|
||||||
ctx: &mut Context,
|
ctx: &mut Context,
|
||||||
) -> Result<Option<Type>, RuntimeMsg> {
|
) -> Result<Option<Type>, RuntimeMsg> {
|
||||||
let old_item: Option<Type>;
|
let old_item: Option<Type> = if ctx.variables.exists(ITEM_VARIABLE_NAME) {
|
||||||
if ctx.variables.exists(ITEM_VARIABLE_NAME) {
|
Some(ctx.variables.remove(ITEM_VARIABLE_NAME)?)
|
||||||
old_item = Some(ctx.variables.remove(ITEM_VARIABLE_NAME)?);
|
|
||||||
} else {
|
} else {
|
||||||
old_item = None;
|
None
|
||||||
}
|
};
|
||||||
ctx.variables
|
ctx.variables
|
||||||
.declare(ITEM_VARIABLE_NAME, Type::Op(Box::new(single)))?;
|
.declare(ITEM_VARIABLE_NAME, Type::Op(Box::new(single)))?;
|
||||||
Ok(old_item)
|
Ok(old_item)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#![allow(clippy::new_without_default)]
|
||||||
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};
|
||||||
|
@ -67,11 +68,11 @@ pub struct ItemBlockStatement {
|
||||||
impl Display for ItemBlockStatement {
|
impl Display for ItemBlockStatement {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
write!(f, "{}.{{", self.iterable)?;
|
write!(f, "{}.{{", self.iterable)?;
|
||||||
if self.statements.len() > 0 {
|
if !self.statements.is_empty() {
|
||||||
write!(f, "\n")?;
|
writeln!(f)?;
|
||||||
}
|
}
|
||||||
for statement in self.statements.iter() {
|
for statement in self.statements.iter() {
|
||||||
write!(f, "{}\n", statement)?;
|
writeln!(f, "{}", statement)?;
|
||||||
}
|
}
|
||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
}
|
}
|
||||||
|
@ -213,7 +214,7 @@ pub struct ItemBlockFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemBlockFactory {
|
impl ItemBlockFactory {
|
||||||
pub fn add<
|
pub fn push<
|
||||||
T: ItemOpFactory<Y> + 'static,
|
T: ItemOpFactory<Y> + 'static,
|
||||||
Y: Deref<Target = dyn ItemOp> + ItemOp + 'static,
|
Y: Deref<Target = dyn ItemOp> + ItemOp + 'static,
|
||||||
>(
|
>(
|
||||||
|
@ -317,12 +318,11 @@ fn restore_item_var(
|
||||||
ctx: &mut Context,
|
ctx: &mut Context,
|
||||||
old_var: Option<Type>,
|
old_var: Option<Type>,
|
||||||
) -> Result<Option<Type>, RuntimeMsg> {
|
) -> Result<Option<Type>, RuntimeMsg> {
|
||||||
let new_var;
|
let new_var = if ctx.variables.exists(ITEM_VARIABLE_NAME) {
|
||||||
if ctx.variables.exists(ITEM_VARIABLE_NAME) {
|
Some(ctx.variables.remove(ITEM_VARIABLE_NAME)?)
|
||||||
new_var = Some(ctx.variables.remove(ITEM_VARIABLE_NAME)?);
|
|
||||||
} else {
|
} else {
|
||||||
new_var = None;
|
None
|
||||||
}
|
};
|
||||||
if let Some(old_var) = old_var {
|
if let Some(old_var) = old_var {
|
||||||
ctx.variables.declare(ITEM_VARIABLE_NAME, old_var)?;
|
ctx.variables.declare(ITEM_VARIABLE_NAME, old_var)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(clippy::match_like_matches_macro)]
|
||||||
|
#![allow(clippy::needless_range_loop)]
|
||||||
mod db_items;
|
mod db_items;
|
||||||
mod dictionary;
|
mod dictionary;
|
||||||
mod error;
|
mod error;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#![allow(clippy::borrowed_box)]
|
||||||
use std::fmt::{Debug, Display, Error, Formatter};
|
use std::fmt::{Debug, Display, Error, Formatter};
|
||||||
|
|
||||||
use super::Op;
|
use super::Op;
|
||||||
|
|
|
@ -13,7 +13,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 {
|
||||||
fn sort<'a>(
|
fn sort(
|
||||||
&mut self,
|
&mut self,
|
||||||
iterator: &mut dyn Op,
|
iterator: &mut dyn Op,
|
||||||
item_buf: &mut VecDeque<IteratorItem>,
|
item_buf: &mut VecDeque<IteratorItem>,
|
||||||
|
|
|
@ -19,7 +19,7 @@ impl Display for NonEmptyFilter {
|
||||||
|
|
||||||
impl FilterPredicate for NonEmptyFilter {
|
impl FilterPredicate for NonEmptyFilter {
|
||||||
fn matches(&mut self, item: &Item, _ctx: &mut Context) -> Result<bool, RuntimeMsg> {
|
fn matches(&mut self, item: &Item, _ctx: &mut Context) -> Result<bool, RuntimeMsg> {
|
||||||
if item.len() != 0 {
|
if !item.is_empty() {
|
||||||
if item.len() == 1 && item.field("filename").is_some() {
|
if item.len() == 1 && item.field("filename").is_some() {
|
||||||
Ok(false) // ignore filename field, since that almost always exists
|
Ok(false) // ignore filename field, since that almost always exists
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -90,7 +90,7 @@ pub struct UniqueFilterFactory;
|
||||||
|
|
||||||
impl FilterFactory<UniqueFieldFilter> for UniqueFilterFactory {
|
impl FilterFactory<UniqueFieldFilter> for UniqueFilterFactory {
|
||||||
fn is_filter(&self, tokens: &VecDeque<&Token>) -> bool {
|
fn is_filter(&self, tokens: &VecDeque<&Token>) -> bool {
|
||||||
tokens.len() >= 2 && check_name("unique", &tokens[0])
|
tokens.len() >= 2 && check_name("unique", tokens[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_filter(
|
fn build_filter(
|
||||||
|
@ -128,7 +128,7 @@ impl FilterFactory<UniqueFieldFilter> for UniqueFilterFactory {
|
||||||
|
|
||||||
impl FilterFactory<UniqueFilter> for UniqueFilterFactory {
|
impl FilterFactory<UniqueFilter> for UniqueFilterFactory {
|
||||||
fn is_filter(&self, tokens: &VecDeque<&Token>) -> bool {
|
fn is_filter(&self, tokens: &VecDeque<&Token>) -> bool {
|
||||||
tokens.len() == 1 && check_name("unique", &tokens[0])
|
tokens.len() == 1 && check_name("unique", tokens[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_filter(
|
fn build_filter(
|
||||||
|
|
|
@ -49,7 +49,7 @@ impl Iterator for IntersectionStatement {
|
||||||
type Item = IteratorItem;
|
type Item = IteratorItem;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.ops.len() == 0 {
|
if self.ops.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
} else if self.init_needed {
|
} else if self.init_needed {
|
||||||
self.init_needed = false;
|
self.init_needed = false;
|
||||||
|
|
|
@ -36,7 +36,7 @@ impl ItemOp for AddItemOp {
|
||||||
let rhs = self.rhs.execute(context)?;
|
let rhs = self.rhs.execute(context)?;
|
||||||
if let Type::Primitive(rhs) = &rhs {
|
if let Type::Primitive(rhs) = &rhs {
|
||||||
Ok(Type::Primitive(
|
Ok(Type::Primitive(
|
||||||
lhs.try_add(rhs).map_err(|e| RuntimeMsg(e))?,
|
lhs.try_add(rhs).map_err(RuntimeMsg)?,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Err(RuntimeMsg(format!(
|
Err(RuntimeMsg(format!(
|
||||||
|
|
|
@ -28,29 +28,29 @@ impl Display for BranchItemOp {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
write!(f, "if {} {{", self.condition)?;
|
write!(f, "if {} {{", self.condition)?;
|
||||||
if self.inner_ifs.len() > 1 {
|
if self.inner_ifs.len() > 1 {
|
||||||
write!(f, "\n")?;
|
writeln!(f)?;
|
||||||
}
|
}
|
||||||
for i in 0..self.inner_ifs.len() {
|
for i in 0..self.inner_ifs.len() {
|
||||||
write!(f, "{}", self.inner_ifs[i])?;
|
write!(f, "{}", self.inner_ifs[i])?;
|
||||||
if i != self.inner_ifs.len() - 1 {
|
if i != self.inner_ifs.len() - 1 {
|
||||||
write!(f, ",\n")?;
|
writeln!(f, ",")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.inner_ifs.len() > 1 {
|
if self.inner_ifs.len() > 1 {
|
||||||
write!(f, "\n")?;
|
writeln!(f)?;
|
||||||
}
|
}
|
||||||
write!(f, "}} else {{")?;
|
write!(f, "}} else {{")?;
|
||||||
if self.inner_elses.len() > 1 {
|
if self.inner_elses.len() > 1 {
|
||||||
write!(f, "\n")?;
|
writeln!(f)?;
|
||||||
}
|
}
|
||||||
for i in 0..self.inner_elses.len() {
|
for i in 0..self.inner_elses.len() {
|
||||||
write!(f, "{}", self.inner_elses[i])?;
|
write!(f, "{}", self.inner_elses[i])?;
|
||||||
if i != self.inner_elses.len() - 1 {
|
if i != self.inner_elses.len() - 1 {
|
||||||
write!(f, ",\n")?;
|
writeln!(f, ",")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.inner_elses.len() > 1 {
|
if self.inner_elses.len() > 1 {
|
||||||
write!(f, "\n")?;
|
writeln!(f)?;
|
||||||
}
|
}
|
||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ impl ItemOp for CompareItemOp {
|
||||||
let rhs_val = self.rhs.execute(context)?;
|
let rhs_val = self.rhs.execute(context)?;
|
||||||
if let Type::Primitive(lhs) = lhs_val {
|
if let Type::Primitive(lhs) = lhs_val {
|
||||||
if let Type::Primitive(rhs) = rhs_val {
|
if let Type::Primitive(rhs) = rhs_val {
|
||||||
let compare = lhs.compare(&rhs).map_err(|e| RuntimeMsg(e))?;
|
let compare = lhs.compare(&rhs).map_err(RuntimeMsg)?;
|
||||||
let mut is_match = false;
|
let mut is_match = false;
|
||||||
for comparator in self.comparison {
|
for comparator in self.comparison {
|
||||||
if comparator == compare {
|
if comparator == compare {
|
||||||
|
|
|
@ -35,7 +35,7 @@ impl Display for ConstructorItemOp {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
write!(f, "Item(")?;
|
write!(f, "Item(")?;
|
||||||
if self.fields.len() > 1 {
|
if self.fields.len() > 1 {
|
||||||
write!(f, "\n")?;
|
writeln!(f)?;
|
||||||
for i in 0..self.fields.len() - 1 {
|
for i in 0..self.fields.len() - 1 {
|
||||||
let field = &self.fields[i];
|
let field = &self.fields[i];
|
||||||
write!(f, "{}: {}, ", field.name, field.value)?;
|
write!(f, "{}: {}, ", field.name, field.value)?;
|
||||||
|
|
|
@ -78,11 +78,10 @@ impl ItemOpFactory<FieldAssignItemOp> for FieldAssignItemOpFactory {
|
||||||
factory: &ItemBlockFactory,
|
factory: &ItemBlockFactory,
|
||||||
dict: &LanguageDictionary,
|
dict: &LanguageDictionary,
|
||||||
) -> Result<FieldAssignItemOp, SyntaxError> {
|
) -> Result<FieldAssignItemOp, SyntaxError> {
|
||||||
let var_name;
|
let var_name =if tokens[0].is_dot() {
|
||||||
if tokens[0].is_dot() {
|
"item".to_string()
|
||||||
var_name = "item".to_string();
|
|
||||||
} else {
|
} else {
|
||||||
var_name = assert_token(
|
assert_token(
|
||||||
|t| match t {
|
|t| match t {
|
||||||
Token::Name(s) => Some(s),
|
Token::Name(s) => Some(s),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -90,7 +89,7 @@ impl ItemOpFactory<FieldAssignItemOp> for FieldAssignItemOpFactory {
|
||||||
Token::Name("variable_name".into()),
|
Token::Name("variable_name".into()),
|
||||||
tokens,
|
tokens,
|
||||||
)?
|
)?
|
||||||
}
|
};
|
||||||
assert_token_raw(Token::Dot, tokens)?;
|
assert_token_raw(Token::Dot, tokens)?;
|
||||||
let f_name = assert_token(
|
let f_name = assert_token(
|
||||||
|t| match t {
|
|t| match t {
|
||||||
|
|
|
@ -30,7 +30,7 @@ impl Display for IterItemOp {
|
||||||
|
|
||||||
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().into()))
|
Ok(Type::Op(self.inner.dup()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ impl ItemOp for NegateItemOp {
|
||||||
let rhs = self.rhs.execute(context)?;
|
let rhs = self.rhs.execute(context)?;
|
||||||
if let Type::Primitive(rhs) = &rhs {
|
if let Type::Primitive(rhs) = &rhs {
|
||||||
Ok(Type::Primitive(
|
Ok(Type::Primitive(
|
||||||
rhs.try_negate().map_err(|e| RuntimeMsg(e))?,
|
rhs.try_negate().map_err(RuntimeMsg)?,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Err(RuntimeMsg(format!(
|
Err(RuntimeMsg(format!(
|
||||||
|
|
|
@ -33,7 +33,7 @@ impl ItemOp for NotItemOp {
|
||||||
let rhs = self.rhs.execute(context)?;
|
let rhs = self.rhs.execute(context)?;
|
||||||
if let Type::Primitive(rhs) = &rhs {
|
if let Type::Primitive(rhs) = &rhs {
|
||||||
Ok(Type::Primitive(
|
Ok(Type::Primitive(
|
||||||
rhs.try_not().map_err(|e| RuntimeMsg(e))?,
|
rhs.try_not().map_err(RuntimeMsg)?,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Err(RuntimeMsg(format!(
|
Err(RuntimeMsg(format!(
|
||||||
|
|
|
@ -75,20 +75,19 @@ impl ItemOpFactory<RemoveItemOp> for RemoveItemOpFactory {
|
||||||
Token::Name("variable_name".into()),
|
Token::Name("variable_name".into()),
|
||||||
tokens,
|
tokens,
|
||||||
)?;
|
)?;
|
||||||
let field_opt;
|
let field_opt = if tokens.is_empty() {
|
||||||
if tokens.is_empty() {
|
None
|
||||||
field_opt = None;
|
|
||||||
} else {
|
} else {
|
||||||
assert_token_raw(Token::Dot, tokens)?;
|
assert_token_raw(Token::Dot, tokens)?;
|
||||||
field_opt = Some(assert_token(
|
Some(assert_token(
|
||||||
|t| match t {
|
|t| match t {
|
||||||
Token::Name(s) => Some(s),
|
Token::Name(s) => Some(s),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
Token::Name("field_name".into()),
|
Token::Name("field_name".into()),
|
||||||
tokens,
|
tokens,
|
||||||
)?);
|
)?)
|
||||||
}
|
};
|
||||||
Ok(RemoveItemOp {
|
Ok(RemoveItemOp {
|
||||||
variable_name: name,
|
variable_name: name,
|
||||||
field_name: field_opt,
|
field_name: field_opt,
|
||||||
|
|
|
@ -86,20 +86,19 @@ impl ItemOpFactory<VariableRetrieveItemOp> for VariableRetrieveItemOpFactory {
|
||||||
Token::Name("variable_name".into()),
|
Token::Name("variable_name".into()),
|
||||||
tokens,
|
tokens,
|
||||||
)?;
|
)?;
|
||||||
let field_opt;
|
let field_opt = if tokens.is_empty() {
|
||||||
if tokens.is_empty() {
|
None
|
||||||
field_opt = None;
|
|
||||||
} else {
|
} else {
|
||||||
assert_token_raw(Token::Dot, tokens)?;
|
assert_token_raw(Token::Dot, tokens)?;
|
||||||
field_opt = Some(assert_token(
|
Some(assert_token(
|
||||||
|t| match t {
|
|t| match t {
|
||||||
Token::Name(s) => Some(s),
|
Token::Name(s) => Some(s),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
Token::Name("field_name".into()),
|
Token::Name("field_name".into()),
|
||||||
tokens,
|
tokens,
|
||||||
)?);
|
)?)
|
||||||
}
|
};
|
||||||
Ok(VariableRetrieveItemOp {
|
Ok(VariableRetrieveItemOp {
|
||||||
variable_name: var_name,
|
variable_name: var_name,
|
||||||
field_name: field_opt,
|
field_name: field_opt,
|
||||||
|
|
|
@ -39,7 +39,7 @@ impl ItemOp for InterpolateStringItemOp {
|
||||||
}
|
}
|
||||||
Type::Item(item) => {
|
Type::Item(item) => {
|
||||||
let mut result;
|
let mut result;
|
||||||
if item.len() == 0 {
|
if item.is_empty() {
|
||||||
result = self.format.clone();
|
result = self.format.clone();
|
||||||
} else {
|
} else {
|
||||||
let mut iter = item.iter();
|
let mut iter = item.iter();
|
||||||
|
|
|
@ -36,7 +36,7 @@ impl ItemOp for SubtractItemOp {
|
||||||
let rhs = self.rhs.execute(context)?;
|
let rhs = self.rhs.execute(context)?;
|
||||||
if let Type::Primitive(rhs) = &rhs {
|
if let Type::Primitive(rhs) = &rhs {
|
||||||
Ok(Type::Primitive(
|
Ok(Type::Primitive(
|
||||||
lhs.try_subtract(rhs).map_err(|e| RuntimeMsg(e))?,
|
lhs.try_subtract(rhs).map_err(RuntimeMsg)?,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Err(RuntimeMsg(format!(
|
Err(RuntimeMsg(format!(
|
||||||
|
|
|
@ -40,13 +40,11 @@ impl ItemOp for VariableDeclareItemOp {
|
||||||
if !context.variables.exists(&self.variable_name) {
|
if !context.variables.exists(&self.variable_name) {
|
||||||
context.variables.declare(&self.variable_name, mps_type)?;
|
context.variables.declare(&self.variable_name, mps_type)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else if !context.variables.exists(&self.variable_name) {
|
||||||
if !context.variables.exists(&self.variable_name) {
|
|
||||||
context
|
context
|
||||||
.variables
|
.variables
|
||||||
.declare(&self.variable_name, Type::empty())?;
|
.declare(&self.variable_name, Type::empty())?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(Type::empty())
|
Ok(Type::empty())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,13 +72,12 @@ impl ItemOpFactory<VariableDeclareItemOp> for VariableDeclareItemOpFactory {
|
||||||
Token::Name("variable_name".into()),
|
Token::Name("variable_name".into()),
|
||||||
tokens,
|
tokens,
|
||||||
)?;
|
)?;
|
||||||
let inner_op: Option<Box<dyn ItemOp>>;
|
let inner_op: Option<Box<dyn ItemOp>> = if !tokens.is_empty() {
|
||||||
if !tokens.is_empty() {
|
|
||||||
assert_token_raw(Token::Equals, tokens)?;
|
assert_token_raw(Token::Equals, tokens)?;
|
||||||
inner_op = Some(factory.try_build_item_statement(tokens, dict)?);
|
Some(factory.try_build_item_statement(tokens, dict)?)
|
||||||
} else {
|
} else {
|
||||||
inner_op = None;
|
None
|
||||||
}
|
};
|
||||||
Ok(VariableDeclareItemOp {
|
Ok(VariableDeclareItemOp {
|
||||||
variable_name: var_name,
|
variable_name: var_name,
|
||||||
inner: inner_op,
|
inner: inner_op,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#![allow(clippy::while_let_on_iterator)]
|
||||||
mod empties;
|
mod empties;
|
||||||
pub(crate) mod empty;
|
pub(crate) mod empty;
|
||||||
mod files;
|
mod files;
|
||||||
|
|
|
@ -117,7 +117,7 @@ impl Iterator for MpdQueryStatement {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let results = self.results.as_mut().unwrap();
|
let results = self.results.as_mut().unwrap();
|
||||||
results.pop_front().map(|x| Ok(x))
|
results.pop_front().map(Ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
|
|
@ -69,7 +69,7 @@ impl Iterator for RepeatStatement {
|
||||||
}
|
}
|
||||||
if real_op.is_resetable() {
|
if real_op.is_resetable() {
|
||||||
while self.loop_forever || !self.inner_done {
|
while self.loop_forever || !self.inner_done {
|
||||||
for item in real_op.by_ref() {
|
if let Some(item) = real_op.next() {
|
||||||
return Some(item);
|
return Some(item);
|
||||||
}
|
}
|
||||||
if !self.loop_forever {
|
if !self.loop_forever {
|
||||||
|
@ -79,16 +79,14 @@ impl Iterator for RepeatStatement {
|
||||||
self.context = Some(real_op.escape());
|
self.context = Some(real_op.escape());
|
||||||
} else {
|
} else {
|
||||||
self.repetitions -= 1;
|
self.repetitions -= 1;
|
||||||
match real_op.reset() {
|
if let Err(e) = real_op.reset() {
|
||||||
Err(e) => return Some(Err(e)),
|
return Some(Err(e));
|
||||||
Ok(_) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// always reset in infinite loop mode
|
// always reset in infinite loop mode
|
||||||
match real_op.reset() {
|
if let Err(e) = real_op.reset() {
|
||||||
Err(e) => return Some(Err(e)),
|
return Some(Err(e));
|
||||||
Ok(_) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,18 +68,16 @@ impl Sorter for BlissNextSorter {
|
||||||
let mut ctx = iterator.escape();
|
let mut ctx = iterator.escape();
|
||||||
for i in 1..self.item_buf.len() {
|
for i in 1..self.item_buf.len() {
|
||||||
let item = &self.item_buf[i];
|
let item = &self.item_buf[i];
|
||||||
match ctx.analysis.prepare_distance(first, item) {
|
if let Err(e) = ctx.analysis.prepare_distance(first, item) {
|
||||||
Err(e) => {
|
|
||||||
iterator.enter(ctx);
|
iterator.enter(ctx);
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
Ok(_) => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
iterator.enter(ctx);
|
iterator.enter(ctx);
|
||||||
items_out.push_back(Ok(first.to_owned()));
|
items_out.push_back(Ok(first.to_owned()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
#[allow(clippy::collapsible_else_if)]
|
||||||
if self.item_buf.len() > 2 {
|
if self.item_buf.len() > 2 {
|
||||||
let last = self.item_buf.pop_front().unwrap();
|
let last = self.item_buf.pop_front().unwrap();
|
||||||
let mut best_index = 0;
|
let mut best_index = 0;
|
||||||
|
@ -107,13 +105,10 @@ impl Sorter for BlissNextSorter {
|
||||||
let next = &self.item_buf[0];
|
let next = &self.item_buf[0];
|
||||||
for i in 1..self.item_buf.len() {
|
for i in 1..self.item_buf.len() {
|
||||||
let item = &self.item_buf[i];
|
let item = &self.item_buf[i];
|
||||||
match ctx.analysis.prepare_distance(next, item) {
|
if let Err(e) = ctx.analysis.prepare_distance(next, item) {
|
||||||
Err(e) => {
|
|
||||||
iterator.enter(ctx);
|
iterator.enter(ctx);
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
Ok(_) => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
iterator.enter(ctx);
|
iterator.enter(ctx);
|
||||||
} else if self.item_buf.len() == 2 {
|
} else if self.item_buf.len() == 2 {
|
||||||
|
|
|
@ -64,12 +64,7 @@ impl Sorter for BlissSorter {
|
||||||
// when buf_len_old == item_buf.len(), iterator was already complete
|
// when buf_len_old == item_buf.len(), iterator was already complete
|
||||||
// no need to sort in that case, since buffer was sorted in last call to sort or buffer never had any items to sort
|
// no need to sort in that case, since buffer was sorted in last call to sort or buffer never had any items to sort
|
||||||
if self.first_song.is_none() {
|
if self.first_song.is_none() {
|
||||||
for item in item_buf.iter() {
|
self.first_song = item_buf.iter().flatten().next().map(|x| x.to_owned());
|
||||||
if let Ok(item) = item {
|
|
||||||
self.first_song = Some(item.clone());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(first) = &self.first_song {
|
if let Some(first) = &self.first_song {
|
||||||
let mut ctx = iterator.escape();
|
let mut ctx = iterator.escape();
|
||||||
|
@ -78,13 +73,10 @@ impl Sorter for BlissSorter {
|
||||||
if item == first {
|
if item == first {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match ctx.analysis.prepare_distance(first, item) {
|
if let Err(e) = ctx.analysis.prepare_distance(first, item) {
|
||||||
Err(e) => {
|
|
||||||
iterator.enter(ctx);
|
iterator.enter(ctx);
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
Ok(_) => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iterator.enter(ctx);
|
iterator.enter(ctx);
|
||||||
|
@ -115,8 +107,8 @@ impl Sorter for BlissSorter {
|
||||||
item_buf.make_contiguous().sort_by(|a, b| {
|
item_buf.make_contiguous().sort_by(|a, b| {
|
||||||
if let Ok(a) = a {
|
if let Ok(a) = a {
|
||||||
if let Ok(b) = b {
|
if let Ok(b) = b {
|
||||||
let float_a = cache.get(&a).unwrap();
|
let float_a = cache.get(a).unwrap();
|
||||||
let float_b = cache.get(&b).unwrap();
|
let float_b = cache.get(b).unwrap();
|
||||||
return float_a.partial_cmp(float_b).unwrap_or(DEFAULT_ORDER);
|
return float_a.partial_cmp(float_b).unwrap_or(DEFAULT_ORDER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,10 +53,10 @@ impl Sorter for ShuffleSorter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// end case: everything is completely empty -- end loop without a new result
|
// end case: everything is completely empty -- end loop without a new result
|
||||||
if item_buf.len() == 0 {
|
if item_buf.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
random = random % item_buf.len();
|
random %= item_buf.len();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,10 +71,10 @@ pub struct ShuffleSorterFactory;
|
||||||
|
|
||||||
impl SorterFactory<ShuffleSorter> for ShuffleSorterFactory {
|
impl SorterFactory<ShuffleSorter> for ShuffleSorterFactory {
|
||||||
fn is_sorter(&self, tokens: &VecDeque<&Token>) -> bool {
|
fn is_sorter(&self, tokens: &VecDeque<&Token>) -> bool {
|
||||||
(!tokens.is_empty() && check_name("shuffle", &tokens[0]))
|
(!tokens.is_empty() && check_name("shuffle", tokens[0]))
|
||||||
|| (tokens.len() > 1
|
|| (tokens.len() > 1
|
||||||
&& check_name("random", &tokens[0])
|
&& check_name("random", tokens[0])
|
||||||
&& check_name("shuffle", &tokens[1]))
|
&& check_name("shuffle", tokens[1]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_sorter(
|
fn build_sorter(
|
||||||
|
|
|
@ -65,7 +65,7 @@ impl Iterator for UnionStatement {
|
||||||
Err(e) => return Some(Err(e)),
|
Err(e) => return Some(Err(e)),
|
||||||
};
|
};
|
||||||
real_op.enter(self.context.take().unwrap());
|
real_op.enter(self.context.take().unwrap());
|
||||||
while let Some(item) = real_op.next() {
|
if let Some(item) = real_op.next() {
|
||||||
self.context = Some(real_op.escape());
|
self.context = Some(real_op.escape());
|
||||||
return Some(item);
|
return Some(item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,22 +74,21 @@ impl Iterator for AssignStatement {
|
||||||
Ok(real) => real,
|
Ok(real) => real,
|
||||||
Err(e) => return Some(Err(e)),
|
Err(e) => return Some(Err(e)),
|
||||||
};
|
};
|
||||||
let result;
|
let result = if self.is_declaration {
|
||||||
if self.is_declaration {
|
self
|
||||||
result = self
|
|
||||||
.context
|
.context
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.variables
|
.variables
|
||||||
.declare(&self.variable_name, Type::Op(real));
|
.declare(&self.variable_name, Type::Op(real))
|
||||||
} else {
|
} else {
|
||||||
result = self
|
self
|
||||||
.context
|
.context
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.variables
|
.variables
|
||||||
.assign(&self.variable_name, Type::Op(real));
|
.assign(&self.variable_name, Type::Op(real))
|
||||||
}
|
};
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => None,
|
Ok(_) => None,
|
||||||
Err(e) => Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))),
|
Err(e) => Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))),
|
||||||
|
@ -107,22 +106,21 @@ impl Iterator for AssignStatement {
|
||||||
}))*/
|
}))*/
|
||||||
} else {
|
} else {
|
||||||
let assign_type = self.assign_type.clone().unwrap();
|
let assign_type = self.assign_type.clone().unwrap();
|
||||||
let result;
|
let result = if self.is_declaration {
|
||||||
if self.is_declaration {
|
self
|
||||||
result = self
|
|
||||||
.context
|
.context
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.variables
|
.variables
|
||||||
.declare(&self.variable_name, Type::Primitive(assign_type));
|
.declare(&self.variable_name, Type::Primitive(assign_type))
|
||||||
} else {
|
} else {
|
||||||
result = self
|
self
|
||||||
.context
|
.context
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.variables
|
.variables
|
||||||
.assign(&self.variable_name, Type::Primitive(assign_type));
|
.assign(&self.variable_name, Type::Primitive(assign_type))
|
||||||
}
|
};
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => None,
|
Ok(_) => None,
|
||||||
Err(e) => Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))),
|
Err(e) => Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))),
|
||||||
|
|
|
@ -246,6 +246,8 @@
|
||||||
//! Load an item from file, populating the item with the song's tags.
|
//! Load an item from file, populating the item with the song's tags.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
#![allow(clippy::redundant_field_names)]
|
||||||
|
|
||||||
mod context;
|
mod context;
|
||||||
mod debug;
|
mod debug;
|
||||||
mod errors;
|
mod errors;
|
||||||
|
|
|
@ -36,6 +36,10 @@ impl Library {
|
||||||
self.songs.len()
|
self.songs.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.songs.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn clear_modified(&mut self) {
|
pub fn clear_modified(&mut self) {
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +58,7 @@ impl Library {
|
||||||
self.files.contains(&path.as_ref().to_path_buf())
|
self.files.contains(&path.as_ref().to_path_buf())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_songs<'a>(&'a self) -> Vec<&'a DbMusicItem> {
|
pub fn all_songs(&self) -> Vec<&'_ DbMusicItem> {
|
||||||
self.songs.values().collect()
|
self.songs.values().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +71,7 @@ impl Library {
|
||||||
self.songs.insert(song.song_id, song);
|
self.songs.insert(song.song_id, song);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_metadata<'a>(&'a self) -> Vec<&'a DbMetaItem> {
|
pub fn all_metadata(& self) -> Vec<&'_ DbMetaItem> {
|
||||||
self.metadata.values().collect()
|
self.metadata.values().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +81,7 @@ impl Library {
|
||||||
self.metadata.insert(meta.meta_id, meta);
|
self.metadata.insert(meta.meta_id, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_artists<'a>(&'a self) -> Vec<&'a DbArtistItem> {
|
pub fn all_artists(&self) -> Vec<&'_ DbArtistItem> {
|
||||||
self.artists.values().collect()
|
self.artists.values().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +92,7 @@ impl Library {
|
||||||
.insert(Self::sanitise_key(&artist.name), artist);
|
.insert(Self::sanitise_key(&artist.name), artist);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_albums<'a>(&'a self) -> Vec<&'a DbAlbumItem> {
|
pub fn all_albums(&self) -> Vec<&'_ DbAlbumItem> {
|
||||||
self.albums.values().collect()
|
self.albums.values().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +102,7 @@ impl Library {
|
||||||
self.albums.insert(Self::sanitise_key(&album.title), album);
|
self.albums.insert(Self::sanitise_key(&album.title), album);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_genres<'a>(&'a self) -> Vec<&'a DbGenreItem> {
|
pub fn all_genres(&self) -> Vec<&'_ DbGenreItem> {
|
||||||
self.genres.values().collect()
|
self.genres.values().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +240,7 @@ impl Library {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn find_or_gen_id<'a, D: DatabaseObj>(map: &'a HashMap<String, D>, key: &str) -> u64 {
|
fn find_or_gen_id<D: DatabaseObj>(map: &HashMap<String, D>, key: &str) -> u64 {
|
||||||
if let Some(obj) = Self::find_by_key(map, key) {
|
if let Some(obj) = Self::find_by_key(map, key) {
|
||||||
obj.id()
|
obj.id()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -49,7 +49,7 @@ impl Tags {
|
||||||
.file_name()
|
.file_name()
|
||||||
.and_then(|file| file.to_str())
|
.and_then(|file| file.to_str())
|
||||||
.map(|file| file.replacen(&format!(".{}", extension), "", 1))
|
.map(|file| file.replacen(&format!(".{}", extension), "", 1))
|
||||||
.unwrap_or("Unknown Title".into())
|
.unwrap_or_else(|| "Unknown Title".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -149,7 +149,7 @@ impl Tags {
|
||||||
pub fn artist(&self, id: u64, genre_id: u64) -> DbArtistItem {
|
pub fn artist(&self, id: u64, genre_id: u64) -> DbArtistItem {
|
||||||
DbArtistItem {
|
DbArtistItem {
|
||||||
artist_id: id,
|
artist_id: id,
|
||||||
name: self.artist_name().unwrap_or("Unknown Artist".into()),
|
name: self.artist_name().unwrap_or_else(|| "Unknown Artist".into()),
|
||||||
genre: genre_id,
|
genre: genre_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ impl Tags {
|
||||||
pub fn album(&self, id: u64, meta_id: u64, artist_id: u64, genre_id: u64) -> DbAlbumItem {
|
pub fn album(&self, id: u64, meta_id: u64, artist_id: u64, genre_id: u64) -> DbAlbumItem {
|
||||||
DbAlbumItem {
|
DbAlbumItem {
|
||||||
album_id: id,
|
album_id: id,
|
||||||
title: self.album_title().unwrap_or("Unknown Album".into()),
|
title: self.album_title().unwrap_or_else(|| "Unknown Album".into()),
|
||||||
metadata: meta_id,
|
metadata: meta_id,
|
||||||
artist: artist_id,
|
artist: artist_id,
|
||||||
genre: genre_id,
|
genre: genre_id,
|
||||||
|
@ -212,7 +212,7 @@ impl Tags {
|
||||||
pub fn genre(&self, id: u64) -> DbGenreItem {
|
pub fn genre(&self, id: u64) -> DbGenreItem {
|
||||||
DbGenreItem {
|
DbGenreItem {
|
||||||
genre_id: id,
|
genre_id: id,
|
||||||
title: self.genre_title().unwrap_or("Unknown Genre".into()),
|
title: self.genre_title().unwrap_or_else(|| "Unknown Genre".into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,10 +41,11 @@ impl Iterator for SortedReadDir {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.dir_iter_complete = true;
|
self.dir_iter_complete = true;
|
||||||
self.cache.sort_by(
|
self.cache.sort_by_key(|b| std::cmp::Reverse(b.path().to_string_lossy().to_lowercase()));
|
||||||
|
/*self.cache.sort_by(
|
||||||
|a, b| b.path().to_string_lossy().to_lowercase().cmp(
|
|a, b| b.path().to_string_lossy().to_lowercase().cmp(
|
||||||
&a.path().to_string_lossy().to_lowercase())
|
&a.path().to_string_lossy().to_lowercase())
|
||||||
);
|
);*/
|
||||||
}
|
}
|
||||||
if self.cache.is_empty() {
|
if self.cache.is_empty() {
|
||||||
None
|
None
|
||||||
|
@ -73,7 +74,7 @@ impl Display for FileIter {
|
||||||
self.pattern
|
self.pattern
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|re| re.to_string())
|
.map(|re| re.to_string())
|
||||||
.unwrap_or("[none]".to_string()),
|
.unwrap_or_else(|| "[none]".to_string()),
|
||||||
self.recursive
|
self.recursive
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -224,8 +225,7 @@ impl FileIter {
|
||||||
) {
|
) {
|
||||||
// populates fields from named capture groups
|
// populates fields from named capture groups
|
||||||
if let Some(captures) = captures {
|
if let Some(captures) = captures {
|
||||||
for name_maybe in capture_names {
|
for name in capture_names.flatten() {
|
||||||
if let Some(name) = name_maybe {
|
|
||||||
if item.field(name).is_some() {
|
if item.field(name).is_some() {
|
||||||
// do nothing
|
// do nothing
|
||||||
} else if let Some(value) = captures.name(name).map(|m| m.as_str().to_string()) {
|
} else if let Some(value) = captures.name(name).map(|m| m.as_str().to_string()) {
|
||||||
|
@ -233,7 +233,6 @@ impl FileIter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
item.set_field("filename", format!("file://{}", path_str).into());
|
item.set_field("filename", format!("file://{}", path_str).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ impl MpdQuerier for MpdExecutor {
|
||||||
query_mut = query_mut.and(str_to_term(term), value);
|
query_mut = query_mut.and(str_to_term(term), value);
|
||||||
}
|
}
|
||||||
let songs = self.connection.as_mut().unwrap().search(query_mut, None).map_err(|e| RuntimeMsg(format!("MPD search error: {}", e)))?;
|
let songs = self.connection.as_mut().unwrap().search(query_mut, None).map_err(|e| RuntimeMsg(format!("MPD search error: {}", e)))?;
|
||||||
Ok(songs.into_iter().map(|x| song_to_item(x)).collect())
|
Ok(songs.into_iter().map(song_to_item).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn one_shot_search(&self, addr: SocketAddr, params: Vec<(&str, String)>) -> Result<VecDeque<Item>, RuntimeMsg> {
|
fn one_shot_search(&self, addr: SocketAddr, params: Vec<(&str, String)>) -> Result<VecDeque<Item>, RuntimeMsg> {
|
||||||
|
@ -53,7 +53,7 @@ impl MpdQuerier for MpdExecutor {
|
||||||
query_mut = query_mut.and(str_to_term(term), value);
|
query_mut = query_mut.and(str_to_term(term), value);
|
||||||
}
|
}
|
||||||
let songs = connection.search(query_mut, None).map_err(|e| RuntimeMsg(format!("MPD search error: {}", e)))?;
|
let songs = connection.search(query_mut, None).map_err(|e| RuntimeMsg(format!("MPD search error: {}", e)))?;
|
||||||
Ok(songs.into_iter().map(|x| song_to_item(x)).collect())
|
Ok(songs.into_iter().map(song_to_item).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ fn song_to_item(song: Song) -> Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn str_to_term<'a>(s: &'a str) -> Term<'a> {
|
fn str_to_term(s: &str) -> Term<'_> {
|
||||||
match s {
|
match s {
|
||||||
"any" => Term::Any,
|
"any" => Term::Any,
|
||||||
"file" => Term::File,
|
"file" => Term::File,
|
||||||
|
|
|
@ -208,7 +208,7 @@ enum ResponseType {
|
||||||
},
|
},
|
||||||
Song {
|
Song {
|
||||||
path: String,
|
path: String,
|
||||||
song: Result<Song, BlissError>,
|
song: Result<Box<Song>, BlissError>,
|
||||||
},
|
},
|
||||||
UnsupportedSong {
|
UnsupportedSong {
|
||||||
path: String,
|
path: String,
|
||||||
|
@ -257,13 +257,13 @@ impl CacheThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_song(&mut self, path: String, song_result: Result<Song, BlissError>) {
|
fn insert_song(&mut self, path: String, song_result: Result<Box<Song>, BlissError>) {
|
||||||
self.song_in_progress.remove(&path);
|
self.song_in_progress.remove(&path);
|
||||||
if self.song_cache.len() > MAX_SONG_CACHE_SIZE {
|
if self.song_cache.len() > MAX_SONG_CACHE_SIZE {
|
||||||
// avoid using too much memory -- songs are big memory objects
|
// avoid using too much memory -- songs are big memory objects
|
||||||
self.song_cache.clear();
|
self.song_cache.clear();
|
||||||
}
|
}
|
||||||
self.song_cache.insert(path, song_result);
|
self.song_cache.insert(path, song_result.map(|x| x.as_ref().to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_distance(
|
fn insert_distance(
|
||||||
|
@ -305,7 +305,7 @@ impl CacheThread {
|
||||||
if result.is_none() && auto_add {
|
if result.is_none() && auto_add {
|
||||||
self.song_in_progress.insert(path.to_owned());
|
self.song_in_progress.insert(path.to_owned());
|
||||||
}
|
}
|
||||||
return result;
|
return result.map(|x| x.as_ref().to_owned());
|
||||||
} else {
|
} else {
|
||||||
self.insert_song(path2, song);
|
self.insert_song(path2, song);
|
||||||
}
|
}
|
||||||
|
@ -322,7 +322,7 @@ impl CacheThread {
|
||||||
let result = self
|
let result = self
|
||||||
.song_cache
|
.song_cache
|
||||||
.get(path)
|
.get(path)
|
||||||
.and_then(|r| r.clone().ok().to_owned());
|
.and_then(|r| r.clone().ok());
|
||||||
if result.is_none() && auto_add {
|
if result.is_none() && auto_add {
|
||||||
self.song_in_progress.insert(path.to_owned());
|
self.song_in_progress.insert(path.to_owned());
|
||||||
}
|
}
|
||||||
|
@ -331,7 +331,7 @@ impl CacheThread {
|
||||||
if auto_add {
|
if auto_add {
|
||||||
self.song_in_progress.insert(path.to_owned());
|
self.song_in_progress.insert(path.to_owned());
|
||||||
}
|
}
|
||||||
return None;
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_distance_req(
|
fn handle_distance_req(
|
||||||
|
@ -346,11 +346,11 @@ impl CacheThread {
|
||||||
if let Some(result) = self.distance_cache.get(&key) {
|
if let Some(result) = self.distance_cache.get(&key) {
|
||||||
if ack {
|
if ack {
|
||||||
let result = result.to_owned();
|
let result = result.to_owned();
|
||||||
if let Err(_) = self.responses.send(ResponseType::Distance {
|
if self.responses.send(ResponseType::Distance {
|
||||||
path1: path1,
|
path1: path1,
|
||||||
path2: path2,
|
path2: path2,
|
||||||
distance: result,
|
distance: result,
|
||||||
}) {
|
}).is_err() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,15 +360,13 @@ impl CacheThread {
|
||||||
// also prevents deadlock in self.get_song_option()
|
// also prevents deadlock in self.get_song_option()
|
||||||
// due to waiting on song that isn't being processed yet
|
// due to waiting on song that isn't being processed yet
|
||||||
// (first call adds it to song_in_progress set, second call just waits)
|
// (first call adds it to song_in_progress set, second call just waits)
|
||||||
if ack {
|
if ack && self.responses.send(ResponseType::Distance {
|
||||||
if let Err(_) = self.responses.send(ResponseType::Distance {
|
|
||||||
path1: path1,
|
path1: path1,
|
||||||
path2: path2,
|
path2: path2,
|
||||||
distance: Ok(0.0),
|
distance: Ok(0.0),
|
||||||
}) {
|
}).is_err() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if !self.distance_in_progress.contains(&key) {
|
} else if !self.distance_in_progress.contains(&key) {
|
||||||
// distance worker uses 3 threads (it's own thread + 1 extra per song) for 2 songs
|
// distance worker uses 3 threads (it's own thread + 1 extra per song) for 2 songs
|
||||||
let available_parallelism =
|
let available_parallelism =
|
||||||
|
@ -433,11 +431,11 @@ impl CacheThread {
|
||||||
distance.clone(),
|
distance.clone(),
|
||||||
);
|
);
|
||||||
if path1_2 == key.0 && path2_2 == key.1 {
|
if path1_2 == key.0 && path2_2 == key.1 {
|
||||||
if let Err(_) = self.responses.send(ResponseType::Distance {
|
if self.responses.send(ResponseType::Distance {
|
||||||
path1: path1_2,
|
path1: path1_2,
|
||||||
path2: path2_2,
|
path2: path2_2,
|
||||||
distance: distance,
|
distance: distance,
|
||||||
}) {
|
}).is_err() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break 'inner1;
|
break 'inner1;
|
||||||
|
@ -448,10 +446,10 @@ impl CacheThread {
|
||||||
},
|
},
|
||||||
ResponseType::UnsupportedSong { path: unsupported_path, msg } => {
|
ResponseType::UnsupportedSong { path: unsupported_path, msg } => {
|
||||||
self.song_in_progress.remove(&unsupported_path);
|
self.song_in_progress.remove(&unsupported_path);
|
||||||
if let Err(_) = self.responses.send(ResponseType::UnsupportedSong {
|
if self.responses.send(ResponseType::UnsupportedSong {
|
||||||
path: unsupported_path.clone(),
|
path: unsupported_path.clone(),
|
||||||
msg: msg
|
msg: msg
|
||||||
}) {
|
}).is_err() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if unsupported_path == key.0 || unsupported_path == key.1 {
|
if unsupported_path == key.0 || unsupported_path == key.1 {
|
||||||
|
@ -478,10 +476,10 @@ impl CacheThread {
|
||||||
} else if !path.contains("://") {
|
} else if !path.contains("://") {
|
||||||
path
|
path
|
||||||
} else {
|
} else {
|
||||||
if let Err(_) = self.responses.send(ResponseType::UnsupportedSong {
|
if self.responses.send(ResponseType::UnsupportedSong {
|
||||||
msg: format!("Song path is not a supported URI, it's `{}`", path),
|
msg: format!("Song path is not a supported URI, it's `{}`", path),
|
||||||
path: path,
|
path: path,
|
||||||
}) {
|
}).is_err() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -489,10 +487,10 @@ impl CacheThread {
|
||||||
if let Some(song) = self.song_cache.get(&path) {
|
if let Some(song) = self.song_cache.get(&path) {
|
||||||
if ack {
|
if ack {
|
||||||
let song = song.to_owned();
|
let song = song.to_owned();
|
||||||
if let Err(_) = self.responses.send(ResponseType::Song {
|
if self.responses.send(ResponseType::Song {
|
||||||
path: path,
|
path: path,
|
||||||
song: song,
|
song: song.map(Box::new),
|
||||||
}) {
|
}).is_err() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -539,7 +537,7 @@ impl CacheThread {
|
||||||
results
|
results
|
||||||
.send(ResponseType::Song {
|
.send(ResponseType::Song {
|
||||||
path: path_clone,
|
path: path_clone,
|
||||||
song: song_result,
|
song: song_result.map(Box::new),
|
||||||
})
|
})
|
||||||
.unwrap_or(());
|
.unwrap_or(());
|
||||||
});
|
});
|
||||||
|
@ -557,10 +555,10 @@ impl CacheThread {
|
||||||
ResponseType::Song { path: path2, song } => {
|
ResponseType::Song { path: path2, song } => {
|
||||||
self.insert_song(path2.clone(), song.clone());
|
self.insert_song(path2.clone(), song.clone());
|
||||||
if path2 == path {
|
if path2 == path {
|
||||||
if let Err(_) = self.responses.send(ResponseType::Song {
|
if self.responses.send(ResponseType::Song {
|
||||||
path: path,
|
path: path,
|
||||||
song: song,
|
song: song,
|
||||||
}) {
|
}).is_err() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break 'inner3;
|
break 'inner3;
|
||||||
|
@ -569,10 +567,10 @@ impl CacheThread {
|
||||||
ResponseType::UnsupportedSong { path: unsupported_path, msg } => {
|
ResponseType::UnsupportedSong { path: unsupported_path, msg } => {
|
||||||
self.song_in_progress.remove(&unsupported_path);
|
self.song_in_progress.remove(&unsupported_path);
|
||||||
if unsupported_path == path {
|
if unsupported_path == path {
|
||||||
if let Err(_) = self.responses.send(ResponseType::UnsupportedSong {
|
if self.responses.send(ResponseType::UnsupportedSong {
|
||||||
path: unsupported_path,
|
path: unsupported_path,
|
||||||
msg: msg
|
msg: msg
|
||||||
}) {
|
}).is_err() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break 'inner3;
|
break 'inner3;
|
||||||
|
@ -624,7 +622,7 @@ fn worker_distance(
|
||||||
results
|
results
|
||||||
.send(ResponseType::Song {
|
.send(ResponseType::Song {
|
||||||
path: path1.to_string(),
|
path: path1.to_string(),
|
||||||
song: new_song1.clone(),
|
song: new_song1.clone().map(Box::new),
|
||||||
})
|
})
|
||||||
.unwrap_or(());
|
.unwrap_or(());
|
||||||
new_song1?
|
new_song1?
|
||||||
|
@ -637,7 +635,7 @@ fn worker_distance(
|
||||||
results
|
results
|
||||||
.send(ResponseType::Song {
|
.send(ResponseType::Song {
|
||||||
path: path2.to_string(),
|
path: path2.to_string(),
|
||||||
song: new_song2.clone(),
|
song: new_song2.clone().map(Box::new),
|
||||||
})
|
})
|
||||||
.unwrap_or(());
|
.unwrap_or(());
|
||||||
if new_song2.is_err() {
|
if new_song2.is_err() {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
use std::fmt::Write;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use crate::lang::db::*;
|
use crate::lang::db::*;
|
||||||
|
@ -159,9 +160,11 @@ impl DatabaseQuerier for SQLiteExecutor {
|
||||||
for key in keys.drain() {
|
for key in keys.drain() {
|
||||||
if first {
|
if first {
|
||||||
first = false;
|
first = false;
|
||||||
concat_keys += key;
|
write!(concat_keys, "{}", key).unwrap();
|
||||||
|
//concat_keys += key;
|
||||||
} else {
|
} else {
|
||||||
concat_keys += &format!("{}, ", key);
|
write!(concat_keys, "{}, ", key).unwrap();
|
||||||
|
//concat_keys += &format!("{}, ", key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(RuntimeMsg(format!(
|
return Err(RuntimeMsg(format!(
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#![allow(clippy::match_like_matches_macro)]
|
||||||
mod error;
|
mod error;
|
||||||
mod token_enum;
|
mod token_enum;
|
||||||
mod tokenizer;
|
mod tokenizer;
|
||||||
|
|
|
@ -268,7 +268,7 @@ impl ReaderStateMachine {
|
||||||
Self::Escaped { inside } => match inside {
|
Self::Escaped { inside } => match inside {
|
||||||
'`' => Self::InsideTickLiteral { out: input },
|
'`' => Self::InsideTickLiteral { out: input },
|
||||||
'"' => Self::InsideQuoteLiteral { out: input },
|
'"' => Self::InsideQuoteLiteral { out: input },
|
||||||
'_' | _ => Self::Regular { out: input },
|
_ => Self::Regular { out: input },
|
||||||
},
|
},
|
||||||
Self::StartTickLiteral {} | Self::InsideTickLiteral { .. } => match input_char {
|
Self::StartTickLiteral {} | Self::InsideTickLiteral { .. } => match input_char {
|
||||||
'\\' => Self::Escaped { inside: '`' },
|
'\\' => Self::Escaped { inside: '`' },
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use std::fmt::{Debug, Display, Error, Formatter};
|
use std::fmt::{Debug, Display, Error, Formatter};
|
||||||
use std::convert::Into;
|
use std::convert::From;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum PlayerError {
|
pub enum PlayerError {
|
||||||
|
@ -58,9 +58,9 @@ impl Display for PlaybackError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<PlayerError> for PlaybackError {
|
impl From<PlaybackError> for PlayerError {
|
||||||
fn into(self) -> PlayerError {
|
fn from(other: PlaybackError) -> Self {
|
||||||
PlayerError::Playback(self)
|
PlayerError::Playback(other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,8 +86,8 @@ impl Display for UriError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<PlayerError> for UriError {
|
impl From<UriError> for PlayerError {
|
||||||
fn into(self) -> PlayerError {
|
fn from(other: UriError) -> Self {
|
||||||
PlayerError::Uri(self)
|
PlayerError::Uri(other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
//! Music playback and m3u8 playlist generation are implemented in this part of the project.
|
//! Music playback and m3u8 playlist generation are implemented in this part of the project.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
#![allow(clippy::match_like_matches_macro)]
|
||||||
|
#![allow(clippy::redundant_field_names)]
|
||||||
|
|
||||||
mod controller;
|
mod controller;
|
||||||
mod errors;
|
mod errors;
|
||||||
pub(crate) mod os_controls;
|
pub(crate) mod os_controls;
|
||||||
|
|
|
@ -165,7 +165,7 @@ impl<I: std::iter::Iterator<Item=Result<Item, InterpreterError>>> PlayerServer<I
|
||||||
pub fn unblocking_timer_loop(ctrl_tx: Sender<ControlAction>, sleep_ms: u64) {
|
pub fn unblocking_timer_loop(ctrl_tx: Sender<ControlAction>, sleep_ms: u64) {
|
||||||
let dur = std::time::Duration::from_millis(sleep_ms);
|
let dur = std::time::Duration::from_millis(sleep_ms);
|
||||||
loop {
|
loop {
|
||||||
if let Err(_) = ctrl_tx.send(ControlAction::NoOp { ack: false }) {
|
if ctrl_tx.send(ControlAction::NoOp { ack: false }).is_err() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
thread::sleep(dur);
|
thread::sleep(dur);
|
||||||
|
|
|
@ -15,9 +15,9 @@ impl<'a> Uri<&'a str> {
|
||||||
match self.0.find("//") {
|
match self.0.find("//") {
|
||||||
Some(end) => {
|
Some(end) => {
|
||||||
// proper URI
|
// proper URI
|
||||||
if let Some(query_start) = self.0.find("?") {
|
if let Some(query_start) = self.0.find('?') {
|
||||||
self.0.get(end+2..query_start).unwrap()
|
self.0.get(end+2..query_start).unwrap()
|
||||||
} else if let Some(frag_start) = self.0.find("#") {
|
} else if let Some(frag_start) = self.0.find('#') {
|
||||||
self.0.get(end+2..frag_start).unwrap()
|
self.0.get(end+2..frag_start).unwrap()
|
||||||
} else {
|
} else {
|
||||||
self.0.get(end+2..).unwrap()
|
self.0.get(end+2..).unwrap()
|
||||||
|
|
|
@ -80,7 +80,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
// build playback controller
|
// build playback controller
|
||||||
let script_file2 = script_file.clone();
|
let script_file2 = script_file.clone();
|
||||||
let volume = args.volume.clone();
|
let volume = args.volume;
|
||||||
let mpd = match args.mpd.clone().map(|a| muss_player::mpd_connection(a.parse().unwrap())).transpose() {
|
let mpd = match args.mpd.clone().map(|a| muss_player::mpd_connection(a.parse().unwrap())).transpose() {
|
||||||
Ok(mpd) => mpd,
|
Ok(mpd) => mpd,
|
||||||
Err(e) => panic!("Abort: Cannot connect to MPD: {}", e),
|
Err(e) => panic!("Abort: Cannot connect to MPD: {}", e),
|
||||||
|
|
39
src/repl.rs
39
src/repl.rs
|
@ -1,4 +1,5 @@
|
||||||
//! Read, Execute, Print Loop functionality
|
//! Read, Execute, Print Loop functionality
|
||||||
|
#![allow(clippy::single_match)]
|
||||||
use std::sync::{RwLock};
|
use std::sync::{RwLock};
|
||||||
use std::sync::mpsc::{self, Receiver};
|
use std::sync::mpsc::{self, Receiver};
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
@ -79,7 +80,7 @@ impl ReplState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interpreter_event_callback<'a, T: muss_interpreter::tokens::TokenReader>(_interpreter: &mut Interpreter<'a, T>, event: InterpreterEvent) -> Result<(), InterpreterError> {
|
fn interpreter_event_callback<T: muss_interpreter::tokens::TokenReader>(_interpreter: &mut Interpreter<'_, T>, event: InterpreterEvent) -> Result<(), InterpreterError> {
|
||||||
match event {
|
match event {
|
||||||
InterpreterEvent::StatementComplete => {
|
InterpreterEvent::StatementComplete => {
|
||||||
if let Ok(mut d_state) = DEBUG_STATE.write() {
|
if let Ok(mut d_state) = DEBUG_STATE.write() {
|
||||||
|
@ -165,7 +166,7 @@ pub fn repl(args: CliArgs) {
|
||||||
let term = Term::stdout();
|
let term = Term::stdout();
|
||||||
term.set_title("muss");
|
term.set_title("muss");
|
||||||
let (writer, reader) = channel_io();
|
let (writer, reader) = channel_io();
|
||||||
let volume = args.volume.clone();
|
let volume = args.volume;
|
||||||
let mpd = match args.mpd.clone().map(|a| muss_player::mpd_connection(a.parse().unwrap())).transpose() {
|
let mpd = match args.mpd.clone().map(|a| muss_player::mpd_connection(a.parse().unwrap())).transpose() {
|
||||||
Ok(mpd) => mpd,
|
Ok(mpd) => mpd,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -187,7 +188,7 @@ pub fn repl(args: CliArgs) {
|
||||||
match flag {
|
match flag {
|
||||||
DebugFlag::Normal => item,
|
DebugFlag::Normal => item,
|
||||||
DebugFlag::Skip => {
|
DebugFlag::Skip => {
|
||||||
while let Some(_) = interpretor.next() {
|
for _ in interpretor.by_ref() {
|
||||||
// NOTE: recursion occurs here
|
// NOTE: recursion occurs here
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
@ -195,7 +196,7 @@ pub fn repl(args: CliArgs) {
|
||||||
DebugFlag::List => {
|
DebugFlag::List => {
|
||||||
if let Some(x) = item {
|
if let Some(x) = item {
|
||||||
list_tx.send(x.map_err(|e| e.to_string())).unwrap_or(());
|
list_tx.send(x.map_err(|e| e.to_string())).unwrap_or(());
|
||||||
while let Some(x) = interpretor.next() {
|
for x in interpretor.by_ref() {
|
||||||
// NOTE: recursion occurs here
|
// NOTE: recursion occurs here
|
||||||
// in most cases this will never be a case of Some(...) because
|
// in most cases this will never be a case of Some(...) because
|
||||||
// recursive calls to this function intercept it first and return None
|
// recursive calls to this function intercept it first and return None
|
||||||
|
@ -241,10 +242,10 @@ pub fn repl(args: CliArgs) {
|
||||||
match player.save_m3u8(&mut playlist_writer) {
|
match player.save_m3u8(&mut playlist_writer) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error_prompt(e, &args);
|
error_prompt(e, args);
|
||||||
// consume any further errors (this shouldn't actually write anything)
|
// consume any further errors (this shouldn't actually write anything)
|
||||||
while let Err(e) = player.save_m3u8(&mut playlist_writer) {
|
while let Err(e) = player.save_m3u8(&mut playlist_writer) {
|
||||||
error_prompt(e, &args);
|
error_prompt(e, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,7 +267,7 @@ pub fn repl(args: CliArgs) {
|
||||||
if args.wait {
|
if args.wait {
|
||||||
match ctrl.wait_for_empty() {
|
match ctrl.wait_for_empty() {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => error_prompt(e, &args),
|
Err(e) => error_prompt(e, args),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// consume all incoming errors
|
// consume all incoming errors
|
||||||
|
@ -274,7 +275,7 @@ pub fn repl(args: CliArgs) {
|
||||||
while had_err {
|
while had_err {
|
||||||
let mut new_had_err = false;
|
let mut new_had_err = false;
|
||||||
for e in ctrl.check_ack() {
|
for e in ctrl.check_ack() {
|
||||||
error_prompt(e, &args);
|
error_prompt(e, args);
|
||||||
new_had_err = true;
|
new_had_err = true;
|
||||||
}
|
}
|
||||||
had_err = new_had_err;
|
had_err = new_had_err;
|
||||||
|
@ -354,7 +355,7 @@ fn read_loop<F: FnMut(&mut ReplState, &CliArgs)>(args: &CliArgs, state: &mut Rep
|
||||||
if !statement_result.starts_with('?') {
|
if !statement_result.starts_with('?') {
|
||||||
state
|
state
|
||||||
.writer
|
.writer
|
||||||
.write(state.statement_buf.iter().collect::<String>().as_bytes())
|
.write_all(state.statement_buf.iter().collect::<String>().as_bytes())
|
||||||
.expect(INTERPRETER_WRITE_ERROR);
|
.expect(INTERPRETER_WRITE_ERROR);
|
||||||
execute(state, args);
|
execute(state, args);
|
||||||
state.statement_buf.clear();
|
state.statement_buf.clear();
|
||||||
|
@ -427,8 +428,7 @@ fn read_loop<F: FnMut(&mut ReplState, &CliArgs)>(args: &CliArgs, state: &mut Rep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if state.current_line.len() != state.cursor_rightward_position {
|
||||||
if state.current_line.len() != state.cursor_rightward_position {
|
|
||||||
// if not at start of line
|
// if not at start of line
|
||||||
let removed_char = state
|
let removed_char = state
|
||||||
.current_line
|
.current_line
|
||||||
|
@ -479,7 +479,6 @@ fn read_loop<F: FnMut(&mut ReplState, &CliArgs)>(args: &CliArgs, state: &mut Rep
|
||||||
.expect(TERMINAL_WRITE_ERROR);
|
.expect(TERMINAL_WRITE_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Key::Del => {
|
Key::Del => {
|
||||||
if state.cursor_rightward_position != 0 {
|
if state.cursor_rightward_position != 0 {
|
||||||
let removed_char = state
|
let removed_char = state
|
||||||
|
@ -547,7 +546,7 @@ fn read_loop<F: FnMut(&mut ReplState, &CliArgs)>(args: &CliArgs, state: &mut Rep
|
||||||
let complete_statement = state.statement_buf.iter().collect::<String>();
|
let complete_statement = state.statement_buf.iter().collect::<String>();
|
||||||
state
|
state
|
||||||
.writer
|
.writer
|
||||||
.write(complete_statement.as_bytes())
|
.write_all(complete_statement.as_bytes())
|
||||||
.expect("Failed to write to MPS interpreter");
|
.expect("Failed to write to MPS interpreter");
|
||||||
execute(state, args);
|
execute(state, args);
|
||||||
state.statement_buf.clear();
|
state.statement_buf.clear();
|
||||||
|
@ -575,10 +574,8 @@ fn read_loop<F: FnMut(&mut ReplState, &CliArgs)>(args: &CliArgs, state: &mut Rep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Key::ArrowDown => {
|
Key::ArrowDown => {
|
||||||
if state.selected_history > 1 {
|
match state.selected_history {
|
||||||
state.selected_history -= 1;
|
1 => {
|
||||||
display_history_line(state, args);
|
|
||||||
} else if state.selected_history == 1 {
|
|
||||||
state.selected_history = 0;
|
state.selected_history = 0;
|
||||||
state.line_number -= 1;
|
state.line_number -= 1;
|
||||||
state
|
state
|
||||||
|
@ -592,6 +589,12 @@ fn read_loop<F: FnMut(&mut ReplState, &CliArgs)>(args: &CliArgs, state: &mut Rep
|
||||||
state.in_literal = None;
|
state.in_literal = None;
|
||||||
state.bracket_depth = 0;
|
state.bracket_depth = 0;
|
||||||
state.curly_depth = 0;
|
state.curly_depth = 0;
|
||||||
|
},
|
||||||
|
0 => {},
|
||||||
|
_ => {
|
||||||
|
state.selected_history -= 1;
|
||||||
|
display_history_line(state, args);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Key::ArrowLeft => {
|
Key::ArrowLeft => {
|
||||||
|
@ -642,7 +645,7 @@ fn display_history_line(state: &mut ReplState, args: &CliArgs) {
|
||||||
let new_statement = state.history[state.history.len() - state.selected_history].trim();
|
let new_statement = state.history[state.history.len() - state.selected_history].trim();
|
||||||
state
|
state
|
||||||
.terminal
|
.terminal
|
||||||
.write(new_statement.as_bytes())
|
.write_all(new_statement.as_bytes())
|
||||||
.expect(TERMINAL_WRITE_ERROR);
|
.expect(TERMINAL_WRITE_ERROR);
|
||||||
// clear stale input buffer
|
// clear stale input buffer
|
||||||
state.statement_buf.clear();
|
state.statement_buf.clear();
|
||||||
|
|
Loading…
Reference in a new issue