diff --git a/Cargo.lock b/Cargo.lock index ae3b339..5a95ac0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -692,9 +692,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "fallible-iterator" @@ -1131,17 +1131,6 @@ dependencies = [ "adler", ] -[[package]] -name = "mpd" -version = "0.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a20784da57fa01bf7910a5da686d9f39ff37feaa774856b71f050e4331bf82" -dependencies = [ - "bufstream", - "rustc-serialize", - "time", -] - [[package]] name = "mpd" version = "0.1.0" @@ -1178,7 +1167,7 @@ dependencies = [ "criterion", "dirs", "m3u8-rs", - "mpd 0.1.0", + "mpd", "rand 0.8.5", "regex 1.9.1", "rusqlite", @@ -1203,7 +1192,7 @@ version = "0.9.0" dependencies = [ "base64", "m3u8-rs", - "mpd 0.0.12", + "mpd", "mpris-player", "muss-interpreter", "rodio", @@ -1609,9 +1598,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.3.3" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794" +checksum = "d220334a184db82b31b83f5ff093e3315280fb2b6bbc032022b2304a509aab7a" [[package]] name = "ppv-lite86" @@ -1870,7 +1859,7 @@ dependencies = [ "aho-corasick 1.0.2", "memchr 2.5.0", "regex-automata", - "regex-syntax 0.7.3", + "regex-syntax 0.7.4", ] [[package]] @@ -1881,7 +1870,7 @@ checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" dependencies = [ "aho-corasick 1.0.2", "memchr 2.5.0", - "regex-syntax 0.7.3", + "regex-syntax 0.7.4", ] [[package]] @@ -1892,9 +1881,9 @@ checksum = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" [[package]] name = "regex-syntax" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "remove_dir_all" @@ -1965,12 +1954,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" - [[package]] name = "rustc_version" version = "0.2.3" @@ -2047,9 +2030,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.170" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56657f512baabca8f840542f9ca8152aecf182c473c26e46e58d6aab4f6e439" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] @@ -2066,9 +2049,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.170" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77d477848e6b23adba0db397777d5aad864555bc17fd9c89abb3b8009788b7b8" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", diff --git a/interpreter/src/interpretor.rs b/interpreter/src/interpretor.rs index 669214f..5be9aa5 100644 --- a/interpreter/src/interpretor.rs +++ b/interpreter/src/interpretor.rs @@ -6,13 +6,14 @@ pub(crate) fn standard_vocab(vocabulary: &mut LanguageDictionary) { // filters .add_transform(crate::lang::vocabulary::filters::empty_filter()) .add_transform(crate::lang::vocabulary::filters::range_filter()) - .add_transform( // accepts any .(.something) + .add_transform( + // accepts any .(.something) crate::lang::vocabulary::filters::field::FieldFilterBlockFactory::new() .push(crate::lang::vocabulary::filters::field::FieldFilterComparisonFactory) .push(crate::lang::vocabulary::filters::field::FieldFilterMaybeFactory) .push(crate::lang::vocabulary::filters::field::FieldLikeFilterFactory) .push(crate::lang::vocabulary::filters::field::FieldRegexFilterFactory) - .to_statement_factory() + .to_statement_factory(), ) .add_transform(crate::lang::vocabulary::filters::unique_field_filter()) .add_transform(crate::lang::vocabulary::filters::unique_filter()) @@ -48,7 +49,7 @@ pub(crate) fn standard_vocab(vocabulary: &mut LanguageDictionary) { .push(crate::lang::vocabulary::item_ops::BracketsItemOpFactory) .push(crate::lang::vocabulary::item_ops::FieldRetrieveItemOpFactory) .push(crate::lang::vocabulary::item_ops::ConstantItemOpFactory) - .push(crate::lang::vocabulary::item_ops::VariableRetrieveItemOpFactory) + .push(crate::lang::vocabulary::item_ops::VariableRetrieveItemOpFactory), ) // functions and misc // functions don't enforce bracket coherence diff --git a/interpreter/src/lang/dictionary.rs b/interpreter/src/lang/dictionary.rs index 23a2b44..e46f7d6 100644 --- a/interpreter/src/lang/dictionary.rs +++ b/interpreter/src/lang/dictionary.rs @@ -1,7 +1,7 @@ use std::collections::VecDeque; use super::SyntaxError; -use super::{BoxedOpFactory, Op, BoxedTransformOpFactory}; +use super::{BoxedOpFactory, BoxedTransformOpFactory, Op}; use crate::tokens::Token; pub struct LanguageDictionary { @@ -69,7 +69,7 @@ impl LanguageDictionary { for factory in &self.transform_vocabulary { if factory.is_transform_op(tokens) { op = factory.build_transform_op(tokens, self, op)?; - return Ok((op, true)) + return Ok((op, true)); } } Ok((op, false)) diff --git a/interpreter/src/lang/filter.rs b/interpreter/src/lang/filter.rs index 972bd0d..17a83c3 100644 --- a/interpreter/src/lang/filter.rs +++ b/interpreter/src/lang/filter.rs @@ -135,7 +135,7 @@ impl Op for FilterStatement

{ } } -impl FilterStatement

{ +impl FilterStatement

{ fn next_item(&mut self) -> Option { match self.iterable.try_real() { Ok(real_op) => { @@ -163,7 +163,9 @@ impl Iterator for FilterStatement

{ match next_item { Ok(item) => { //let ctx = self.context.as_mut().unwrap(); - let matches_result = self.predicate.matches(&item, self.context.as_mut().unwrap()); + let matches_result = self + .predicate + .matches(&item, self.context.as_mut().unwrap()); let matches = match matches_result { Err(e) => { //maybe_result = Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))); @@ -177,30 +179,41 @@ impl Iterator for FilterStatement

{ // make fake inner item //println!("Making fake inner variable `{}`", INNER_VARIABLE_NAME); let single_op = SingleItem::new_ok(item.clone()); - let preexisting_var = self.context.as_mut().unwrap() + let preexisting_var = self + .context + .as_mut() + .unwrap() .variables .swap(INNER_VARIABLE_NAME, Some(Type::Op(Box::new(single_op)))); let inner_real = match inner.try_real() { Ok(x) => x, - Err(e) => return Some(Err(e)) + Err(e) => return Some(Err(e)), }; inner_real.enter(self.context.take().unwrap()); match inner_real.next() { Some(item) => { self.context = Some(inner_real.escape()); - self.context.as_mut().unwrap().variables.swap(INNER_VARIABLE_NAME, preexisting_var); + self.context + .as_mut() + .unwrap() + .variables + .swap(INNER_VARIABLE_NAME, preexisting_var); return Some(item); } None => { self.context = Some(inner_real.escape()); // move ctx back to expected spot - self.context.as_mut().unwrap().variables.swap(INNER_VARIABLE_NAME, preexisting_var); + self.context + .as_mut() + .unwrap() + .variables + .swap(INNER_VARIABLE_NAME, preexisting_var); } } } if matches { return Some(Ok(item)); } - }, + } Err(e) => return Some(Err(e)), }; } @@ -208,7 +221,11 @@ impl Iterator for FilterStatement

{ } fn size_hint(&self) -> (usize, Option) { - self.iterable.try_real_ref().map(|x| x.size_hint()).ok().unwrap_or((0, None)) + self.iterable + .try_real_ref() + .map(|x| x.size_hint()) + .ok() + .unwrap_or((0, None)) } } @@ -227,7 +244,8 @@ impl + 'static> FilterStatemen } impl + 'static> BoxedTransformOpFactory - for FilterStatementFactory { + for FilterStatementFactory +{ fn build_transform_op( &self, tokens: &mut VecDeque, @@ -267,7 +285,7 @@ impl + 'static> BoxedTransform assert_token_raw(Token::CloseBracket, tokens)?; Ok(Box::new(FilterReplaceStatement { predicate: filter, - iterable: op.into(), + iterable: op.into(), context: None, op_if: if_op, op_else: else_op, @@ -302,13 +320,11 @@ impl + 'static> BoxedTransform let inner_op = dict.try_build_statement(&mut inner_tokens)?; let (inner_op, op_transformed) = dict.try_build_one_transform(inner_op, tokens)?; if !op_transformed { - return Err( - SyntaxError { - token: Token::Name(INNER_VARIABLE_NAME.into()), - got: Some(Token::Name(INNER_VARIABLE_NAME.into())), - line: 0, - } - ) + return Err(SyntaxError { + token: Token::Name(INNER_VARIABLE_NAME.into()), + got: Some(Token::Name(INNER_VARIABLE_NAME.into())), + line: 0, + }); } //println!("Built 2nd filter: {}", inner_op); another_filter = Some(inner_op.into()); @@ -318,7 +334,7 @@ impl + 'static> BoxedTransform } Ok(Box::new(FilterStatement { predicate: filter, - iterable: op.into(), + iterable: op.into(), context: None, other_filters: another_filter, is_failing: false, @@ -329,12 +345,10 @@ impl + 'static> BoxedTransform fn is_transform_op(&self, tokens: &VecDeque) -> bool { let result = if tokens.len() > 2 && tokens[0].is_dot() && tokens[1].is_open_bracket() { if check_name("if", &tokens[2]) { - let tokens2: VecDeque<&Token> = - VecDeque::from_iter(tokens.range(3..)); + let tokens2: VecDeque<&Token> = VecDeque::from_iter(tokens.range(3..)); self.filter_factory.is_filter(&tokens2) } else { - let tokens2: VecDeque<&Token> = - VecDeque::from_iter(tokens.range(2..)); + let tokens2: VecDeque<&Token> = VecDeque::from_iter(tokens.range(2..)); self.filter_factory.is_filter(&tokens2) } } else { diff --git a/interpreter/src/lang/filter_replace.rs b/interpreter/src/lang/filter_replace.rs index 2d95821..8eaff1e 100644 --- a/interpreter/src/lang/filter_replace.rs +++ b/interpreter/src/lang/filter_replace.rs @@ -2,8 +2,8 @@ use std::collections::VecDeque; use std::fmt::{Debug, Display, Error, Formatter}; use std::iter::Iterator; -use crate::lang::SingleItem; use crate::lang::FilterPredicate; +use crate::lang::SingleItem; use crate::lang::{IteratorItem, Op, PseudoOp}; use crate::lang::{RuntimeError, RuntimeMsg, RuntimeOp}; use crate::processing::general::Type; @@ -243,7 +243,11 @@ impl Iterator for FilterReplaceStatement

{ } fn size_hint(&self) -> (usize, Option) { - self.iterable.try_real_ref().map(|x| x.size_hint()).ok().unwrap_or((0, None)) + self.iterable + .try_real_ref() + .map(|x| x.size_hint()) + .ok() + .unwrap_or((0, None)) } } diff --git a/interpreter/src/lang/function.rs b/interpreter/src/lang/function.rs index 298ec20..001cf93 100644 --- a/interpreter/src/lang/function.rs +++ b/interpreter/src/lang/function.rs @@ -42,10 +42,7 @@ impl + 'static> BoxedOpFactory false } else { match &tokens[0] { - Token::Name(n) => { - self.op_factory.is_function(n) - && tokens[1].is_open_bracket() - } + Token::Name(n) => self.op_factory.is_function(n) && tokens[1].is_open_bracket(), _ => false, } } diff --git a/interpreter/src/lang/generator_op.rs b/interpreter/src/lang/generator_op.rs index c573d94..55c857d 100644 --- a/interpreter/src/lang/generator_op.rs +++ b/interpreter/src/lang/generator_op.rs @@ -2,7 +2,7 @@ use std::fmt::{Debug, Display, Error, Formatter}; use std::iter::Iterator; use crate::lang::{IteratorItem, Op, RuntimeError}; -use crate::lang::{RuntimeOp, RuntimeMsg, PseudoOp}; +use crate::lang::{PseudoOp, RuntimeMsg, RuntimeOp}; use crate::Context; use crate::Item; @@ -12,7 +12,9 @@ pub struct GeneratorOp { } impl GeneratorOp { - pub fn new Option>) + Send + 'static>(generator_fn: F) -> Self { + pub fn new Option>) + Send + 'static>( + generator_fn: F, + ) -> Self { Self { context: None, generator: Box::new(generator_fn), @@ -62,17 +64,15 @@ impl Op for GeneratorOp { } fn reset(&mut self) -> Result<(), RuntimeError> { - Err( - RuntimeMsg("Cannot reset generator op".to_string()) - .with(RuntimeOp(PseudoOp::from_printable(self))) - ) + Err(RuntimeMsg("Cannot reset generator op".to_string()) + .with(RuntimeOp(PseudoOp::from_printable(self)))) } fn dup(&self) -> Box { // this shouldn't be called Box::new(Self { context: None, - generator: Box::new(|_| None) + generator: Box::new(|_| None), }) } } diff --git a/interpreter/src/lang/iter_block.rs b/interpreter/src/lang/iter_block.rs index 1a63b4d..a2107a8 100644 --- a/interpreter/src/lang/iter_block.rs +++ b/interpreter/src/lang/iter_block.rs @@ -278,7 +278,7 @@ impl BoxedTransformOpFactory for ItemBlockFactory { got: tokens.pop_front(), token: Token::Literal(", or }".into()), line: 0, - }) + }); } } assert_token_raw(Token::CloseCurly, tokens)?; diff --git a/interpreter/src/lang/mod.rs b/interpreter/src/lang/mod.rs index e13d15f..cbd1d69 100644 --- a/interpreter/src/lang/mod.rs +++ b/interpreter/src/lang/mod.rs @@ -29,7 +29,9 @@ pub use function::{FunctionFactory, FunctionStatementFactory}; pub use generator_op::GeneratorOp; pub use iter_block::{ItemBlockFactory, ItemOp, ItemOpFactory}; pub use lookup::Lookup; -pub use operation::{BoxedOpFactory, IteratorItem, Op, OpFactory, SimpleOpFactory, BoxedTransformOpFactory}; +pub use operation::{ + BoxedOpFactory, BoxedTransformOpFactory, IteratorItem, Op, OpFactory, SimpleOpFactory, +}; pub use pseudo_op::PseudoOp; pub use repeated_meme::{repeated_tokens, RepeatedTokens}; pub use single_op::SingleItem; @@ -41,12 +43,10 @@ pub use vec_op::VecOp; pub mod vocabulary; pub mod db { - pub use super::db_items::{ - DbAlbumItem, DbArtistItem, DbGenreItem, DbMetaItem, DbMusicItem, DatabaseObj - }; #[cfg(feature = "sql")] + pub use super::db_items::{generate_db, generate_default_db, DEFAULT_SQLITE_FILEPATH}; pub use super::db_items::{ - generate_db, generate_default_db, DEFAULT_SQLITE_FILEPATH + DatabaseObj, DbAlbumItem, DbArtistItem, DbGenreItem, DbMetaItem, DbMusicItem, }; } diff --git a/interpreter/src/lang/operation.rs b/interpreter/src/lang/operation.rs index 330a456..37b8e6d 100644 --- a/interpreter/src/lang/operation.rs +++ b/interpreter/src/lang/operation.rs @@ -37,11 +37,8 @@ impl + 'static> OpFactory for X { pub trait OpFactory { fn is_op(&self, tokens: &TokenList) -> bool; - fn build_op( - &self, - tokens: &mut TokenList, - dict: &LanguageDictionary, - ) -> Result; + fn build_op(&self, tokens: &mut TokenList, dict: &LanguageDictionary) + -> Result; #[inline] fn build_box( diff --git a/interpreter/src/lang/sorter.rs b/interpreter/src/lang/sorter.rs index 840fe9b..6ea5c38 100644 --- a/interpreter/src/lang/sorter.rs +++ b/interpreter/src/lang/sorter.rs @@ -5,7 +5,7 @@ use std::marker::PhantomData; use crate::lang::utility::assert_token_raw; use crate::lang::LanguageDictionary; -use crate::lang::{IteratorItem, Op, PseudoOp, BoxedTransformOpFactory}; +use crate::lang::{BoxedTransformOpFactory, IteratorItem, Op, PseudoOp}; use crate::lang::{RuntimeError, RuntimeMsg, RuntimeOp, SyntaxError}; use crate::tokens::Token; use crate::Context; @@ -149,12 +149,10 @@ impl + 'static> BoxedTransformOpFactory fn is_transform_op(&self, tokens: &VecDeque) -> bool { if tokens.len() > 2 { - let tokens2: VecDeque<&Token> = - VecDeque::from_iter(tokens.range(2..)); + let tokens2: VecDeque<&Token> = VecDeque::from_iter(tokens.range(2..)); tokens[0].is_tilde() && self.sort_factory.is_sorter(&tokens2) } else { false } - } } diff --git a/interpreter/src/lang/vec_op.rs b/interpreter/src/lang/vec_op.rs index 053bdb9..f50bd88 100644 --- a/interpreter/src/lang/vec_op.rs +++ b/interpreter/src/lang/vec_op.rs @@ -2,7 +2,7 @@ use std::fmt::{Debug, Display, Error, Formatter}; use std::iter::Iterator; use crate::lang::{IteratorItem, Op, RuntimeError}; -use crate::lang::{RuntimeOp, RuntimeMsg, PseudoOp}; +use crate::lang::{PseudoOp, RuntimeMsg, RuntimeOp}; use crate::Context; use crate::Item; diff --git a/interpreter/src/lang/vocabulary/filters/field/field_filter.rs b/interpreter/src/lang/vocabulary/filters/field/field_filter.rs index c3bcd32..7258d6f 100644 --- a/interpreter/src/lang/vocabulary/filters/field/field_filter.rs +++ b/interpreter/src/lang/vocabulary/filters/field/field_filter.rs @@ -110,8 +110,7 @@ impl FieldFilterFactory for FieldFilterComparisonFactory { || (tokens_len >= 2 // .field >= variable OR .field <= variable OR .field != variable OR .field == variable && (tokens[0].is_open_angle_bracket() || tokens[0].is_close_angle_bracket() || tokens[0].is_equals() || tokens[0].is_exclamation()) && tokens[1].is_equals() - && !(tokens_len > 2 && tokens[2].is_equals()) - ) + && !(tokens_len > 2 && tokens[2].is_equals())) } fn build_filter( diff --git a/interpreter/src/lang/vocabulary/filters/field/field_filter_factory.rs b/interpreter/src/lang/vocabulary/filters/field/field_filter_factory.rs index f8523de..3dfedce 100644 --- a/interpreter/src/lang/vocabulary/filters/field/field_filter_factory.rs +++ b/interpreter/src/lang/vocabulary/filters/field/field_filter_factory.rs @@ -1,11 +1,11 @@ use std::collections::VecDeque; use std::fmt::{Debug, Display, Error, Formatter}; -use crate::lang::{FilterFactory, FilterPredicate, FilterStatementFactory}; -use crate::tokens::Token; use crate::lang::utility::{assert_token, assert_token_raw}; use crate::lang::LanguageDictionary; +use crate::lang::{FilterFactory, FilterPredicate, FilterStatementFactory}; use crate::lang::{RuntimeMsg, SyntaxError}; +use crate::tokens::Token; use crate::Context; use crate::Item; @@ -31,18 +31,18 @@ pub trait FieldFilterPredicate: Send + Sync + Debug + Display { } pub struct FieldFilterFactoryBoxer { - inner: Box> + inner: Box>, } #[derive(Debug)] pub struct BoxedFilterPredicate { - inner: Box + inner: Box, } impl Clone for BoxedFilterPredicate { fn clone(&self) -> Self { Self { - inner: self.inner.box_clone() + inner: self.inner.box_clone(), } } } @@ -85,7 +85,9 @@ impl FieldFilterPredicate for BoxedFilterPredicate { } } -impl FieldFilterFactory for FieldFilterFactoryBoxer { +impl FieldFilterFactory + for FieldFilterFactoryBoxer +{ fn is_filter(&self, tokens: &[Token]) -> bool { self.inner.is_filter(tokens) } @@ -96,7 +98,9 @@ impl FieldFilterFactory Result { - self.inner.build_filter(tokens, field, dict).map(|x| BoxedFilterPredicate { inner: Box::new(x) }) + self.inner + .build_filter(tokens, field, dict) + .map(|x| BoxedFilterPredicate { inner: Box::new(x) }) } } @@ -111,10 +115,13 @@ impl FieldFilterBlockFactory { } } - pub fn push + 'static>(mut self, factory: F) -> Self { - self.field_filters.push( - Box::new(FieldFilterFactoryBoxer { inner: Box::new(factory) }) - ); + pub fn push + 'static>( + mut self, + factory: F, + ) -> Self { + self.field_filters.push(Box::new(FieldFilterFactoryBoxer { + inner: Box::new(factory), + })); self } diff --git a/interpreter/src/lang/vocabulary/filters/field/field_like_filter.rs b/interpreter/src/lang/vocabulary/filters/field/field_like_filter.rs index 3e700c0..bf9bfe7 100644 --- a/interpreter/src/lang/vocabulary/filters/field/field_like_filter.rs +++ b/interpreter/src/lang/vocabulary/filters/field/field_like_filter.rs @@ -2,10 +2,10 @@ use std::collections::VecDeque; use std::fmt::{Debug, Display, Error, Formatter}; use super::field_filter::{FieldFilterErrorHandling, VariableOrValue}; +use super::{FieldFilterFactory, FieldFilterPredicate}; use crate::lang::utility::{assert_token, assert_token_raw, check_name}; use crate::lang::LanguageDictionary; use crate::lang::TypePrimitive; -use super::{FieldFilterFactory, FieldFilterPredicate}; use crate::lang::{RuntimeMsg, SyntaxError}; use crate::processing::general::Type; use crate::tokens::Token; diff --git a/interpreter/src/lang/vocabulary/filters/field/field_match_filter.rs b/interpreter/src/lang/vocabulary/filters/field/field_match_filter.rs index 6194b9b..ca4512a 100644 --- a/interpreter/src/lang/vocabulary/filters/field/field_match_filter.rs +++ b/interpreter/src/lang/vocabulary/filters/field/field_match_filter.rs @@ -4,10 +4,10 @@ use std::fmt::{Debug, Display, Error, Formatter}; use regex::{Regex, RegexBuilder}; use super::field_filter::{FieldFilterErrorHandling, VariableOrValue}; +use super::{FieldFilterFactory, FieldFilterPredicate}; use crate::lang::utility::{assert_name, assert_token, assert_token_raw, check_name}; use crate::lang::LanguageDictionary; use crate::lang::TypePrimitive; -use super::{FieldFilterFactory, FieldFilterPredicate}; use crate::lang::{RuntimeMsg, SyntaxError}; use crate::processing::general::Type; use crate::tokens::Token; diff --git a/interpreter/src/lang/vocabulary/filters/field/mod.rs b/interpreter/src/lang/vocabulary/filters/field/mod.rs index f419ae5..c365bee 100644 --- a/interpreter/src/lang/vocabulary/filters/field/mod.rs +++ b/interpreter/src/lang/vocabulary/filters/field/mod.rs @@ -4,9 +4,7 @@ mod field_filter_maybe; mod field_like_filter; mod field_match_filter; -pub use field_filter::{ - FieldFilter, FieldFilterErrorHandling, FieldFilterComparisonFactory, -}; +pub use field_filter::{FieldFilter, FieldFilterComparisonFactory, FieldFilterErrorHandling}; pub use field_filter_maybe::FieldFilterMaybeFactory; pub use field_like_filter::FieldLikeFilterFactory; pub use field_match_filter::FieldRegexFilterFactory; diff --git a/interpreter/src/lang/vocabulary/filters/unique.rs b/interpreter/src/lang/vocabulary/filters/unique.rs index ed88138..a99669b 100644 --- a/interpreter/src/lang/vocabulary/filters/unique.rs +++ b/interpreter/src/lang/vocabulary/filters/unique.rs @@ -108,17 +108,18 @@ impl FilterFactory for UniqueFilterFactory { Token::Name("field_name".into()), tokens, )?; - let error_handling = if !tokens.is_empty() && (tokens[0].is_exclamation() || tokens[0].is_interrogation()) { - if tokens[0].is_exclamation() { - assert_token_raw(Token::Exclamation, tokens)?; - FieldFilterErrorHandling::Ignore + let error_handling = + if !tokens.is_empty() && (tokens[0].is_exclamation() || tokens[0].is_interrogation()) { + if tokens[0].is_exclamation() { + assert_token_raw(Token::Exclamation, tokens)?; + FieldFilterErrorHandling::Ignore + } else { + assert_token_raw(Token::Interrogation, tokens)?; + FieldFilterErrorHandling::Include + } } else { - assert_token_raw(Token::Interrogation, tokens)?; - FieldFilterErrorHandling::Include - } - } else { - FieldFilterErrorHandling::Error - }; + FieldFilterErrorHandling::Error + }; Ok(UniqueFieldFilter { field: field_name, field_errors: error_handling, diff --git a/interpreter/src/lang/vocabulary/item_ops/brackets.rs b/interpreter/src/lang/vocabulary/item_ops/brackets.rs index 8cc5826..78a4820 100644 --- a/interpreter/src/lang/vocabulary/item_ops/brackets.rs +++ b/interpreter/src/lang/vocabulary/item_ops/brackets.rs @@ -13,8 +13,7 @@ pub struct BracketsItemOpFactory; impl ItemOpFactory> for BracketsItemOpFactory { fn is_item_op(&self, tokens: &VecDeque) -> bool { - !tokens.is_empty() - && tokens[0].is_open_bracket() + !tokens.is_empty() && tokens[0].is_open_bracket() } fn build_item_op( diff --git a/interpreter/src/lang/vocabulary/item_ops/compare.rs b/interpreter/src/lang/vocabulary/item_ops/compare.rs index af7be92..f2d065d 100644 --- a/interpreter/src/lang/vocabulary/item_ops/compare.rs +++ b/interpreter/src/lang/vocabulary/item_ops/compare.rs @@ -123,7 +123,7 @@ fn find_first_comparison(tokens: &VecDeque) -> Option { { return Some(i); } - }, + } Token::Comma if curly_depth == 0 && bracket_depth == 0 => { return None; } diff --git a/interpreter/src/lang/vocabulary/item_ops/constructor.rs b/interpreter/src/lang/vocabulary/item_ops/constructor.rs index e654fc7..c80cf4d 100644 --- a/interpreter/src/lang/vocabulary/item_ops/constructor.rs +++ b/interpreter/src/lang/vocabulary/item_ops/constructor.rs @@ -2,9 +2,7 @@ use core::ops::Deref; use std::collections::VecDeque; use std::fmt::{Debug, Display, Error, Formatter}; -use crate::lang::utility::{ - assert_name, assert_token, assert_token_raw, check_name, -}; +use crate::lang::utility::{assert_name, assert_token, assert_token_raw, check_name}; use crate::lang::LanguageDictionary; use crate::lang::{ItemBlockFactory, ItemOp, ItemOpFactory}; use crate::lang::{RuntimeMsg, SyntaxError}; diff --git a/interpreter/src/lang/vocabulary/item_ops/empty.rs b/interpreter/src/lang/vocabulary/item_ops/empty.rs index 107fe7d..11cbec5 100644 --- a/interpreter/src/lang/vocabulary/item_ops/empty.rs +++ b/interpreter/src/lang/vocabulary/item_ops/empty.rs @@ -36,8 +36,7 @@ pub struct EmptyItemOpFactory; impl ItemOpFactory for EmptyItemOpFactory { fn is_item_op(&self, tokens: &VecDeque) -> bool { - !tokens.is_empty() - && check_name("empty", &tokens[0]) + !tokens.is_empty() && check_name("empty", &tokens[0]) } fn build_item_op( diff --git a/interpreter/src/lang/vocabulary/item_ops/iter_op.rs b/interpreter/src/lang/vocabulary/item_ops/iter_op.rs index 95bc67f..e97731a 100644 --- a/interpreter/src/lang/vocabulary/item_ops/iter_op.rs +++ b/interpreter/src/lang/vocabulary/item_ops/iter_op.rs @@ -27,7 +27,7 @@ impl Display for IterItemOp { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { match self.inner.lock() { Ok(inner) => write!(f, "iter {}", inner), - Err(e) => write!(f, "iter !?!? (e:{})", e) + Err(e) => write!(f, "iter !?!? (e:{})", e), } } } @@ -36,7 +36,7 @@ impl ItemOp for IterItemOp { fn execute(&self, _context: &mut Context) -> Result { match self.inner.lock() { Ok(inner) => Ok(Type::Op(inner.dup())), - Err(e) => Err(RuntimeMsg(format!("IterItemOp lock failed: {}", e))) + Err(e) => Err(RuntimeMsg(format!("IterItemOp lock failed: {}", e))), } } } @@ -56,6 +56,8 @@ impl ItemOpFactory for IterItemOpFactory { ) -> Result { assert_name("iter", tokens)?; let inner_op = dict.try_build_statement(tokens)?; - Ok(IterItemOp { inner: Mutex::new(inner_op) }) + Ok(IterItemOp { + inner: Mutex::new(inner_op), + }) } } diff --git a/interpreter/src/lang/vocabulary/item_ops/retrieve_field.rs b/interpreter/src/lang/vocabulary/item_ops/retrieve_field.rs index 5025bec..6d3a445 100644 --- a/interpreter/src/lang/vocabulary/item_ops/retrieve_field.rs +++ b/interpreter/src/lang/vocabulary/item_ops/retrieve_field.rs @@ -2,8 +2,8 @@ use std::collections::VecDeque; use crate::lang::utility::{assert_token, assert_token_raw}; use crate::lang::LanguageDictionary; -use crate::lang::{ItemBlockFactory, ItemOpFactory}; use crate::lang::SyntaxError; +use crate::lang::{ItemBlockFactory, ItemOpFactory}; use crate::tokens::Token; use super::VariableRetrieveItemOp; @@ -12,10 +12,7 @@ pub struct FieldRetrieveItemOpFactory; impl ItemOpFactory for FieldRetrieveItemOpFactory { fn is_item_op(&self, tokens: &VecDeque) -> bool { - tokens.len() > 2 - && tokens[0].is_name() - && tokens[1].is_dot() - && tokens[2].is_name() + tokens.len() > 2 && tokens[0].is_name() && tokens[1].is_dot() && tokens[2].is_name() } fn build_item_op( diff --git a/interpreter/src/lang/vocabulary/playlist.rs b/interpreter/src/lang/vocabulary/playlist.rs index 9fa20ab..330ba0c 100644 --- a/interpreter/src/lang/vocabulary/playlist.rs +++ b/interpreter/src/lang/vocabulary/playlist.rs @@ -6,8 +6,8 @@ use crate::tokens::Token; use crate::Context; use crate::lang::LanguageDictionary; -use crate::lang::{FunctionFactory, FunctionStatementFactory, IteratorItem, Op, GeneratorOp}; -use crate::lang::{PseudoOp, RuntimeError, RuntimeOp, SyntaxError, Lookup, TypePrimitive}; +use crate::lang::{FunctionFactory, FunctionStatementFactory, GeneratorOp, IteratorItem, Op}; +use crate::lang::{Lookup, PseudoOp, RuntimeError, RuntimeOp, SyntaxError, TypePrimitive}; //use crate::processing::general::FileIter; use crate::processing::general::Type; @@ -51,13 +51,13 @@ impl Iterator for PlaylistStatement { let ctx = self.context.as_mut().unwrap(); let file = match self.file.get(ctx) { Ok(Type::Primitive(TypePrimitive::String(s))) => s.to_owned(), - Ok(x) => return Some(Err( - RuntimeError { + Ok(x) => { + return Some(Err(RuntimeError { msg: format!("Cannot use {} as filepath", x), line: 0, op: PseudoOp::from_printable(self), - } - )), + })) + } Err(e) => return Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))), }; let iter = ctx.filesystem.read_file(&file); @@ -65,7 +65,7 @@ impl Iterator for PlaylistStatement { Ok(mut x) => { x.enter(self.context.take().unwrap()); x - }, + } Err(e) => return Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))), }); } @@ -145,7 +145,8 @@ impl FunctionFactory for PlaylistFunctionFactory { } } -pub type PlaylistStatementFactory = FunctionStatementFactory; +pub type PlaylistStatementFactory = + FunctionStatementFactory; #[inline(always)] pub fn playlist_function_factory() -> PlaylistStatementFactory { diff --git a/interpreter/src/lang/vocabulary/sorters/bliss_next_sorter.rs b/interpreter/src/lang/vocabulary/sorters/bliss_next_sorter.rs index 8bb2d54..4b58048 100644 --- a/interpreter/src/lang/vocabulary/sorters/bliss_next_sorter.rs +++ b/interpreter/src/lang/vocabulary/sorters/bliss_next_sorter.rs @@ -2,7 +2,7 @@ use std::collections::VecDeque; #[cfg(feature = "advanced")] use std::fmt::{Debug, Display, Error, Formatter}; -use crate::lang::utility::{assert_name, check_name, assert_token_raw}; +use crate::lang::utility::{assert_name, assert_token_raw, check_name}; use crate::lang::SyntaxError; #[cfg(feature = "advanced")] use crate::lang::{IteratorItem, Op, RuntimeMsg, Sorter}; diff --git a/interpreter/src/lang/vocabulary/sorters/bliss_sorter.rs b/interpreter/src/lang/vocabulary/sorters/bliss_sorter.rs index 74374f9..1641cf5 100644 --- a/interpreter/src/lang/vocabulary/sorters/bliss_sorter.rs +++ b/interpreter/src/lang/vocabulary/sorters/bliss_sorter.rs @@ -5,7 +5,7 @@ use std::fmt::{Debug, Display, Error, Formatter}; #[cfg(feature = "advanced")] use std::collections::HashMap; -use crate::lang::utility::{assert_name, check_name, assert_token_raw}; +use crate::lang::utility::{assert_name, assert_token_raw, check_name}; use crate::lang::SyntaxError; #[cfg(feature = "advanced")] use crate::lang::{IteratorItem, Op, RuntimeMsg, Sorter}; diff --git a/interpreter/src/lang/vocabulary/sorters/radio_sorter.rs b/interpreter/src/lang/vocabulary/sorters/radio_sorter.rs index bb42a32..7aedbd0 100644 --- a/interpreter/src/lang/vocabulary/sorters/radio_sorter.rs +++ b/interpreter/src/lang/vocabulary/sorters/radio_sorter.rs @@ -4,16 +4,16 @@ use std::fmt::{Debug, Display, Error, Formatter}; use rand::{thread_rng, Rng}; -use crate::lang::utility::{assert_name, check_name, assert_token_raw, assert_token}; +use crate::lang::utility::{assert_name, assert_token, assert_token_raw, check_name}; use crate::lang::SyntaxError; #[cfg(feature = "advanced")] use crate::lang::{IteratorItem, Op, RuntimeMsg, Sorter}; use crate::lang::{LanguageDictionary, SortStatementFactory, SorterFactory}; +#[cfg(feature = "advanced")] +use crate::processing::advanced::MusicAnalyzerDistance; use crate::tokens::Token; #[cfg(feature = "advanced")] use crate::Item; -#[cfg(feature = "advanced")] -use crate::processing::advanced::MusicAnalyzerDistance; #[cfg(feature = "advanced")] #[derive(Debug)] @@ -124,7 +124,6 @@ impl Sorter for RadioSorter { } } } - } if best_index != 0 { self.item_buf.swap(0, best_index); @@ -170,9 +169,7 @@ pub struct RadioSorterFactory; impl SorterFactory for RadioSorterFactory { fn is_sorter(&self, tokens: &VecDeque<&Token>) -> bool { - tokens.len() > 1 - && tokens[0].is_tilde() - && check_name("radio", tokens[1]) + tokens.len() > 1 && tokens[0].is_tilde() && check_name("radio", tokens[1]) } fn build_sorter( @@ -184,31 +181,38 @@ impl SorterFactory for RadioSorterFactory { assert_name("radio", tokens)?; #[allow(dead_code)] let mode = if !tokens.is_empty() { - Some(assert_token(|t| match t { - Token::Name(n) => match &n as &str { - "tempo" | "beat" => Some(MusicAnalyzerDistance::Tempo), - "spectrum" | "s" => Some(MusicAnalyzerDistance::Spectrum), - "loudness" | "volume" => Some(MusicAnalyzerDistance::Loudness), - "chroma" | "c" => Some(MusicAnalyzerDistance::Chroma), - _ => None + Some(assert_token( + |t| match t { + Token::Name(n) => match &n as &str { + "tempo" | "beat" => Some(MusicAnalyzerDistance::Tempo), + "spectrum" | "s" => Some(MusicAnalyzerDistance::Spectrum), + "loudness" | "volume" => Some(MusicAnalyzerDistance::Loudness), + "chroma" | "c" => Some(MusicAnalyzerDistance::Chroma), + _ => None, + }, + _ => None, }, - _ => None, - }, Token::Name("".into()), tokens)?) + Token::Name("".into()), + tokens, + )?) } else { None }; #[cfg(not(feature = "advanced"))] - {Ok(RadioSorter::default())} + { + Ok(RadioSorter::default()) + } #[cfg(feature = "advanced")] - {Ok(RadioSorter { - comparison: mode, - ..Default::default() - })} + { + Ok(RadioSorter { + comparison: mode, + ..Default::default() + }) + } } } -pub type RadioSorterStatementFactory = - SortStatementFactory; +pub type RadioSorterStatementFactory = SortStatementFactory; #[inline(always)] pub fn radio_sort() -> RadioSorterStatementFactory { diff --git a/interpreter/src/lang/vocabulary/sorters/shuffle.rs b/interpreter/src/lang/vocabulary/sorters/shuffle.rs index 495ce12..20deb00 100644 --- a/interpreter/src/lang/vocabulary/sorters/shuffle.rs +++ b/interpreter/src/lang/vocabulary/sorters/shuffle.rs @@ -3,7 +3,7 @@ use std::fmt::{Debug, Display, Error, Formatter}; use rand::{thread_rng, Rng}; -use crate::lang::utility::{assert_name, check_name, assert_token_raw}; +use crate::lang::utility::{assert_name, assert_token_raw, check_name}; use crate::lang::{IteratorItem, LanguageDictionary, Op}; use crate::lang::{RuntimeMsg, SyntaxError}; use crate::lang::{SortStatementFactory, Sorter, SorterFactory}; diff --git a/interpreter/src/lang/vocabulary/sql_query.rs b/interpreter/src/lang/vocabulary/sql_query.rs index 886a6a0..d2f5074 100644 --- a/interpreter/src/lang/vocabulary/sql_query.rs +++ b/interpreter/src/lang/vocabulary/sql_query.rs @@ -21,10 +21,12 @@ pub struct SqlStatement { impl SqlStatement { fn get_item(&mut self) -> Option { - let result = self.rows.as_mut().unwrap().next().map(|opt| opt.map_err(|mut e| { - e.op = PseudoOp::from_printable(self); - e - })); + let result = self.rows.as_mut().unwrap().next().map(|opt| { + opt.map_err(|mut e| { + e.op = PseudoOp::from_printable(self); + e + }) + }); if result.is_none() { self.is_complete = true; } @@ -47,7 +49,6 @@ impl Op for SqlStatement { } else { self.rows.as_mut().unwrap().escape() } - } fn is_resetable(&self) -> bool { @@ -111,7 +112,10 @@ impl Iterator for SqlStatement { } fn size_hint(&self) -> (usize, Option) { - self.rows.as_ref().map(|x| x.size_hint()).unwrap_or_default() + self.rows + .as_ref() + .map(|x| x.size_hint()) + .unwrap_or_default() } } diff --git a/interpreter/src/lang/vocabulary/sql_simple_query.rs b/interpreter/src/lang/vocabulary/sql_simple_query.rs index ae597bd..c32791c 100644 --- a/interpreter/src/lang/vocabulary/sql_simple_query.rs +++ b/interpreter/src/lang/vocabulary/sql_simple_query.rs @@ -70,10 +70,12 @@ pub struct SimpleSqlStatement { impl SimpleSqlStatement { fn get_item(&mut self) -> Option { - let result = self.rows.as_mut().unwrap().next().map(|opt| opt.map_err(|mut e| { - e.op = PseudoOp::from_printable(self); - e - })); + let result = self.rows.as_mut().unwrap().next().map(|opt| { + opt.map_err(|mut e| { + e.op = PseudoOp::from_printable(self); + e + }) + }); if result.is_none() { self.is_complete = true; } @@ -96,7 +98,6 @@ impl Op for SimpleSqlStatement { } else { self.rows.as_mut().unwrap().escape() } - } fn is_resetable(&self) -> bool { @@ -169,7 +170,10 @@ impl Iterator for SimpleSqlStatement { } fn size_hint(&self) -> (usize, Option) { - self.rows.as_ref().map(|x| x.size_hint()).unwrap_or_default() + self.rows + .as_ref() + .map(|x| x.size_hint()) + .unwrap_or_default() } } diff --git a/interpreter/src/lang/vocabulary/union.rs b/interpreter/src/lang/vocabulary/union.rs index 3b41da9..13fb1f3 100644 --- a/interpreter/src/lang/vocabulary/union.rs +++ b/interpreter/src/lang/vocabulary/union.rs @@ -163,10 +163,12 @@ impl FunctionFactory for UnionFunctionFactory { ) -> Result { // union(op1, op2, ...) let operations = repeated_tokens( - |tokens| if tokens[0].is_close_bracket() { - Ok(None) - } else { - Ok(Some(PseudoOp::from(dict.try_build_statement(tokens)?))) + |tokens| { + if tokens[0].is_close_bracket() { + Ok(None) + } else { + Ok(Some(PseudoOp::from(dict.try_build_statement(tokens)?))) + } }, Token::Comma, ) diff --git a/interpreter/src/lang/vocabulary/variable_iter.rs b/interpreter/src/lang/vocabulary/variable_iter.rs index 3346ffc..57cf0f4 100644 --- a/interpreter/src/lang/vocabulary/variable_iter.rs +++ b/interpreter/src/lang/vocabulary/variable_iter.rs @@ -41,40 +41,62 @@ impl Iterator for VariableRetrieveStatement { if self.is_tried { return None; } - let var = self.context.as_mut() + let var = self + .context + .as_mut() .unwrap() - .variables.remove(&self.variable_name) + .variables + .remove(&self.variable_name) .map_err(|e| e.with(RuntimeOp(PseudoOp::from_printable(self)))); match var { Ok(Type::Op(mut op)) => { op.enter(self.context.take().unwrap()); let next_item = op.next(); self.enter(op.escape()); - if let Err(e) = self.context.as_mut().unwrap().variables.declare(&self.variable_name, Type::Op(op)) { + if let Err(e) = self + .context + .as_mut() + .unwrap() + .variables + .declare(&self.variable_name, Type::Op(op)) + { return Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))); } next_item - }, + } Ok(Type::Item(item)) => { self.is_tried = true; - if let Err(e) = self.context.as_mut().unwrap().variables.declare(&self.variable_name, Type::Item(item.clone())) { + if let Err(e) = self + .context + .as_mut() + .unwrap() + .variables + .declare(&self.variable_name, Type::Item(item.clone())) + { return Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))); } Some(Ok(item)) - }, + } Ok(Type::Primitive(p)) => { self.is_tried = true; - let err_msg = format!("Cannot iterate over primitive `{}` ({})", self.variable_name, p); - if let Err(e) = self.context.as_mut().unwrap().variables.declare(&self.variable_name, Type::Primitive(p)) { + let err_msg = format!( + "Cannot iterate over primitive `{}` ({})", + self.variable_name, p + ); + if let Err(e) = self + .context + .as_mut() + .unwrap() + .variables + .declare(&self.variable_name, Type::Primitive(p)) + { return Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))); } - Some(Err( - RuntimeError { - line: 0, - op: PseudoOp::from_printable(self), - msg: err_msg, - } - )) + Some(Err(RuntimeError { + line: 0, + op: PseudoOp::from_printable(self), + msg: err_msg, + })) } Err(e) => { self.is_tried = true; @@ -114,9 +136,12 @@ impl Op for VariableRetrieveStatement { fn reset(&mut self) -> Result<(), RuntimeError> { self.is_tried = false; let runtime_op = RuntimeOp(PseudoOp::from_printable(self)); - let var = self.context.as_mut() + let var = self + .context + .as_mut() .unwrap() - .variables.get_mut(&self.variable_name) + .variables + .get_mut(&self.variable_name) .map_err(|e| e.with(runtime_op))?; if let Type::Op(op) = var { diff --git a/interpreter/src/music/tag.rs b/interpreter/src/music/tag.rs index b12c682..5dbfd0b 100644 --- a/interpreter/src/music/tag.rs +++ b/interpreter/src/music/tag.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; -use symphonia::core::meta::{Value, Visual, Tag, StandardTagKey}; +use symphonia::core::meta::{StandardTagKey, Tag, Value, Visual}; use crate::lang::db::*; @@ -302,8 +302,7 @@ impl Tags { pub fn album_artist(&self, id: u64, genre_id: u64) -> DbArtistItem { DbArtistItem { artist_id: id, - name: self.albumartist_name() - .unwrap_or("Unknown Artist".into()), + name: self.albumartist_name().unwrap_or("Unknown Artist".into()), genre: genre_id, } } @@ -359,12 +358,12 @@ impl Tags { pub fn export_to_item(self, item: &mut crate::Item, overwrite: bool) { for (key, val) in self.data { if let Some(primitive_val) = val.to_primitive() { - if overwrite || item.field(&key).is_none() { + if overwrite || item.field(&key).is_none() { item.set_field(&key, primitive_val); } } } - if overwrite || item.field("filename").is_none() { + if overwrite || item.field("filename").is_none() { item.set_field("filename", self.filename.display().to_string().into()); } } @@ -396,7 +395,11 @@ impl TagType { #[inline] fn from_symphonia_visual(visual: &Visual) -> Option { - Some(Self::Str(format!("data:{};base64,{}", &visual.media_type, base64::encode_config(&visual.data, BASE64_CONF)))) + Some(Self::Str(format!( + "data:{};base64,{}", + &visual.media_type, + base64::encode_config(&visual.data, BASE64_CONF) + ))) } fn str(&self) -> Option<&str> { diff --git a/interpreter/src/processing/filesystem.rs b/interpreter/src/processing/filesystem.rs index 04a15e7..cc55516 100644 --- a/interpreter/src/processing/filesystem.rs +++ b/interpreter/src/processing/filesystem.rs @@ -1,12 +1,12 @@ use std::fmt::{Debug, Display, Error, Formatter}; use std::fs::{DirEntry, ReadDir}; +use std::io::Read; use std::iter::Iterator; use std::path::{Path, PathBuf}; -use std::io::Read; use regex::Regex; -use crate::lang::{RuntimeMsg, TypePrimitive, GeneratorOp}; +use crate::lang::{GeneratorOp, RuntimeMsg, TypePrimitive}; use crate::Item; const DEFAULT_REGEX: &str = r"/(?P[^/]+)/(?P[^/]+)/(?:(?:(?P\d+)\s+)?(?P\d+)\.?\s+)?(?P[^/]+)\.(?P<format>(?:mp3)|(?:wav)|(?:ogg)|(?:flac)|(?:mp4)|(?:aac))$"; @@ -369,13 +369,24 @@ pub struct FilesystemExecutor {} impl FilesystemExecutor { #[cfg(feature = "collections")] - 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)))?; + 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)))?; - let (_, playlist) = m3u8_rs::parse_playlist(&file_bytes).map_err(|e| RuntimeMsg(format!("Playlist read error: {}", e)))?; + file.read_to_end(&mut file_bytes) + .map_err(|e| RuntimeMsg(format!("File read error: {}", e)))?; + let (_, playlist) = m3u8_rs::parse_playlist(&file_bytes) + .map_err(|e| RuntimeMsg(format!("Playlist read error: {}", e)))?; let playlist = match playlist { - m3u8_rs::Playlist::MasterPlaylist(_) => return Err(RuntimeMsg(format!("Playlist not supported: `{}` is a master (not media) playlist", path.as_ref().display()))), + m3u8_rs::Playlist::MasterPlaylist(_) => { + return Err(RuntimeMsg(format!( + "Playlist not supported: `{}` is a master (not media) playlist", + path.as_ref().display() + ))) + } m3u8_rs::Playlist::MediaPlaylist(l) => l, }; let mut index = 0; @@ -388,7 +399,10 @@ impl FilesystemExecutor { if let Some(s) = joined_path.to_str() { s.to_owned() } else { - return Some(Err(RuntimeMsg(format!("Failed to convert path to string for `{}`", joined_path.display())))); + return Some(Err(RuntimeMsg(format!( + "Failed to convert path to string for `{}`", + joined_path.display() + )))); } } else { segment.uri.clone() @@ -434,10 +448,17 @@ impl FilesystemQuerier for FilesystemExecutor { match &ext.to_lowercase() as &str { #[cfg(feature = "collections")] "m3u8" => self.read_m3u8(path), - ext => Err(RuntimeMsg(format!("Unrecognised extension `{}` in path `{}`", ext, path.display()))) + ext => Err(RuntimeMsg(format!( + "Unrecognised extension `{}` in path `{}`", + ext, + path.display() + ))), } } else { - Err(RuntimeMsg(format!("Unrecognised path `{}`", path.display()))) + Err(RuntimeMsg(format!( + "Unrecognised path `{}`", + path.display() + ))) } } } diff --git a/interpreter/src/processing/mod.rs b/interpreter/src/processing/mod.rs index 935a182..1f1ec23 100644 --- a/interpreter/src/processing/mod.rs +++ b/interpreter/src/processing/mod.rs @@ -11,13 +11,13 @@ mod variables; pub mod database { #[cfg(feature = "mpd")] pub use super::mpd::{MpdExecutor, MpdQuerier}; - pub use super::sql::{DatabaseQuerier, QueryResult}; - #[cfg(feature = "sql")] - pub use super::sql::{SQLiteExecutor}; - #[cfg(feature = "fakesql")] - pub use super::sql::{SQLiteTranspileExecutor}; #[cfg(all(not(feature = "fakesql"), not(feature = "sql")))] - pub use super::sql::{SQLErrExecutor}; + pub use super::sql::SQLErrExecutor; + #[cfg(feature = "sql")] + pub use super::sql::SQLiteExecutor; + #[cfg(feature = "fakesql")] + pub use super::sql::SQLiteTranspileExecutor; + pub use super::sql::{DatabaseQuerier, QueryResult}; } pub mod general { diff --git a/interpreter/src/processing/music_analysis.rs b/interpreter/src/processing/music_analysis.rs index 2cebff7..7115247 100644 --- a/interpreter/src/processing/music_analysis.rs +++ b/interpreter/src/processing/music_analysis.rs @@ -7,7 +7,7 @@ use std::sync::mpsc::{channel, Receiver, Sender}; #[cfg(feature = "bliss-audio-symphonia")] use crate::lang::TypePrimitive; #[cfg(feature = "bliss-audio-symphonia")] -use bliss_audio_symphonia::{BlissError, Song, AnalysisIndex}; +use bliss_audio_symphonia::{AnalysisIndex, BlissError, Song}; // assumed processor threads const DEFAULT_PARALLELISM: usize = 2; @@ -38,7 +38,12 @@ pub trait MusicAnalyzer: Debug + Send { fn get_distance(&mut self, from: &Item, to: &Item) -> Result<f64, RuntimeMsg>; - fn get_custom_distance(&mut self, from: &Item, to: &Item, compare: MusicAnalyzerDistance) -> Result<f64, RuntimeMsg>; + fn get_custom_distance( + &mut self, + from: &Item, + to: &Item, + compare: MusicAnalyzerDistance, + ) -> Result<f64, RuntimeMsg>; fn clear_cache(&mut self) -> Result<(), RuntimeMsg>; } @@ -184,7 +189,12 @@ impl MusicAnalyzer for DefaultAnalyzer { )) } - fn get_custom_distance(&mut self, from: &Item, to: &Item, compare: MusicAnalyzerDistance) -> Result<f64, RuntimeMsg> { + fn get_custom_distance( + &mut self, + from: &Item, + to: &Item, + compare: MusicAnalyzerDistance, + ) -> Result<f64, RuntimeMsg> { self.request_song(from, true)?; self.request_song(to, true)?; let path_from = Self::get_path(from)?; @@ -193,20 +203,19 @@ impl MusicAnalyzer for DefaultAnalyzer { let mut to_song = None; for response in self.responses.iter() { match response { - ResponseType::Distance { .. } => {}, - ResponseType::Song { - path, - song - } => { + ResponseType::Distance { .. } => {} + ResponseType::Song { path, song } => { if path_from == path { - from_song = Some(song.map_err(|e| RuntimeMsg(format!("Bliss error: {}", e)))?); + from_song = + Some(song.map_err(|e| RuntimeMsg(format!("Bliss error: {}", e)))?); } else if path_to == path { - to_song = Some(song.map_err(|e| RuntimeMsg(format!("Bliss error: {}", e)))?); + to_song = + Some(song.map_err(|e| RuntimeMsg(format!("Bliss error: {}", e)))?); } if to_song.is_some() && from_song.is_some() { break; } - }, + } ResponseType::UnsupportedSong { path, msg } => { if path == path_to || path == path_from { return Err(RuntimeMsg(format!("Bliss error: {}", msg))); @@ -218,36 +227,72 @@ impl MusicAnalyzer for DefaultAnalyzer { let to_arr = Self::bliss_song_to_array(&to_song.unwrap()); let from_arr = Self::bliss_song_to_array(&from_song.unwrap()); Ok(match compare { - MusicAnalyzerDistance::Tempo => ( - (to_arr[AnalysisIndex::Tempo as usize] - from_arr[AnalysisIndex::Tempo as usize]).powi(2) - + (to_arr[AnalysisIndex::Zcr as usize] - from_arr[AnalysisIndex::Zcr as usize]).powi(2) - ).sqrt(), - MusicAnalyzerDistance::Spectrum => ( - (to_arr[AnalysisIndex::MeanSpectralCentroid as usize] - from_arr[AnalysisIndex::MeanSpectralCentroid as usize]).powi(2) - + (to_arr[AnalysisIndex::StdDeviationSpectralCentroid as usize] - from_arr[AnalysisIndex::StdDeviationSpectralCentroid as usize]).powi(2) - + (to_arr[AnalysisIndex::MeanSpectralRolloff as usize] - from_arr[AnalysisIndex::MeanSpectralRolloff as usize]).powi(2) - + (to_arr[AnalysisIndex::StdDeviationSpectralRolloff as usize] - from_arr[AnalysisIndex::StdDeviationSpectralRolloff as usize]).powi(2) - + (to_arr[AnalysisIndex::MeanSpectralFlatness as usize] - from_arr[AnalysisIndex::MeanSpectralFlatness as usize]).powi(2) - + (to_arr[AnalysisIndex::StdDeviationSpectralFlatness as usize] - from_arr[AnalysisIndex::StdDeviationSpectralFlatness as usize]).powi(2) - ).sqrt(), + MusicAnalyzerDistance::Tempo => ((to_arr[AnalysisIndex::Tempo as usize] + - from_arr[AnalysisIndex::Tempo as usize]) + .powi(2) + + (to_arr[AnalysisIndex::Zcr as usize] + - from_arr[AnalysisIndex::Zcr as usize]) + .powi(2)) + .sqrt(), + MusicAnalyzerDistance::Spectrum => ((to_arr + [AnalysisIndex::MeanSpectralCentroid as usize] + - from_arr[AnalysisIndex::MeanSpectralCentroid as usize]) + .powi(2) + + (to_arr[AnalysisIndex::StdDeviationSpectralCentroid as usize] + - from_arr[AnalysisIndex::StdDeviationSpectralCentroid as usize]) + .powi(2) + + (to_arr[AnalysisIndex::MeanSpectralRolloff as usize] + - from_arr[AnalysisIndex::MeanSpectralRolloff as usize]) + .powi(2) + + (to_arr[AnalysisIndex::StdDeviationSpectralRolloff as usize] + - from_arr[AnalysisIndex::StdDeviationSpectralRolloff as usize]) + .powi(2) + + (to_arr[AnalysisIndex::MeanSpectralFlatness as usize] + - from_arr[AnalysisIndex::MeanSpectralFlatness as usize]) + .powi(2) + + (to_arr[AnalysisIndex::StdDeviationSpectralFlatness as usize] + - from_arr[AnalysisIndex::StdDeviationSpectralFlatness as usize]) + .powi(2)) + .sqrt(), MusicAnalyzerDistance::Loudness => { - let mean_delta = to_arr[AnalysisIndex::MeanLoudness as usize] - from_arr[AnalysisIndex::MeanLoudness as usize]; - let deviation_delta = to_arr[AnalysisIndex::StdDeviationLoudness as usize] - from_arr[AnalysisIndex::StdDeviationLoudness as usize]; + let mean_delta = to_arr[AnalysisIndex::MeanLoudness as usize] + - from_arr[AnalysisIndex::MeanLoudness as usize]; + let deviation_delta = to_arr[AnalysisIndex::StdDeviationLoudness as usize] + - from_arr[AnalysisIndex::StdDeviationLoudness as usize]; (mean_delta.powi(2) + deviation_delta.powi(2)).sqrt() - }, - MusicAnalyzerDistance::Chroma => ( - (to_arr[AnalysisIndex::Chroma1 as usize] - from_arr[AnalysisIndex::Chroma1 as usize]).powi(2) - + (to_arr[AnalysisIndex::Chroma2 as usize] - from_arr[AnalysisIndex::Chroma2 as usize]).powi(2) - + (to_arr[AnalysisIndex::Chroma3 as usize] - from_arr[AnalysisIndex::Chroma3 as usize]).powi(2) - + (to_arr[AnalysisIndex::Chroma4 as usize] - from_arr[AnalysisIndex::Chroma4 as usize]).powi(2) - + (to_arr[AnalysisIndex::Chroma5 as usize] - from_arr[AnalysisIndex::Chroma5 as usize]).powi(2) - + (to_arr[AnalysisIndex::Chroma6 as usize] - from_arr[AnalysisIndex::Chroma6 as usize]).powi(2) - + (to_arr[AnalysisIndex::Chroma7 as usize] - from_arr[AnalysisIndex::Chroma7 as usize]).powi(2) - + (to_arr[AnalysisIndex::Chroma8 as usize] - from_arr[AnalysisIndex::Chroma8 as usize]).powi(2) - + (to_arr[AnalysisIndex::Chroma9 as usize] - from_arr[AnalysisIndex::Chroma9 as usize]).powi(2) - + (to_arr[AnalysisIndex::Chroma10 as usize] - from_arr[AnalysisIndex::Chroma10 as usize]).powi(2) - ).sqrt(), + } + MusicAnalyzerDistance::Chroma => ((to_arr[AnalysisIndex::Chroma1 as usize] + - from_arr[AnalysisIndex::Chroma1 as usize]) + .powi(2) + + (to_arr[AnalysisIndex::Chroma2 as usize] + - from_arr[AnalysisIndex::Chroma2 as usize]) + .powi(2) + + (to_arr[AnalysisIndex::Chroma3 as usize] + - from_arr[AnalysisIndex::Chroma3 as usize]) + .powi(2) + + (to_arr[AnalysisIndex::Chroma4 as usize] + - from_arr[AnalysisIndex::Chroma4 as usize]) + .powi(2) + + (to_arr[AnalysisIndex::Chroma5 as usize] + - from_arr[AnalysisIndex::Chroma5 as usize]) + .powi(2) + + (to_arr[AnalysisIndex::Chroma6 as usize] + - from_arr[AnalysisIndex::Chroma6 as usize]) + .powi(2) + + (to_arr[AnalysisIndex::Chroma7 as usize] + - from_arr[AnalysisIndex::Chroma7 as usize]) + .powi(2) + + (to_arr[AnalysisIndex::Chroma8 as usize] + - from_arr[AnalysisIndex::Chroma8 as usize]) + .powi(2) + + (to_arr[AnalysisIndex::Chroma9 as usize] + - from_arr[AnalysisIndex::Chroma9 as usize]) + .powi(2) + + (to_arr[AnalysisIndex::Chroma10 as usize] + - from_arr[AnalysisIndex::Chroma10 as usize]) + .powi(2)) + .sqrt(), }) } else { Err(RuntimeMsg( @@ -281,7 +326,12 @@ impl MusicAnalyzer for DefaultAnalyzer { Ok(f64::MAX) } - fn get_custom_distance(&mut self, _from: &Item, _to: &Item, _compare: MusicAnalyzerDistance) -> Result<f64, RuntimeMsg> { + fn get_custom_distance( + &mut self, + _from: &Item, + _to: &Item, + _compare: MusicAnalyzerDistance, + ) -> Result<f64, RuntimeMsg> { Ok(f64::MAX) } diff --git a/interpreter/src/processing/sql/executor.rs b/interpreter/src/processing/sql/executor.rs index 94a8474..033c0c7 100644 --- a/interpreter/src/processing/sql/executor.rs +++ b/interpreter/src/processing/sql/executor.rs @@ -8,8 +8,8 @@ use std::fmt::Write; #[cfg(feature = "sql")] use crate::lang::db::*; -use crate::lang::RuntimeMsg; use crate::lang::Op; +use crate::lang::RuntimeMsg; #[cfg(feature = "sql")] use crate::lang::VecOp; #[cfg(feature = "sql")] @@ -68,10 +68,14 @@ impl SQLiteExecutor { self.gen_db_maybe()?; let conn = self.sqlite_connection.as_mut().unwrap(); match perform_single_param_query(conn, query, param) { - Ok(items) => Ok(Box::new(VecOp::from(items - .into_iter() - .map(|item| item.map_err(|e| RuntimeMsg(format!("SQL item mapping error: {}", e)))) - .collect::<Vec<_>>()))), + Ok(items) => Ok(Box::new(VecOp::from( + items + .into_iter() + .map(|item| { + item.map_err(|e| RuntimeMsg(format!("SQL item mapping error: {}", e))) + }) + .collect::<Vec<_>>(), + ))), Err(e) => Err(RuntimeMsg(e)), } } @@ -84,10 +88,14 @@ impl DatabaseQuerier for SQLiteExecutor { let conn = self.sqlite_connection.as_mut().unwrap(); // execute query match perform_query(conn, query) { - Ok(items) => Ok(Box::new(VecOp::from(items - .into_iter() - .map(|item| item.map_err(|e| RuntimeMsg(format!("SQL item mapping error: {}", e)))) - .collect::<Vec<_>>()))), + Ok(items) => Ok(Box::new(VecOp::from( + items + .into_iter() + .map(|item| { + item.map_err(|e| RuntimeMsg(format!("SQL item mapping error: {}", e))) + }) + .collect::<Vec<_>>(), + ))), Err(e) => Err(RuntimeMsg(e)), } } diff --git a/interpreter/src/processing/sql/raw_emit.rs b/interpreter/src/processing/sql/raw_emit.rs index fe7de8a..3943d46 100644 --- a/interpreter/src/processing/sql/raw_emit.rs +++ b/interpreter/src/processing/sql/raw_emit.rs @@ -1,14 +1,14 @@ +use std::collections::VecDeque; use std::fmt::{Debug, Display, Error, Formatter}; use std::iter::Iterator; -use std::collections::VecDeque; -use sqlparser::{parser::Parser, dialect::SQLiteDialect}; -use sqlparser::ast::{Statement, SetExpr, Expr, OrderByExpr, Value, BinaryOperator}; +use sqlparser::ast::{BinaryOperator, Expr, OrderByExpr, SetExpr, Statement, Value}; +use sqlparser::{dialect::SQLiteDialect, parser::Parser}; use crate::Context; use crate::lang::{IteratorItem, Op, PseudoOp}; -use crate::lang::{RuntimeError, RuntimeOp, RuntimeMsg, TypePrimitive}; +use crate::lang::{RuntimeError, RuntimeMsg, RuntimeOp, TypePrimitive}; use crate::processing::general::FileIter; use crate::Item; @@ -25,7 +25,8 @@ pub struct RawSqlQuery { impl RawSqlQuery { pub fn emit(query_str: &str) -> Result<Self, RuntimeMsg> { - let mut statements = Parser::parse_sql(&SQLiteDialect{}, query_str).map_err(|e| RuntimeMsg(format!("Could not parse SQL query: {}", e)))?; + let mut statements = Parser::parse_sql(&SQLiteDialect {}, query_str) + .map_err(|e| RuntimeMsg(format!("Could not parse SQL query: {}", e)))?; if statements.len() == 1 { if let Statement::Query(mut query) = statements.remove(0) { let matching = if let SetExpr::Select(select) = *query.body { @@ -55,7 +56,10 @@ impl RawSqlQuery { Err(RuntimeMsg("Expected SQL SELECT statement".to_owned())) } } else { - Err(RuntimeMsg(format!("Expected exactly 1 SQL SELECT statement, got {} statements", statements.len()))) + Err(RuntimeMsg(format!( + "Expected exactly 1 SQL SELECT statement, got {} statements", + statements.len() + ))) } } @@ -99,11 +103,12 @@ impl Iterator for RawSqlQuery { } else { self.has_tried = true; } - let iter = self.context.as_mut().unwrap().filesystem.raw( - None, - None, - true, - ); + let iter = self + .context + .as_mut() + .unwrap() + .filesystem + .raw(None, None, true); self.file_iter = Some(match iter { Ok(x) => x, Err(e) => return Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))), @@ -118,12 +123,12 @@ impl Iterator for RawSqlQuery { if self.matches_filters(&item) { self.items_buffer.push_back(Ok(item)); } - }, + } Err(e) => self.items_buffer.push_back(Err(RuntimeError { line: 0, op: PseudoOp::from_printable(self), msg: e, - })) + })), } } let new_len = self.items_buffer.len(); @@ -140,12 +145,14 @@ impl Iterator for RawSqlQuery { if self.matches_filters(&item) { return Some(Ok(item)); } - }, - Err(e) => return Some(Err(RuntimeError { - line: 0, - op: PseudoOp::from_printable(self), - msg: e, - })) + } + Err(e) => { + return Some(Err(RuntimeError { + line: 0, + op: PseudoOp::from_printable(self), + msg: e, + })) + } } } None @@ -153,7 +160,10 @@ impl Iterator for RawSqlQuery { } fn size_hint(&self) -> (usize, Option<usize>) { - self.file_iter.as_ref().map(|x| x.size_hint()).unwrap_or_default() + self.file_iter + .as_ref() + .map(|x| x.size_hint()) + .unwrap_or_default() } } @@ -181,25 +191,51 @@ impl Op for RawSqlQuery { #[derive(Debug, Clone)] enum MatchRule { - Like { field: String, pattern: LikePattern, negated: bool }, - CompareVal { field: String, value: TypePrimitive, comparison: [i8; 2] }, - CompareFields { field_a: String, field_b: String, comparison: [i8; 2] }, - And { a: Box<MatchRule>, b: Box<MatchRule> }, - Or { a: Box<MatchRule>, b: Box<MatchRule> }, + Like { + field: String, + pattern: LikePattern, + negated: bool, + }, + CompareVal { + field: String, + value: TypePrimitive, + comparison: [i8; 2], + }, + CompareFields { + field_a: String, + field_b: String, + comparison: [i8; 2], + }, + And { + a: Box<MatchRule>, + b: Box<MatchRule>, + }, + Or { + a: Box<MatchRule>, + b: Box<MatchRule>, + }, } impl MatchRule { #[inline] fn is_match(&self, item: &Item) -> bool { match self { - Self::Like { field, pattern, negated } => { + Self::Like { + field, + pattern, + negated, + } => { if let Some(TypePrimitive::String(val)) = item.field(field) { pattern.is_match(val) != *negated } else { *negated } - }, - Self::CompareVal { field, value, comparison } => { + } + Self::CompareVal { + field, + value, + comparison, + } => { if let Some(val) = item.field(field) { match val.compare(value) { Ok(cmp) => comparison[0] == cmp || comparison[1] == cmp, @@ -211,8 +247,12 @@ impl MatchRule { Err(_) => comparison[0] != 0 && comparison[1] != 0, } } - }, - Self::CompareFields { field_a, field_b, comparison} => { + } + Self::CompareFields { + field_a, + field_b, + comparison, + } => { if let Some(val_a) = item.field(field_a) { if let Some(val_b) = item.field(field_b) { match val_a.compare(val_b) { @@ -238,84 +278,163 @@ impl MatchRule { } } } - }, - Self::And { a, b } => { - a.is_match(item) && b.is_match(item) - }, - Self::Or { a, b } => { - a.is_match(item) || b.is_match(item) - }, + } + Self::And { a, b } => a.is_match(item) && b.is_match(item), + Self::Or { a, b } => a.is_match(item) || b.is_match(item), } } #[inline] fn from_parsed(expr: Expr) -> Result<Self, RuntimeMsg> { match expr { - Expr::IsFalse(x) => if let Expr::Identifier(id) = *x { - Ok(Self::CompareVal{ field: id.value, value:TypePrimitive::Bool(false), comparison: [0, 0] }) - } else { - Err(RuntimeMsg(format!("Unsupported SQL IS FALSE syntax: {}", x))) + Expr::IsFalse(x) => { + if let Expr::Identifier(id) = *x { + Ok(Self::CompareVal { + field: id.value, + value: TypePrimitive::Bool(false), + comparison: [0, 0], + }) + } else { + Err(RuntimeMsg(format!( + "Unsupported SQL IS FALSE syntax: {}", + x + ))) + } + } + Expr::IsNotFalse(x) => { + if let Expr::Identifier(id) = *x { + Ok(Self::CompareVal { + field: id.value, + value: TypePrimitive::Bool(false), + comparison: [1, -1], + }) + } else { + Err(RuntimeMsg(format!( + "Unsupported SQL IS NOT FALSE syntax: {}", + x + ))) + } + } + Expr::IsTrue(x) => { + if let Expr::Identifier(id) = *x { + Ok(Self::CompareVal { + field: id.value, + value: TypePrimitive::Bool(true), + comparison: [0, 0], + }) + } else { + Err(RuntimeMsg(format!("Unsupported SQL IS TRUE syntax: {}", x))) + } + } + Expr::IsNotTrue(x) => { + if let Expr::Identifier(id) = *x { + Ok(Self::CompareVal { + field: id.value, + value: TypePrimitive::Bool(true), + comparison: [1, -1], + }) + } else { + Err(RuntimeMsg(format!( + "Unsupported SQL IS NOT TRUE syntax: {}", + x + ))) + } + } + Expr::IsNull(x) => { + if let Expr::Identifier(id) = *x { + Ok(Self::CompareVal { + field: id.value, + value: TypePrimitive::Empty, + comparison: [0, 0], + }) + } else { + Err(RuntimeMsg(format!("Unsupported SQL IS NULL syntax: {}", x))) + } + } + Expr::IsNotNull(x) => { + if let Expr::Identifier(id) = *x { + Ok(Self::CompareVal { + field: id.value, + value: TypePrimitive::Empty, + comparison: [1, -1], + }) + } else { + Err(RuntimeMsg(format!( + "Unsupported SQL IS NOT NULL syntax: {}", + x + ))) + } + } + Expr::Like { + negated, + expr, + pattern, + .. + } => match (*expr, *pattern) { + (Expr::Identifier(expr), Expr::Value(Value::SingleQuotedString(pattern))) => { + Ok(Self::Like { + field: expr.value, + negated: negated, + pattern: LikePattern::from_string(pattern), + }) + } + (x, y) => Err(RuntimeMsg(format!( + "Unsupported SQL LIKE syntax: {} LIKE {}", + x, y + ))), }, - Expr::IsNotFalse(x) => if let Expr::Identifier(id) = *x { - Ok(Self::CompareVal{ field: id.value, value:TypePrimitive::Bool(false), comparison: [1, -1] }) - } else { - Err(RuntimeMsg(format!("Unsupported SQL IS NOT FALSE syntax: {}", x))) - }, - Expr::IsTrue(x) => if let Expr::Identifier(id) = *x { - Ok(Self::CompareVal{ field: id.value, value:TypePrimitive::Bool(true), comparison: [0, 0] }) - } else { - Err(RuntimeMsg(format!("Unsupported SQL IS TRUE syntax: {}", x))) - }, - Expr::IsNotTrue(x) => if let Expr::Identifier(id) = *x { - Ok(Self::CompareVal{ field: id.value, value:TypePrimitive::Bool(true), comparison: [1, -1] }) - } else { - Err(RuntimeMsg(format!("Unsupported SQL IS NOT TRUE syntax: {}", x))) - }, - Expr::IsNull(x) => if let Expr::Identifier(id) = *x { - Ok(Self::CompareVal{ field: id.value, value:TypePrimitive::Empty, comparison: [0, 0] }) - } else { - Err(RuntimeMsg(format!("Unsupported SQL IS NULL syntax: {}", x))) - }, - Expr::IsNotNull(x) => if let Expr::Identifier(id) = *x { - Ok(Self::CompareVal{ field: id.value, value:TypePrimitive::Empty, comparison: [1, -1] }) - } else { - Err(RuntimeMsg(format!("Unsupported SQL IS NOT NULL syntax: {}", x))) - }, - Expr::Like { negated, expr, pattern, .. } => match (*expr, *pattern) { - (Expr::Identifier(expr), Expr::Value(Value::SingleQuotedString(pattern))) => - Ok(Self::Like{ field: expr.value, negated: negated, pattern: LikePattern::from_string(pattern) }), - (x, y) => Err(RuntimeMsg(format!("Unsupported SQL LIKE syntax: {} LIKE {}", x, y))) - }, - Expr::ILike { negated, expr, pattern, .. } => match (*expr, *pattern) { - (Expr::Identifier(expr), Expr::Value(Value::SingleQuotedString(pattern))) => - Ok(Self::Like{ field: expr.value, negated: negated, pattern: LikePattern::from_string(pattern) }), - (x, y) => Err(RuntimeMsg(format!("Unsupported SQL ILIKE syntax: {} ILIKE {}", x, y))) + Expr::ILike { + negated, + expr, + pattern, + .. + } => match (*expr, *pattern) { + (Expr::Identifier(expr), Expr::Value(Value::SingleQuotedString(pattern))) => { + Ok(Self::Like { + field: expr.value, + negated: negated, + pattern: LikePattern::from_string(pattern), + }) + } + (x, y) => Err(RuntimeMsg(format!( + "Unsupported SQL ILIKE syntax: {} ILIKE {}", + x, y + ))), }, Expr::Nested(x) => Self::from_parsed(*x), Expr::BinaryOp { left, op, right } => { if let BinaryOperator::And = op { - Ok(Self::And { a: Box::new(Self::from_parsed(*left)?), b: Box::new(Self::from_parsed(*right)?) }) + Ok(Self::And { + a: Box::new(Self::from_parsed(*left)?), + b: Box::new(Self::from_parsed(*right)?), + }) } else if let BinaryOperator::Or = op { - Ok(Self::Or { a: Box::new(Self::from_parsed(*left)?), b: Box::new(Self::from_parsed(*right)?) }) + Ok(Self::Or { + a: Box::new(Self::from_parsed(*left)?), + b: Box::new(Self::from_parsed(*right)?), + }) } else { match (*left, *right) { - (Expr::Identifier(left), Expr::Value(right)) => - Ok(Self::CompareVal { - field: left.value, - value: value_to_primitive(right)?, - comparison: binary_op_to_compare(op)?, - }), - (Expr::Identifier(left), Expr::Identifier(right)) => + (Expr::Identifier(left), Expr::Value(right)) => Ok(Self::CompareVal { + field: left.value, + value: value_to_primitive(right)?, + comparison: binary_op_to_compare(op)?, + }), + (Expr::Identifier(left), Expr::Identifier(right)) => { Ok(Self::CompareFields { field_a: left.value, field_b: right.value, comparison: binary_op_to_compare(op)?, - }), - (x, y) => Err(RuntimeMsg(format!("Unsupported SQL operator syntax: {} {} {}", x, op, y))) + }) + } + (x, y) => Err(RuntimeMsg(format!( + "Unsupported SQL operator syntax: {} {} {}", + x, op, y + ))), } } - }, - x => Err(RuntimeMsg(format!("Unsupported SQL WHERE syntax: {}", x))) + } + x => Err(RuntimeMsg(format!("Unsupported SQL WHERE syntax: {}", x))), } } } @@ -329,7 +448,10 @@ fn binary_op_to_compare(op: BinaryOperator) -> Result<[i8; 2], RuntimeMsg> { BinaryOperator::LtEq => Ok([-1, 0]), BinaryOperator::Eq => Ok([0, 0]), BinaryOperator::NotEq => Ok([-1, 1]), - x => Err(RuntimeMsg(format!("Unsupported SQL operator syntax: {}", x))) + x => Err(RuntimeMsg(format!( + "Unsupported SQL operator syntax: {}", + x + ))), } } @@ -341,7 +463,10 @@ fn value_to_primitive(val: Value) -> Result<TypePrimitive, RuntimeMsg> { Value::DoubleQuotedString(s) => Ok(TypePrimitive::String(s)), Value::Boolean(b) => Ok(TypePrimitive::Bool(b)), Value::Null => Ok(TypePrimitive::Empty), - x => Err(RuntimeMsg(format!("Unsupported SQL operator syntax: {}", x))) + x => Err(RuntimeMsg(format!( + "Unsupported SQL operator syntax: {}", + x + ))), } } @@ -367,9 +492,9 @@ impl LikePattern { #[inline] fn from_string(pattern: String) -> Self { match (pattern.starts_with('%'), pattern.ends_with('%')) { - (false, true) => Self::EndsWith(pattern[..pattern.len()-1].to_owned()), + (false, true) => Self::EndsWith(pattern[..pattern.len() - 1].to_owned()), (true, false) => Self::StartWith(pattern[1..].to_owned()), - (true, true) => Self::Contains(pattern[1..pattern.len()-1].to_owned()), + (true, true) => Self::Contains(pattern[1..pattern.len() - 1].to_owned()), (false, false) => Self::Is(pattern), } } @@ -402,7 +527,7 @@ impl SortRule { } std::cmp::Ordering::Equal }); - }, + } Self::Descending(field) => { buffer.sort_by(|a, b| { if let Ok(a) = a { @@ -427,7 +552,9 @@ impl SortRule { let field = if let Expr::Identifier(id) = order.expr { id.value } else { - return Err(RuntimeMsg(format!("Unsupported SQL syntax: ORDER BY value must be a field identifier"))); + return Err(RuntimeMsg(format!( + "Unsupported SQL syntax: ORDER BY value must be a field identifier" + ))); }; if order.asc.unwrap_or(true) { Ok(Self::Ascending(field)) diff --git a/interpreter/src/processing/sql/simple_emit.rs b/interpreter/src/processing/sql/simple_emit.rs index 21f3952..8420937 100644 --- a/interpreter/src/processing/sql/simple_emit.rs +++ b/interpreter/src/processing/sql/simple_emit.rs @@ -56,11 +56,12 @@ impl Iterator for SimpleSqlQuery { } else { self.has_tried = true; } - let iter = self.context.as_mut().unwrap().filesystem.raw( - None, - None, - true, - ); + let iter = self + .context + .as_mut() + .unwrap() + .filesystem + .raw(None, None, true); self.file_iter = Some(match iter { Ok(x) => x, Err(e) => return Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))), @@ -71,23 +72,30 @@ impl Iterator for SimpleSqlQuery { Ok(item) => { // apply filter if let Some(TypePrimitive::String(field_val)) = item.field(&self.field_name) { - if crate::lang::vocabulary::filters::utility::sanitise_string(field_val).contains(&self.val) { + if crate::lang::vocabulary::filters::utility::sanitise_string(field_val) + .contains(&self.val) + { return Some(Ok(item)); } } - }, - Err(e) => return Some(Err(RuntimeError { - line: 0, - op: PseudoOp::from_printable(self), - msg: e, - })) + } + Err(e) => { + return Some(Err(RuntimeError { + line: 0, + op: PseudoOp::from_printable(self), + msg: e, + })) + } } } None } fn size_hint(&self) -> (usize, Option<usize>) { - self.file_iter.as_ref().map(|x| x.size_hint()).unwrap_or_default() + self.file_iter + .as_ref() + .map(|x| x.size_hint()) + .unwrap_or_default() } } diff --git a/interpreter/tests/single_line.rs b/interpreter/tests/single_line.rs index bb1a8e7..9d049a5 100644 --- a/interpreter/tests/single_line.rs +++ b/interpreter/tests/single_line.rs @@ -110,7 +110,11 @@ fn execute_single_line( #[test] fn execute_sql_line() -> Result<(), InterpreterError> { - execute_single_line("sql(`SELECT * FROM songs WHERE artist IS NOT NULL ORDER BY artist;`)", false, true)?; + execute_single_line( + "sql(`SELECT * FROM songs WHERE artist IS NOT NULL ORDER BY artist;`)", + false, + true, + )?; execute_single_line("sql(`SELECT * FROM songs WHERE artist IS NOT NULL AND format = 'flac' ORDER BY title DESC;`)", false, true) } @@ -873,11 +877,7 @@ fn execute_mpdfunction_line() -> Result<(), InterpreterError> { #[test] fn execute_playlist_line() -> Result<(), InterpreterError> { - execute_single_line( - r"playlist(`~/Music/Playlists/cabello.m3u8`)", - false, - true, - )?; + execute_single_line(r"playlist(`~/Music/Playlists/cabello.m3u8`)", false, true)?; execute_single_line( r"playlist(`/home/ngnius/Music/Playlists/powers.m3u8`)", false, diff --git a/player/Cargo.toml b/player/Cargo.toml index 900c66f..555f7bf 100644 --- a/player/Cargo.toml +++ b/player/Cargo.toml @@ -8,7 +8,7 @@ readme = "README.md" [dependencies] rodio = { version = "^0.16", features = ["symphonia-all"], default-features = false} m3u8-rs = { version = "^3.0" } -mpd = { version = "0.0.12", optional = true } +mpd = { version = "0.1", optional = true } # local muss-interpreter = { path = "../interpreter", version = "0.9.0" } diff --git a/player/src/errors.rs b/player/src/errors.rs index f5e4305..fa29968 100644 --- a/player/src/errors.rs +++ b/player/src/errors.rs @@ -14,8 +14,13 @@ impl PlayerError { Self::Playback(PlaybackError::from_err(err)) } - pub(crate) fn from_file_err_playback<E: Display, P: AsRef<std::path::Path>>(err: E, path: P) -> Self { - Self::Playback(PlaybackError { msg: format!("{}: `{}`", err, path.as_ref().display()) }) + pub(crate) fn from_file_err_playback<E: Display, P: AsRef<std::path::Path>>( + err: E, + path: P, + ) -> Self { + Self::Playback(PlaybackError { + msg: format!("{}: `{}`", err, path.as_ref().display()), + }) } /*pub(crate) fn from_err_uri<E: Display>(err: E) -> Self { diff --git a/player/src/os_controls.rs b/player/src/os_controls.rs index 3a235e9..0a0af09 100644 --- a/player/src/os_controls.rs +++ b/player/src/os_controls.rs @@ -148,7 +148,7 @@ impl SystemControlWrapper { Ok(DbusControl::Die) => break, Ok(DbusControl::SetMetadata(meta)) => { dbus_conn.set_metadata(meta); - }, + } Ok(DbusControl::SetPosition(pos)) => { dbus_conn.set_position(pos); } @@ -171,16 +171,21 @@ impl SystemControlWrapper { playback_time = 0; duration_cache = None; Self::enqueued(item, &dbus_ctrl_tx_clone); - }, + } Ok(PlaybackAction::Empty) => Self::empty(&dbus_ctrl_tx_clone), Ok(PlaybackAction::Time(item, duration)) => { duration_cache = Some(duration); Self::time(item, duration, &dbus_ctrl_tx_clone); - }, + } Ok(PlaybackAction::UpdateTick(item)) => { - Self::time_update(item, playback_time, &duration_cache, &dbus_ctrl_tx_clone); + Self::time_update( + item, + playback_time, + &duration_cache, + &dbus_ctrl_tx_clone, + ); playback_time += 1; - }, + } } } })); @@ -205,25 +210,34 @@ impl SystemControlWrapper { fn build_metadata(item: Item) -> Metadata { let file_uri = item.field("filename").and_then(|x| x.to_owned().to_str()); - let cover_art = item.field("cover") - .and_then(|x| x.to_owned().to_str()); + let cover_art = item.field("cover").and_then(|x| x.to_owned().to_str()); let cover_url = if let Some(art) = &cover_art { const DATA_START: usize = 23; const DATA_PREVIEW: usize = 32; const DATA_PREVIEW_OFFSET: usize = 128; - let preview_slice_start = (DATA_START+DATA_PREVIEW_OFFSET).clamp(0, art.len()-2); - let preview_slide_end = (DATA_START+DATA_PREVIEW+DATA_PREVIEW_OFFSET).clamp(preview_slice_start, art.len()); - let path = format!("{}/muss-cover-{}.jpg", - std::env::var("HOME").map(|home| home + "/.cache").unwrap_or_else(|_| "/tmp".to_owned()), - &art[preview_slice_start..preview_slide_end].replace("/", "")); + let preview_slice_start = (DATA_START + DATA_PREVIEW_OFFSET).clamp(0, art.len() - 2); + let preview_slide_end = (DATA_START + DATA_PREVIEW + DATA_PREVIEW_OFFSET) + .clamp(preview_slice_start, art.len()); + let path = format!( + "{}/muss-cover-{}.jpg", + std::env::var("HOME") + .map(|home| home + "/.cache") + .unwrap_or_else(|_| "/tmp".to_owned()), + &art[preview_slice_start..preview_slide_end].replace("/", "") + ); //let pathbuf = std::path::PathBuf::from(&path); /*if !pathbuf.exists() { } else { Some(path) }*/ - base64::decode(&art[DATA_START..]).ok() - .and_then(|decoded| std::fs::File::create(&path).ok().map(|file| (decoded, file))) + base64::decode(&art[DATA_START..]) + .ok() + .and_then(|decoded| { + std::fs::File::create(&path) + .ok() + .map(|file| (decoded, file)) + }) .and_then(|(decoded, mut file)| file.write(&decoded).ok()) .map(|_| path) } else { @@ -290,12 +304,15 @@ impl SystemControlWrapper { fn time(item: Item, duration: std::time::Duration, dbus_ctrl: &Sender<DbusControl>) { let mut meta = Self::build_metadata(item); meta.length = Some(duration.as_secs_f64().round() as i64 * 1_000_000); - dbus_ctrl - .send(DbusControl::SetMetadata(meta)) - .unwrap_or(()); + dbus_ctrl.send(DbusControl::SetMetadata(meta)).unwrap_or(()); } - fn time_update(_item: Item, new_time: i64, duration: &Option<std::time::Duration>, dbus_ctrl: &Sender<DbusControl>) { + fn time_update( + _item: Item, + new_time: i64, + duration: &Option<std::time::Duration>, + dbus_ctrl: &Sender<DbusControl>, + ) { //println!("Position update tick"); if duration.is_some() { /*let mut meta = Self::build_metadata(item); diff --git a/player/src/player.rs b/player/src/player.rs index 665c7f3..1787e23 100644 --- a/player/src/player.rs +++ b/player/src/player.rs @@ -133,7 +133,14 @@ impl<I: std::iter::Iterator<Item = Result<Item, InterpreterError>>> Player<I> { Ok(enqueued) } - pub fn enqueue_modified(&mut self, count: usize, modify: &dyn Fn(Decoder<io::BufReader<fs::File>>, Item) -> Box<dyn Source<Item=i16> + Send>) -> Result<Vec<Item>, PlayerError> { + pub fn enqueue_modified( + &mut self, + count: usize, + modify: &dyn Fn( + Decoder<io::BufReader<fs::File>>, + Item, + ) -> Box<dyn Source<Item = i16> + Send>, + ) -> Result<Vec<Item>, PlayerError> { let mut items_left = count; let mut enqueued = Vec::with_capacity(count); if items_left == 0 { @@ -245,8 +252,8 @@ impl<I: std::iter::Iterator<Item = Result<Item, InterpreterError>>> Player<I> { match uri.scheme() { Some(s) => match &s.to_lowercase() as &str { "file:" => { - let file = - fs::File::open(uri.without_scheme()).map_err(|e| PlayerError::from_file_err_playback(e, uri.path()))?; + let file = fs::File::open(uri.without_scheme()) + .map_err(|e| PlayerError::from_file_err_playback(e, uri.path()))?; let stream = io::BufReader::new(file); let source = Decoder::new(stream).map_err(PlayerError::from_err_playback)?; self.sink.append(source); @@ -284,13 +291,17 @@ impl<I: std::iter::Iterator<Item = Result<Item, InterpreterError>>> Player<I> { } } - fn append_source_modified(&mut self, filename: &str, modify: &dyn Fn(Decoder<io::BufReader<fs::File>>) -> Box<dyn Source<Item=i16> + Send>) -> Result<(), PlayerError> { + fn append_source_modified( + &mut self, + filename: &str, + modify: &dyn Fn(Decoder<io::BufReader<fs::File>>) -> Box<dyn Source<Item = i16> + Send>, + ) -> Result<(), PlayerError> { let uri = Uri::new(filename); match uri.scheme() { Some(s) => match &s.to_lowercase() as &str { "file:" => { - let file = - fs::File::open(uri.without_scheme()).map_err(|e| PlayerError::from_file_err_playback(e, uri.path()))?; + let file = fs::File::open(uri.without_scheme()) + .map_err(|e| PlayerError::from_file_err_playback(e, uri.path()))?; let stream = io::BufReader::new(file); let source = Decoder::new(stream).map_err(PlayerError::from_err_playback)?; self.sink.append(modify(source)); diff --git a/player/src/player_wrapper.rs b/player/src/player_wrapper.rs index c405cd8..d9abdcb 100644 --- a/player/src/player_wrapper.rs +++ b/player/src/player_wrapper.rs @@ -38,29 +38,35 @@ impl<I: std::iter::Iterator<Item = Result<Item, InterpreterError>>> PlayerServer } } - fn modify(&self) -> impl Fn(rodio::Decoder<std::io::BufReader<std::fs::File>>, Item) -> Box<dyn Source<Item=i16> + Send> { + fn modify( + &self, + ) -> impl Fn( + rodio::Decoder<std::io::BufReader<std::fs::File>>, + Item, + ) -> Box<dyn Source<Item = i16> + Send> { let event = std::sync::Arc::new(std::sync::Mutex::new(self.playback.clone())); move |source_in, item| { let event2 = event.clone(); if let Some(duration) = source_in.total_duration() { - event.lock().map(|event| - event.send( - PlaybackAction::Time(item.clone(), duration) - ).unwrap_or(()) - ).unwrap_or(()); + event + .lock() + .map(|event| { + event + .send(PlaybackAction::Time(item.clone(), duration)) + .unwrap_or(()) + }) + .unwrap_or(()); Box::new( - source_in.periodic_access( - std::time::Duration::from_secs(1), - move |_| - { - //println!("Debug tick"); - event2.lock() - .map(|x| - x.send(PlaybackAction::UpdateTick(item.clone())).unwrap_or(()) - ) - .unwrap_or(()); - } - ) + source_in.periodic_access(std::time::Duration::from_secs(1), move |_| { + //println!("Debug tick"); + event2 + .lock() + .map(|x| { + x.send(PlaybackAction::UpdateTick(item.clone())) + .unwrap_or(()) + }) + .unwrap_or(()); + }), ) } else { // manually calculate length @@ -73,25 +79,28 @@ impl<I: std::iter::Iterator<Item = Result<Item, InterpreterError>>> PlayerServer let sample_rate = source_in2.sample_rate(); let channels = source_in2.channels() as u32; let sample_count = source_in2.count() as f64; - let duration = std::time::Duration::from_secs_f64(sample_count / ((sample_rate * channels) as f64)); - event3.lock().map(|event| - event.send( - PlaybackAction::Time(item2.clone(), duration) - ).unwrap_or(()) - ).unwrap_or(()); + let duration = std::time::Duration::from_secs_f64( + sample_count / ((sample_rate * channels) as f64), + ); + event3 + .lock() + .map(|event| { + event + .send(PlaybackAction::Time(item2.clone(), duration)) + .unwrap_or(()) + }) + .unwrap_or(()); }); Box::new( - source_in.periodic_access( - std::time::Duration::from_secs(1), - move |_| - { - event2.lock() - .map(|x| - x.send(PlaybackAction::UpdateTick(item.clone())).unwrap_or(()) - ) - .unwrap_or(()); - } - ) + source_in.periodic_access(std::time::Duration::from_secs(1), move |_| { + event2 + .lock() + .map(|x| { + x.send(PlaybackAction::UpdateTick(item.clone())) + .unwrap_or(()) + }) + .unwrap_or(()); + }), ) } } diff --git a/src/repl.rs b/src/repl.rs index 27616b9..7647259 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -120,17 +120,11 @@ fn pretty_print_item(item: &Item, terminal: &mut Term, args: &CliArgs, verbose: terminal, " {}: `{}[...]`", field, - &field_str[..max_len-5] + &field_str[..max_len - 5] ) .expect(TERMINAL_WRITE_ERROR); } else { - writeln!( - terminal, - " {}: `{}`", - field, - field_str - ) - .expect(TERMINAL_WRITE_ERROR); + writeln!(terminal, " {}: `{}`", field, field_str).expect(TERMINAL_WRITE_ERROR); } } }