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]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.8.0" version = "3.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
[[package]] [[package]]
name = "bytemuck" name = "bytemuck"
version = "1.7.2" version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
@ -159,9 +159,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "3.0.0" version = "3.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d17bf219fcd37199b9a29e00ba65dfb8cd5b2688b7297ec14ff829c40ac50ca9" checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375"
dependencies = [ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
@ -176,9 +176,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "3.0.0" version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1b9752c030a14235a0bd5ef3ad60a1dcac8468c30921327fc8af36b20c790b9" checksum = "517358c28fcef6607bf6f76108e02afad7e82297d132a6b846dcc1fc3efcd153"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro-error", "proc-macro-error",
@ -195,9 +195,9 @@ checksum = "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688"
[[package]] [[package]]
name = "combine" name = "combine"
version = "4.6.2" version = "4.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2b2f5d0ee456f3928812dfc8c6d9a1d592b98678f6d56db9b0cd2b7bc6c8db5" checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062"
dependencies = [ dependencies = [
"bytes", "bytes",
"memchr", "memchr",
@ -259,8 +259,18 @@ version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
dependencies = [ dependencies = [
"darling_core", "darling_core 0.10.2",
"darling_macro", "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]] [[package]]
@ -277,13 +287,38 @@ dependencies = [
"syn", "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]] [[package]]
name = "darling_macro" name = "darling_macro"
version = "0.10.2" version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
dependencies = [ 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", "quote",
"syn", "syn",
] ]
@ -298,17 +333,6 @@ dependencies = [
"libdbus-sys", "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]] [[package]]
name = "dirs" name = "dirs"
version = "4.0.0" version = "4.0.0"
@ -352,9 +376,9 @@ dependencies = [
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.29" version = "0.8.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746" checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@ -379,9 +403,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.3" version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@ -414,12 +438,9 @@ dependencies = [
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.3.3" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
dependencies = [
"unicode-segmentation",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
@ -444,9 +465,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.7.0" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@ -492,9 +513,9 @@ dependencies = [
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.55" version = "0.3.56"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04"
dependencies = [ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
@ -524,9 +545,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.108" version = "0.2.113"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9"
[[package]] [[package]]
name = "libdbus-sys" name = "libdbus-sys"
@ -539,9 +560,9 @@ dependencies = [
[[package]] [[package]]
name = "libloading" name = "libloading"
version = "0.7.2" version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52" checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"winapi", "winapi",
@ -549,9 +570,9 @@ dependencies = [
[[package]] [[package]]
name = "libsqlite3-sys" name = "libsqlite3-sys"
version = "0.23.1" version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abd5850c449b40bacb498b2bbdfaff648b1b055630073ba8db499caf2d0ea9f2" checksum = "d2cafc7c74096c336d9d27145f7ebd4f4b6f95ba16aa5a282387267e6925cb58"
dependencies = [ dependencies = [
"pkg-config", "pkg-config",
"vcpkg", "vcpkg",
@ -634,7 +655,7 @@ dependencies = [
[[package]] [[package]]
name = "mps" name = "mps"
version = "0.2.0" version = "0.3.0"
dependencies = [ dependencies = [
"clap", "clap",
"mps-interpreter", "mps-interpreter",
@ -643,7 +664,7 @@ dependencies = [
[[package]] [[package]]
name = "mps-interpreter" name = "mps-interpreter"
version = "0.2.0" version = "0.3.0"
dependencies = [ dependencies = [
"dirs", "dirs",
"regex", "regex",
@ -654,7 +675,7 @@ dependencies = [
[[package]] [[package]]
name = "mps-player" name = "mps-player"
version = "0.2.0" version = "0.3.0"
dependencies = [ dependencies = [
"m3u8-rs", "m3u8-rs",
"mpris-player", "mpris-player",
@ -669,20 +690,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab" checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab"
dependencies = [ dependencies = [
"jni-sys", "jni-sys",
"ndk-sys", "ndk-sys 0.2.2",
"num_enum", "num_enum",
"thiserror", "thiserror",
] ]
[[package]] [[package]]
name = "ndk" name = "ndk"
version = "0.4.0" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d64d6af06fde0e527b1ba5c7b79a6cc89cfc46325b0b2887dffe8f70197e0c3c" checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"jni-sys", "jni-sys",
"ndk-sys", "ndk-sys 0.3.0",
"num_enum", "num_enum",
"thiserror", "thiserror",
] ]
@ -697,22 +718,22 @@ dependencies = [
"libc", "libc",
"log", "log",
"ndk 0.3.0", "ndk 0.3.0",
"ndk-macro", "ndk-macro 0.2.0",
"ndk-sys", "ndk-sys 0.2.2",
] ]
[[package]] [[package]]
name = "ndk-glue" name = "ndk-glue"
version = "0.4.0" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3e9e94628f24e7a3cb5b96a2dc5683acd9230bf11991c2a1677b87695138420" checksum = "04c0d14b0858eb9962a5dac30b809b19f19da7e4547d64af2b0bb051d2e55d79"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"libc", "libc",
"log", "log",
"ndk 0.4.0", "ndk 0.6.0",
"ndk-macro", "ndk-macro 0.3.0",
"ndk-sys", "ndk-sys 0.3.0",
] ]
[[package]] [[package]]
@ -721,19 +742,41 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d"
dependencies = [ dependencies = [
"darling", "darling 0.10.2",
"proc-macro-crate 0.1.5", "proc-macro-crate 0.1.5",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "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]] [[package]]
name = "ndk-sys" name = "ndk-sys"
version = "0.2.2" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" 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]] [[package]]
name = "nix" name = "nix"
version = "0.20.0" version = "0.20.0"
@ -789,19 +832,18 @@ dependencies = [
[[package]] [[package]]
name = "num_enum" name = "num_enum"
version = "0.5.4" version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9bd055fb730c4f8f4f57d45d35cd6b3f0980535b056dc7ff119cee6a66ed6f" checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad"
dependencies = [ dependencies = [
"derivative",
"num_enum_derive", "num_enum_derive",
] ]
[[package]] [[package]]
name = "num_enum_derive" name = "num_enum_derive"
version = "0.5.4" version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9" checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21"
dependencies = [ dependencies = [
"proc-macro-crate 1.1.0", "proc-macro-crate 1.1.0",
"proc-macro2", "proc-macro2",
@ -811,13 +853,13 @@ dependencies = [
[[package]] [[package]]
name = "oboe" name = "oboe"
version = "0.4.4" version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e15e22bc67e047fe342a32ecba55f555e3be6166b04dd157cd0f803dfa9f48e1" checksum = "2463c8f2e19b4e0d0710a21f8e4011501ff28db1c95d7a5482a553b2100502d2"
dependencies = [ dependencies = [
"jni", "jni",
"ndk 0.4.0", "ndk 0.6.0",
"ndk-glue 0.4.0", "ndk-glue 0.6.0",
"num-derive", "num-derive",
"num-traits", "num-traits",
"oboe-sys", "oboe-sys",
@ -825,9 +867,9 @@ dependencies = [
[[package]] [[package]]
name = "oboe-sys" name = "oboe-sys"
version = "0.4.4" version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "338142ae5ab0aaedc8275aa8f67f460e43ae0fca76a695a742d56da0a269eadc" checksum = "3370abb7372ed744232c12954d920d1a40f1c4686de9e79e800021ef492294bd"
dependencies = [ dependencies = [
"cc", "cc",
] ]
@ -843,9 +885,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.8.0" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
[[package]] [[package]]
name = "os_str_bytes" name = "os_str_bytes"
@ -889,9 +931,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.22" version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
@ -938,18 +980,18 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.32" version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.10" version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -1041,9 +1083,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.130" version = "1.0.133"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a"
[[package]] [[package]]
name = "shellexpand" name = "shellexpand"
@ -1073,9 +1115,9 @@ dependencies = [
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.7.0" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
[[package]] [[package]]
name = "stdweb" name = "stdweb"
@ -1210,9 +1252,9 @@ dependencies = [
[[package]] [[package]]
name = "symphonia-format-wav" name = "symphonia-format-wav"
version = "0.4.0" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da3586e944a951f3ff19ae14d3f46643c063784f119bffb091fc536102909575" checksum = "6d9fa5e5b420dea6763ba2547887eb1a02a142c676c5b02ed1b113a247101dad"
dependencies = [ dependencies = [
"log", "log",
"symphonia-core", "symphonia-core",
@ -1243,9 +1285,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.82" version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1311,12 +1353,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.2" version = "0.2.2"
@ -1331,9 +1367,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.3" version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "walkdir" name = "walkdir"
@ -1354,9 +1390,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.78" version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"wasm-bindgen-macro", "wasm-bindgen-macro",
@ -1364,9 +1400,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.78" version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"lazy_static", "lazy_static",
@ -1379,9 +1415,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.78" version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@ -1389,9 +1425,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.78" version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1402,15 +1438,15 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.78" version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2"
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.55" version = "0.3.56"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "mps" name = "mps"
version = "0.2.0" version = "0.3.0"
edition = "2021" edition = "2021"
authors = ["NGnius (Graham) <ngniusness@gmail.com>"] authors = ["NGnius (Graham) <ngniusness@gmail.com>"]
description = "Music Playlist Scripting language (MPS)" description = "Music Playlist Scripting language (MPS)"
@ -15,14 +15,14 @@ members = [
[dependencies] [dependencies]
# local # local
mps-interpreter = { version = "0.2.0", path = "./mps-interpreter" } mps-interpreter = { version = "0.3.0", path = "./mps-interpreter" }
# external # external
clap = { version = "3.0", features = ["derive"] } clap = { version = "3.0", features = ["derive"] }
# termios = { version = "^0.3"} # termios = { version = "^0.3"}
[target.'cfg(not(target_os = "linux"))'.dependencies] [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] [target.'cfg(target_os = "linux")'.dependencies]
# TODO fix need to specify OS-specific dependency of mps-player # 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] [package]
name = "mps-interpreter" name = "mps-interpreter"
version = "0.2.0" version = "0.3.0"
edition = "2021" edition = "2021"
license = "LGPL-2.1-only OR GPL-2.0-or-later" license = "LGPL-2.1-only OR GPL-2.0-or-later"
readme = "README.md" readme = "README.md"

View file

@ -6,7 +6,7 @@ use std::path::Path;
use super::lang::{MpsLanguageDictionary, MpsLanguageError, MpsOp}; use super::lang::{MpsLanguageDictionary, MpsLanguageError, MpsOp};
use super::tokens::MpsToken; use super::tokens::MpsToken;
use super::MpsContext; use super::MpsContext;
use super::MpsMusicItem; use super::MpsItem;
/// The script interpreter. /// The script interpreter.
/// Use MpsRunner for a better interface. /// Use MpsRunner for a better interface.
@ -81,7 +81,7 @@ impl<T> Iterator for MpsInterpretor<T>
where where
T: crate::tokens::MpsTokenReader, 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> { fn next(&mut self) -> Option<Self::Item> {
let mut is_stmt_done = false; 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::utility::{assert_token, assert_token_raw, check_name, assert_name};
use crate::lang::MpsLanguageDictionary; 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::{RuntimeError, SyntaxError};
use crate::lang::SingleItem; use crate::lang::SingleItem;
use crate::lang::MpsFilterReplaceStatement; use crate::lang::MpsFilterReplaceStatement;
@ -13,14 +13,14 @@ use crate::processing::general::MpsType;
use crate::processing::OpGetter; use crate::processing::OpGetter;
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem; use crate::MpsItem;
const INNER_VARIABLE_NAME: &str = "[inner variable]"; const INNER_VARIABLE_NAME: &str = "[inner variable]";
pub trait MpsFilterPredicate: Clone + Debug + Display { pub trait MpsFilterPredicate: Clone + Debug + Display {
fn matches( fn matches(
&mut self, &mut self,
item: &MpsMusicItem, item: &MpsItem,
ctx: &mut MpsContext, ctx: &mut MpsContext,
op: &mut OpGetter, op: &mut OpGetter,
) -> Result<bool, RuntimeError>; ) -> Result<bool, RuntimeError>;
@ -161,7 +161,7 @@ impl<P: MpsFilterPredicate + 'static> MpsOp for MpsFilterStatement<P> {
} }
impl<P: MpsFilterPredicate + 'static> Iterator 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> { fn next(&mut self) -> Option<Self::Item> {
if self.predicate.is_complete() && self.other_filters.is_none() { 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 { if start_of_predicate > tokens_len - 1 {
false false
} else { } 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 { if pipe_location_opt.is_some() && pipe_location_opt.unwrap() > start_of_predicate {
let pipe_location = pipe_location_opt.unwrap(); let pipe_location = pipe_location_opt.unwrap();
// filters combined by OR operations // filters combined by OR operations
@ -470,7 +470,7 @@ impl<P: MpsFilterPredicate + 'static, F: MpsFilterFactory<P> + 'static> BoxedMps
} }
} else { } else {
let mut another_filter = None; 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 (true, tokens.split_off(pipe_location)) // parse up to OR operator
} else { } else {
(false, tokens.split_off(tokens.len()-1)) // don't parse closing bracket in filter (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 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 inside_brackets = 0;
let mut pipe_found = false; 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 tokens[i].is_pipe() && inside_brackets == in_brackets {
if pipe_found { if pipe_found {
return Some(i); return Some(i-1);
} else { } else {
pipe_found = true; pipe_found = true;
} }
} else { } else {
pipe_found = false; pipe_found = false;
if tokens[i].is_close_bracket() { if tokens[i].is_open_bracket() {
inside_brackets += 1; 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; inside_brackets -= 1;
} }
} }

View file

@ -2,20 +2,20 @@ use std::collections::VecDeque;
use std::fmt::{Debug, Display, Error, Formatter}; use std::fmt::{Debug, Display, Error, Formatter};
use std::iter::Iterator; use std::iter::Iterator;
use crate::lang::{MpsOp, PseudoOp}; use crate::lang::{MpsOp, PseudoOp, MpsIteratorItem};
use crate::lang::RuntimeError; use crate::lang::RuntimeError;
use crate::lang::{MpsFilterPredicate, filter::VariableOrOp}; use crate::lang::{MpsFilterPredicate, filter::VariableOrOp};
use crate::lang::SingleItem; use crate::lang::SingleItem;
use crate::processing::general::MpsType; use crate::processing::general::MpsType;
use crate::processing::OpGetter; use crate::processing::OpGetter;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem; use crate::MpsItem;
const ITEM_VARIABLE_NAME: &str = "item"; const ITEM_VARIABLE_NAME: &str = "item";
const ITEM_CACHE_DEFAULT_SIZE: usize = 8; const ITEM_CACHE_DEFAULT_SIZE: usize = 8;
#[inline(always)] #[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) VecDeque::with_capacity(ITEM_CACHE_DEFAULT_SIZE)
} }
@ -26,7 +26,7 @@ pub struct MpsFilterReplaceStatement<P: MpsFilterPredicate + 'static> {
pub(super) context: Option<MpsContext>, pub(super) context: Option<MpsContext>,
pub(super) op_if: PseudoOp, pub(super) op_if: PseudoOp,
pub(super) op_else: Option<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> { 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> { impl<P: MpsFilterPredicate + 'static> Iterator for MpsFilterReplaceStatement<P> {
type Item = Result<MpsMusicItem, RuntimeError>; type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if !self.item_cache.is_empty() { if !self.item_cache.is_empty() {

View file

@ -21,7 +21,7 @@ pub use filter::{
pub use filter_replace::MpsFilterReplaceStatement; pub use filter_replace::MpsFilterReplaceStatement;
pub use function::{MpsFunctionFactory, MpsFunctionStatementFactory}; pub use function::{MpsFunctionFactory, MpsFunctionStatementFactory};
pub use lookup::Lookup; 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 pseudo_op::PseudoOp;
pub use repeated_meme::{repeated_tokens, RepeatedTokens}; pub use repeated_meme::{repeated_tokens, RepeatedTokens};
pub use single_op::SingleItem; pub use single_op::SingleItem;

View file

@ -7,7 +7,7 @@ use super::PseudoOp;
use super::{RuntimeError, SyntaxError}; use super::{RuntimeError, SyntaxError};
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem; use crate::MpsItem;
pub trait SimpleMpsOpFactory<T: MpsOp + 'static> { pub trait SimpleMpsOpFactory<T: MpsOp + 'static> {
fn is_op_simple(&self, tokens: &VecDeque<MpsToken>) -> bool; 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; 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 enter(&mut self, ctx: MpsContext);
fn escape(&mut self) -> MpsContext; fn escape(&mut self) -> MpsContext;

View file

@ -1,19 +1,19 @@
use std::fmt::{Debug, Display, Error, Formatter}; use std::fmt::{Debug, Display, Error, Formatter};
use std::iter::Iterator; use std::iter::Iterator;
use crate::lang::{MpsOp, RuntimeError}; use crate::lang::{MpsOp, RuntimeError, MpsIteratorItem};
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem; use crate::MpsItem;
#[derive(Debug)] #[derive(Debug)]
pub struct SingleItem { pub struct SingleItem {
context: Option<MpsContext>, context: Option<MpsContext>,
item: Result<MpsMusicItem, RuntimeError>, item: Result<MpsItem, RuntimeError>,
is_complete: bool, is_complete: bool,
} }
impl SingleItem { impl SingleItem {
pub fn new(item: Result<MpsMusicItem, RuntimeError>) -> Self { pub fn new(item: Result<MpsItem, RuntimeError>) -> Self {
Self { Self {
context: None, context: None,
item: item, 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)) 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 self.item = new_item
} }
} }
@ -33,7 +33,7 @@ impl SingleItem {
impl Display for SingleItem { impl Display for SingleItem {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
match &self.item { 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) Err(e) => write!(f, "*single-item*[Err({})]", e)
} }
} }
@ -50,7 +50,7 @@ impl std::clone::Clone for SingleItem {
} }
impl Iterator for SingleItem { impl Iterator for SingleItem {
type Item = Result<MpsMusicItem, RuntimeError>; type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.is_complete { 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 { impl Display for MpsTypePrimitive {
@ -96,3 +137,33 @@ fn map_ordering(ordering: std::cmp::Ordering) -> i8 {
std::cmp::Ordering::Greater => 1, 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::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem;
use crate::lang::utility::assert_token; use crate::lang::utility::assert_token;
use crate::lang::MpsLanguageDictionary; use crate::lang::MpsLanguageDictionary;
use crate::lang::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory}; use crate::lang::{BoxedMpsOpFactory, MpsOp, MpsOpFactory, SimpleMpsOpFactory, MpsIteratorItem};
use crate::lang::{RuntimeError, SyntaxError}; use crate::lang::SyntaxError;
#[derive(Debug)] #[derive(Debug)]
pub struct CommentStatement { pub struct CommentStatement {
@ -45,7 +44,7 @@ impl std::clone::Clone for CommentStatement {
} }
impl Iterator for CommentStatement { impl Iterator for CommentStatement {
type Item = Result<MpsMusicItem, RuntimeError>; type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
None None

View file

@ -4,12 +4,11 @@ use std::iter::Iterator;
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem;
use crate::lang::repeated_tokens; use crate::lang::repeated_tokens;
use crate::lang::utility::{assert_token, assert_token_raw}; use crate::lang::utility::{assert_token, assert_token_raw};
use crate::lang::MpsLanguageDictionary; use crate::lang::MpsLanguageDictionary;
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp}; use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, MpsIteratorItem};
use crate::lang::{RuntimeError, SyntaxError}; use crate::lang::{RuntimeError, SyntaxError};
use crate::processing::general::FileIter; use crate::processing::general::FileIter;
@ -65,7 +64,7 @@ impl std::clone::Clone for FilesStatement {
} }
impl Iterator for FilesStatement { impl Iterator for FilesStatement {
type Item = Result<MpsMusicItem, RuntimeError>; type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.file_iter.is_none() { if self.file_iter.is_none() {
@ -87,7 +86,7 @@ impl Iterator for FilesStatement {
}); });
} }
match self.file_iter.as_mut().unwrap().next() { 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 { Some(Err(e)) => Some(Err(RuntimeError {
line: 0, line: 0,
op: (Box::new(self.clone()) as Box<dyn MpsOp>).into(), 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::processing::OpGetter;
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem; use crate::MpsItem;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct EmptyFilter; pub struct EmptyFilter;
@ -21,7 +21,7 @@ impl Display for EmptyFilter {
impl MpsFilterPredicate for EmptyFilter { impl MpsFilterPredicate for EmptyFilter {
fn matches( fn matches(
&mut self, &mut self,
_item: &MpsMusicItem, _item: &MpsItem,
_ctx: &mut MpsContext, _ctx: &mut MpsContext,
_op: &mut OpGetter, _op: &mut OpGetter,
) -> Result<bool, RuntimeError> { ) -> Result<bool, RuntimeError> {

View file

@ -1,7 +1,7 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt::{Debug, Display, Error, Formatter}; 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::utility::{assert_token, assert_type, check_is_type};
use crate::lang::MpsLanguageDictionary; use crate::lang::MpsLanguageDictionary;
use crate::lang::MpsTypePrimitive; use crate::lang::MpsTypePrimitive;
@ -11,7 +11,7 @@ use crate::processing::general::MpsType;
use crate::processing::OpGetter; use crate::processing::OpGetter;
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem; use crate::MpsItem;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(super) enum VariableOrValue { pub(super) enum VariableOrValue {
@ -61,11 +61,10 @@ impl Display for FieldFilter {
impl MpsFilterPredicate for FieldFilter { impl MpsFilterPredicate for FieldFilter {
fn matches( fn matches(
&mut self, &mut self,
item: &MpsMusicItem, music_item_lut: &MpsItem,
ctx: &mut MpsContext, ctx: &mut MpsContext,
op: &mut OpGetter, op: &mut OpGetter,
) -> Result<bool, RuntimeError> { ) -> Result<bool, RuntimeError> {
let music_item_lut = item_to_primitive_lut(item.to_owned());
let variable = match &self.val { let variable = match &self.val {
VariableOrValue::Variable(name) => match ctx.variables.get(&name, op)? { VariableOrValue::Variable(name) => match ctx.variables.get(&name, op)? {
MpsType::Primitive(t) => Ok(t), MpsType::Primitive(t) => Ok(t),
@ -77,7 +76,7 @@ impl MpsFilterPredicate for FieldFilter {
}, },
VariableOrValue::Value(val) => Ok(val), 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); let compare_res = field.compare(variable);
if let Err(e) = compare_res { if let Err(e) = compare_res {
match self.comparison_errors { 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::processing::{OpGetter, general::MpsType};
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem; use crate::MpsItem;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct IndexFilter { pub struct IndexFilter {
@ -28,7 +28,7 @@ impl Display for IndexFilter {
impl MpsFilterPredicate for IndexFilter { impl MpsFilterPredicate for IndexFilter {
fn matches( fn matches(
&mut self, &mut self,
_item: &MpsMusicItem, _item: &MpsItem,
ctx: &mut MpsContext, ctx: &mut MpsContext,
op: &mut OpGetter, op: &mut OpGetter,
) -> Result<bool, RuntimeError> { ) -> Result<bool, RuntimeError> {

View file

@ -9,7 +9,7 @@ use crate::lang::utility::assert_token_raw;
use crate::processing::{OpGetter, general::MpsType}; use crate::processing::{OpGetter, general::MpsType};
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem; use crate::MpsItem;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct RangeFilter { pub struct RangeFilter {
@ -33,7 +33,7 @@ impl Display for RangeFilter {
impl MpsFilterPredicate for RangeFilter { impl MpsFilterPredicate for RangeFilter {
fn matches( fn matches(
&mut self, &mut self,
_item: &MpsMusicItem, _item: &MpsItem,
ctx: &mut MpsContext, ctx: &mut MpsContext,
op: &mut OpGetter, op: &mut OpGetter,
) -> Result<bool, RuntimeError> { ) -> Result<bool, RuntimeError> {

View file

@ -1,38 +1,8 @@
use std::collections::HashMap;
use std::collections::VecDeque; use std::collections::VecDeque;
use crate::lang::utility::assert_token_raw; use crate::lang::utility::assert_token_raw;
use crate::lang::MpsTypePrimitive;
use crate::lang::SyntaxError; use crate::lang::SyntaxError;
use crate::tokens::MpsToken; 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> { pub fn assert_comparison_operator(tokens: &mut VecDeque<MpsToken>) -> Result<[i8; 2], SyntaxError> {
let token1 = tokens.pop_front().unwrap(); let token1 = tokens.pop_front().unwrap();

View file

@ -4,11 +4,11 @@ use std::iter::Iterator;
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem; use crate::MpsItem;
use crate::lang::utility::{assert_token, assert_token_raw}; use crate::lang::utility::{assert_token, assert_token_raw};
use crate::lang::MpsLanguageDictionary; use crate::lang::MpsLanguageDictionary;
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, PseudoOp}; use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, PseudoOp, MpsIteratorItem};
use crate::lang::{RuntimeError, SyntaxError}; use crate::lang::{RuntimeError, SyntaxError};
#[derive(Debug)] #[derive(Debug)]
@ -16,7 +16,7 @@ pub struct RepeatStatement {
inner_statement: PseudoOp, inner_statement: PseudoOp,
inner_done: bool, inner_done: bool,
context: Option<MpsContext>, context: Option<MpsContext>,
cache: Vec<MpsMusicItem>, cache: Vec<MpsItem>,
cache_position: usize, cache_position: usize,
repetitions: usize, repetitions: usize,
loop_forever: bool, loop_forever: bool,
@ -49,7 +49,7 @@ impl std::clone::Clone for RepeatStatement {
} }
impl Iterator for RepeatStatement { impl Iterator for RepeatStatement {
type Item = Result<MpsMusicItem, RuntimeError>; type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let real_op = match self.inner_statement.try_real() { 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::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem;
use crate::lang::repeated_tokens; use crate::lang::repeated_tokens;
use crate::lang::utility::{assert_token, assert_token_raw}; use crate::lang::utility::{assert_token, assert_token_raw};
use crate::lang::MpsLanguageDictionary; use crate::lang::MpsLanguageDictionary;
use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp}; use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsOp, MpsIteratorItem};
use crate::lang::{RuntimeError, SyntaxError}; use crate::lang::SyntaxError;
#[derive(Debug)] #[derive(Debug)]
pub struct SqlInitStatement { pub struct SqlInitStatement {
@ -39,7 +38,7 @@ impl std::clone::Clone for SqlInitStatement {
} }
impl Iterator for SqlInitStatement { impl Iterator for SqlInitStatement {
type Item = Result<MpsMusicItem, RuntimeError>; type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let pseudo_clone = self.clone(); let pseudo_clone = self.clone();

View file

@ -3,23 +3,23 @@ use std::fmt::{Debug, Display, Error, Formatter};
use std::iter::Iterator; use std::iter::Iterator;
use crate::lang::utility::assert_token; 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::lang::{RuntimeError, SyntaxError};
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem; use crate::MpsItem;
//use super::db::*; //use super::db::*;
#[derive(Debug)] #[derive(Debug)]
pub struct SqlStatement { pub struct SqlStatement {
query: String, query: String,
context: Option<MpsContext>, context: Option<MpsContext>,
rows: Option<Vec<Result<MpsMusicItem, RuntimeError>>>, rows: Option<Vec<Result<MpsItem, RuntimeError>>>,
current: usize, current: usize,
} }
impl SqlStatement { 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 let Some(rows) = &self.rows {
if increment { if increment {
if self.current == rows.len() { if self.current == rows.len() {
@ -32,7 +32,7 @@ impl SqlStatement {
} else { } else {
//Some(rows[self.current].clone()) //Some(rows[self.current].clone())
match &rows[self.current] { match &rows[self.current] {
Ok(item) => Some(Ok(item.clone())), Ok(item) => Some(Ok(item.clone().into())),
Err(e) => Some(Err(RuntimeError { Err(e) => Some(Err(RuntimeError {
line: e.line, line: e.line,
op: (Box::new(self.clone()) as Box<dyn MpsOp>).into(), op: (Box::new(self.clone()) as Box<dyn MpsOp>).into(),
@ -82,7 +82,7 @@ impl std::clone::Clone for SqlStatement {
} }
impl Iterator for SqlStatement { impl Iterator for SqlStatement {
type Item = Result<MpsMusicItem, RuntimeError>; type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.rows.is_some() { if self.rows.is_some() {

View file

@ -3,11 +3,11 @@ use std::fmt::{Debug, Display, Error, Formatter};
use std::iter::Iterator; use std::iter::Iterator;
use crate::lang::utility::assert_token; 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::lang::{RuntimeError, SyntaxError};
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem; use crate::MpsItem;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum QueryMode { enum QueryMode {
@ -63,12 +63,12 @@ pub struct SimpleSqlStatement {
query: String, query: String,
mode: QueryMode, mode: QueryMode,
context: Option<MpsContext>, context: Option<MpsContext>,
rows: Option<Vec<Result<MpsMusicItem, RuntimeError>>>, rows: Option<Vec<Result<MpsItem, RuntimeError>>>,
current: usize, current: usize,
} }
impl SimpleSqlStatement { 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 let Some(rows) = &self.rows {
if increment { if increment {
if self.current == rows.len() { if self.current == rows.len() {
@ -81,7 +81,7 @@ impl SimpleSqlStatement {
} else { } else {
//Some(rows[self.current].clone()) //Some(rows[self.current].clone())
match &rows[self.current] { match &rows[self.current] {
Ok(item) => Some(Ok(item.clone())), Ok(item) => Some(Ok(item.clone().into())),
Err(e) => Some(Err(RuntimeError { Err(e) => Some(Err(RuntimeError {
line: e.line, line: e.line,
op: (Box::new(self.clone()) as Box<dyn MpsOp>).into(), op: (Box::new(self.clone()) as Box<dyn MpsOp>).into(),
@ -132,7 +132,7 @@ impl std::clone::Clone for SimpleSqlStatement {
} }
impl Iterator for SimpleSqlStatement { impl Iterator for SimpleSqlStatement {
type Item = Result<MpsMusicItem, RuntimeError>; type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.rows.is_some() { if self.rows.is_some() {

View file

@ -4,11 +4,10 @@ use std::iter::Iterator;
use crate::tokens::MpsToken; use crate::tokens::MpsToken;
use crate::MpsContext; use crate::MpsContext;
use crate::MpsMusicItem;
use crate::lang::utility::{assert_token, assert_token_raw, assert_type, check_is_type}; use crate::lang::utility::{assert_token, assert_token_raw, assert_type, check_is_type};
use crate::lang::MpsLanguageDictionary; 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::lang::{RuntimeError, SyntaxError};
use crate::processing::general::MpsType; use crate::processing::general::MpsType;
@ -46,7 +45,7 @@ impl std::clone::Clone for AssignStatement {
} }
impl Iterator for AssignStatement { impl Iterator for AssignStatement {
type Item = Result<MpsMusicItem, RuntimeError>; type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if let Some(inner_statement) = &mut self.inner_statement { if let Some(inner_statement) = &mut self.inner_statement {

View file

@ -125,17 +125,20 @@
mod context; mod context;
mod interpretor; mod interpretor;
mod item;
pub mod lang; pub mod lang;
#[cfg(feature = "music_library")] #[cfg(feature = "music_library")]
pub mod music; pub mod music;
mod music_item; //mod music_item;
pub mod processing; pub mod processing;
mod runner; mod runner;
pub mod tokens; pub mod tokens;
pub use context::MpsContext; pub use context::MpsContext;
pub use interpretor::{interpretor, MpsInterpretor}; 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; pub use runner::MpsRunner;
#[cfg(test)] #[cfg(test)]

View file

@ -1,6 +1,7 @@
use super::lang::db::{ use super::lang::db::{
DatabaseObj, DbAlbumItem, DbArtistItem, DbGenreItem, DbMetaItem, DbMusicItem, DatabaseObj, DbAlbumItem, DbArtistItem, DbGenreItem, DbMetaItem, DbMusicItem,
}; };
use super::MpsItem;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MpsMusicItem { 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 regex::Regex;
use super::OpGetter; use super::OpGetter;
use crate::lang::RuntimeError; use crate::lang::{RuntimeError, MpsTypePrimitive};
use crate::MpsMusicItem; 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))$"; 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 = filepath.as_ref();
let path_str = path.to_str()?; let path_str = path.to_str()?;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -135,8 +135,9 @@ impl FileIter {
panic!("Got non-file path `{}` when building music item", path_str) panic!("Got non-file path `{}` when building music item", path_str)
} }
let captures = self.pattern.captures(path_str)?; let captures = self.pattern.captures(path_str)?;
let capture_names = self.pattern.capture_names();
// populate fields // populate fields
self.populate_item_impl(path, path_str, captures) self.populate_item_impl(path, path_str, captures, capture_names)
} }
#[cfg(feature = "music_library")] #[cfg(feature = "music_library")]
@ -145,105 +146,90 @@ impl FileIter {
path: &Path, path: &Path,
path_str: &str, path_str: &str,
captures: regex::Captures, captures: regex::Captures,
) -> Option<MpsMusicItem> { capture_names: regex::CaptureNames,
) -> Option<MpsItem> {
match crate::music::MpsLibrary::read_media_tags(path) { match crate::music::MpsLibrary::read_media_tags(path) {
Ok(tags) => Some(MpsMusicItem { Ok(tags) => {
title: captures let mut item = MpsItem::new();
.name("title") self.populate_item_impl_simple(&mut item, path_str, captures, capture_names);
.and_then(|m| Some(m.as_str().to_string())) if item.field("title").is_none() {
.unwrap_or_else(|| tags.track_title()), item.set_field("title", tags.track_title().into());
artist: captures }
.name("artist") if item.field("artist").is_none() {
.and_then(|m| Some(m.as_str().to_string())) if let Some(artist) = tags.artist_name() {
.or_else(|| tags.artist_name()), item.set_field("artist", artist.into());
album: captures }
.name("album") }
.and_then(|m| Some(m.as_str().to_string())) if item.field("album").is_none() {
.or_else(|| tags.album_title()), if let Some(album) = tags.album_title() {
filename: path_str.to_string(), item.set_field("album", album.into());
genre: captures }
.name("genre") }
.and_then(|m| Some(m.as_str().to_string())) if item.field("genre").is_none() {
.or_else(|| tags.genre_title()), if let Some(genre) = tags.genre_title() {
track: match captures.name("track") { item.set_field("genre", genre.into());
None => tags.track_number(), }
Some(m) => match m.as_str().parse::<u64>() { }
Ok(u) => Some(u), if item.field("track").is_none() {
Err(_) => tags.track_number(), if let Some(track) = tags.track_number() {
}, item.set_field("track", track.into());
}, }
year: match captures.name("year") { }
None => tags.track_date(), if item.field("year").is_none() {
Some(m) => match m.as_str().parse::<u64>() { if let Some(year) = tags.track_date() {
Ok(u) => Some(u), item.set_field("year", year.into());
Err(_) => tags.track_date(), }
}, }
}, Some(item)
}), },
Err(_) => self.populate_item_impl_simple(path, path_str, captures), 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"))] #[cfg(not(feature = "music_library"))]
fn populate_item_impl( fn populate_item_impl(
&self, &self,
path: &Path,
path_str: &str, path_str: &str,
captures: regex::Captures, captures: regex::Captures,
) -> Option<MpsMusicItem> { capture_names: regex::CaptureNames,
self.populate_item_impl_simple(path, path_str, captures) ) -> Option<MpsItem> {
let mut item = MpsItem::new();
self.populate_item_impl_simple(&mut item, path_str, captures, capture_names);
Some(item)
} }
#[inline] #[inline]
fn populate_item_impl_simple( fn populate_item_impl_simple(
&self, &self,
path: &Path, item: &mut MpsItem,
path_str: &str, path_str: &str,
captures: regex::Captures, captures: regex::Captures,
) -> Option<MpsMusicItem> { mut capture_names: regex::CaptureNames,
Some(MpsMusicItem { ) {
title: captures // populates fields from named capture groups
.name("title") while let Some(Some(name)) = capture_names.next() {
.and_then(|m| Some(m.as_str().to_string())) if let Some(value) = captures.name(name).and_then(|m| Some(m.as_str().to_string())) {
.unwrap_or_else(|| Self::default_title(path)), item.set_field(name, MpsTypePrimitive::parse(value));
artist: captures }
.name("artist") }
.and_then(|m| Some(m.as_str().to_string())), item.set_field("filename", path_str.to_string().into());
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,
},
},
})
} }
fn default_title(path: &Path) -> String { /*fn default_title(path: &Path) -> String {
let extension = path.extension().and_then(|ext| ext.to_str()).unwrap_or(""); let extension = path.extension().and_then(|ext| ext.to_str()).unwrap_or("");
path.file_name() path.file_name()
.and_then(|file| file.to_str()) .and_then(|file| file.to_str())
.and_then(|file| Some(file.replacen(&format!(".{}", extension), "", 1))) .and_then(|file| Some(file.replacen(&format!(".{}", extension), "", 1)))
.unwrap_or("Unknown Title".into()) .unwrap_or("Unknown Title".into())
} }*/
} }
impl Iterator for FileIter { impl Iterator for FileIter {
type Item = Result<MpsMusicItem, String>; type Item = Result<MpsItem, String>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.is_complete { if self.is_complete {

View file

@ -3,11 +3,11 @@ use std::collections::{HashMap, HashSet};
use crate::lang::db::*; use crate::lang::db::*;
use crate::lang::RuntimeError; use crate::lang::RuntimeError;
use crate::MpsMusicItem; use crate::MpsItem;
use super::OpGetter as QueryOp; 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) /// SQL querying functionality, loosely de-coupled from any specific SQL dialect (excluding raw call)
pub trait MpsDatabaseQuerier: Debug { pub trait MpsDatabaseQuerier: Debug {
@ -250,7 +250,7 @@ impl std::convert::TryInto<rusqlite::Connection> for SqliteSettings {
let music_path = self let music_path = self
.music_path .music_path
.and_then(|p| Some(std::path::PathBuf::from(p))) .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 let sqlite_path = self
.db_path .db_path
.unwrap_or_else(|| crate::lang::db::DEFAULT_SQLITE_FILEPATH.to_string()); .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( fn build_mps_item(
conn: &mut rusqlite::Connection, conn: &mut rusqlite::Connection,
item: DbMusicItem, item: DbMusicItem,
) -> rusqlite::Result<MpsMusicItem> { ) -> rusqlite::Result<MpsItem> {
// query artist // query artist
let mut stmt = conn.prepare_cached("SELECT * from artists WHERE artist_id = ?")?; let mut stmt = conn.prepare_cached("SELECT * from artists WHERE artist_id = ?")?;
let artist = stmt.query_row([item.artist], DbArtistItem::map_row)?; 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 mut stmt = conn.prepare_cached("SELECT * from genres WHERE genre_id = ?")?;
let genre = stmt.query_row([item.genre], DbGenreItem::map_row)?; 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] #[inline]
fn perform_query( fn perform_query(
conn: &mut rusqlite::Connection, conn: &mut rusqlite::Connection,
query: &str, query: &str,
) -> Result<Vec<rusqlite::Result<MpsMusicItem>>, String> { ) -> Result<Vec<rusqlite::Result<MpsItem>>, String> {
let collection: Vec<rusqlite::Result<DbMusicItem>>; let collection: Vec<rusqlite::Result<DbMusicItem>>;
{ {
let mut stmt = conn let mut stmt = conn
@ -306,7 +306,7 @@ fn perform_single_param_query(
conn: &mut rusqlite::Connection, conn: &mut rusqlite::Connection,
query: &str, query: &str,
param: &str, param: &str,
) -> Result<Vec<rusqlite::Result<MpsMusicItem>>, String> { ) -> Result<Vec<rusqlite::Result<MpsItem>>, String> {
let collection: Vec<rusqlite::Result<DbMusicItem>>; let collection: Vec<rusqlite::Result<DbMusicItem>>;
{ {
let mut stmt = conn let mut stmt = conn
@ -323,3 +323,28 @@ fn perform_single_param_query(
}); });
Ok(iter2.collect()) 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::lang::{MpsLanguageDictionary, MpsLanguageError};
use super::tokens::{MpsTokenReader, MpsTokenizer}; use super::tokens::{MpsTokenReader, MpsTokenizer};
use super::{MpsContext, MpsInterpretor, MpsMusicItem}; use super::{MpsContext, MpsInterpretor, MpsItem};
pub struct MpsRunnerSettings<T: MpsTokenReader> { pub struct MpsRunnerSettings<T: MpsTokenReader> {
pub vocabulary: MpsLanguageDictionary, pub vocabulary: MpsLanguageDictionary,
@ -57,7 +57,7 @@ impl<R: Read> MpsRunner<MpsTokenizer<R>> {
} }
impl<T: MpsTokenReader> Iterator for MpsRunner<T> { 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> { fn next(&mut self) -> Option<Self::Item> {
let mut item = self.interpretor.next(); let mut item = self.interpretor.next();

View file

@ -62,7 +62,10 @@ fn execute_single_line(
break; break;
} }
} // no need to spam the rest of the songs } // 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 { } else {
println!("!!! Got error while iterating (executing) !!!"); println!("!!! Got error while iterating (executing) !!!");
eprintln!("{}", result.as_ref().err().unwrap()); eprintln!("{}", result.as_ref().err().unwrap());

View file

@ -1,6 +1,6 @@
[package] [package]
name = "mps-player" name = "mps-player"
version = "0.2.0" version = "0.3.0"
edition = "2021" edition = "2021"
license = "LGPL-2.1-only OR GPL-2.0-or-later" license = "LGPL-2.1-only OR GPL-2.0-or-later"
readme = "README.md" readme = "README.md"
@ -10,7 +10,7 @@ rodio = { version = "^0.14"}
m3u8-rs = { version = "^3.0.0" } m3u8-rs = { version = "^3.0.0" }
# local # 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] [target.'cfg(target_os = "linux")'.dependencies]
#dbus = { version = "^0.9" } #dbus = { version = "^0.9" }

View file

@ -7,7 +7,7 @@ use std::thread::JoinHandle;
use mpris_player::{MprisPlayer, PlaybackStatus, Metadata}; use mpris_player::{MprisPlayer, PlaybackStatus, Metadata};
#[cfg(all(target_os = "linux", feature = "os-controls"))] #[cfg(all(target_os = "linux", feature = "os-controls"))]
use mps_interpreter::MpsMusicItem; use mps_interpreter::MpsItem;
//use super::MpsController; //use super::MpsController;
use super::player_wrapper::{ControlAction, PlaybackAction}; 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); //println!("Got enqueued item {}", &item.title);
dbus_ctrl.send(DbusControl::SetMetadata(Metadata { dbus_ctrl.send(DbusControl::SetMetadata(Metadata {
length: None, length: None,
art_url: None, art_url: None,
album: item.album, album: item.field("album").and_then(|x| x.to_owned().to_str()),
album_artist: None, // TODO maybe? 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, composer: None,
disc_number: None, disc_number: None,
genre: item.genre.map(|genre| vec![genre]), genre: item.field("genre").and_then(|x| x.to_owned().to_str()).map(|genre| vec![genre]),
title: Some(item.title), title: item.field("title").and_then(|x| x.to_owned().to_str()),
track_number: item.track.map(|track| track as i32), track_number: item.field("track").and_then(|x| x.to_owned().to_i64()).map(|track| track as i32),
url: Some(item.filename), url: item.field("filename").and_then(|x| x.to_owned().to_str()),
})).unwrap_or(()); })).unwrap_or(());
} }

View file

@ -5,7 +5,7 @@ use rodio::{decoder::Decoder, OutputStream, OutputStreamHandle, Sink};
use m3u8_rs::{MediaPlaylist, MediaSegment}; use m3u8_rs::{MediaPlaylist, MediaSegment};
use mps_interpreter::{tokens::MpsTokenReader, MpsRunner, MpsMusicItem}; use mps_interpreter::{tokens::MpsTokenReader, MpsRunner, MpsItem};
use super::PlaybackError; use super::PlaybackError;
@ -36,12 +36,15 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
self.sink.sleep_until_end(); self.sink.sleep_until_end();
match item { match item {
Ok(music) => { Ok(music) => {
let file = fs::File::open(music.filename).map_err(PlaybackError::from_err)?; if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) {
let stream = io::BufReader::new(file); let file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?; let stream = io::BufReader::new(file);
self.sink.append(source); let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
//self.sink.play(); // idk if this is necessary self.sink.append(source);
Ok(()) Ok(())
} else {
Err(PlaybackError::from_err("Field `filename` does not exist on item"))
}
} }
Err(e) => Err(PlaybackError::from_err(e)), Err(e) => Err(PlaybackError::from_err(e)),
}?; }?;
@ -50,18 +53,21 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
Ok(()) 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(); let mut enqueued = Vec::new();
for item in &mut self.runner { for item in &mut self.runner {
match item { match item {
Ok(music) => { Ok(music) => {
enqueued.push(music.clone()); enqueued.push(music.clone());
let file = fs::File::open(music.filename).map_err(PlaybackError::from_err)?; if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) {
let stream = io::BufReader::new(file); let file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?; let stream = io::BufReader::new(file);
self.sink.append(source); let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
//self.sink.play(); // idk if this is necessary self.sink.append(source);
Ok(()) Ok(())
} else {
Err(PlaybackError::from_err("Field `filename` does not exist on item"))
}
} }
Err(e) => Err(PlaybackError::from_err(e)), Err(e) => Err(PlaybackError::from_err(e)),
}?; }?;
@ -69,7 +75,7 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
Ok(enqueued) 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 items_left = count;
let mut enqueued = Vec::with_capacity(count); let mut enqueued = Vec::with_capacity(count);
if items_left == 0 { if items_left == 0 {
@ -79,12 +85,15 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
match item { match item {
Ok(music) => { Ok(music) => {
enqueued.push(music.clone()); enqueued.push(music.clone());
let file = fs::File::open(music.filename).map_err(PlaybackError::from_err)?; if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) {
let stream = io::BufReader::new(file); let file = fs::File::open(filename).map_err(PlaybackError::from_err)?;
let source = Decoder::new(stream).map_err(PlaybackError::from_err)?; let stream = io::BufReader::new(file);
self.sink.append(source); let source = Decoder::new(stream).map_err(PlaybackError::from_err)?;
//self.sink.play(); // idk if this is necessary self.sink.append(source);
Ok(()) Ok(())
} else {
Err(PlaybackError::from_err("Field `filename` does not exist on item"))
}
} }
Err(e) => Err(PlaybackError::from_err(e)), Err(e) => Err(PlaybackError::from_err(e)),
}?; }?;
@ -130,12 +139,16 @@ impl<T: MpsTokenReader> MpsPlayer<T> {
for item in &mut self.runner { for item in &mut self.runner {
match item { match item {
Ok(music) => { Ok(music) => {
playlist.segments.push(MediaSegment { if let Some(filename) = music.field("filename").and_then(|x| x.to_owned().to_str()) {
uri: music.filename, playlist.segments.push(MediaSegment {
title: Some(music.title), uri: filename,
..Default::default() title: music.field("title").and_then(|x| x.to_owned().to_str()),
}); ..Default::default()
Ok(()) });
Ok(())
} else {
Err(PlaybackError::from_err("Field `filename` does not exist on item"))
}
} }
Err(e) => Err(PlaybackError::from_err(e)), Err(e) => Err(PlaybackError::from_err(e)),
}?; }?;
@ -173,7 +186,7 @@ mod tests {
use std::io; use std::io;
#[allow(dead_code)] #[allow(dead_code)]
#[test] //#[test]
fn play_cursor() -> Result<(), PlaybackError> { 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 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); let runner = MpsRunner::with_stream(cursor);

View file

@ -2,7 +2,7 @@ use std::sync::mpsc::{Receiver, Sender};
use std::{thread, thread::JoinHandle}; use std::{thread, thread::JoinHandle};
use mps_interpreter::tokens::MpsTokenReader; use mps_interpreter::tokens::MpsTokenReader;
use mps_interpreter::MpsMusicItem; use mps_interpreter::MpsItem;
use super::MpsPlayer; use super::MpsPlayer;
use super::PlaybackError; use super::PlaybackError;
@ -215,7 +215,7 @@ pub enum PlayerAction {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum PlaybackAction { pub enum PlaybackAction {
Empty, Empty,
Enqueued(MpsMusicItem), Enqueued(MpsItem),
Exit, Exit,
} }