From 58cae6155cac96903ffa1f3629c6dbfdb02bb2c2 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Thu, 20 Jan 2022 19:52:03 -0500 Subject: [PATCH] Replace MpsMusicItem with general-purpose MpsItem and bump version to v0.3.0 --- Cargo.lock | 246 ++++++++++-------- Cargo.toml | 8 +- mps-interpreter/Cargo.toml | 2 +- mps-interpreter/src/interpretor.rs | 4 +- mps-interpreter/src/item.rs | 58 +++++ mps-interpreter/src/lang/filter.rs | 22 +- mps-interpreter/src/lang/filter_replace.rs | 10 +- mps-interpreter/src/lang/mod.rs | 2 +- mps-interpreter/src/lang/operation.rs | 6 +- mps-interpreter/src/lang/single_op.rs | 16 +- mps-interpreter/src/lang/type_primitives.rs | 71 +++++ .../src/lang/vocabulary/comment.rs | 7 +- mps-interpreter/src/lang/vocabulary/files.rs | 7 +- .../lang/vocabulary/filters/empty_filter.rs | 4 +- .../lang/vocabulary/filters/field_filter.rs | 9 +- .../lang/vocabulary/filters/index_filter.rs | 4 +- .../lang/vocabulary/filters/range_filter.rs | 4 +- .../src/lang/vocabulary/filters/utility.rs | 30 --- mps-interpreter/src/lang/vocabulary/repeat.rs | 8 +- .../src/lang/vocabulary/sql_init.rs | 7 +- .../src/lang/vocabulary/sql_query.rs | 12 +- .../src/lang/vocabulary/sql_simple_query.rs | 12 +- .../src/lang/vocabulary/variable_assign.rs | 5 +- mps-interpreter/src/lib.rs | 7 +- mps-interpreter/src/music_item.rs | 33 +++ mps-interpreter/src/processing/filesystem.rs | 140 +++++----- mps-interpreter/src/processing/sql.rs | 39 ++- mps-interpreter/src/runner.rs | 4 +- mps-interpreter/tests/single_line.rs | 5 +- mps-player/Cargo.toml | 4 +- mps-player/src/os_controls.rs | 16 +- mps-player/src/player.rs | 69 +++-- mps-player/src/player_wrapper.rs | 4 +- 33 files changed, 535 insertions(+), 340 deletions(-) create mode 100644 mps-interpreter/src/item.rs diff --git a/Cargo.lock b/Cargo.lock index 77ac895..81f090a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,15 +94,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.8.0" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" [[package]] name = "bytemuck" -version = "1.7.2" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" +checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" [[package]] name = "byteorder" @@ -159,9 +159,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.0.0" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d17bf219fcd37199b9a29e00ba65dfb8cd5b2688b7297ec14ff829c40ac50ca9" +checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375" dependencies = [ "atty", "bitflags", @@ -176,9 +176,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.0.0" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b9752c030a14235a0bd5ef3ad60a1dcac8468c30921327fc8af36b20c790b9" +checksum = "517358c28fcef6607bf6f76108e02afad7e82297d132a6b846dcc1fc3efcd153" dependencies = [ "heck", "proc-macro-error", @@ -195,9 +195,9 @@ checksum = "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688" [[package]] name = "combine" -version = "4.6.2" +version = "4.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b2f5d0ee456f3928812dfc8c6d9a1d592b98678f6d56db9b0cd2b7bc6c8db5" +checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062" dependencies = [ "bytes", "memchr", @@ -259,8 +259,18 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.10.2", + "darling_macro 0.10.2", +] + +[[package]] +name = "darling" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" +dependencies = [ + "darling_core 0.13.1", + "darling_macro 0.13.1", ] [[package]] @@ -277,13 +287,38 @@ dependencies = [ "syn", ] +[[package]] +name = "darling_core" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn", +] + [[package]] name = "darling_macro" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ - "darling_core", + "darling_core 0.10.2", + "quote", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" +dependencies = [ + "darling_core 0.13.1", "quote", "syn", ] @@ -298,17 +333,6 @@ dependencies = [ "libdbus-sys", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "dirs" version = "4.0.0" @@ -352,9 +376,9 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.29" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746" +checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" dependencies = [ "cfg-if", ] @@ -379,9 +403,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" dependencies = [ "cfg-if", "libc", @@ -414,12 +438,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" @@ -444,9 +465,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ "autocfg", "hashbrown", @@ -492,9 +513,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.55" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" dependencies = [ "wasm-bindgen", ] @@ -524,9 +545,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.108" +version = "0.2.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" +checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9" [[package]] name = "libdbus-sys" @@ -539,9 +560,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" dependencies = [ "cfg-if", "winapi", @@ -549,9 +570,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abd5850c449b40bacb498b2bbdfaff648b1b055630073ba8db499caf2d0ea9f2" +checksum = "d2cafc7c74096c336d9d27145f7ebd4f4b6f95ba16aa5a282387267e6925cb58" dependencies = [ "pkg-config", "vcpkg", @@ -634,7 +655,7 @@ dependencies = [ [[package]] name = "mps" -version = "0.2.0" +version = "0.3.0" dependencies = [ "clap", "mps-interpreter", @@ -643,7 +664,7 @@ dependencies = [ [[package]] name = "mps-interpreter" -version = "0.2.0" +version = "0.3.0" dependencies = [ "dirs", "regex", @@ -654,7 +675,7 @@ dependencies = [ [[package]] name = "mps-player" -version = "0.2.0" +version = "0.3.0" dependencies = [ "m3u8-rs", "mpris-player", @@ -669,20 +690,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab" dependencies = [ "jni-sys", - "ndk-sys", + "ndk-sys 0.2.2", "num_enum", "thiserror", ] [[package]] name = "ndk" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64d6af06fde0e527b1ba5c7b79a6cc89cfc46325b0b2887dffe8f70197e0c3c" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" dependencies = [ "bitflags", "jni-sys", - "ndk-sys", + "ndk-sys 0.3.0", "num_enum", "thiserror", ] @@ -697,22 +718,22 @@ dependencies = [ "libc", "log", "ndk 0.3.0", - "ndk-macro", - "ndk-sys", + "ndk-macro 0.2.0", + "ndk-sys 0.2.2", ] [[package]] name = "ndk-glue" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e9e94628f24e7a3cb5b96a2dc5683acd9230bf11991c2a1677b87695138420" +checksum = "04c0d14b0858eb9962a5dac30b809b19f19da7e4547d64af2b0bb051d2e55d79" dependencies = [ "lazy_static", "libc", "log", - "ndk 0.4.0", - "ndk-macro", - "ndk-sys", + "ndk 0.6.0", + "ndk-macro 0.3.0", + "ndk-sys 0.3.0", ] [[package]] @@ -721,19 +742,41 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" dependencies = [ - "darling", + "darling 0.10.2", "proc-macro-crate 0.1.5", "proc-macro2", "quote", "syn", ] +[[package]] +name = "ndk-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" +dependencies = [ + "darling 0.13.1", + "proc-macro-crate 1.1.0", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ndk-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + [[package]] name = "nix" version = "0.20.0" @@ -789,19 +832,18 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9bd055fb730c4f8f4f57d45d35cd6b3f0980535b056dc7ff119cee6a66ed6f" +checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad" dependencies = [ - "derivative", "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9" +checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -811,13 +853,13 @@ dependencies = [ [[package]] name = "oboe" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e15e22bc67e047fe342a32ecba55f555e3be6166b04dd157cd0f803dfa9f48e1" +checksum = "2463c8f2e19b4e0d0710a21f8e4011501ff28db1c95d7a5482a553b2100502d2" dependencies = [ "jni", - "ndk 0.4.0", - "ndk-glue 0.4.0", + "ndk 0.6.0", + "ndk-glue 0.6.0", "num-derive", "num-traits", "oboe-sys", @@ -825,9 +867,9 @@ dependencies = [ [[package]] name = "oboe-sys" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "338142ae5ab0aaedc8275aa8f67f460e43ae0fca76a695a742d56da0a269eadc" +checksum = "3370abb7372ed744232c12954d920d1a40f1c4686de9e79e800021ef492294bd" dependencies = [ "cc", ] @@ -843,9 +885,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" [[package]] name = "os_str_bytes" @@ -889,9 +931,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pkg-config" -version = "0.3.22" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" [[package]] name = "proc-macro-crate" @@ -938,18 +980,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.32" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.10" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" dependencies = [ "proc-macro2", ] @@ -1041,9 +1083,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.130" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" [[package]] name = "shellexpand" @@ -1073,9 +1115,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "stdweb" @@ -1210,9 +1252,9 @@ dependencies = [ [[package]] name = "symphonia-format-wav" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3586e944a951f3ff19ae14d3f46643c063784f119bffb091fc536102909575" +checksum = "6d9fa5e5b420dea6763ba2547887eb1a02a142c676c5b02ed1b113a247101dad" dependencies = [ "log", "symphonia-core", @@ -1243,9 +1285,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.82" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" dependencies = [ "proc-macro2", "quote", @@ -1311,12 +1353,6 @@ dependencies = [ "serde", ] -[[package]] -name = "unicode-segmentation" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" - [[package]] name = "unicode-xid" version = "0.2.2" @@ -1331,9 +1367,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" @@ -1354,9 +1390,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1364,9 +1400,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" dependencies = [ "bumpalo", "lazy_static", @@ -1379,9 +1415,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1389,9 +1425,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" dependencies = [ "proc-macro2", "quote", @@ -1402,15 +1438,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" [[package]] name = "web-sys" -version = "0.3.55" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index b71e5e3..5ef181b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mps" -version = "0.2.0" +version = "0.3.0" edition = "2021" authors = ["NGnius (Graham) "] description = "Music Playlist Scripting language (MPS)" @@ -15,14 +15,14 @@ members = [ [dependencies] # local -mps-interpreter = { version = "0.2.0", path = "./mps-interpreter" } +mps-interpreter = { version = "0.3.0", path = "./mps-interpreter" } # external clap = { version = "3.0", features = ["derive"] } # termios = { version = "^0.3"} [target.'cfg(not(target_os = "linux"))'.dependencies] -mps-player = { version = "0.2.0", path = "./mps-player", default-features = false } +mps-player = { version = "0.3.0", path = "./mps-player", default-features = false } [target.'cfg(target_os = "linux")'.dependencies] # TODO fix need to specify OS-specific dependency of mps-player -mps-player = { version = "0.2.0", path = "./mps-player", features = ["mpris-player"] } +mps-player = { version = "0.3.0", path = "./mps-player", features = ["mpris-player"] } diff --git a/mps-interpreter/Cargo.toml b/mps-interpreter/Cargo.toml index 8ea5b75..0b9303f 100644 --- a/mps-interpreter/Cargo.toml +++ b/mps-interpreter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mps-interpreter" -version = "0.2.0" +version = "0.3.0" edition = "2021" license = "LGPL-2.1-only OR GPL-2.0-or-later" readme = "README.md" diff --git a/mps-interpreter/src/interpretor.rs b/mps-interpreter/src/interpretor.rs index 68505dd..3029cc0 100644 --- a/mps-interpreter/src/interpretor.rs +++ b/mps-interpreter/src/interpretor.rs @@ -6,7 +6,7 @@ use std::path::Path; use super::lang::{MpsLanguageDictionary, MpsLanguageError, MpsOp}; use super::tokens::MpsToken; use super::MpsContext; -use super::MpsMusicItem; +use super::MpsItem; /// The script interpreter. /// Use MpsRunner for a better interface. @@ -81,7 +81,7 @@ impl Iterator for MpsInterpretor where T: crate::tokens::MpsTokenReader, { - type Item = Result>; + type Item = Result>; fn next(&mut self) -> Option { let mut is_stmt_done = false; diff --git a/mps-interpreter/src/item.rs b/mps-interpreter/src/item.rs new file mode 100644 index 0000000..dfcd3be --- /dev/null +++ b/mps-interpreter/src/item.rs @@ -0,0 +1,58 @@ +use std::collections::HashMap; +use std::fmt::{Debug, Display, Error, Formatter}; + +use crate::lang::MpsTypePrimitive; +//use crate::lang::RuntimeError; +//use crate::processing::OpGetter; + +/// general type object for MPS +#[derive(Clone, Debug, Default)] +pub struct MpsItem { + fields: HashMap, +} + +impl MpsItem { + pub fn new() -> Self { + Self::default() + } + + pub fn field(&self, name: &str) -> Option<&MpsTypePrimitive> { + self.fields.get(name) + } + + pub fn set_field(&mut self, name: &str, value: MpsTypePrimitive) -> Option { + self.fields.insert(name.to_owned(), value) + } + + pub fn set_field_chain(&mut self, name: &str, value: MpsTypePrimitive) -> &mut Self { + self.set_field(name, value); + self + } + + pub fn remove_field(&mut self, name: &str) -> Option { + self.fields.remove(name) + } +} + +impl Display for MpsItem { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + write!(f, "MpsItem[({} fields)]", self.fields.len()) + } +} + +/*pub(crate) trait MpsItemRuntimeUtil { + fn get_field_runtime(&self, name: &str, op: &mut OpGetter) -> Result<&MpsTypePrimitive, RuntimeError>; +} + +impl MpsItemRuntimeUtil for MpsItem { + fn get_field_runtime(&self, name: &str, op: &mut OpGetter) -> Result<&MpsTypePrimitive, RuntimeError> { + match self.field(name) { + Some(item) => Ok(item), + None => Err(RuntimeError{ + line: 0, + op: op(), + msg: format!("Field {} not found on item", name), + }) + } + } +}*/ diff --git a/mps-interpreter/src/lang/filter.rs b/mps-interpreter/src/lang/filter.rs index 93c1cf5..8fe5bc9 100644 --- a/mps-interpreter/src/lang/filter.rs +++ b/mps-interpreter/src/lang/filter.rs @@ -5,7 +5,7 @@ use std::marker::PhantomData; use crate::lang::utility::{assert_token, assert_token_raw, check_name, assert_name}; use crate::lang::MpsLanguageDictionary; -use crate::lang::{BoxedMpsOpFactory, MpsOp, PseudoOp}; +use crate::lang::{BoxedMpsOpFactory, MpsOp, PseudoOp, MpsIteratorItem}; use crate::lang::{RuntimeError, SyntaxError}; use crate::lang::SingleItem; use crate::lang::MpsFilterReplaceStatement; @@ -13,14 +13,14 @@ use crate::processing::general::MpsType; use crate::processing::OpGetter; use crate::tokens::MpsToken; use crate::MpsContext; -use crate::MpsMusicItem; +use crate::MpsItem; const INNER_VARIABLE_NAME: &str = "[inner variable]"; pub trait MpsFilterPredicate: Clone + Debug + Display { fn matches( &mut self, - item: &MpsMusicItem, + item: &MpsItem, ctx: &mut MpsContext, op: &mut OpGetter, ) -> Result; @@ -161,7 +161,7 @@ impl MpsOp for MpsFilterStatement

{ } impl Iterator for MpsFilterStatement

{ - type Item = Result; + type Item = MpsIteratorItem; fn next(&mut self) -> Option { if self.predicate.is_complete() && self.other_filters.is_none() { @@ -363,7 +363,7 @@ impl + 'static> BoxedMps if start_of_predicate > tokens_len - 1 { false } else { - let pipe_location_opt = last_double_pipe(tokens, 1); + let pipe_location_opt = first_double_pipe(tokens, 1); if pipe_location_opt.is_some() && pipe_location_opt.unwrap() > start_of_predicate { let pipe_location = pipe_location_opt.unwrap(); // filters combined by OR operations @@ -470,7 +470,7 @@ impl + 'static> BoxedMps } } else { let mut another_filter = None; - let (has_or, end_tokens) = if let Some(pipe_location) = last_double_pipe(tokens, 1) { + let (has_or, end_tokens) = if let Some(pipe_location) = first_double_pipe(tokens, 0) { (true, tokens.split_off(pipe_location)) // parse up to OR operator } else { (false, tokens.split_off(tokens.len()-1)) // don't parse closing bracket in filter @@ -546,21 +546,21 @@ fn last_dot_before_open_bracket(tokens: &VecDeque) -> usize { 0 } -fn last_double_pipe(tokens: &VecDeque, in_brackets: usize) -> Option { +fn first_double_pipe(tokens: &VecDeque, in_brackets: usize) -> Option { let mut inside_brackets = 0; let mut pipe_found = false; - for i in (0..tokens.len()).rev() { + for i in 0..tokens.len() { if tokens[i].is_pipe() && inside_brackets == in_brackets { if pipe_found { - return Some(i); + return Some(i-1); } else { pipe_found = true; } } else { pipe_found = false; - if tokens[i].is_close_bracket() { + if tokens[i].is_open_bracket() { inside_brackets += 1; - } else if tokens[i].is_open_bracket() && inside_brackets != 0 { + } else if tokens[i].is_close_bracket() && inside_brackets != 0 { inside_brackets -= 1; } } diff --git a/mps-interpreter/src/lang/filter_replace.rs b/mps-interpreter/src/lang/filter_replace.rs index 474186c..9372fe0 100644 --- a/mps-interpreter/src/lang/filter_replace.rs +++ b/mps-interpreter/src/lang/filter_replace.rs @@ -2,20 +2,20 @@ use std::collections::VecDeque; use std::fmt::{Debug, Display, Error, Formatter}; use std::iter::Iterator; -use crate::lang::{MpsOp, PseudoOp}; +use crate::lang::{MpsOp, PseudoOp, MpsIteratorItem}; use crate::lang::RuntimeError; use crate::lang::{MpsFilterPredicate, filter::VariableOrOp}; use crate::lang::SingleItem; use crate::processing::general::MpsType; use crate::processing::OpGetter; use crate::MpsContext; -use crate::MpsMusicItem; +use crate::MpsItem; const ITEM_VARIABLE_NAME: &str = "item"; const ITEM_CACHE_DEFAULT_SIZE: usize = 8; #[inline(always)] -pub(super) fn item_cache_deque() -> VecDeque> { +pub(super) fn item_cache_deque() -> VecDeque> { VecDeque::with_capacity(ITEM_CACHE_DEFAULT_SIZE) } @@ -26,7 +26,7 @@ pub struct MpsFilterReplaceStatement { pub(super) context: Option, pub(super) op_if: PseudoOp, pub(super) op_else: Option, - pub(super) item_cache: VecDeque>, + pub(super) item_cache: VecDeque>, } impl std::clone::Clone for MpsFilterReplaceStatement

{ @@ -120,7 +120,7 @@ impl MpsOp for MpsFilterReplaceStatement

{ } impl Iterator for MpsFilterReplaceStatement

{ - type Item = Result; + type Item = MpsIteratorItem; fn next(&mut self) -> Option { if !self.item_cache.is_empty() { diff --git a/mps-interpreter/src/lang/mod.rs b/mps-interpreter/src/lang/mod.rs index d042337..3be9050 100644 --- a/mps-interpreter/src/lang/mod.rs +++ b/mps-interpreter/src/lang/mod.rs @@ -21,7 +21,7 @@ pub use filter::{ pub use filter_replace::MpsFilterReplaceStatement; pub use function::{MpsFunctionFactory, MpsFunctionStatementFactory}; pub use lookup::Lookup; -pub use operation::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory}; +pub use operation::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory, MpsIteratorItem}; pub use pseudo_op::PseudoOp; pub use repeated_meme::{repeated_tokens, RepeatedTokens}; pub use single_op::SingleItem; diff --git a/mps-interpreter/src/lang/operation.rs b/mps-interpreter/src/lang/operation.rs index b438492..5b9cfc8 100644 --- a/mps-interpreter/src/lang/operation.rs +++ b/mps-interpreter/src/lang/operation.rs @@ -7,7 +7,7 @@ use super::PseudoOp; use super::{RuntimeError, SyntaxError}; use crate::tokens::MpsToken; use crate::MpsContext; -use crate::MpsMusicItem; +use crate::MpsItem; pub trait SimpleMpsOpFactory { fn is_op_simple(&self, tokens: &VecDeque) -> bool; @@ -58,7 +58,9 @@ pub trait BoxedMpsOpFactory { fn is_op_boxed(&self, tokens: &VecDeque) -> bool; } -pub trait MpsOp: Iterator> + Debug + Display { +pub type MpsIteratorItem = Result; + +pub trait MpsOp: Iterator + Debug + Display { fn enter(&mut self, ctx: MpsContext); fn escape(&mut self) -> MpsContext; diff --git a/mps-interpreter/src/lang/single_op.rs b/mps-interpreter/src/lang/single_op.rs index 01f82e5..5f89205 100644 --- a/mps-interpreter/src/lang/single_op.rs +++ b/mps-interpreter/src/lang/single_op.rs @@ -1,19 +1,19 @@ use std::fmt::{Debug, Display, Error, Formatter}; use std::iter::Iterator; -use crate::lang::{MpsOp, RuntimeError}; +use crate::lang::{MpsOp, RuntimeError, MpsIteratorItem}; use crate::MpsContext; -use crate::MpsMusicItem; +use crate::MpsItem; #[derive(Debug)] pub struct SingleItem { context: Option, - item: Result, + item: Result, is_complete: bool, } impl SingleItem { - pub fn new(item: Result) -> Self { + pub fn new(item: Result) -> Self { Self { context: None, item: item, @@ -21,11 +21,11 @@ impl SingleItem { } } - pub fn new_ok(item: MpsMusicItem) -> Self { + pub fn new_ok(item: MpsItem) -> Self { Self::new(Ok(item)) } - pub fn replace(&mut self, new_item: Result) { + pub fn replace(&mut self, new_item: Result) { self.item = new_item } } @@ -33,7 +33,7 @@ impl SingleItem { impl Display for SingleItem { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { match &self.item { - Ok(item) => write!(f, "*single item*[Ok({})]", item.filename), + Ok(item) => write!(f, "*single item*[Ok({})]", item), Err(e) => write!(f, "*single-item*[Err({})]", e) } } @@ -50,7 +50,7 @@ impl std::clone::Clone for SingleItem { } impl Iterator for SingleItem { - type Item = Result; + type Item = MpsIteratorItem; fn next(&mut self) -> Option { if self.is_complete { diff --git a/mps-interpreter/src/lang/type_primitives.rs b/mps-interpreter/src/lang/type_primitives.rs index bcd7e55..268a41d 100644 --- a/mps-interpreter/src/lang/type_primitives.rs +++ b/mps-interpreter/src/lang/type_primitives.rs @@ -74,6 +74,47 @@ impl MpsTypePrimitive { )), } } + + pub fn to_str(self) -> Option { + match self { + Self::String(s) => Some(s), + _ => None, + } + } + + pub fn to_u64(self) -> Option { + match self { + Self::UInt(x) => Some(x), + Self::Int(x) => Some(x as _), + Self::Float(x) => Some(x as _), + _ => None, + } + } + + pub fn to_i64(self) -> Option { + match self { + Self::UInt(x) => Some(x as _), + Self::Int(x) => Some(x), + Self::Float(x) => Some(x as _), + _ => None, + } + } + + pub fn parse(s: String) -> Self { + if let Ok(i) = s.parse::() { + Self::Int(i) + } else if let Ok(u) = s.parse::() { + Self::UInt(u) + } else if let Ok(f) = s.parse::() { + Self::Float(f) + } else if s == "false" { + Self::Bool(false) + } else if s == "true" { + Self::Bool(true) + } else { + Self::String(s) + } + } } impl Display for MpsTypePrimitive { @@ -96,3 +137,33 @@ fn map_ordering(ordering: std::cmp::Ordering) -> i8 { std::cmp::Ordering::Greater => 1, } } + +impl std::convert::From for MpsTypePrimitive { + fn from(item: String) -> Self { + Self::String(item) + } +} + +impl std::convert::From for MpsTypePrimitive { + fn from(item: i64) -> Self { + Self::Int(item) + } +} + +impl std::convert::From for MpsTypePrimitive { + fn from(item: u64) -> Self { + Self::UInt(item) + } +} + +impl std::convert::From for MpsTypePrimitive { + fn from(item: f64) -> Self { + Self::Float(item) + } +} + +impl std::convert::From for MpsTypePrimitive { + fn from(item: bool) -> Self { + Self::Bool(item) + } +} diff --git a/mps-interpreter/src/lang/vocabulary/comment.rs b/mps-interpreter/src/lang/vocabulary/comment.rs index 7d0afbf..dff0612 100644 --- a/mps-interpreter/src/lang/vocabulary/comment.rs +++ b/mps-interpreter/src/lang/vocabulary/comment.rs @@ -4,12 +4,11 @@ use std::iter::Iterator; use crate::tokens::MpsToken; use crate::MpsContext; -use crate::MpsMusicItem; use crate::lang::utility::assert_token; use crate::lang::MpsLanguageDictionary; -use crate::lang::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory}; -use crate::lang::{RuntimeError, SyntaxError}; +use crate::lang::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory, MpsIteratorItem}; +use crate::lang::SyntaxError; #[derive(Debug)] pub struct CommentStatement { @@ -45,7 +44,7 @@ impl std::clone::Clone for CommentStatement { } impl Iterator for CommentStatement { - type Item = Result; + type Item = MpsIteratorItem; fn next(&mut self) -> Option { None diff --git a/mps-interpreter/src/lang/vocabulary/files.rs b/mps-interpreter/src/lang/vocabulary/files.rs index 5e012cf..fd688f2 100644 --- a/mps-interpreter/src/lang/vocabulary/files.rs +++ b/mps-interpreter/src/lang/vocabulary/files.rs @@ -4,12 +4,11 @@ use std::iter::Iterator; use crate::tokens::MpsToken; use crate::MpsContext; -use crate::MpsMusicItem; use crate::lang::repeated_tokens; use crate::lang::utility::{assert_token, assert_token_raw}; use crate::lang::MpsLanguageDictionary; -use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp}; +use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, MpsIteratorItem}; use crate::lang::{RuntimeError, SyntaxError}; use crate::processing::general::FileIter; @@ -65,7 +64,7 @@ impl std::clone::Clone for FilesStatement { } impl Iterator for FilesStatement { - type Item = Result; + type Item = MpsIteratorItem; fn next(&mut self) -> Option { if self.file_iter.is_none() { @@ -87,7 +86,7 @@ impl Iterator for FilesStatement { }); } match self.file_iter.as_mut().unwrap().next() { - Some(Ok(item)) => Some(Ok(item)), + Some(Ok(item)) => Some(Ok(item.into())), Some(Err(e)) => Some(Err(RuntimeError { line: 0, op: (Box::new(self.clone()) as Box).into(), diff --git a/mps-interpreter/src/lang/vocabulary/filters/empty_filter.rs b/mps-interpreter/src/lang/vocabulary/filters/empty_filter.rs index f859a36..6d6b5ec 100644 --- a/mps-interpreter/src/lang/vocabulary/filters/empty_filter.rs +++ b/mps-interpreter/src/lang/vocabulary/filters/empty_filter.rs @@ -7,7 +7,7 @@ use crate::lang::{RuntimeError, SyntaxError}; use crate::processing::OpGetter; use crate::tokens::MpsToken; use crate::MpsContext; -use crate::MpsMusicItem; +use crate::MpsItem; #[derive(Debug, Clone)] pub struct EmptyFilter; @@ -21,7 +21,7 @@ impl Display for EmptyFilter { impl MpsFilterPredicate for EmptyFilter { fn matches( &mut self, - _item: &MpsMusicItem, + _item: &MpsItem, _ctx: &mut MpsContext, _op: &mut OpGetter, ) -> Result { diff --git a/mps-interpreter/src/lang/vocabulary/filters/field_filter.rs b/mps-interpreter/src/lang/vocabulary/filters/field_filter.rs index 3291d46..56529b5 100644 --- a/mps-interpreter/src/lang/vocabulary/filters/field_filter.rs +++ b/mps-interpreter/src/lang/vocabulary/filters/field_filter.rs @@ -1,7 +1,7 @@ use std::collections::VecDeque; use std::fmt::{Debug, Display, Error, Formatter}; -use super::utility::{assert_comparison_operator, item_to_primitive_lut}; +use super::utility::assert_comparison_operator; use crate::lang::utility::{assert_token, assert_type, check_is_type}; use crate::lang::MpsLanguageDictionary; use crate::lang::MpsTypePrimitive; @@ -11,7 +11,7 @@ use crate::processing::general::MpsType; use crate::processing::OpGetter; use crate::tokens::MpsToken; use crate::MpsContext; -use crate::MpsMusicItem; +use crate::MpsItem; #[derive(Debug, Clone)] pub(super) enum VariableOrValue { @@ -61,11 +61,10 @@ impl Display for FieldFilter { impl MpsFilterPredicate for FieldFilter { fn matches( &mut self, - item: &MpsMusicItem, + music_item_lut: &MpsItem, ctx: &mut MpsContext, op: &mut OpGetter, ) -> Result { - let music_item_lut = item_to_primitive_lut(item.to_owned()); let variable = match &self.val { VariableOrValue::Variable(name) => match ctx.variables.get(&name, op)? { MpsType::Primitive(t) => Ok(t), @@ -77,7 +76,7 @@ impl MpsFilterPredicate for FieldFilter { }, VariableOrValue::Value(val) => Ok(val), }?; - if let Some(field) = music_item_lut.get(&self.field_name) { + if let Some(field) = music_item_lut.field(&self.field_name) { let compare_res = field.compare(variable); if let Err(e) = compare_res { match self.comparison_errors { diff --git a/mps-interpreter/src/lang/vocabulary/filters/index_filter.rs b/mps-interpreter/src/lang/vocabulary/filters/index_filter.rs index f2ee9ad..d8fafc6 100644 --- a/mps-interpreter/src/lang/vocabulary/filters/index_filter.rs +++ b/mps-interpreter/src/lang/vocabulary/filters/index_filter.rs @@ -8,7 +8,7 @@ use crate::lang::{Lookup, utility::assert_token_raw}; use crate::processing::{OpGetter, general::MpsType}; use crate::tokens::MpsToken; use crate::MpsContext; -use crate::MpsMusicItem; +use crate::MpsItem; #[derive(Debug, Clone)] pub struct IndexFilter { @@ -28,7 +28,7 @@ impl Display for IndexFilter { impl MpsFilterPredicate for IndexFilter { fn matches( &mut self, - _item: &MpsMusicItem, + _item: &MpsItem, ctx: &mut MpsContext, op: &mut OpGetter, ) -> Result { diff --git a/mps-interpreter/src/lang/vocabulary/filters/range_filter.rs b/mps-interpreter/src/lang/vocabulary/filters/range_filter.rs index ea10c4e..a4d78f0 100644 --- a/mps-interpreter/src/lang/vocabulary/filters/range_filter.rs +++ b/mps-interpreter/src/lang/vocabulary/filters/range_filter.rs @@ -9,7 +9,7 @@ use crate::lang::utility::assert_token_raw; use crate::processing::{OpGetter, general::MpsType}; use crate::tokens::MpsToken; use crate::MpsContext; -use crate::MpsMusicItem; +use crate::MpsItem; #[derive(Debug, Clone)] pub struct RangeFilter { @@ -33,7 +33,7 @@ impl Display for RangeFilter { impl MpsFilterPredicate for RangeFilter { fn matches( &mut self, - _item: &MpsMusicItem, + _item: &MpsItem, ctx: &mut MpsContext, op: &mut OpGetter, ) -> Result { diff --git a/mps-interpreter/src/lang/vocabulary/filters/utility.rs b/mps-interpreter/src/lang/vocabulary/filters/utility.rs index 4060843..ccc3e7a 100644 --- a/mps-interpreter/src/lang/vocabulary/filters/utility.rs +++ b/mps-interpreter/src/lang/vocabulary/filters/utility.rs @@ -1,38 +1,8 @@ -use std::collections::HashMap; use std::collections::VecDeque; use crate::lang::utility::assert_token_raw; -use crate::lang::MpsTypePrimitive; use crate::lang::SyntaxError; use crate::tokens::MpsToken; -use crate::MpsMusicItem; - -pub fn item_to_primitive_lut(item: MpsMusicItem) -> HashMap { - let mut result = HashMap::new(); - result.insert("title".into(), MpsTypePrimitive::String(item.title)); - result.insert( - "artist".into(), - MpsTypePrimitive::String(item.artist.unwrap_or("".to_owned())), - ); - result.insert( - "album".into(), - MpsTypePrimitive::String(item.album.unwrap_or("".to_owned())), - ); - result.insert("filename".into(), MpsTypePrimitive::String(item.filename)); - result.insert( - "genre".into(), - MpsTypePrimitive::String(item.genre.unwrap_or("".to_owned())), - ); - result.insert( - "track".into(), - MpsTypePrimitive::UInt(item.track.unwrap_or(0)), - ); - result.insert( - "year".into(), - MpsTypePrimitive::UInt(item.year.unwrap_or(0)), - ); - result -} pub fn assert_comparison_operator(tokens: &mut VecDeque) -> Result<[i8; 2], SyntaxError> { let token1 = tokens.pop_front().unwrap(); diff --git a/mps-interpreter/src/lang/vocabulary/repeat.rs b/mps-interpreter/src/lang/vocabulary/repeat.rs index 65d1ca9..579d472 100644 --- a/mps-interpreter/src/lang/vocabulary/repeat.rs +++ b/mps-interpreter/src/lang/vocabulary/repeat.rs @@ -4,11 +4,11 @@ use std::iter::Iterator; use crate::tokens::MpsToken; use crate::MpsContext; -use crate::MpsMusicItem; +use crate::MpsItem; use crate::lang::utility::{assert_token, assert_token_raw}; use crate::lang::MpsLanguageDictionary; -use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, PseudoOp}; +use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, PseudoOp, MpsIteratorItem}; use crate::lang::{RuntimeError, SyntaxError}; #[derive(Debug)] @@ -16,7 +16,7 @@ pub struct RepeatStatement { inner_statement: PseudoOp, inner_done: bool, context: Option, - cache: Vec, + cache: Vec, cache_position: usize, repetitions: usize, loop_forever: bool, @@ -49,7 +49,7 @@ impl std::clone::Clone for RepeatStatement { } impl Iterator for RepeatStatement { - type Item = Result; + type Item = MpsIteratorItem; fn next(&mut self) -> Option { let real_op = match self.inner_statement.try_real() { diff --git a/mps-interpreter/src/lang/vocabulary/sql_init.rs b/mps-interpreter/src/lang/vocabulary/sql_init.rs index e5430ea..6698c10 100644 --- a/mps-interpreter/src/lang/vocabulary/sql_init.rs +++ b/mps-interpreter/src/lang/vocabulary/sql_init.rs @@ -5,13 +5,12 @@ use std::iter::Iterator; use crate::tokens::MpsToken; use crate::MpsContext; -use crate::MpsMusicItem; use crate::lang::repeated_tokens; use crate::lang::utility::{assert_token, assert_token_raw}; use crate::lang::MpsLanguageDictionary; -use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp}; -use crate::lang::{RuntimeError, SyntaxError}; +use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, MpsIteratorItem}; +use crate::lang::SyntaxError; #[derive(Debug)] pub struct SqlInitStatement { @@ -39,7 +38,7 @@ impl std::clone::Clone for SqlInitStatement { } impl Iterator for SqlInitStatement { - type Item = Result; + type Item = MpsIteratorItem; fn next(&mut self) -> Option { let pseudo_clone = self.clone(); diff --git a/mps-interpreter/src/lang/vocabulary/sql_query.rs b/mps-interpreter/src/lang/vocabulary/sql_query.rs index 93d63ac..af178ed 100644 --- a/mps-interpreter/src/lang/vocabulary/sql_query.rs +++ b/mps-interpreter/src/lang/vocabulary/sql_query.rs @@ -3,23 +3,23 @@ use std::fmt::{Debug, Display, Error, Formatter}; use std::iter::Iterator; use crate::lang::utility::assert_token; -use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsLanguageDictionary, MpsOp}; +use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsLanguageDictionary, MpsOp, MpsIteratorItem}; use crate::lang::{RuntimeError, SyntaxError}; use crate::tokens::MpsToken; use crate::MpsContext; -use crate::MpsMusicItem; +use crate::MpsItem; //use super::db::*; #[derive(Debug)] pub struct SqlStatement { query: String, context: Option, - rows: Option>>, + rows: Option>>, current: usize, } impl SqlStatement { - fn get_item(&mut self, increment: bool) -> Option> { + fn get_item(&mut self, increment: bool) -> Option { if let Some(rows) = &self.rows { if increment { if self.current == rows.len() { @@ -32,7 +32,7 @@ impl SqlStatement { } else { //Some(rows[self.current].clone()) match &rows[self.current] { - Ok(item) => Some(Ok(item.clone())), + Ok(item) => Some(Ok(item.clone().into())), Err(e) => Some(Err(RuntimeError { line: e.line, op: (Box::new(self.clone()) as Box).into(), @@ -82,7 +82,7 @@ impl std::clone::Clone for SqlStatement { } impl Iterator for SqlStatement { - type Item = Result; + type Item = MpsIteratorItem; fn next(&mut self) -> Option { if self.rows.is_some() { diff --git a/mps-interpreter/src/lang/vocabulary/sql_simple_query.rs b/mps-interpreter/src/lang/vocabulary/sql_simple_query.rs index 796a350..2e8d340 100644 --- a/mps-interpreter/src/lang/vocabulary/sql_simple_query.rs +++ b/mps-interpreter/src/lang/vocabulary/sql_simple_query.rs @@ -3,11 +3,11 @@ use std::fmt::{Debug, Display, Error, Formatter}; use std::iter::Iterator; use crate::lang::utility::assert_token; -use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsLanguageDictionary, MpsOp}; +use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsLanguageDictionary, MpsOp, MpsIteratorItem}; use crate::lang::{RuntimeError, SyntaxError}; use crate::tokens::MpsToken; use crate::MpsContext; -use crate::MpsMusicItem; +use crate::MpsItem; #[derive(Debug, Clone)] enum QueryMode { @@ -63,12 +63,12 @@ pub struct SimpleSqlStatement { query: String, mode: QueryMode, context: Option, - rows: Option>>, + rows: Option>>, current: usize, } impl SimpleSqlStatement { - fn get_item(&mut self, increment: bool) -> Option> { + fn get_item(&mut self, increment: bool) -> Option { if let Some(rows) = &self.rows { if increment { if self.current == rows.len() { @@ -81,7 +81,7 @@ impl SimpleSqlStatement { } else { //Some(rows[self.current].clone()) match &rows[self.current] { - Ok(item) => Some(Ok(item.clone())), + Ok(item) => Some(Ok(item.clone().into())), Err(e) => Some(Err(RuntimeError { line: e.line, op: (Box::new(self.clone()) as Box).into(), @@ -132,7 +132,7 @@ impl std::clone::Clone for SimpleSqlStatement { } impl Iterator for SimpleSqlStatement { - type Item = Result; + type Item = MpsIteratorItem; fn next(&mut self) -> Option { if self.rows.is_some() { diff --git a/mps-interpreter/src/lang/vocabulary/variable_assign.rs b/mps-interpreter/src/lang/vocabulary/variable_assign.rs index 4f8369c..6e8d639 100644 --- a/mps-interpreter/src/lang/vocabulary/variable_assign.rs +++ b/mps-interpreter/src/lang/vocabulary/variable_assign.rs @@ -4,11 +4,10 @@ use std::iter::Iterator; use crate::tokens::MpsToken; use crate::MpsContext; -use crate::MpsMusicItem; use crate::lang::utility::{assert_token, assert_token_raw, assert_type, check_is_type}; use crate::lang::MpsLanguageDictionary; -use crate::lang::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, MpsTypePrimitive, PseudoOp}; +use crate::lang::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, MpsTypePrimitive, PseudoOp, MpsIteratorItem}; use crate::lang::{RuntimeError, SyntaxError}; use crate::processing::general::MpsType; @@ -46,7 +45,7 @@ impl std::clone::Clone for AssignStatement { } impl Iterator for AssignStatement { - type Item = Result; + type Item = MpsIteratorItem; fn next(&mut self) -> Option { if let Some(inner_statement) = &mut self.inner_statement { diff --git a/mps-interpreter/src/lib.rs b/mps-interpreter/src/lib.rs index 9e01634..d9617e6 100644 --- a/mps-interpreter/src/lib.rs +++ b/mps-interpreter/src/lib.rs @@ -125,17 +125,20 @@ mod context; mod interpretor; +mod item; pub mod lang; #[cfg(feature = "music_library")] pub mod music; -mod music_item; +//mod music_item; pub mod processing; mod runner; pub mod tokens; pub use context::MpsContext; pub use interpretor::{interpretor, MpsInterpretor}; -pub use music_item::MpsMusicItem; +pub use item::MpsItem; +//pub(crate) use item::MpsItemRuntimeUtil; +//pub use music_item::MpsMusicItem; pub use runner::MpsRunner; #[cfg(test)] diff --git a/mps-interpreter/src/music_item.rs b/mps-interpreter/src/music_item.rs index 8d5de4d..a2af4e8 100644 --- a/mps-interpreter/src/music_item.rs +++ b/mps-interpreter/src/music_item.rs @@ -1,6 +1,7 @@ use super::lang::db::{ DatabaseObj, DbAlbumItem, DbArtistItem, DbGenreItem, DbMetaItem, DbMusicItem, }; +use super::MpsItem; #[derive(Clone, Debug)] pub struct MpsMusicItem { @@ -45,3 +46,35 @@ impl MpsMusicItem { } } } + +impl std::convert::From for MpsMusicItem { + fn from(mut item: MpsItem) -> Self { + let default_str = "".to_string(); + Self { + title: item.remove_field("title").and_then(|x| x.to_str()).unwrap_or(default_str.clone()), + artist: item.remove_field("artist").and_then(|x| x.to_str()), + album: item.remove_field("album").and_then(|x| x.to_str()), + filename: item.remove_field("filename").and_then(|x| x.to_str()).unwrap_or(default_str), + genre: item.remove_field("genre").and_then(|x| x.to_str()), + track: item.remove_field("track").and_then(|x| x.to_u64()), + year: item.remove_field("year").and_then(|x| x.to_u64()), + } + } +} + +impl std::convert::Into for MpsMusicItem { + fn into(self) -> MpsItem { + let mut result = MpsItem::new(); + result.set_field("title", self.title.into()); + result.set_field("filename", self.filename.into()); + + if let Some(artist) = self.artist {result.set_field("artist", artist.into());} + if let Some(album) = self.album {result.set_field("album", album.into());} + if let Some(genre) = self.genre {result.set_field("genre", genre.into());} + + if let Some(track) = self.track {result.set_field("track", track.into());} + if let Some(year) = self.year {result.set_field("year", year.into());} + + result + } +} diff --git a/mps-interpreter/src/processing/filesystem.rs b/mps-interpreter/src/processing/filesystem.rs index b633645..4e4182c 100644 --- a/mps-interpreter/src/processing/filesystem.rs +++ b/mps-interpreter/src/processing/filesystem.rs @@ -6,8 +6,8 @@ use std::path::{Path, PathBuf}; use regex::Regex; use super::OpGetter; -use crate::lang::RuntimeError; -use crate::MpsMusicItem; +use crate::lang::{RuntimeError, MpsTypePrimitive}; +use crate::MpsItem; const DEFAULT_REGEX: &str = r"/(?P[^/]+)/(?P[^/]+)/(?:(?:(?P\d+)\s+)?(?P\d+)\.?\s+)?(?P[^/]+)\.(?P<format>(?:mp3)|(?:wav)|(?:ogg)|(?:flac)|(?:mp4)|(?:aac))$"; @@ -127,7 +127,7 @@ impl FileIter { } } - fn build_item<P: AsRef<Path>>(&self, filepath: P) -> Option<MpsMusicItem> { + fn build_item<P: AsRef<Path>>(&self, filepath: P) -> Option<MpsItem> { let path = filepath.as_ref(); let path_str = path.to_str()?; #[cfg(debug_assertions)] @@ -135,8 +135,9 @@ impl FileIter { panic!("Got non-file path `{}` when building music item", path_str) } let captures = self.pattern.captures(path_str)?; + let capture_names = self.pattern.capture_names(); // populate fields - self.populate_item_impl(path, path_str, captures) + self.populate_item_impl(path, path_str, captures, capture_names) } #[cfg(feature = "music_library")] @@ -145,105 +146,90 @@ impl FileIter { path: &Path, path_str: &str, captures: regex::Captures, - ) -> Option<MpsMusicItem> { + capture_names: regex::CaptureNames, + ) -> Option<MpsItem> { match crate::music::MpsLibrary::read_media_tags(path) { - Ok(tags) => Some(MpsMusicItem { - title: captures - .name("title") - .and_then(|m| Some(m.as_str().to_string())) - .unwrap_or_else(|| tags.track_title()), - artist: captures - .name("artist") - .and_then(|m| Some(m.as_str().to_string())) - .or_else(|| tags.artist_name()), - album: captures - .name("album") - .and_then(|m| Some(m.as_str().to_string())) - .or_else(|| tags.album_title()), - filename: path_str.to_string(), - genre: captures - .name("genre") - .and_then(|m| Some(m.as_str().to_string())) - .or_else(|| tags.genre_title()), - track: match captures.name("track") { - None => tags.track_number(), - Some(m) => match m.as_str().parse::<u64>() { - Ok(u) => Some(u), - Err(_) => tags.track_number(), - }, - }, - year: match captures.name("year") { - None => tags.track_date(), - Some(m) => match m.as_str().parse::<u64>() { - Ok(u) => Some(u), - Err(_) => tags.track_date(), - }, - }, - }), - Err(_) => self.populate_item_impl_simple(path, path_str, captures), + Ok(tags) => { + let mut item = MpsItem::new(); + self.populate_item_impl_simple(&mut item, path_str, captures, capture_names); + if item.field("title").is_none() { + item.set_field("title", tags.track_title().into()); + } + if item.field("artist").is_none() { + if let Some(artist) = tags.artist_name() { + item.set_field("artist", artist.into()); + } + } + if item.field("album").is_none() { + if let Some(album) = tags.album_title() { + item.set_field("album", album.into()); + } + } + if item.field("genre").is_none() { + if let Some(genre) = tags.genre_title() { + item.set_field("genre", genre.into()); + } + } + if item.field("track").is_none() { + if let Some(track) = tags.track_number() { + item.set_field("track", track.into()); + } + } + if item.field("year").is_none() { + if let Some(year) = tags.track_date() { + item.set_field("year", year.into()); + } + } + Some(item) + }, + Err(_) => { + let mut item = MpsItem::new(); + self.populate_item_impl_simple(&mut item, path_str, captures, capture_names); + Some(item) + }, } } #[cfg(not(feature = "music_library"))] fn populate_item_impl( &self, - path: &Path, path_str: &str, captures: regex::Captures, - ) -> Option<MpsMusicItem> { - self.populate_item_impl_simple(path, path_str, captures) + capture_names: regex::CaptureNames, + ) -> Option<MpsItem> { + let mut item = MpsItem::new(); + self.populate_item_impl_simple(&mut item, path_str, captures, capture_names); + Some(item) } #[inline] fn populate_item_impl_simple( &self, - path: &Path, + item: &mut MpsItem, path_str: &str, captures: regex::Captures, - ) -> Option<MpsMusicItem> { - Some(MpsMusicItem { - title: captures - .name("title") - .and_then(|m| Some(m.as_str().to_string())) - .unwrap_or_else(|| Self::default_title(path)), - artist: captures - .name("artist") - .and_then(|m| Some(m.as_str().to_string())), - album: captures - .name("album") - .and_then(|m| Some(m.as_str().to_string())), - filename: path_str.to_string(), - genre: captures - .name("genre") - .and_then(|m| Some(m.as_str().to_string())), - track: match captures.name("track") { - None => None, - Some(m) => match m.as_str().parse::<u64>() { - Ok(u) => Some(u), - Err(_) => None, - }, - }, - year: match captures.name("year") { - None => None, - Some(m) => match m.as_str().parse::<u64>() { - Ok(u) => Some(u), - Err(_) => None, - }, - }, - }) + mut capture_names: regex::CaptureNames, + ) { + // populates fields from named capture groups + while let Some(Some(name)) = capture_names.next() { + if let Some(value) = captures.name(name).and_then(|m| Some(m.as_str().to_string())) { + item.set_field(name, MpsTypePrimitive::parse(value)); + } + } + item.set_field("filename", path_str.to_string().into()); } - fn default_title(path: &Path) -> String { + /*fn default_title(path: &Path) -> String { let extension = path.extension().and_then(|ext| ext.to_str()).unwrap_or(""); path.file_name() .and_then(|file| file.to_str()) .and_then(|file| Some(file.replacen(&format!(".{}", extension), "", 1))) .unwrap_or("Unknown Title".into()) - } + }*/ } impl Iterator for FileIter { - type Item = Result<MpsMusicItem, String>; + type Item = Result<MpsItem, String>; fn next(&mut self) -> Option<Self::Item> { if self.is_complete { diff --git a/mps-interpreter/src/processing/sql.rs b/mps-interpreter/src/processing/sql.rs index aa4b382..12eb834 100644 --- a/mps-interpreter/src/processing/sql.rs +++ b/mps-interpreter/src/processing/sql.rs @@ -3,11 +3,11 @@ use std::collections::{HashMap, HashSet}; use crate::lang::db::*; use crate::lang::RuntimeError; -use crate::MpsMusicItem; +use crate::MpsItem; use super::OpGetter as QueryOp; -pub type QueryResult = Result<Vec<Result<MpsMusicItem, RuntimeError>>, RuntimeError>; +pub type QueryResult = Result<Vec<Result<MpsItem, RuntimeError>>, RuntimeError>; /// SQL querying functionality, loosely de-coupled from any specific SQL dialect (excluding raw call) pub trait MpsDatabaseQuerier: Debug { @@ -250,7 +250,7 @@ impl std::convert::TryInto<rusqlite::Connection> for SqliteSettings { let music_path = self .music_path .and_then(|p| Some(std::path::PathBuf::from(p))) - .unwrap_or_else(|| crate::lang::utility::music_folder()); + .unwrap_or_else(crate::lang::utility::music_folder); let sqlite_path = self .db_path .unwrap_or_else(|| crate::lang::db::DEFAULT_SQLITE_FILEPATH.to_string()); @@ -262,7 +262,7 @@ impl std::convert::TryInto<rusqlite::Connection> for SqliteSettings { fn build_mps_item( conn: &mut rusqlite::Connection, item: DbMusicItem, -) -> rusqlite::Result<MpsMusicItem> { +) -> rusqlite::Result<MpsItem> { // query artist let mut stmt = conn.prepare_cached("SELECT * from artists WHERE artist_id = ?")?; let artist = stmt.query_row([item.artist], DbArtistItem::map_row)?; @@ -276,14 +276,14 @@ fn build_mps_item( let mut stmt = conn.prepare_cached("SELECT * from genres WHERE genre_id = ?")?; let genre = stmt.query_row([item.genre], DbGenreItem::map_row)?; - Ok(MpsMusicItem::merge(item, artist, album, meta, genre)) + Ok(rows_to_item(item, artist, album, meta, genre)) } #[inline] fn perform_query( conn: &mut rusqlite::Connection, query: &str, -) -> Result<Vec<rusqlite::Result<MpsMusicItem>>, String> { +) -> Result<Vec<rusqlite::Result<MpsItem>>, String> { let collection: Vec<rusqlite::Result<DbMusicItem>>; { let mut stmt = conn @@ -306,7 +306,7 @@ fn perform_single_param_query( conn: &mut rusqlite::Connection, query: &str, param: &str, -) -> Result<Vec<rusqlite::Result<MpsMusicItem>>, String> { +) -> Result<Vec<rusqlite::Result<MpsItem>>, String> { let collection: Vec<rusqlite::Result<DbMusicItem>>; { let mut stmt = conn @@ -323,3 +323,28 @@ fn perform_single_param_query( }); Ok(iter2.collect()) } + +fn rows_to_item( + music: DbMusicItem, + artist: DbArtistItem, + album: DbAlbumItem, + meta: DbMetaItem, + genre: DbGenreItem, +) -> MpsItem { + + let mut item = MpsItem::new(); + item + // music row + .set_field_chain("title", music.title.into()) + .set_field_chain("filename", music.filename.into()) + // artist row + .set_field_chain("artist", artist.name.into()) + // album row + .set_field_chain("album", album.title.into()) + // genre row + .set_field_chain("genre", genre.title.into()) + // music metadata + .set_field_chain("track", meta.track.into()) + .set_field_chain("year", meta.date.into()); + item +} diff --git a/mps-interpreter/src/runner.rs b/mps-interpreter/src/runner.rs index fe48cff..fbb9585 100644 --- a/mps-interpreter/src/runner.rs +++ b/mps-interpreter/src/runner.rs @@ -3,7 +3,7 @@ use std::iter::Iterator; use super::lang::{MpsLanguageDictionary, MpsLanguageError}; use super::tokens::{MpsTokenReader, MpsTokenizer}; -use super::{MpsContext, MpsInterpretor, MpsMusicItem}; +use super::{MpsContext, MpsInterpretor, MpsItem}; pub struct MpsRunnerSettings<T: MpsTokenReader> { pub vocabulary: MpsLanguageDictionary, @@ -57,7 +57,7 @@ impl<R: Read> MpsRunner<MpsTokenizer<R>> { } impl<T: MpsTokenReader> Iterator for MpsRunner<T> { - type Item = Result<MpsMusicItem, Box<dyn MpsLanguageError>>; + type Item = Result<MpsItem, Box<dyn MpsLanguageError>>; fn next(&mut self) -> Option<Self::Item> { let mut item = self.interpretor.next(); diff --git a/mps-interpreter/tests/single_line.rs b/mps-interpreter/tests/single_line.rs index 64ec59c..fe894b0 100644 --- a/mps-interpreter/tests/single_line.rs +++ b/mps-interpreter/tests/single_line.rs @@ -62,7 +62,10 @@ fn execute_single_line( break; } } // no need to spam the rest of the songs - println!("Got song `{}` (file: `{}`)", item.title, item.filename); + println!("Got song `{}` (file: `{}`)", + item.field("title").expect("Expected field `title` to exist").clone().to_str().expect("Expected field `title` to be String"), + item.field("filename").expect("Expected field `filename` to exist").clone().to_str().expect("Expected field `filename` to be String") + ); } else { println!("!!! Got error while iterating (executing) !!!"); eprintln!("{}", result.as_ref().err().unwrap()); diff --git a/mps-player/Cargo.toml b/mps-player/Cargo.toml index 2a2bc78..fa88bbc 100644 --- a/mps-player/Cargo.toml +++ b/mps-player/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mps-player" -version = "0.2.0" +version = "0.3.0" edition = "2021" license = "LGPL-2.1-only OR GPL-2.0-or-later" readme = "README.md" @@ -10,7 +10,7 @@ rodio = { version = "^0.14"} m3u8-rs = { version = "^3.0.0" } # local -mps-interpreter = { path = "../mps-interpreter", version = "0.2.0" } +mps-interpreter = { path = "../mps-interpreter", version = "0.3.0" } [target.'cfg(target_os = "linux")'.dependencies] #dbus = { version = "^0.9" } diff --git a/mps-player/src/os_controls.rs b/mps-player/src/os_controls.rs index 010c211..af3336d 100644 --- a/mps-player/src/os_controls.rs +++ b/mps-player/src/os_controls.rs @@ -7,7 +7,7 @@ use std::thread::JoinHandle; use mpris_player::{MprisPlayer, PlaybackStatus, Metadata}; #[cfg(all(target_os = "linux", feature = "os-controls"))] -use mps_interpreter::MpsMusicItem; +use mps_interpreter::MpsItem; //use super::MpsController; use super::player_wrapper::{ControlAction, PlaybackAction}; @@ -177,20 +177,20 @@ impl SystemControlWrapper { } } - fn enqueued(item: MpsMusicItem, dbus_ctrl: &Sender<DbusControl>) { + fn enqueued(item: MpsItem, dbus_ctrl: &Sender<DbusControl>) { //println!("Got enqueued item {}", &item.title); dbus_ctrl.send(DbusControl::SetMetadata(Metadata { length: None, art_url: None, - album: item.album, + album: item.field("album").and_then(|x| x.to_owned().to_str()), album_artist: None, // TODO maybe? - artist: item.artist.map(|artist| vec![artist]), + artist: item.field("artist").and_then(|x| x.to_owned().to_str()).map(|x| vec![x]), composer: None, disc_number: None, - genre: item.genre.map(|genre| vec![genre]), - title: Some(item.title), - track_number: item.track.map(|track| track as i32), - url: Some(item.filename), + genre: item.field("genre").and_then(|x| x.to_owned().to_str()).map(|genre| vec![genre]), + title: item.field("title").and_then(|x| x.to_owned().to_str()), + track_number: item.field("track").and_then(|x| x.to_owned().to_i64()).map(|track| track as i32), + url: item.field("filename").and_then(|x| x.to_owned().to_str()), })).unwrap_or(()); } diff --git a/mps-player/src/player.rs b/mps-player/src/player.rs index 95ca607..ffb9e7a 100644 --- a/mps-player/src/player.rs +++ b/mps-player/src/player.rs @@ -5,7 +5,7 @@ use rodio::{decoder::Decoder, OutputStream, OutputStreamHandle, Sink}; use m3u8_rs::{MediaPlaylist, MediaSegment}; -use mps_interpreter::{tokens::MpsTokenReader, MpsRunner, MpsMusicItem}; +use mps_interpreter::{tokens::MpsTokenReader, MpsRunner, MpsItem}; use super::PlaybackError; @@ -36,12 +36,15 @@ impl<T: MpsTokenReader> MpsPlayer<T> { self.sink.sleep_until_end(); match item { Ok(music) => { - let file = fs::File::open(music.filename).map_err(PlaybackError::from_err)?; - let stream = io::BufReader::new(file); - let source = Decoder::new(stream).map_err(PlaybackError::from_err)?; - self.sink.append(source); - //self.sink.play(); // idk if this is necessary - Ok(()) + if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) { + let file = fs::File::open(filename).map_err(PlaybackError::from_err)?; + let stream = io::BufReader::new(file); + let source = Decoder::new(stream).map_err(PlaybackError::from_err)?; + self.sink.append(source); + Ok(()) + } else { + Err(PlaybackError::from_err("Field `filename` does not exist on item")) + } } Err(e) => Err(PlaybackError::from_err(e)), }?; @@ -50,18 +53,21 @@ impl<T: MpsTokenReader> MpsPlayer<T> { Ok(()) } - pub fn enqueue_all(&mut self) -> Result<Vec<MpsMusicItem>, PlaybackError> { + pub fn enqueue_all(&mut self) -> Result<Vec<MpsItem>, PlaybackError> { let mut enqueued = Vec::new(); for item in &mut self.runner { match item { Ok(music) => { enqueued.push(music.clone()); - let file = fs::File::open(music.filename).map_err(PlaybackError::from_err)?; - let stream = io::BufReader::new(file); - let source = Decoder::new(stream).map_err(PlaybackError::from_err)?; - self.sink.append(source); - //self.sink.play(); // idk if this is necessary - Ok(()) + if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) { + let file = fs::File::open(filename).map_err(PlaybackError::from_err)?; + let stream = io::BufReader::new(file); + let source = Decoder::new(stream).map_err(PlaybackError::from_err)?; + self.sink.append(source); + Ok(()) + } else { + Err(PlaybackError::from_err("Field `filename` does not exist on item")) + } } Err(e) => Err(PlaybackError::from_err(e)), }?; @@ -69,7 +75,7 @@ impl<T: MpsTokenReader> MpsPlayer<T> { Ok(enqueued) } - pub fn enqueue(&mut self, count: usize) -> Result<Vec<MpsMusicItem>, PlaybackError> { + pub fn enqueue(&mut self, count: usize) -> Result<Vec<MpsItem>, PlaybackError> { let mut items_left = count; let mut enqueued = Vec::with_capacity(count); if items_left == 0 { @@ -79,12 +85,15 @@ impl<T: MpsTokenReader> MpsPlayer<T> { match item { Ok(music) => { enqueued.push(music.clone()); - let file = fs::File::open(music.filename).map_err(PlaybackError::from_err)?; - let stream = io::BufReader::new(file); - let source = Decoder::new(stream).map_err(PlaybackError::from_err)?; - self.sink.append(source); - //self.sink.play(); // idk if this is necessary - Ok(()) + if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) { + let file = fs::File::open(filename).map_err(PlaybackError::from_err)?; + let stream = io::BufReader::new(file); + let source = Decoder::new(stream).map_err(PlaybackError::from_err)?; + self.sink.append(source); + Ok(()) + } else { + Err(PlaybackError::from_err("Field `filename` does not exist on item")) + } } Err(e) => Err(PlaybackError::from_err(e)), }?; @@ -130,12 +139,16 @@ impl<T: MpsTokenReader> MpsPlayer<T> { for item in &mut self.runner { match item { Ok(music) => { - playlist.segments.push(MediaSegment { - uri: music.filename, - title: Some(music.title), - ..Default::default() - }); - Ok(()) + if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) { + playlist.segments.push(MediaSegment { + uri: filename, + title: music.field("title").and_then(|x| x.to_owned().to_str()), + ..Default::default() + }); + Ok(()) + } else { + Err(PlaybackError::from_err("Field `filename` does not exist on item")) + } } Err(e) => Err(PlaybackError::from_err(e)), }?; @@ -173,7 +186,7 @@ mod tests { use std::io; #[allow(dead_code)] - #[test] + //#[test] fn play_cursor() -> Result<(), PlaybackError> { let cursor = io::Cursor::new("sql(`SELECT * FROM songs JOIN artists ON songs.artist = artists.artist_id WHERE artists.name like 'thundercat'`);"); let runner = MpsRunner::with_stream(cursor); diff --git a/mps-player/src/player_wrapper.rs b/mps-player/src/player_wrapper.rs index 332a09c..0a498fd 100644 --- a/mps-player/src/player_wrapper.rs +++ b/mps-player/src/player_wrapper.rs @@ -2,7 +2,7 @@ use std::sync::mpsc::{Receiver, Sender}; use std::{thread, thread::JoinHandle}; use mps_interpreter::tokens::MpsTokenReader; -use mps_interpreter::MpsMusicItem; +use mps_interpreter::MpsItem; use super::MpsPlayer; use super::PlaybackError; @@ -215,7 +215,7 @@ pub enum PlayerAction { #[derive(Clone, Debug)] pub enum PlaybackAction { Empty, - Enqueued(MpsMusicItem), + Enqueued(MpsItem), Exit, }