Replace MpsMusicItem with general-purpose MpsItem and bump version to v0.3.0

This commit is contained in:
NGnius (Graham) 2022-01-20 19:52:03 -05:00
parent 9afda71f6a
commit 58cae6155c
33 changed files with 535 additions and 340 deletions

246
Cargo.lock generated
View file

@ -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",

View file

@ -1,6 +1,6 @@
[package]
name = "mps"
version = "0.2.0"
version = "0.3.0"
edition = "2021"
authors = ["NGnius (Graham) <ngniusness@gmail.com>"]
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"] }

View file

@ -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"

View file

@ -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<T> Iterator for MpsInterpretor<T>
where
T: crate::tokens::MpsTokenReader,
{
type Item = Result<MpsMusicItem, Box<dyn MpsLanguageError>>;
type Item = Result<MpsItem, Box<dyn MpsLanguageError>>;
fn next(&mut self) -> Option<Self::Item> {
let mut is_stmt_done = false;

View file

@ -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<String, MpsTypePrimitive>,
}
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<MpsTypePrimitive> {
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<MpsTypePrimitive> {
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),
})
}
}
}*/

View file

@ -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<bool, RuntimeError>;
@ -161,7 +161,7 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterStatement<P> {
}
impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterStatement<P> {
type Item = Result<MpsMusicItem, RuntimeError>;
type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> {
if self.predicate.is_complete() && self.other_filters.is_none() {
@ -363,7 +363,7 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + '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<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + '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<MpsToken>) -> usize {
0
}
fn last_double_pipe(tokens: &VecDeque<MpsToken>, in_brackets: usize) -> Option<usize> {
fn first_double_pipe(tokens: &VecDeque<MpsToken>, in_brackets: usize) -> Option<usize> {
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;
}
}

View file

@ -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<Result<MpsMusicItem, RuntimeError>> {
pub(super) fn item_cache_deque() -> VecDeque<Result<MpsItem, RuntimeError>> {
VecDeque::with_capacity(ITEM_CACHE_DEFAULT_SIZE)
}
@ -26,7 +26,7 @@ pub struct MpsFilterReplaceStatement<P: MpsFilterPredicate + 'static> {
pub(super) context: Option<MpsContext>,
pub(super) op_if: PseudoOp,
pub(super) op_else: Option<PseudoOp>,
pub(super) item_cache: VecDeque<Result<MpsMusicItem, RuntimeError>>,
pub(super) item_cache: VecDeque<Result<MpsItem, RuntimeError>>,
}
impl<P: MpsFilterPredicate + 'static> std::clone::Clone for MpsFilterReplaceStatement<P> {
@ -120,7 +120,7 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterReplaceStatement<P> {
}
impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterReplaceStatement<P> {
type Item = Result<MpsMusicItem, RuntimeError>;
type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> {
if !self.item_cache.is_empty() {

View file

@ -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;

View file

@ -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<T: MpsOp + 'static> {
fn is_op_simple(&self, tokens: &VecDeque<MpsToken>) -> bool;
@ -58,7 +58,9 @@ pub trait BoxedMpsOpFactory {
fn is_op_boxed(&self, tokens: &VecDeque<MpsToken>) -> bool;
}
pub trait MpsOp: Iterator<Item = Result<MpsMusicItem, RuntimeError>> + Debug + Display {
pub type MpsIteratorItem = Result<MpsItem, RuntimeError>;
pub trait MpsOp: Iterator<Item = MpsIteratorItem> + Debug + Display {
fn enter(&mut self, ctx: MpsContext);
fn escape(&mut self) -> MpsContext;

View file

@ -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<MpsContext>,
item: Result<MpsMusicItem, RuntimeError>,
item: Result<MpsItem, RuntimeError>,
is_complete: bool,
}
impl SingleItem {
pub fn new(item: Result<MpsMusicItem, RuntimeError>) -> Self {
pub fn new(item: Result<MpsItem, RuntimeError>) -> 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<MpsMusicItem, RuntimeError>) {
pub fn replace(&mut self, new_item: Result<MpsItem, RuntimeError>) {
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<MpsMusicItem, RuntimeError>;
type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> {
if self.is_complete {

View file

@ -74,6 +74,47 @@ impl MpsTypePrimitive {
)),
}
}
pub fn to_str(self) -> Option<String> {
match self {
Self::String(s) => Some(s),
_ => None,
}
}
pub fn to_u64(self) -> Option<u64> {
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<i64> {
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::<i64>() {
Self::Int(i)
} else if let Ok(u) = s.parse::<u64>() {
Self::UInt(u)
} else if let Ok(f) = s.parse::<f64>() {
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<String> for MpsTypePrimitive {
fn from(item: String) -> Self {
Self::String(item)
}
}
impl std::convert::From<i64> for MpsTypePrimitive {
fn from(item: i64) -> Self {
Self::Int(item)
}
}
impl std::convert::From<u64> for MpsTypePrimitive {
fn from(item: u64) -> Self {
Self::UInt(item)
}
}
impl std::convert::From<f64> for MpsTypePrimitive {
fn from(item: f64) -> Self {
Self::Float(item)
}
}
impl std::convert::From<bool> for MpsTypePrimitive {
fn from(item: bool) -> Self {
Self::Bool(item)
}
}

View file

@ -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<MpsMusicItem, RuntimeError>;
type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> {
None

View file

@ -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<MpsMusicItem, RuntimeError>;
type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> {
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<dyn MpsOp>).into(),

View file

@ -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<bool, RuntimeError> {

View file

@ -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<bool, RuntimeError> {
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 {

View file

@ -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<bool, RuntimeError> {

View file

@ -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<bool, RuntimeError> {

View file

@ -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<String, MpsTypePrimitive> {
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<MpsToken>) -> Result<[i8; 2], SyntaxError> {
let token1 = tokens.pop_front().unwrap();

View file

@ -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<MpsContext>,
cache: Vec<MpsMusicItem>,
cache: Vec<MpsItem>,
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<MpsMusicItem, RuntimeError>;
type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> {
let real_op = match self.inner_statement.try_real() {

View file

@ -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<MpsMusicItem, RuntimeError>;
type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> {
let pseudo_clone = self.clone();

View file

@ -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<MpsContext>,
rows: Option<Vec<Result<MpsMusicItem, RuntimeError>>>,
rows: Option<Vec<Result<MpsItem, RuntimeError>>>,
current: usize,
}
impl SqlStatement {
fn get_item(&mut self, increment: bool) -> Option<Result<MpsMusicItem, RuntimeError>> {
fn get_item(&mut self, increment: bool) -> Option<MpsIteratorItem> {
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<dyn MpsOp>).into(),
@ -82,7 +82,7 @@ impl std::clone::Clone for SqlStatement {
}
impl Iterator for SqlStatement {
type Item = Result<MpsMusicItem, RuntimeError>;
type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> {
if self.rows.is_some() {

View file

@ -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<MpsContext>,
rows: Option<Vec<Result<MpsMusicItem, RuntimeError>>>,
rows: Option<Vec<Result<MpsItem, RuntimeError>>>,
current: usize,
}
impl SimpleSqlStatement {
fn get_item(&mut self, increment: bool) -> Option<Result<MpsMusicItem, RuntimeError>> {
fn get_item(&mut self, increment: bool) -> Option<MpsIteratorItem> {
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<dyn MpsOp>).into(),
@ -132,7 +132,7 @@ impl std::clone::Clone for SimpleSqlStatement {
}
impl Iterator for SimpleSqlStatement {
type Item = Result<MpsMusicItem, RuntimeError>;
type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> {
if self.rows.is_some() {

View file

@ -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<MpsMusicItem, RuntimeError>;
type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> {
if let Some(inner_statement) = &mut self.inner_statement {

View file

@ -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)]

View file

@ -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<MpsItem> 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<MpsItem> 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
}
}

View file

@ -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<artist>[^/]+)/(?P<album>[^/]+)/(?:(?:(?P<disc>\d+)\s+)?(?P<track>\d+)\.?\s+)?(?P<title>[^/]+)\.(?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 {

View file

@ -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
}

View file

@ -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();

View file

@ -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());

View file

@ -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" }

View file

@ -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(());
}

View file

@ -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);

View file

@ -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,
}