Compare commits
132 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
291aa6877c
|
|||
|
c48a8adcdc
|
|||
|
1f1e7fbb53
|
|||
|
7ec268094d
|
|||
|
afa690366f
|
|||
|
02ba7f2684
|
|||
|
44903f2ce0
|
|||
|
9f50d61ad5
|
|||
|
788a01ce83
|
|||
|
f5451b6c2f
|
|||
|
2de18cdbdb
|
|||
|
23bfd0c4a7
|
|||
|
3342293bf2
|
|||
|
2b3ab7389d
|
|||
|
f80d36e962
|
|||
|
86edd4c5b3
|
|||
|
a7a8ceedeb
|
|||
|
7ce0d68021
|
|||
|
b5cb4677ee
|
|||
|
38faf99de7
|
|||
|
69f252bad8
|
|||
|
c177c089a3
|
|||
|
d964e7857b
|
|||
|
8430592bee
|
|||
|
78cfc09d60
|
|||
|
a7b764ad0f
|
|||
|
f3e6fe13df
|
|||
|
4f8f5db620
|
|||
|
1e39640508
|
|||
|
b388bc727b
|
|||
|
9f859e1df1
|
|||
|
4bb5702eba
|
|||
|
955fdbcff1
|
|||
|
322c8c8fc3
|
|||
|
93afaf1bde
|
|||
|
c915c67f08
|
|||
|
813ffac614
|
|||
|
b0bc2752cc
|
|||
|
07e9161137
|
|||
|
f2977f1ba9
|
|||
|
b0b4134829
|
|||
|
c1dbdd4644
|
|||
|
64c94d6e89
|
|||
|
4d11df5ad1
|
|||
|
0cacbe2229
|
|||
|
7bbe1c4ced
|
|||
|
83918fd432
|
|||
|
07e1c76aa9
|
|||
|
d84e653db2
|
|||
|
7834bbd956
|
|||
|
249ffb2a36
|
|||
|
fdd4880d05
|
|||
|
9ca6544057
|
|||
|
e5f70ca87a
|
|||
|
b03f60c985
|
|||
|
b22016e970
|
|||
|
65c7798d01
|
|||
|
5188809327
|
|||
|
a4276a2caa
|
|||
|
7b27a650a1
|
|||
|
062dbcafb8
|
|||
|
57a6b0a3ee
|
|||
|
b5fbaadca2
|
|||
|
3bd7aaaad2
|
|||
|
8aba3d8859
|
|||
|
e4ece7d6b2
|
|||
|
f07f90aee5
|
|||
|
6e2aa2ba65
|
|||
|
1ef8ef669a
|
|||
|
c6a123a6e1
|
|||
|
06e24f0ce0
|
|||
|
da31ab75e2
|
|||
|
d09ca013d5
|
|||
|
10913fd48c
|
|||
|
73ddb6d498
|
|||
|
ede28623ef
|
|||
|
130fe49597
|
|||
|
4a1df97ad6
|
|||
|
7a966051d5
|
|||
|
7dc3d7f9cf
|
|||
|
2b1e99445a
|
|||
|
e932b62195
|
|||
|
49f440770e
|
|||
|
153ae9520f
|
|||
|
424c530d5d
|
|||
|
a637f24e66
|
|||
|
1d693b7b2a
|
|||
|
484b1fb68d
|
|||
|
2fa58533ba
|
|||
|
088665c9ff
|
|||
|
3e2e3fdc68
|
|||
|
59994ce740
|
|||
|
b42cad0b52
|
|||
|
3c49ece1a9
|
|||
|
5a5870d7de
|
|||
|
e5303954c5
|
|||
|
c95d39a9ec
|
|||
|
e910d29aa4
|
|||
|
58a06bd930
|
|||
|
380a4aed2c
|
|||
|
ed7f9a6917
|
|||
|
432f16ae2b
|
|||
|
44ba3eb4dc
|
|||
|
d80ebfc4cf
|
|||
|
9f07114401
|
|||
|
5e0fe71feb
|
|||
|
366f56da9e
|
|||
|
9cef59eb88
|
|||
|
abacb54c8d
|
|||
|
86183e56ad
|
|||
|
6a9cd00275
|
|||
|
9cb92741a4
|
|||
|
cea3d3da04
|
|||
|
87fa93fb1c
|
|||
|
cf0db472e8
|
|||
|
4f6392e376
|
|||
|
2fb97a9964
|
|||
|
48beaa7732
|
|||
|
2bd53462d7
|
|||
|
edeb0e3b78
|
|||
|
2ee6bbc582
|
|||
|
3e512092bd
|
|||
|
08104b3537
|
|||
|
1561ae2e80
|
|||
|
d45502a43e
|
|||
|
4fada75fe9
|
|||
|
184f9fc215
|
|||
|
74074bf9c7
|
|||
|
84f061a79f
|
|||
|
472be6c083
|
|||
|
49e070a41d
|
|||
|
8293c6e6e5
|
@@ -1,2 +0,0 @@
|
|||||||
[registries]
|
|
||||||
pvv-git = { index = "sparse+https://git.pvv.ntnu.no/api/packages/Grzegorz/cargo/" }
|
|
||||||
@@ -7,7 +7,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: debian-latest
|
runs-on: debian-latest-slim
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ jobs:
|
|||||||
run: cargo build --verbose --release
|
run: cargo build --verbose --release
|
||||||
|
|
||||||
check:
|
check:
|
||||||
runs-on: debian-latest
|
runs-on: debian-latest-slim
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
run: cargo clippy
|
run: cargo clippy
|
||||||
|
|
||||||
test:
|
test:
|
||||||
runs-on: debian-latest
|
runs-on: debian-latest-slim
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
- uses: cargo-bins/cargo-binstall@main
|
- uses: cargo-bins/cargo-binstall@main
|
||||||
@@ -88,7 +88,7 @@ jobs:
|
|||||||
known-hosts: "pages.pvv.ntnu.no ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH2QjfFB+city1SYqltkVqWACfo1j37k+oQQfj13mtgg"
|
known-hosts: "pages.pvv.ntnu.no ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH2QjfFB+city1SYqltkVqWACfo1j37k+oQQfj13mtgg"
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
runs-on: debian-latest
|
runs-on: debian-latest-slim
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ jobs:
|
|||||||
run: cargo doc --document-private-items --release
|
run: cargo doc --document-private-items --release
|
||||||
|
|
||||||
- name: Transfer files
|
- name: Transfer files
|
||||||
uses: https://git.pvv.ntnu.no/Projects/rsync-action@v2
|
uses: https://git.pvv.ntnu.no/Projects/rsync-action@v1
|
||||||
with:
|
with:
|
||||||
source: target/doc/
|
source: target/doc/
|
||||||
target: ${{ gitea.ref_name }}/docs/
|
target: ${{ gitea.ref_name }}/docs/
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
/target
|
/target
|
||||||
result
|
result
|
||||||
result-*
|
result-*
|
||||||
|
|
||||||
|
Cargo.lock
|
||||||
|
|||||||
Generated
-900
@@ -1,900 +0,0 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 4
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aho-corasick"
|
|
||||||
version = "1.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "android_system_properties"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyhow"
|
|
||||||
version = "1.0.102"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ascii-canvas"
|
|
||||||
version = "4.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ef1e3e699d84ab1b0911a1010c5c106aa34ae89aeac103be5ce0c3859db1e891"
|
|
||||||
dependencies = [
|
|
||||||
"term",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autocfg"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bit-set"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
|
||||||
dependencies = [
|
|
||||||
"bit-vec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bit-vec"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "2.11.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "block-buffer"
|
|
||||||
version = "0.10.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bumpalo"
|
|
||||||
version = "3.20.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytes"
|
|
||||||
version = "1.11.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.2.58"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1"
|
|
||||||
dependencies = [
|
|
||||||
"find-msvc-tools",
|
|
||||||
"shlex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chrono"
|
|
||||||
version = "0.4.44"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
|
||||||
dependencies = [
|
|
||||||
"iana-time-zone",
|
|
||||||
"js-sys",
|
|
||||||
"num-traits",
|
|
||||||
"serde",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"windows-link",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "core-foundation-sys"
|
|
||||||
version = "0.8.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cpufeatures"
|
|
||||||
version = "0.2.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crypto-common"
|
|
||||||
version = "0.1.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array",
|
|
||||||
"typenum",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "diff"
|
|
||||||
version = "0.1.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "digest"
|
|
||||||
version = "0.10.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
|
||||||
dependencies = [
|
|
||||||
"block-buffer",
|
|
||||||
"crypto-common",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "either"
|
|
||||||
version = "1.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "empidee"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"chrono",
|
|
||||||
"futures-util",
|
|
||||||
"indoc",
|
|
||||||
"lalrpop",
|
|
||||||
"lalrpop-util",
|
|
||||||
"paste",
|
|
||||||
"pretty_assertions",
|
|
||||||
"serde",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ena"
|
|
||||||
version = "0.14.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "eabffdaee24bd1bf95c5ef7cec31260444317e72ea56c4c91750e8b7ee58d5f1"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "equivalent"
|
|
||||||
version = "1.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "find-msvc-tools"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fixedbitset"
|
|
||||||
version = "0.5.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-core"
|
|
||||||
version = "0.3.32"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-io"
|
|
||||||
version = "0.3.32"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-macro"
|
|
||||||
version = "0.3.32"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-task"
|
|
||||||
version = "0.3.32"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-util"
|
|
||||||
version = "0.3.32"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
"futures-io",
|
|
||||||
"futures-macro",
|
|
||||||
"futures-task",
|
|
||||||
"memchr",
|
|
||||||
"pin-project-lite",
|
|
||||||
"slab",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "generic-array"
|
|
||||||
version = "0.14.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
|
||||||
dependencies = [
|
|
||||||
"typenum",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.16.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iana-time-zone"
|
|
||||||
version = "0.1.65"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
|
|
||||||
dependencies = [
|
|
||||||
"android_system_properties",
|
|
||||||
"core-foundation-sys",
|
|
||||||
"iana-time-zone-haiku",
|
|
||||||
"js-sys",
|
|
||||||
"log",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"windows-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iana-time-zone-haiku"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indexmap"
|
|
||||||
version = "2.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
|
||||||
dependencies = [
|
|
||||||
"equivalent",
|
|
||||||
"hashbrown",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indoc"
|
|
||||||
version = "2.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
|
|
||||||
dependencies = [
|
|
||||||
"rustversion",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itertools"
|
|
||||||
version = "0.14.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "js-sys"
|
|
||||||
version = "0.3.94"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9"
|
|
||||||
dependencies = [
|
|
||||||
"once_cell",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "keccak"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653"
|
|
||||||
dependencies = [
|
|
||||||
"cpufeatures",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lalrpop"
|
|
||||||
version = "0.22.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ba4ebbd48ce411c1d10fb35185f5a51a7bfa3d8b24b4e330d30c9e3a34129501"
|
|
||||||
dependencies = [
|
|
||||||
"ascii-canvas",
|
|
||||||
"bit-set",
|
|
||||||
"ena",
|
|
||||||
"itertools",
|
|
||||||
"lalrpop-util",
|
|
||||||
"petgraph",
|
|
||||||
"pico-args",
|
|
||||||
"regex",
|
|
||||||
"regex-syntax",
|
|
||||||
"sha3",
|
|
||||||
"string_cache",
|
|
||||||
"term",
|
|
||||||
"unicode-xid",
|
|
||||||
"walkdir",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lalrpop-util"
|
|
||||||
version = "0.22.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b5baa5e9ff84f1aefd264e6869907646538a52147a755d494517a8007fb48733"
|
|
||||||
dependencies = [
|
|
||||||
"regex-automata",
|
|
||||||
"rustversion",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.184"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lock_api"
|
|
||||||
version = "0.4.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
|
|
||||||
dependencies = [
|
|
||||||
"scopeguard",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "log"
|
|
||||||
version = "0.4.29"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mio"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"wasi",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "new_debug_unreachable"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-traits"
|
|
||||||
version = "0.2.19"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "once_cell"
|
|
||||||
version = "1.21.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot"
|
|
||||||
version = "0.12.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
|
|
||||||
dependencies = [
|
|
||||||
"lock_api",
|
|
||||||
"parking_lot_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot_core"
|
|
||||||
version = "0.9.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"redox_syscall",
|
|
||||||
"smallvec",
|
|
||||||
"windows-link",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "paste"
|
|
||||||
version = "1.0.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "petgraph"
|
|
||||||
version = "0.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
|
|
||||||
dependencies = [
|
|
||||||
"fixedbitset",
|
|
||||||
"indexmap",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_shared"
|
|
||||||
version = "0.11.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
|
||||||
dependencies = [
|
|
||||||
"siphasher",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pico-args"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-project-lite"
|
|
||||||
version = "0.2.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "precomputed-hash"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pretty_assertions"
|
|
||||||
version = "1.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
|
|
||||||
dependencies = [
|
|
||||||
"diff",
|
|
||||||
"yansi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2"
|
|
||||||
version = "1.0.106"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote"
|
|
||||||
version = "1.0.45"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "redox_syscall"
|
|
||||||
version = "0.5.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex"
|
|
||||||
version = "1.12.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-automata",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-automata"
|
|
||||||
version = "0.4.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.8.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustversion"
|
|
||||||
version = "1.0.22"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "same-file"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scopeguard"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde"
|
|
||||||
version = "1.0.228"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
|
||||||
dependencies = [
|
|
||||||
"serde_core",
|
|
||||||
"serde_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_core"
|
|
||||||
version = "1.0.228"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
|
||||||
dependencies = [
|
|
||||||
"serde_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_derive"
|
|
||||||
version = "1.0.228"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sha3"
|
|
||||||
version = "0.10.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
|
|
||||||
dependencies = [
|
|
||||||
"digest",
|
|
||||||
"keccak",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "shlex"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "siphasher"
|
|
||||||
version = "1.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "slab"
|
|
||||||
version = "0.4.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smallvec"
|
|
||||||
version = "1.15.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "socket2"
|
|
||||||
version = "0.6.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "string_cache"
|
|
||||||
version = "0.8.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f"
|
|
||||||
dependencies = [
|
|
||||||
"new_debug_unreachable",
|
|
||||||
"parking_lot",
|
|
||||||
"phf_shared",
|
|
||||||
"precomputed-hash",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "2.0.117"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "term"
|
|
||||||
version = "1.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d8c27177b12a6399ffc08b98f76f7c9a1f4fe9fc967c784c5a071fa8d93cf7e1"
|
|
||||||
dependencies = [
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror"
|
|
||||||
version = "2.0.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
|
||||||
dependencies = [
|
|
||||||
"thiserror-impl",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror-impl"
|
|
||||||
version = "2.0.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio"
|
|
||||||
version = "1.50.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"libc",
|
|
||||||
"mio",
|
|
||||||
"pin-project-lite",
|
|
||||||
"socket2",
|
|
||||||
"tokio-macros",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-macros"
|
|
||||||
version = "2.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typenum"
|
|
||||||
version = "1.19.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-ident"
|
|
||||||
version = "1.0.24"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-xid"
|
|
||||||
version = "0.2.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version_check"
|
|
||||||
version = "0.9.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "walkdir"
|
|
||||||
version = "2.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
|
||||||
dependencies = [
|
|
||||||
"same-file",
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.11.1+wasi-snapshot-preview1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen"
|
|
||||||
version = "0.2.117"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"once_cell",
|
|
||||||
"rustversion",
|
|
||||||
"wasm-bindgen-macro",
|
|
||||||
"wasm-bindgen-shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-macro"
|
|
||||||
version = "0.2.117"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be"
|
|
||||||
dependencies = [
|
|
||||||
"quote",
|
|
||||||
"wasm-bindgen-macro-support",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-macro-support"
|
|
||||||
version = "0.2.117"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2"
|
|
||||||
dependencies = [
|
|
||||||
"bumpalo",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"wasm-bindgen-shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-shared"
|
|
||||||
version = "0.2.117"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-util"
|
|
||||||
version = "0.1.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
|
||||||
dependencies = [
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-core"
|
|
||||||
version = "0.62.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
|
||||||
dependencies = [
|
|
||||||
"windows-implement",
|
|
||||||
"windows-interface",
|
|
||||||
"windows-link",
|
|
||||||
"windows-result",
|
|
||||||
"windows-strings",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-implement"
|
|
||||||
version = "0.60.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-interface"
|
|
||||||
version = "0.59.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-link"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-result"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
|
|
||||||
dependencies = [
|
|
||||||
"windows-link",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-strings"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
|
|
||||||
dependencies = [
|
|
||||||
"windows-link",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.61.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
|
||||||
dependencies = [
|
|
||||||
"windows-link",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "yansi"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
|
||||||
+6
-7
@@ -4,7 +4,6 @@ version = "0.1.0"
|
|||||||
authors = [
|
authors = [
|
||||||
"Øystein Tveit <oysteikt@pvv.ntnu.no>"
|
"Øystein Tveit <oysteikt@pvv.ntnu.no>"
|
||||||
]
|
]
|
||||||
license = "MIT"
|
|
||||||
description = "A rust implementation of the mpd protocol, both client and serverside"
|
description = "A rust implementation of the mpd protocol, both client and serverside"
|
||||||
repository = "https://git.pvv.ntnu.no/Grzegorz/empidee"
|
repository = "https://git.pvv.ntnu.no/Grzegorz/empidee"
|
||||||
documentation = "https://pages.pvv.ntnu.no/Grzegorz/empidee/main/docs/empidee/"
|
documentation = "https://pages.pvv.ntnu.no/Grzegorz/empidee/main/docs/empidee/"
|
||||||
@@ -12,13 +11,13 @@ edition = "2024"
|
|||||||
rust-version = "1.85.0"
|
rust-version = "1.85.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = { version = "0.4.44", features = ["serde"] }
|
chrono = { version = "0.4.42", features = ["serde"] }
|
||||||
futures-util = { version = "0.3.32", optional = true, features = ["io"] }
|
futures-util = { version = "0.3.31", optional = true, features = ["io"] }
|
||||||
lalrpop-util = { version = "0.22.2", features = ["lexer"] }
|
lalrpop-util = { version = "0.22.2", features = ["lexer"] }
|
||||||
paste = "1.0.15"
|
paste = "1.0.15"
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
thiserror = "2.0.18"
|
thiserror = "2.0.17"
|
||||||
tokio = { version = "1.50.0", optional = true, features = ["io-util"] }
|
tokio = { version = "1.48.0", optional = true, features = ["io-util"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["tokio"]
|
default = ["tokio"]
|
||||||
@@ -26,10 +25,10 @@ futures = ["dep:futures-util"]
|
|||||||
tokio = ["dep:tokio"]
|
tokio = ["dep:tokio"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
anyhow = "1.0.102"
|
anyhow = "1.0.100"
|
||||||
indoc = "2.0.7"
|
indoc = "2.0.7"
|
||||||
pretty_assertions = "1.4.1"
|
pretty_assertions = "1.4.1"
|
||||||
tokio = { version = "1.50.0", features = ["macros", "net", "rt"] }
|
tokio = { version = "1.48.0", features = ["macros", "net", "rt"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
lalrpop = "0.22.2"
|
lalrpop = "0.22.2"
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2025 Programvareverkstedet <projects@pvv.ntnu.no>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
|
lalrpop::process_root().unwrap();
|
||||||
// let debug_mode = std::env::var("PROFILE").unwrap() == "debug";
|
// let debug_mode = std::env::var("PROFILE").unwrap() == "debug";
|
||||||
|
// lalrpop::Configuration::new()
|
||||||
lalrpop::Configuration::new()
|
// .emit_comments(debug_mode)
|
||||||
//.emit_comments(debug_mode)
|
// .process()
|
||||||
// .generate_in_source_tree()
|
// .unwrap();
|
||||||
.process()
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,9 @@ use empidee::MpdClient;
|
|||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
let socket = tokio::net::TcpSocket::new_v4()?;
|
let socket = tokio::net::TcpSocket::new_v4()?;
|
||||||
let mut stream = socket.connect("127.0.0.1:6600".parse()?).await?;
|
let mut stream = socket.connect("127.0.0.1:6600".parse()?).await?;
|
||||||
let mut client = MpdClient::new(&mut stream).await?;
|
|
||||||
println!(
|
let mut client = MpdClient::new(&mut stream);
|
||||||
"Connected to MPD server: {}",
|
println!("{}", client.read_initial_mpd_version().await?);
|
||||||
client.get_mpd_version().unwrap_or("unknown")
|
|
||||||
);
|
|
||||||
|
|
||||||
client.play(None).await?;
|
client.play(None).await?;
|
||||||
|
|
||||||
|
|||||||
Generated
+6
-6
@@ -2,11 +2,11 @@
|
|||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1775036866,
|
"lastModified": 1764950072,
|
||||||
"narHash": "sha256-ZojAnPuCdy657PbTq5V0Y+AHKhZAIwSIT2cb8UgAz/U=",
|
"narHash": "sha256-BmPWzogsG2GsXZtlT+MTcAWeDK5hkbGRZTeZNW42fwA=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "6201e203d09599479a3b3450ed24fa81537ebc4e",
|
"rev": "f61125a668a320878494449750330ca58b78c557",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -29,11 +29,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1775099554,
|
"lastModified": 1765075567,
|
||||||
"narHash": "sha256-3xBsGnGDLOFtnPZ1D3j2LU19wpAlYefRKTlkv648rU0=",
|
"narHash": "sha256-KFDCdQcHJ0hE3Nt5Gm5enRIhmtEifAjpxgUQ3mzSJpA=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "8d6387ed6d8e6e6672fd3ed4b61b59d44b124d99",
|
"rev": "769156779b41e8787a46ca3d7d76443aaf68be6f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -42,46 +42,5 @@
|
|||||||
RUST_SRC_PATH = "${toolchain}/lib/rustlib/src/rust/library";
|
RUST_SRC_PATH = "${toolchain}/lib/rustlib/src/rust/library";
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
packages = forAllSystems (system: pkgs: toolchain: let
|
|
||||||
rustPlatform = pkgs.makeRustPlatform {
|
|
||||||
cargo = toolchain;
|
|
||||||
rustc = toolchain;
|
|
||||||
};
|
|
||||||
cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml);
|
|
||||||
src = lib.fileset.toSource {
|
|
||||||
root = ./.;
|
|
||||||
fileset = lib.fileset.unions [
|
|
||||||
./.cargo
|
|
||||||
./Cargo.toml
|
|
||||||
./Cargo.lock
|
|
||||||
./LICENSE
|
|
||||||
./README.md
|
|
||||||
./build.rs
|
|
||||||
./examples
|
|
||||||
./rustfmt.toml
|
|
||||||
./src
|
|
||||||
];
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
default = self.packages.${system}.example-binaries;
|
|
||||||
example-binaries = rustPlatform.buildRustPackage {
|
|
||||||
pname = "empidee-example-bins";
|
|
||||||
inherit (cargoToml.package) version;
|
|
||||||
inherit src;
|
|
||||||
|
|
||||||
cargoLock.lockFile = ./Cargo.lock;
|
|
||||||
|
|
||||||
cargoBuildFlags = [ "--examples" ];
|
|
||||||
|
|
||||||
# TODO: avoid the binary variant with the hash at the end
|
|
||||||
postInstall = ''
|
|
||||||
find "$releaseDir"/examples -type f -executable -exec install -Dt "$out/bin" {} \;
|
|
||||||
'';
|
|
||||||
|
|
||||||
doCheck = true;
|
|
||||||
useNextest = true;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-55
@@ -4,25 +4,23 @@
|
|||||||
//! managing the playlist, and returns the expected response types directly
|
//! managing the playlist, and returns the expected response types directly
|
||||||
//! from its methods.
|
//! from its methods.
|
||||||
|
|
||||||
use crate::{commands::*, types::SongPosition};
|
use crate::{Request, commands::*, types::SongPosition};
|
||||||
|
|
||||||
#[cfg(feature = "futures")]
|
#[cfg(feature = "futures")]
|
||||||
use futures_util::{
|
use futures_util::{
|
||||||
AsyncBufReadExt,
|
AsyncBufReadExt,
|
||||||
io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, BufWriter},
|
io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufReader},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "tokio")]
|
|
||||||
use tokio::io::{AsyncBufReadExt, AsyncRead, AsyncWrite, AsyncWriteExt, BufStream};
|
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
#[cfg(feature = "tokio")]
|
||||||
|
use tokio::io::{AsyncBufReadExt, AsyncRead, AsyncWrite, AsyncWriteExt, BufReader};
|
||||||
|
|
||||||
pub struct MpdClient<'a, T>
|
pub struct MpdClient<'a, T>
|
||||||
where
|
where
|
||||||
T: AsyncWrite + AsyncRead + Unpin,
|
T: AsyncWrite + AsyncRead + Unpin,
|
||||||
{
|
{
|
||||||
stream: BufStream<&'a mut T>,
|
connection: &'a mut T,
|
||||||
mpd_version: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
@@ -41,53 +39,30 @@ impl<'a, T> MpdClient<'a, T>
|
|||||||
where
|
where
|
||||||
T: AsyncWrite + AsyncRead + Unpin,
|
T: AsyncWrite + AsyncRead + Unpin,
|
||||||
{
|
{
|
||||||
pub async fn new(connection: &'a mut T) -> Result<Self, MpdClientError> {
|
pub fn new(connection: &'a mut T) -> Self {
|
||||||
let mut client = MpdClient {
|
MpdClient { connection }
|
||||||
stream: BufStream::new(connection),
|
|
||||||
mpd_version: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
client.read_initial_mpd_version().await?;
|
|
||||||
|
|
||||||
Ok(client)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn wrap_existing(connection: &'a mut T, mpd_version: Option<String>) -> Self {
|
pub async fn read_initial_mpd_version(&mut self) -> Result<String, MpdClientError> {
|
||||||
MpdClient {
|
let mut reader = BufReader::new(&mut self.connection);
|
||||||
stream: BufStream::new(connection),
|
|
||||||
mpd_version,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_connection(self) -> &'a mut T {
|
|
||||||
self.stream.into_inner()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_mpd_version(&self) -> Option<&str> {
|
|
||||||
self.mpd_version.as_deref()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn read_initial_mpd_version(&mut self) -> Result<(), MpdClientError> {
|
|
||||||
let mut version_line = String::new();
|
let mut version_line = String::new();
|
||||||
|
|
||||||
self.stream
|
reader
|
||||||
.read_line(&mut version_line)
|
.read_line(&mut version_line)
|
||||||
.await
|
.await
|
||||||
.map_err(MpdClientError::ConnectionError)?;
|
.map_err(MpdClientError::ConnectionError)?;
|
||||||
|
|
||||||
self.mpd_version = Some(version_line.trim().to_string());
|
Ok(version_line.trim().to_string())
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_response(&mut self) -> Result<Vec<u8>, MpdClientError> {
|
async fn read_response(&mut self) -> Result<Vec<u8>, MpdClientError> {
|
||||||
let mut response = Vec::new();
|
let mut response = Vec::new();
|
||||||
|
let mut reader = BufReader::new(&mut self.connection);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut line = Vec::new();
|
let mut line = Vec::new();
|
||||||
|
|
||||||
let bytes_read = self
|
let bytes_read = reader
|
||||||
.stream
|
|
||||||
.read_until(b'\n', &mut line)
|
.read_until(b'\n', &mut line)
|
||||||
.await
|
.await
|
||||||
.map_err(MpdClientError::ConnectionError)?;
|
.map_err(MpdClientError::ConnectionError)?;
|
||||||
@@ -106,33 +81,25 @@ where
|
|||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute<C>(&mut self, request: C::Request) -> Result<C::Response, MpdClientError>
|
pub async fn play(
|
||||||
where
|
&mut self,
|
||||||
C: Command,
|
position: Option<SongPosition>,
|
||||||
{
|
) -> Result<PlayResponse, MpdClientError> {
|
||||||
let payload = request.serialize();
|
let message = Request::Play(position);
|
||||||
|
let payload = message.serialize();
|
||||||
|
|
||||||
self.stream
|
self.connection
|
||||||
.write_all(payload.as_bytes())
|
.write_all(payload.as_bytes())
|
||||||
.await
|
.await
|
||||||
.map_err(MpdClientError::ConnectionError)?;
|
.map_err(MpdClientError::ConnectionError)?;
|
||||||
|
|
||||||
self.stream
|
self.connection
|
||||||
.flush()
|
.flush()
|
||||||
.await
|
.await
|
||||||
.map_err(MpdClientError::ConnectionError)?;
|
.map_err(MpdClientError::ConnectionError)?;
|
||||||
|
|
||||||
let response_bytes = self.read_response().await?;
|
let response_bytes = self.read_response().await?;
|
||||||
let response = C::Response::parse_raw(&response_bytes)?;
|
let response = PlayResponse::parse_raw(&response_bytes)?;
|
||||||
|
|
||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn play(
|
|
||||||
&mut self,
|
|
||||||
position: Option<SongPosition>,
|
|
||||||
) -> Result<PlayResponse, MpdClientError> {
|
|
||||||
let request = <Play as Command>::Request::new(position);
|
|
||||||
self.execute::<Play>(request).await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+179
-32
@@ -9,9 +9,6 @@
|
|||||||
|
|
||||||
use crate::{request_tokenizer::RequestTokenizer, response_tokenizer::ResponseAttributes};
|
use crate::{request_tokenizer::RequestTokenizer, response_tokenizer::ResponseAttributes};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
mod audio_output_devices;
|
mod audio_output_devices;
|
||||||
mod client_to_client;
|
mod client_to_client;
|
||||||
mod connection_settings;
|
mod connection_settings;
|
||||||
@@ -37,11 +34,22 @@ pub use playback_options::*;
|
|||||||
pub use querying_mpd_status::*;
|
pub use querying_mpd_status::*;
|
||||||
pub use queue::*;
|
pub use queue::*;
|
||||||
pub use reflection::*;
|
pub use reflection::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
pub use stickers::*;
|
pub use stickers::*;
|
||||||
pub use stored_playlists::*;
|
pub use stored_playlists::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "futures")]
|
||||||
|
use futures_util::{
|
||||||
|
AsyncBufReadExt,
|
||||||
|
io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufReader},
|
||||||
|
};
|
||||||
|
|
||||||
|
use thiserror::Error;
|
||||||
|
#[cfg(feature = "tokio")]
|
||||||
|
use tokio::io::{AsyncBufReadExt, AsyncRead, AsyncWrite, AsyncWriteExt, BufReader};
|
||||||
|
|
||||||
/// A trait modelling a single MPD command request.
|
/// A trait modelling a single MPD command request.
|
||||||
pub trait CommandRequest
|
pub(crate) trait CommandRequest
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
@@ -88,6 +96,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts this specific request type to it's corresponding variant in the generic Request enum.
|
||||||
|
fn into_request_enum(self) -> crate::Request;
|
||||||
|
|
||||||
|
/// Converts from the generic Request enum to this specific request type.
|
||||||
|
///
|
||||||
|
/// If the enum variant does not match this type, returns None.
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self>;
|
||||||
|
|
||||||
/// Serializes the request into a String.
|
/// Serializes the request into a String.
|
||||||
fn serialize(&self) -> String;
|
fn serialize(&self) -> String;
|
||||||
|
|
||||||
@@ -100,7 +116,7 @@ where
|
|||||||
/// This assumes the raw string starts with the command name, e.g.
|
/// This assumes the raw string starts with the command name, e.g.
|
||||||
/// `command_name arg1 "arg2 arg3"`
|
/// `command_name arg1 "arg2 arg3"`
|
||||||
fn parse_raw(raw: &str) -> Result<Self, RequestParserError> {
|
fn parse_raw(raw: &str) -> Result<Self, RequestParserError> {
|
||||||
let (line, _rest) = raw
|
let (line, rest) = raw
|
||||||
.split_once('\n')
|
.split_once('\n')
|
||||||
.ok_or(RequestParserError::MissingNewline)?;
|
.ok_or(RequestParserError::MissingNewline)?;
|
||||||
|
|
||||||
@@ -129,10 +145,18 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A trait modelling a single MPD command response.
|
/// A trait modelling a single MPD command response.
|
||||||
pub trait CommandResponse
|
pub(crate) trait CommandResponse
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
/// Converts this specific response type to it's corresponding variant in the generic Response enum.
|
||||||
|
fn into_response_enum(self) -> crate::Response;
|
||||||
|
|
||||||
|
/// Converts from the generic Response enum to this specific response type.
|
||||||
|
///
|
||||||
|
/// If the enum variant does not match this type, returns None.
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self>;
|
||||||
|
|
||||||
// /// Serializes the response into a Vec<u8>.
|
// /// Serializes the response into a Vec<u8>.
|
||||||
// fn serialize(&self) -> Vec<u8>;
|
// fn serialize(&self) -> Vec<u8>;
|
||||||
|
|
||||||
@@ -156,6 +180,16 @@ pub trait Command {
|
|||||||
/// The command name used within the protocol
|
/// The command name used within the protocol
|
||||||
const COMMAND: &'static str = Self::Request::COMMAND;
|
const COMMAND: &'static str = Self::Request::COMMAND;
|
||||||
|
|
||||||
|
/// Serialize the request into a string.
|
||||||
|
/// This should optimally produce an input that can be parsed by [`parse_request`]
|
||||||
|
fn serialize_request(&self, request: Self::Request) -> String {
|
||||||
|
request.serialize().to_owned()
|
||||||
|
}
|
||||||
|
/// Serialize the request into a bytestring.
|
||||||
|
fn serialize_request_to_bytes(&self, request: Self::Request) -> Vec<u8> {
|
||||||
|
self.serialize_request(request).into_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse the request from its tokenized parts. See also [`parse_raw_request`].
|
/// Parse the request from its tokenized parts. See also [`parse_raw_request`].
|
||||||
fn parse_request(parts: RequestTokenizer) -> Result<Self::Request, RequestParserError> {
|
fn parse_request(parts: RequestTokenizer) -> Result<Self::Request, RequestParserError> {
|
||||||
Self::Request::parse(parts)
|
Self::Request::parse(parts)
|
||||||
@@ -178,6 +212,55 @@ pub trait Command {
|
|||||||
fn parse_raw_response(raw: &[u8]) -> Result<Self::Response, ResponseParserError> {
|
fn parse_raw_response(raw: &[u8]) -> Result<Self::Response, ResponseParserError> {
|
||||||
Self::Response::parse_raw(raw)
|
Self::Response::parse_raw(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn execute<T>(
|
||||||
|
request: Self::Request,
|
||||||
|
connection: &mut T,
|
||||||
|
) -> Result<Self::Response, crate::MpdClientError>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
T: AsyncWrite + AsyncRead + Unpin,
|
||||||
|
{
|
||||||
|
let payload = request.serialize();
|
||||||
|
|
||||||
|
connection
|
||||||
|
.write_all(payload.as_bytes())
|
||||||
|
.await
|
||||||
|
.map_err(crate::MpdClientError::ConnectionError)?;
|
||||||
|
|
||||||
|
connection
|
||||||
|
.flush()
|
||||||
|
.await
|
||||||
|
.map_err(crate::MpdClientError::ConnectionError)?;
|
||||||
|
|
||||||
|
let mut response_bytes = Vec::new();
|
||||||
|
let mut reader = BufReader::new(connection);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut line = Vec::new();
|
||||||
|
|
||||||
|
let bytes_read = reader
|
||||||
|
.read_until(b'\n', &mut line)
|
||||||
|
.await
|
||||||
|
.map_err(crate::MpdClientError::ConnectionError)?;
|
||||||
|
|
||||||
|
if bytes_read == 0 {
|
||||||
|
break; // EOF reached
|
||||||
|
}
|
||||||
|
|
||||||
|
response_bytes.extend_from_slice(&line);
|
||||||
|
|
||||||
|
// TODO: handle errors properly
|
||||||
|
if line == b"OK\n" || line.starts_with(b"ACK ") {
|
||||||
|
break; // End of response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = Self::parse_raw_response(&response_bytes)
|
||||||
|
.map_err(crate::MpdClientError::ResponseParseError)?;
|
||||||
|
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request/response implementation helpers
|
// Request/response implementation helpers
|
||||||
@@ -189,9 +272,9 @@ macro_rules! empty_command_request {
|
|||||||
pub struct [<$name Request>];
|
pub struct [<$name Request>];
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for paste::paste! { [<$name Request>] } {
|
impl paste::paste! { [<$name Request>] } {
|
||||||
fn default() -> Self {
|
pub fn new() -> Self {
|
||||||
paste::paste! { [<$name Request>] }
|
Self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,6 +283,22 @@ macro_rules! empty_command_request {
|
|||||||
const MIN_ARGS: u32 = 0;
|
const MIN_ARGS: u32 = 0;
|
||||||
const MAX_ARGS: Option<u32> = Some(0);
|
const MAX_ARGS: Option<u32> = Some(0);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
match Self::COMMAND {
|
||||||
|
$command_name => crate::Request::$name,
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match (Self::COMMAND, request) {
|
||||||
|
($command_name, crate::Request::$name) => {
|
||||||
|
Some(paste::paste! { [<$name Request>] })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
Self::COMMAND.to_string() + "\n"
|
Self::COMMAND.to_string() + "\n"
|
||||||
}
|
}
|
||||||
@@ -222,13 +321,21 @@ macro_rules! empty_command_response {
|
|||||||
pub struct [<$name Response>];
|
pub struct [<$name Response>];
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for paste::paste! { [<$name Response>] } {
|
impl paste::paste! { [<$name Response>] } {
|
||||||
fn default() -> Self {
|
pub fn new() -> Self {
|
||||||
paste::paste! { [<$name Response>] }
|
Self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::commands::CommandResponse for paste::paste! { [<$name Response>] } {
|
impl crate::commands::CommandResponse for paste::paste! { [<$name Response>] } {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(_response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(
|
fn parse(
|
||||||
_parts: crate::commands::ResponseAttributes<'_>,
|
_parts: crate::commands::ResponseAttributes<'_>,
|
||||||
) -> Result<Self, crate::commands::ResponseParserError> {
|
) -> Result<Self, crate::commands::ResponseParserError> {
|
||||||
@@ -243,14 +350,12 @@ macro_rules! single_item_command_request {
|
|||||||
($name:ident, $command_name:expr, $item_type:ty) => {
|
($name:ident, $command_name:expr, $item_type:ty) => {
|
||||||
paste::paste! {
|
paste::paste! {
|
||||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct [<$name Request>] (pub $item_type);
|
pub struct [<$name Request>] ($item_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl paste::paste! { [<$name Request>] } {
|
impl paste::paste! { [<$name Request>] } {
|
||||||
pub fn new(item: $item_type) -> Self {
|
pub fn new(arg: $item_type) -> Self {
|
||||||
paste::paste! {
|
Self(arg)
|
||||||
crate::commands::[<$name Request>](item)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,6 +364,22 @@ macro_rules! single_item_command_request {
|
|||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(1);
|
const MAX_ARGS: Option<u32> = Some(1);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
match Self::COMMAND {
|
||||||
|
$command_name => crate::Request::$name(self.0),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match (Self::COMMAND, request) {
|
||||||
|
($command_name, crate::Request::$name(item)) => {
|
||||||
|
Some(paste::paste! { [<$name Request>] ( item ) })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {}\n", Self::COMMAND, self.0)
|
format!("{} {}\n", Self::COMMAND, self.0)
|
||||||
}
|
}
|
||||||
@@ -288,14 +409,12 @@ macro_rules! single_optional_item_command_request {
|
|||||||
($name:ident, $command_name:expr, $item_type:ty) => {
|
($name:ident, $command_name:expr, $item_type:ty) => {
|
||||||
paste::paste! {
|
paste::paste! {
|
||||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct [<$name Request>] (pub Option<$item_type>);
|
pub struct [<$name Request>] (Option<$item_type>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl paste::paste! { [<$name Request>] } {
|
impl paste::paste! { [<$name Request>] } {
|
||||||
pub fn new(item: Option<$item_type>) -> Self {
|
pub fn new(arg: Option<$item_type>) -> Self {
|
||||||
paste::paste! {
|
Self(arg)
|
||||||
crate::commands::[<$name Request>](item)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,6 +423,22 @@ macro_rules! single_optional_item_command_request {
|
|||||||
const MIN_ARGS: u32 = 0;
|
const MIN_ARGS: u32 = 0;
|
||||||
const MAX_ARGS: Option<u32> = Some(1);
|
const MAX_ARGS: Option<u32> = Some(1);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
match Self::COMMAND {
|
||||||
|
$command_name => crate::Request::$name(self.0),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match (Self::COMMAND, request) {
|
||||||
|
($command_name, crate::Request::$name(item)) => {
|
||||||
|
Some(paste::paste! { [<$name Request>] ( item ) })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
Some(item) => format!("{} {}\n", Self::COMMAND, item),
|
Some(item) => format!("{} {}\n", Self::COMMAND, item),
|
||||||
@@ -339,18 +474,24 @@ macro_rules! single_item_command_response {
|
|||||||
($name:ident, $item_name:expr, $item_type:ty) => {
|
($name:ident, $item_name:expr, $item_type:ty) => {
|
||||||
paste::paste! {
|
paste::paste! {
|
||||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct [<$name Response>] (pub $item_type);
|
pub struct [<$name Response>] ( $item_type );
|
||||||
}
|
}
|
||||||
|
|
||||||
impl paste::paste! { [<$name Response>] } {
|
impl paste::paste! { [<$name Response>] } {
|
||||||
pub fn new(item: $item_type) -> Self {
|
pub fn new(arg: $item_type) -> Self {
|
||||||
paste::paste! {
|
Self(arg)
|
||||||
crate::commands::[<$name Response>](item)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::commands::CommandResponse for paste::paste! { [<$name Response>] } {
|
impl crate::commands::CommandResponse for paste::paste! { [<$name Response>] } {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(_response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(
|
fn parse(
|
||||||
parts: crate::commands::ResponseAttributes<'_>,
|
parts: crate::commands::ResponseAttributes<'_>,
|
||||||
) -> Result<Self, crate::commands::ResponseParserError> {
|
) -> Result<Self, crate::commands::ResponseParserError> {
|
||||||
@@ -383,18 +524,24 @@ macro_rules! multi_item_command_response {
|
|||||||
($name:ident, $item_name:expr, $item_type:ty) => {
|
($name:ident, $item_name:expr, $item_type:ty) => {
|
||||||
paste::paste! {
|
paste::paste! {
|
||||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct [<$name Response>] (pub Vec<$item_type>);
|
pub struct [<$name Response>] ( Vec<$item_type> );
|
||||||
}
|
}
|
||||||
|
|
||||||
impl paste::paste! { [<$name Response>] } {
|
impl paste::paste! { [<$name Response>] } {
|
||||||
pub fn new(items: Vec<$item_type>) -> Self {
|
pub fn new(arg: Vec<$item_type>) -> Self {
|
||||||
paste::paste! {
|
Self(arg)
|
||||||
crate::commands::[<$name Response>](items)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::commands::CommandResponse for paste::paste! { [<$name Response>] } {
|
impl crate::commands::CommandResponse for paste::paste! { [<$name Response>] } {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(_response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(
|
fn parse(
|
||||||
parts: crate::commands::ResponseAttributes<'_>,
|
parts: crate::commands::ResponseAttributes<'_>,
|
||||||
) -> Result<Self, crate::commands::ResponseParserError> {
|
) -> Result<Self, crate::commands::ResponseParserError> {
|
||||||
|
|||||||
@@ -15,12 +15,6 @@ empty_command_request!(Outputs, "outputs");
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct OutputsResponse(Vec<Output>);
|
pub struct OutputsResponse(Vec<Output>);
|
||||||
|
|
||||||
impl OutputsResponse {
|
|
||||||
pub fn new(outputs: Vec<Output>) -> Self {
|
|
||||||
OutputsResponse(outputs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Output {
|
pub struct Output {
|
||||||
pub id: AudioOutputId,
|
pub id: AudioOutputId,
|
||||||
@@ -30,25 +24,15 @@ pub struct Output {
|
|||||||
pub attribute: HashMap<String, String>,
|
pub attribute: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Output {
|
|
||||||
pub fn new(
|
|
||||||
id: AudioOutputId,
|
|
||||||
name: String,
|
|
||||||
plugin: String,
|
|
||||||
enabled: bool,
|
|
||||||
attribute: HashMap<String, String>,
|
|
||||||
) -> Self {
|
|
||||||
Output {
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
plugin,
|
|
||||||
enabled,
|
|
||||||
attribute,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for OutputsResponse {
|
impl CommandResponse for OutputsResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts = parts.into_vec()?;
|
let parts = parts.into_vec()?;
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ pub struct OutputSetRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OutputSetRequest {
|
impl OutputSetRequest {
|
||||||
pub fn new(output_id: AudioOutputId, attribute_name: String, attribute_value: String) -> Self {
|
fn new(output_id: AudioOutputId, attribute_name: String, attribute_value: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
output_id,
|
output_id,
|
||||||
attribute_name,
|
attribute_name,
|
||||||
@@ -30,6 +30,23 @@ impl CommandRequest for OutputSetRequest {
|
|||||||
const MIN_ARGS: u32 = 3;
|
const MIN_ARGS: u32 = 3;
|
||||||
const MAX_ARGS: Option<u32> = Some(3);
|
const MAX_ARGS: Option<u32> = Some(3);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::OutputSet(self.output_id, self.attribute_name, self.attribute_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::OutputSet(output_id, attribute_name, attribute_value) => {
|
||||||
|
Some(OutputSetRequest {
|
||||||
|
output_id,
|
||||||
|
attribute_name,
|
||||||
|
attribute_value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} {} {} {}",
|
"{} {} {} {}",
|
||||||
|
|||||||
@@ -15,13 +15,15 @@ pub struct ChannelsResponse {
|
|||||||
pub channels: Vec<ChannelName>,
|
pub channels: Vec<ChannelName>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelsResponse {
|
|
||||||
pub fn new(channels: Vec<ChannelName>) -> Self {
|
|
||||||
ChannelsResponse { channels }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for ChannelsResponse {
|
impl CommandResponse for ChannelsResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: Vec<_> = parts.into_vec()?;
|
let parts: Vec<_> = parts.into_vec()?;
|
||||||
let mut channel_names = Vec::with_capacity(parts.len());
|
let mut channel_names = Vec::with_capacity(parts.len());
|
||||||
|
|||||||
@@ -13,25 +13,21 @@ empty_command_request!(ReadMessages, "readmessages");
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ReadMessagesResponse(Vec<ReadMessagesResponseEntry>);
|
pub struct ReadMessagesResponse(Vec<ReadMessagesResponseEntry>);
|
||||||
|
|
||||||
impl ReadMessagesResponse {
|
|
||||||
pub fn new(entries: Vec<ReadMessagesResponseEntry>) -> Self {
|
|
||||||
ReadMessagesResponse(entries)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ReadMessagesResponseEntry {
|
pub struct ReadMessagesResponseEntry {
|
||||||
channel: ChannelName,
|
channel: ChannelName,
|
||||||
message: String,
|
message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReadMessagesResponseEntry {
|
|
||||||
pub fn new(channel: ChannelName, message: String) -> Self {
|
|
||||||
ReadMessagesResponseEntry { channel, message }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for ReadMessagesResponse {
|
impl CommandResponse for ReadMessagesResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: Vec<_> = parts.into_vec()?;
|
let parts: Vec<_> = parts.into_vec()?;
|
||||||
debug_assert!(parts.len() % 2 == 0);
|
debug_assert!(parts.len() % 2 == 0);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ pub struct SendMessageRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SendMessageRequest {
|
impl SendMessageRequest {
|
||||||
pub fn new(channel: ChannelName, message: String) -> Self {
|
fn new(channel: ChannelName, message: String) -> Self {
|
||||||
Self { channel, message }
|
Self { channel, message }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,19 @@ impl CommandRequest for SendMessageRequest {
|
|||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = None;
|
const MAX_ARGS: Option<u32> = None;
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::SendMessage(self.channel, self.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::SendMessage(channel, message) => {
|
||||||
|
Some(SendMessageRequest { channel, message })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {} {}", Self::COMMAND, self.channel, self.message)
|
format!("{} {} {}", Self::COMMAND, self.channel, self.message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ pub struct ProtocolDisable;
|
|||||||
pub struct ProtocolDisableRequest(Vec<Feature>);
|
pub struct ProtocolDisableRequest(Vec<Feature>);
|
||||||
|
|
||||||
impl ProtocolDisableRequest {
|
impl ProtocolDisableRequest {
|
||||||
pub fn new(features: Vec<Feature>) -> Self {
|
fn new(features: Vec<Feature>) -> Self {
|
||||||
ProtocolDisableRequest(features)
|
Self(features)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,6 +19,17 @@ impl CommandRequest for ProtocolDisableRequest {
|
|||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = None;
|
const MAX_ARGS: Option<u32> = None;
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::ProtocolDisable(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::ProtocolDisable(features) => Some(ProtocolDisableRequest(features)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let features = self
|
let features = self
|
||||||
.0
|
.0
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ pub struct ProtocolEnable;
|
|||||||
pub struct ProtocolEnableRequest(Vec<Feature>);
|
pub struct ProtocolEnableRequest(Vec<Feature>);
|
||||||
|
|
||||||
impl ProtocolEnableRequest {
|
impl ProtocolEnableRequest {
|
||||||
pub fn new(features: Vec<Feature>) -> Self {
|
fn new(features: Vec<Feature>) -> Self {
|
||||||
ProtocolEnableRequest(features)
|
Self(features)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,6 +19,17 @@ impl CommandRequest for ProtocolEnableRequest {
|
|||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = None;
|
const MAX_ARGS: Option<u32> = None;
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::ProtocolEnable(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::ProtocolEnable(features) => Some(ProtocolEnableRequest(features)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let features = self
|
let features = self
|
||||||
.0
|
.0
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::u32;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::{Command, CommandRequest, RequestParserError, empty_command_response},
|
commands::{Command, CommandRequest, RequestParserError, empty_command_response},
|
||||||
request_tokenizer::RequestTokenizer,
|
request_tokenizer::RequestTokenizer,
|
||||||
@@ -9,8 +11,8 @@ pub struct TagTypesDisable;
|
|||||||
pub struct TagTypesDisableRequest(Vec<TagName>);
|
pub struct TagTypesDisableRequest(Vec<TagName>);
|
||||||
|
|
||||||
impl TagTypesDisableRequest {
|
impl TagTypesDisableRequest {
|
||||||
pub fn new(tag_types: Vec<TagName>) -> Self {
|
fn new(tagnames: Vec<TagName>) -> Self {
|
||||||
TagTypesDisableRequest(tag_types)
|
Self(tagnames)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,6 +21,17 @@ impl CommandRequest for TagTypesDisableRequest {
|
|||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = None;
|
const MAX_ARGS: Option<u32> = None;
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::TagTypesDisable(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::TagTypesDisable(req) => Some(TagTypesDisableRequest(req)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ pub struct TagTypesEnable;
|
|||||||
pub struct TagTypesEnableRequest(Vec<TagName>);
|
pub struct TagTypesEnableRequest(Vec<TagName>);
|
||||||
|
|
||||||
impl TagTypesEnableRequest {
|
impl TagTypesEnableRequest {
|
||||||
pub fn new(tag_types: Vec<TagName>) -> Self {
|
fn new(tagnames: Vec<TagName>) -> Self {
|
||||||
TagTypesEnableRequest(tag_types)
|
Self(tagnames)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,6 +19,17 @@ impl CommandRequest for TagTypesEnableRequest {
|
|||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = None;
|
const MAX_ARGS: Option<u32> = None;
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::TagTypesEnable(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::TagTypesEnable(req) => Some(TagTypesEnableRequest(req)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ pub struct TagTypesReset;
|
|||||||
pub struct TagTypesResetRequest(Vec<TagName>);
|
pub struct TagTypesResetRequest(Vec<TagName>);
|
||||||
|
|
||||||
impl TagTypesResetRequest {
|
impl TagTypesResetRequest {
|
||||||
pub fn new(tag_types: Vec<TagName>) -> Self {
|
fn new(tagnames: Vec<TagName>) -> Self {
|
||||||
TagTypesResetRequest(tag_types)
|
Self(tagnames)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,6 +19,17 @@ impl CommandRequest for TagTypesResetRequest {
|
|||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = None;
|
const MAX_ARGS: Option<u32> = None;
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::TagTypesReset(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::TagTypesReset(req) => Some(TagTypesResetRequest(req)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ pub struct Pause;
|
|||||||
pub struct PauseRequest(Option<bool>);
|
pub struct PauseRequest(Option<bool>);
|
||||||
|
|
||||||
impl PauseRequest {
|
impl PauseRequest {
|
||||||
pub fn new(state: Option<bool>) -> Self {
|
fn new(toggle: Option<bool>) -> Self {
|
||||||
PauseRequest(state)
|
Self(toggle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,6 +18,17 @@ impl CommandRequest for PauseRequest {
|
|||||||
const MIN_ARGS: u32 = 0;
|
const MIN_ARGS: u32 = 0;
|
||||||
const MAX_ARGS: Option<u32> = Some(1);
|
const MAX_ARGS: Option<u32> = Some(1);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Pause(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Pause(value) => Some(PauseRequest(value)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Some(true) => format!("{} 1\n", Self::COMMAND),
|
Some(true) => format!("{} 1\n", Self::COMMAND),
|
||||||
|
|||||||
@@ -14,17 +14,22 @@ pub struct SeekRequest {
|
|||||||
pub time: TimeWithFractions,
|
pub time: TimeWithFractions,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SeekRequest {
|
|
||||||
pub fn new(songpos: SongPosition, time: TimeWithFractions) -> Self {
|
|
||||||
Self { songpos, time }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for SeekRequest {
|
impl CommandRequest for SeekRequest {
|
||||||
const COMMAND: &'static str = "seek";
|
const COMMAND: &'static str = "seek";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Seek(self.songpos, self.time)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Seek(songpos, time) => Some(SeekRequest { songpos, time }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {} {}\n", Self::COMMAND, self.songpos, self.time)
|
format!("{} {} {}\n", Self::COMMAND, self.songpos, self.time)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,17 +14,22 @@ pub struct SeekCurRequest {
|
|||||||
pub time: TimeWithFractions,
|
pub time: TimeWithFractions,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SeekCurRequest {
|
|
||||||
pub fn new(mode: SeekMode, time: TimeWithFractions) -> Self {
|
|
||||||
Self { mode, time }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for SeekCurRequest {
|
impl CommandRequest for SeekCurRequest {
|
||||||
const COMMAND: &'static str = "seekcur";
|
const COMMAND: &'static str = "seekcur";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(1);
|
const MAX_ARGS: Option<u32> = Some(1);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::SeekCur(self.mode, self.time)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::SeekCur(mode, time) => Some(SeekCurRequest { mode, time }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let time_str = match self.mode {
|
let time_str = match self.mode {
|
||||||
SeekMode::Absolute => format!("{}", self.time),
|
SeekMode::Absolute => format!("{}", self.time),
|
||||||
|
|||||||
@@ -14,17 +14,22 @@ pub struct SeekIdRequest {
|
|||||||
pub time: TimeWithFractions,
|
pub time: TimeWithFractions,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SeekIdRequest {
|
|
||||||
pub fn new(songid: SongId, time: TimeWithFractions) -> Self {
|
|
||||||
Self { songid, time }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for SeekIdRequest {
|
impl CommandRequest for SeekIdRequest {
|
||||||
const COMMAND: &'static str = "seekid";
|
const COMMAND: &'static str = "seekid";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::SeekId(self.songid, self.time)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::SeekId(songid, time) => Some(SeekIdRequest { songid, time }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {} {}\n", Self::COMMAND, self.songid, self.time)
|
format!("{} {} {}\n", Self::COMMAND, self.songid, self.time)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,15 @@ empty_command_request!(ListNeighbors, "listneighbors");
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ListNeighborsResponse(HashMap<String, String>);
|
pub struct ListNeighborsResponse(HashMap<String, String>);
|
||||||
|
|
||||||
impl ListNeighborsResponse {
|
|
||||||
pub fn new(map: HashMap<String, String>) -> Self {
|
|
||||||
ListNeighborsResponse(map)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for ListNeighborsResponse {
|
impl CommandResponse for ListNeighborsResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: Vec<_> = parts.into_vec()?;
|
let parts: Vec<_> = parts.into_vec()?;
|
||||||
debug_assert!(parts.len() % 2 == 0);
|
debug_assert!(parts.len() % 2 == 0);
|
||||||
|
|||||||
@@ -14,17 +14,22 @@ pub struct MountRequest {
|
|||||||
pub uri: Uri,
|
pub uri: Uri,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MountRequest {
|
|
||||||
pub fn new(path: MountPath, uri: Uri) -> Self {
|
|
||||||
MountRequest { path, uri }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for MountRequest {
|
impl CommandRequest for MountRequest {
|
||||||
const COMMAND: &'static str = "mount";
|
const COMMAND: &'static str = "mount";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Mount(self.path, self.uri)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Mount(path, uri) => Some(MountRequest { path, uri }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
debug_assert!(self.path.to_str().is_some());
|
debug_assert!(self.path.to_str().is_some());
|
||||||
format!(
|
format!(
|
||||||
|
|||||||
@@ -10,17 +10,22 @@ pub struct Unmount;
|
|||||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct UnmountRequest(MountPath);
|
pub struct UnmountRequest(MountPath);
|
||||||
|
|
||||||
impl UnmountRequest {
|
|
||||||
pub fn new(path: MountPath) -> Self {
|
|
||||||
UnmountRequest(path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for UnmountRequest {
|
impl CommandRequest for UnmountRequest {
|
||||||
const COMMAND: &'static str = "unmount";
|
const COMMAND: &'static str = "unmount";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(1);
|
const MAX_ARGS: Option<u32> = Some(1);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Unmount(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Unmount(item) => Some(UnmountRequest(item)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
debug_assert!(self.0.to_str().is_some());
|
debug_assert!(self.0.to_str().is_some());
|
||||||
format!(
|
format!(
|
||||||
|
|||||||
@@ -17,17 +17,22 @@ pub struct AlbumArtRequest {
|
|||||||
offset: Offset,
|
offset: Offset,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AlbumArtRequest {
|
|
||||||
pub fn new(uri: Uri, offset: Offset) -> Self {
|
|
||||||
AlbumArtRequest { uri, offset }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for AlbumArtRequest {
|
impl CommandRequest for AlbumArtRequest {
|
||||||
const COMMAND: &'static str = "albumart";
|
const COMMAND: &'static str = "albumart";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::AlbumArt(self.uri, self.offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::AlbumArt(uri, offset) => Some(AlbumArtRequest { uri, offset }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {} {}\n", Self::COMMAND, self.uri, self.offset)
|
format!("{} {} {}\n", Self::COMMAND, self.uri, self.offset)
|
||||||
}
|
}
|
||||||
@@ -64,13 +69,15 @@ pub struct AlbumArtResponse {
|
|||||||
pub binary: Vec<u8>,
|
pub binary: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AlbumArtResponse {
|
|
||||||
pub fn new(size: usize, binary: Vec<u8>) -> Self {
|
|
||||||
AlbumArtResponse { size, binary }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for AlbumArtResponse {
|
impl CommandResponse for AlbumArtResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: HashMap<_, _> = parts.into_map()?;
|
let parts: HashMap<_, _> = parts.into_map()?;
|
||||||
|
|
||||||
|
|||||||
@@ -18,17 +18,22 @@ pub struct CountRequest {
|
|||||||
group: Option<GroupType>,
|
group: Option<GroupType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CountRequest {
|
|
||||||
pub fn new(filter: Filter, group: Option<GroupType>) -> Self {
|
|
||||||
CountRequest { filter, group }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for CountRequest {
|
impl CommandRequest for CountRequest {
|
||||||
const COMMAND: &'static str = "count";
|
const COMMAND: &'static str = "count";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Count(self.filter, self.group)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Count(filter, group) => Some(CountRequest { filter, group }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
||||||
if let Some(group) = self.group.as_ref() {
|
if let Some(group) = self.group.as_ref() {
|
||||||
@@ -79,13 +84,15 @@ pub struct CountResponse {
|
|||||||
pub playtime: u64,
|
pub playtime: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CountResponse {
|
|
||||||
pub fn new(songs: usize, playtime: u64) -> Self {
|
|
||||||
CountResponse { songs, playtime }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for CountResponse {
|
impl CommandResponse for CountResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: HashMap<_, _> = parts.into_map()?;
|
let parts: HashMap<_, _> = parts.into_map()?;
|
||||||
|
|
||||||
|
|||||||
@@ -17,21 +17,26 @@ pub struct FindRequest {
|
|||||||
window: Option<WindowRange>,
|
window: Option<WindowRange>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FindRequest {
|
|
||||||
pub fn new(filter: Filter, sort: Option<Sort>, window: Option<WindowRange>) -> Self {
|
|
||||||
Self {
|
|
||||||
filter,
|
|
||||||
sort,
|
|
||||||
window,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for FindRequest {
|
impl CommandRequest for FindRequest {
|
||||||
const COMMAND: &'static str = "find";
|
const COMMAND: &'static str = "find";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(3);
|
const MAX_ARGS: Option<u32> = Some(3);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Find(self.filter, self.sort, self.window)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Find(filter, sort, window) => Some(FindRequest {
|
||||||
|
filter,
|
||||||
|
sort,
|
||||||
|
window,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
||||||
if let Some(sort) = &self.sort {
|
if let Some(sort) = &self.sort {
|
||||||
@@ -106,13 +111,15 @@ impl CommandRequest for FindRequest {
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct FindResponse(Vec<DbSongInfo>);
|
pub struct FindResponse(Vec<DbSongInfo>);
|
||||||
|
|
||||||
impl FindResponse {
|
|
||||||
pub fn new(items: Vec<DbSongInfo>) -> Self {
|
|
||||||
FindResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for FindResponse {
|
impl CommandResponse for FindResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
DbSelectionPrintResponse::parse(parts)?
|
DbSelectionPrintResponse::parse(parts)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|||||||
@@ -17,27 +17,27 @@ pub struct FindAddRequest {
|
|||||||
position: Option<SongPosition>,
|
position: Option<SongPosition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FindAddRequest {
|
|
||||||
pub fn new(
|
|
||||||
filter: Filter,
|
|
||||||
sort: Option<Sort>,
|
|
||||||
window: Option<WindowRange>,
|
|
||||||
position: Option<SongPosition>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
filter,
|
|
||||||
sort,
|
|
||||||
window,
|
|
||||||
position,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for FindAddRequest {
|
impl CommandRequest for FindAddRequest {
|
||||||
const COMMAND: &'static str = "findadd";
|
const COMMAND: &'static str = "findadd";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(4);
|
const MAX_ARGS: Option<u32> = Some(4);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::FindAdd(self.filter, self.sort, self.window, self.position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::FindAdd(filter, sort, window, position) => Some(FindAddRequest {
|
||||||
|
filter,
|
||||||
|
sort,
|
||||||
|
window,
|
||||||
|
position,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
||||||
if let Some(sort) = &self.sort {
|
if let Some(sort) = &self.sort {
|
||||||
|
|||||||
@@ -17,13 +17,15 @@ pub struct GetFingerprintResponse {
|
|||||||
pub chromaprint: String,
|
pub chromaprint: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GetFingerprintResponse {
|
|
||||||
pub fn new(chromaprint: String) -> Self {
|
|
||||||
Self { chromaprint }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for GetFingerprintResponse {
|
impl CommandResponse for GetFingerprintResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: HashMap<_, _> = parts.into_map()?;
|
let parts: HashMap<_, _> = parts.into_map()?;
|
||||||
|
|
||||||
|
|||||||
@@ -18,27 +18,27 @@ pub struct ListRequest {
|
|||||||
window: Option<WindowRange>,
|
window: Option<WindowRange>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListRequest {
|
|
||||||
pub fn new(
|
|
||||||
tagname: TagName,
|
|
||||||
filter: Option<Filter>,
|
|
||||||
groups: Vec<GroupType>,
|
|
||||||
window: Option<WindowRange>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
tagname,
|
|
||||||
filter,
|
|
||||||
groups,
|
|
||||||
window,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for ListRequest {
|
impl CommandRequest for ListRequest {
|
||||||
const COMMAND: &'static str = "list";
|
const COMMAND: &'static str = "list";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = None;
|
const MAX_ARGS: Option<u32> = None;
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::List(self.tagname, self.filter, self.groups, self.window)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::List(tagname, filter, groups, window) => Some(ListRequest {
|
||||||
|
tagname,
|
||||||
|
filter,
|
||||||
|
groups,
|
||||||
|
window,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let mut cmd = match &self.filter {
|
let mut cmd = match &self.filter {
|
||||||
Some(f) => format!("{} {} {}", Self::COMMAND, self.tagname, f),
|
Some(f) => format!("{} {} {}", Self::COMMAND, self.tagname, f),
|
||||||
@@ -138,13 +138,15 @@ impl CommandRequest for ListRequest {
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ListResponse(Vec<String>);
|
pub struct ListResponse(Vec<String>);
|
||||||
|
|
||||||
impl ListResponse {
|
|
||||||
pub fn new(items: Vec<String>) -> Self {
|
|
||||||
ListResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for ListResponse {
|
impl CommandResponse for ListResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts_: Vec<_> = parts.into_vec()?;
|
let parts_: Vec<_> = parts.into_vec()?;
|
||||||
debug_assert!({
|
debug_assert!({
|
||||||
|
|||||||
@@ -16,13 +16,15 @@ single_optional_item_command_request!(ListAll, "listall", Uri);
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ListAllResponse(Vec<DbSelectionPrintResponse>);
|
pub struct ListAllResponse(Vec<DbSelectionPrintResponse>);
|
||||||
|
|
||||||
impl ListAllResponse {
|
|
||||||
pub fn new(items: Vec<DbSelectionPrintResponse>) -> Self {
|
|
||||||
ListAllResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for ListAllResponse {
|
impl CommandResponse for ListAllResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let result = DbSelectionPrintResponse::parse(parts)?;
|
let result = DbSelectionPrintResponse::parse(parts)?;
|
||||||
|
|
||||||
|
|||||||
@@ -16,13 +16,15 @@ single_optional_item_command_request!(ListAllInfo, "listallinfo", Uri);
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ListAllInfoResponse(Vec<DbSelectionPrintResponse>);
|
pub struct ListAllInfoResponse(Vec<DbSelectionPrintResponse>);
|
||||||
|
|
||||||
impl ListAllInfoResponse {
|
|
||||||
pub fn new(items: Vec<DbSelectionPrintResponse>) -> Self {
|
|
||||||
ListAllInfoResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for ListAllInfoResponse {
|
impl CommandResponse for ListAllInfoResponse {
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let result = DbSelectionPrintResponse::parse(parts)?;
|
let result = DbSelectionPrintResponse::parse(parts)?;
|
||||||
|
|
||||||
|
|||||||
@@ -15,13 +15,15 @@ single_optional_item_command_request!(ListFiles, "listfiles", Uri);
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ListFilesResponse(Vec<DbDirectoryInfo>);
|
pub struct ListFilesResponse(Vec<DbDirectoryInfo>);
|
||||||
|
|
||||||
impl ListFilesResponse {
|
|
||||||
pub fn new(items: Vec<DbDirectoryInfo>) -> Self {
|
|
||||||
ListFilesResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for ListFilesResponse {
|
impl CommandResponse for ListFilesResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
DbSelectionPrintResponse::parse(parts)?
|
DbSelectionPrintResponse::parse(parts)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|||||||
@@ -15,13 +15,15 @@ single_optional_item_command_request!(LsInfo, "lsinfo", Uri);
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct LsInfoResponse(Vec<DbSelectionPrintResponse>);
|
pub struct LsInfoResponse(Vec<DbSelectionPrintResponse>);
|
||||||
|
|
||||||
impl LsInfoResponse {
|
|
||||||
pub fn new(items: Vec<DbSelectionPrintResponse>) -> Self {
|
|
||||||
LsInfoResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for LsInfoResponse {
|
impl CommandResponse for LsInfoResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let result = DbSelectionPrintResponse::parse(parts)?;
|
let result = DbSelectionPrintResponse::parse(parts)?;
|
||||||
|
|
||||||
|
|||||||
@@ -15,13 +15,15 @@ single_item_command_request!(ReadComments, "readcomments", Uri);
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ReadCommentsResponse(HashMap<String, String>);
|
pub struct ReadCommentsResponse(HashMap<String, String>);
|
||||||
|
|
||||||
impl ReadCommentsResponse {
|
|
||||||
pub fn new(comments: HashMap<String, String>) -> Self {
|
|
||||||
ReadCommentsResponse(comments)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for ReadCommentsResponse {
|
impl CommandResponse for ReadCommentsResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: HashMap<_, _> = parts.into_map()?;
|
let parts: HashMap<_, _> = parts.into_map()?;
|
||||||
|
|
||||||
|
|||||||
@@ -19,17 +19,22 @@ pub struct ReadPictureRequest {
|
|||||||
pub offset: Offset,
|
pub offset: Offset,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReadPictureRequest {
|
|
||||||
pub fn new(uri: Uri, offset: Offset) -> Self {
|
|
||||||
Self { uri, offset }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for ReadPictureRequest {
|
impl CommandRequest for ReadPictureRequest {
|
||||||
const COMMAND: &'static str = "readpicture";
|
const COMMAND: &'static str = "readpicture";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::ReadPicture(self.uri, self.offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::ReadPicture(uri, offset) => Some(ReadPictureRequest { uri, offset }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {} {}\n", Self::COMMAND, self.uri, self.offset)
|
format!("{} {} {}\n", Self::COMMAND, self.uri, self.offset)
|
||||||
}
|
}
|
||||||
@@ -67,17 +72,15 @@ pub struct ReadPictureResponse {
|
|||||||
pub mimetype: Option<String>,
|
pub mimetype: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReadPictureResponse {
|
|
||||||
pub fn new(size: usize, binary: Vec<u8>, mimetype: Option<String>) -> Self {
|
|
||||||
Self {
|
|
||||||
size,
|
|
||||||
binary,
|
|
||||||
mimetype,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for ReadPictureResponse {
|
impl CommandResponse for ReadPictureResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: HashMap<_, _> = parts.into_map()?;
|
let parts: HashMap<_, _> = parts.into_map()?;
|
||||||
|
|
||||||
|
|||||||
@@ -19,13 +19,15 @@ pub struct RescanResponse {
|
|||||||
pub updating_db: usize,
|
pub updating_db: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RescanResponse {
|
|
||||||
pub fn new(updating_db: usize) -> Self {
|
|
||||||
RescanResponse { updating_db }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for RescanResponse {
|
impl CommandResponse for RescanResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: HashMap<_, _> = parts.into_map()?;
|
let parts: HashMap<_, _> = parts.into_map()?;
|
||||||
|
|
||||||
|
|||||||
@@ -17,21 +17,26 @@ pub struct SearchRequest {
|
|||||||
window: Option<WindowRange>,
|
window: Option<WindowRange>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SearchRequest {
|
|
||||||
pub fn new(filter: Filter, sort: Option<Sort>, window: Option<WindowRange>) -> Self {
|
|
||||||
Self {
|
|
||||||
filter,
|
|
||||||
sort,
|
|
||||||
window,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for SearchRequest {
|
impl CommandRequest for SearchRequest {
|
||||||
const COMMAND: &'static str = "search";
|
const COMMAND: &'static str = "search";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(3);
|
const MAX_ARGS: Option<u32> = Some(3);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Search(self.filter, self.sort, self.window)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Search(filter, sort, window) => Some(SearchRequest {
|
||||||
|
filter,
|
||||||
|
sort,
|
||||||
|
window,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
||||||
if let Some(sort) = &self.sort {
|
if let Some(sort) = &self.sort {
|
||||||
@@ -106,13 +111,15 @@ impl CommandRequest for SearchRequest {
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct SearchResponse(Vec<DbSongInfo>);
|
pub struct SearchResponse(Vec<DbSongInfo>);
|
||||||
|
|
||||||
impl SearchResponse {
|
|
||||||
pub fn new(items: Vec<DbSongInfo>) -> Self {
|
|
||||||
SearchResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for SearchResponse {
|
impl CommandResponse for SearchResponse {
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
DbSelectionPrintResponse::parse(parts)?
|
DbSelectionPrintResponse::parse(parts)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|||||||
@@ -17,27 +17,27 @@ pub struct SearchAddRequest {
|
|||||||
position: Option<SongPosition>,
|
position: Option<SongPosition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SearchAddRequest {
|
|
||||||
pub fn new(
|
|
||||||
filter: Filter,
|
|
||||||
sort: Option<Sort>,
|
|
||||||
window: Option<WindowRange>,
|
|
||||||
position: Option<SongPosition>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
filter,
|
|
||||||
sort,
|
|
||||||
window,
|
|
||||||
position,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for SearchAddRequest {
|
impl CommandRequest for SearchAddRequest {
|
||||||
const COMMAND: &'static str = "searchadd";
|
const COMMAND: &'static str = "searchadd";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(4);
|
const MAX_ARGS: Option<u32> = Some(4);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::SearchAdd(self.filter, self.sort, self.window, self.position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::SearchAdd(filter, sort, window, position) => Some(SearchAddRequest {
|
||||||
|
filter,
|
||||||
|
sort,
|
||||||
|
window,
|
||||||
|
position,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
||||||
if let Some(sort) = &self.sort {
|
if let Some(sort) = &self.sort {
|
||||||
|
|||||||
@@ -18,29 +18,36 @@ pub struct SearchAddPlRequest {
|
|||||||
position: Option<SongPosition>,
|
position: Option<SongPosition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SearchAddPlRequest {
|
|
||||||
pub fn new(
|
|
||||||
playlist_name: PlaylistName,
|
|
||||||
filter: Filter,
|
|
||||||
sort: Option<Sort>,
|
|
||||||
window: Option<WindowRange>,
|
|
||||||
position: Option<SongPosition>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
playlist_name,
|
|
||||||
filter,
|
|
||||||
sort,
|
|
||||||
window,
|
|
||||||
position,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for SearchAddPlRequest {
|
impl CommandRequest for SearchAddPlRequest {
|
||||||
const COMMAND: &'static str = "searchaddpl";
|
const COMMAND: &'static str = "searchaddpl";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(5);
|
const MAX_ARGS: Option<u32> = Some(5);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::SearchAddPl(
|
||||||
|
self.playlist_name,
|
||||||
|
self.filter,
|
||||||
|
self.sort,
|
||||||
|
self.window,
|
||||||
|
self.position,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::SearchAddPl(playlist_name, filter, sort, window, position) => {
|
||||||
|
Some(SearchAddPlRequest {
|
||||||
|
playlist_name,
|
||||||
|
filter,
|
||||||
|
sort,
|
||||||
|
window,
|
||||||
|
position,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let mut cmd = format!("{} {} {}", Self::COMMAND, self.playlist_name, self.filter);
|
let mut cmd = format!("{} {} {}", Self::COMMAND, self.playlist_name, self.filter);
|
||||||
if let Some(sort) = &self.sort {
|
if let Some(sort) = &self.sort {
|
||||||
|
|||||||
@@ -18,17 +18,24 @@ pub struct SearchCountRequest {
|
|||||||
group: Option<GroupType>,
|
group: Option<GroupType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SearchCountRequest {
|
|
||||||
pub fn new(filter: Filter, group: Option<GroupType>) -> Self {
|
|
||||||
Self { filter, group }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for SearchCountRequest {
|
impl CommandRequest for SearchCountRequest {
|
||||||
const COMMAND: &'static str = "searchcount";
|
const COMMAND: &'static str = "searchcount";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::SearchCount(self.filter, self.group)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::SearchCount(filter, group) => {
|
||||||
|
Some(SearchCountRequest { filter, group })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
||||||
if let Some(group) = &self.group {
|
if let Some(group) = &self.group {
|
||||||
@@ -78,13 +85,15 @@ pub struct SearchCountResponse {
|
|||||||
pub playtime: Seconds,
|
pub playtime: Seconds,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SearchCountResponse {
|
|
||||||
pub fn new(songs: usize, playtime: Seconds) -> Self {
|
|
||||||
Self { songs, playtime }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for SearchCountResponse {
|
impl CommandResponse for SearchCountResponse {
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: HashMap<_, _> = parts.into_map()?;
|
let parts: HashMap<_, _> = parts.into_map()?;
|
||||||
|
|
||||||
|
|||||||
@@ -19,13 +19,15 @@ pub struct UpdateResponse {
|
|||||||
updating_db: usize,
|
updating_db: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UpdateResponse {
|
|
||||||
pub fn new(updating_db: usize) -> Self {
|
|
||||||
UpdateResponse { updating_db }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for UpdateResponse {
|
impl CommandResponse for UpdateResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: HashMap<_, _> = parts.into_map()?;
|
let parts: HashMap<_, _> = parts.into_map()?;
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use crate::{
|
|||||||
pub struct MixRampDelay;
|
pub struct MixRampDelay;
|
||||||
|
|
||||||
single_item_command_request!(MixRampDelay, "mixrampdelay", Seconds);
|
single_item_command_request!(MixRampDelay, "mixrampdelay", Seconds);
|
||||||
|
|
||||||
empty_command_response!(MixRampDelay);
|
empty_command_response!(MixRampDelay);
|
||||||
|
|
||||||
impl Command for MixRampDelay {
|
impl Command for MixRampDelay {
|
||||||
|
|||||||
@@ -7,17 +7,22 @@ pub struct Random;
|
|||||||
|
|
||||||
pub struct RandomRequest(bool);
|
pub struct RandomRequest(bool);
|
||||||
|
|
||||||
impl RandomRequest {
|
|
||||||
pub fn new(state: bool) -> Self {
|
|
||||||
Self(state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for RandomRequest {
|
impl CommandRequest for RandomRequest {
|
||||||
const COMMAND: &'static str = "random";
|
const COMMAND: &'static str = "random";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(1);
|
const MAX_ARGS: Option<u32> = Some(1);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Random(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Random(state) => Some(RandomRequest(state)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let state = if self.0 { "1" } else { "0" };
|
let state = if self.0 { "1" } else { "0" };
|
||||||
format!("{} {}\n", Self::COMMAND, state)
|
format!("{} {}\n", Self::COMMAND, state)
|
||||||
|
|||||||
@@ -7,17 +7,22 @@ pub struct Repeat;
|
|||||||
|
|
||||||
pub struct RepeatRequest(bool);
|
pub struct RepeatRequest(bool);
|
||||||
|
|
||||||
impl RepeatRequest {
|
|
||||||
pub fn new(state: bool) -> Self {
|
|
||||||
RepeatRequest(state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for RepeatRequest {
|
impl CommandRequest for RepeatRequest {
|
||||||
const COMMAND: &'static str = "repeat";
|
const COMMAND: &'static str = "repeat";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(1);
|
const MAX_ARGS: Option<u32> = Some(1);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Repeat(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Repeat(state) => Some(RepeatRequest(state)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let state = if self.0 { "1" } else { "0" };
|
let state = if self.0 { "1" } else { "0" };
|
||||||
format!("{} {}\n", Self::COMMAND, state)
|
format!("{} {}\n", Self::COMMAND, state)
|
||||||
|
|||||||
@@ -17,13 +17,15 @@ pub struct ReplayGainStatusResponse {
|
|||||||
pub replay_gain_mode: ReplayGainModeMode,
|
pub replay_gain_mode: ReplayGainModeMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReplayGainStatusResponse {
|
|
||||||
pub fn new(replay_gain_mode: ReplayGainModeMode) -> Self {
|
|
||||||
Self { replay_gain_mode }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for ReplayGainStatusResponse {
|
impl CommandResponse for ReplayGainStatusResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: HashMap<_, _> = parts.into_map()?;
|
let parts: HashMap<_, _> = parts.into_map()?;
|
||||||
let replay_gain_mode = get_property!(parts, "replay_gain_mode", Text);
|
let replay_gain_mode = get_property!(parts, "replay_gain_mode", Text);
|
||||||
|
|||||||
@@ -23,23 +23,15 @@ pub struct CurrentSongResponse {
|
|||||||
song_info: DbSongInfo,
|
song_info: DbSongInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CurrentSongResponse {
|
|
||||||
pub fn new(
|
|
||||||
position: SongPosition,
|
|
||||||
id: SongId,
|
|
||||||
priority: Option<Priority>,
|
|
||||||
song_info: DbSongInfo,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
position,
|
|
||||||
id,
|
|
||||||
priority,
|
|
||||||
song_info,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for CurrentSongResponse {
|
impl CommandResponse for CurrentSongResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let mut parts: HashMap<_, _> = parts.into_map()?;
|
let mut parts: HashMap<_, _> = parts.into_map()?;
|
||||||
|
|
||||||
|
|||||||
@@ -10,17 +10,22 @@ pub struct Idle;
|
|||||||
|
|
||||||
pub struct IdleRequest(Option<Vec<SubSystem>>);
|
pub struct IdleRequest(Option<Vec<SubSystem>>);
|
||||||
|
|
||||||
impl IdleRequest {
|
|
||||||
pub fn new(subsystems: Option<Vec<SubSystem>>) -> Self {
|
|
||||||
IdleRequest(subsystems)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for IdleRequest {
|
impl CommandRequest for IdleRequest {
|
||||||
const COMMAND: &'static str = "idle";
|
const COMMAND: &'static str = "idle";
|
||||||
const MIN_ARGS: u32 = 0;
|
const MIN_ARGS: u32 = 0;
|
||||||
const MAX_ARGS: Option<u32> = None;
|
const MAX_ARGS: Option<u32> = None;
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Idle(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Idle(subsystems) => Some(IdleRequest(subsystems)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
Some(subsystems) => {
|
Some(subsystems) => {
|
||||||
|
|||||||
@@ -24,29 +24,15 @@ pub struct StatsResponse {
|
|||||||
pub db_update: Option<u64>,
|
pub db_update: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StatsResponse {
|
|
||||||
pub fn new(
|
|
||||||
uptime: u64,
|
|
||||||
playtime: u64,
|
|
||||||
artists: Option<u64>,
|
|
||||||
albums: Option<u64>,
|
|
||||||
songs: Option<u64>,
|
|
||||||
db_playtime: Option<u64>,
|
|
||||||
db_update: Option<u64>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
uptime,
|
|
||||||
playtime,
|
|
||||||
artists,
|
|
||||||
albums,
|
|
||||||
songs,
|
|
||||||
db_playtime,
|
|
||||||
db_update,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for StatsResponse {
|
impl CommandResponse for StatsResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: HashMap<_, _> = parts.into_map()?;
|
let parts: HashMap<_, _> = parts.into_map()?;
|
||||||
|
|
||||||
|
|||||||
@@ -65,63 +65,15 @@ pub struct StatusResponse {
|
|||||||
pub last_loaded_playlist: Option<String>,
|
pub last_loaded_playlist: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StatusResponse {
|
|
||||||
pub fn new(
|
|
||||||
partition: String,
|
|
||||||
volume: Option<u8>,
|
|
||||||
repeat: bool,
|
|
||||||
random: bool,
|
|
||||||
single: BoolOrOneshot,
|
|
||||||
consume: BoolOrOneshot,
|
|
||||||
playlist: u32,
|
|
||||||
playlist_length: u64,
|
|
||||||
state: StatusResponseState,
|
|
||||||
song: Option<SongPosition>,
|
|
||||||
song_id: Option<SongId>,
|
|
||||||
next_song: Option<SongPosition>,
|
|
||||||
next_song_id: Option<SongId>,
|
|
||||||
time: Option<(u64, u64)>,
|
|
||||||
elapsed: Option<f64>,
|
|
||||||
duration: Option<f64>,
|
|
||||||
bitrate: Option<u32>,
|
|
||||||
xfade: Option<u32>,
|
|
||||||
mixrampdb: Option<f64>,
|
|
||||||
mixrampdelay: Option<f64>,
|
|
||||||
audio: Option<Audio>,
|
|
||||||
updating_db: Option<u64>,
|
|
||||||
error: Option<String>,
|
|
||||||
last_loaded_playlist: Option<String>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
partition,
|
|
||||||
volume,
|
|
||||||
repeat,
|
|
||||||
random,
|
|
||||||
single,
|
|
||||||
consume,
|
|
||||||
playlist,
|
|
||||||
playlist_length,
|
|
||||||
state,
|
|
||||||
song,
|
|
||||||
song_id,
|
|
||||||
next_song,
|
|
||||||
next_song_id,
|
|
||||||
time,
|
|
||||||
elapsed,
|
|
||||||
duration,
|
|
||||||
bitrate,
|
|
||||||
xfade,
|
|
||||||
mixrampdb,
|
|
||||||
mixrampdelay,
|
|
||||||
audio,
|
|
||||||
updating_db,
|
|
||||||
error,
|
|
||||||
last_loaded_playlist,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for StatusResponse {
|
impl CommandResponse for StatusResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: HashMap<_, _> = parts.into_map()?;
|
let parts: HashMap<_, _> = parts.into_map()?;
|
||||||
let partition = get_property!(parts, "partition", Text).to_string();
|
let partition = get_property!(parts, "partition", Text).to_string();
|
||||||
|
|||||||
@@ -14,17 +14,22 @@ pub struct AddRequest {
|
|||||||
position: Option<SongPosition>,
|
position: Option<SongPosition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddRequest {
|
|
||||||
pub fn new(uri: Uri, position: Option<SongPosition>) -> Self {
|
|
||||||
Self { uri, position }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for AddRequest {
|
impl CommandRequest for AddRequest {
|
||||||
const COMMAND: &'static str = "add";
|
const COMMAND: &'static str = "add";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Add(self.uri, self.position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Add(uri, position) => Some(AddRequest { uri, position }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
match self.position {
|
match self.position {
|
||||||
Some(position) => format!("{} {} {}\n", Self::COMMAND, self.uri, position),
|
Some(position) => format!("{} {} {}\n", Self::COMMAND, self.uri, position),
|
||||||
|
|||||||
+19
-12
@@ -15,17 +15,22 @@ pub struct AddIdRequest {
|
|||||||
pub position: Option<SongPosition>,
|
pub position: Option<SongPosition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddIdRequest {
|
|
||||||
pub fn new(uri: Uri, position: Option<SongPosition>) -> Self {
|
|
||||||
Self { uri, position }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for AddIdRequest {
|
impl CommandRequest for AddIdRequest {
|
||||||
const COMMAND: &'static str = "addid";
|
const COMMAND: &'static str = "addid";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::AddId(self.uri, self.position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::AddId(uri, position) => Some(AddIdRequest { uri, position }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
match self.position {
|
match self.position {
|
||||||
Some(pos) => format!("{} {} {}\n", Self::COMMAND, self.uri, pos),
|
Some(pos) => format!("{} {} {}\n", Self::COMMAND, self.uri, pos),
|
||||||
@@ -64,13 +69,15 @@ pub struct AddIdResponse {
|
|||||||
pub id: SongId,
|
pub id: SongId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddIdResponse {
|
|
||||||
pub fn new(id: SongId) -> Self {
|
|
||||||
Self { id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for AddIdResponse {
|
impl CommandResponse for AddIdResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: Vec<_> = parts.into();
|
let parts: Vec<_> = parts.into();
|
||||||
let mut iter = parts.into_iter();
|
let mut iter = parts.into_iter();
|
||||||
|
|||||||
@@ -15,21 +15,26 @@ pub struct AddTagIdRequest {
|
|||||||
pub tag_value: TagValue,
|
pub tag_value: TagValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddTagIdRequest {
|
|
||||||
pub fn new(songid: SongId, tag_name: TagName, tag_value: TagValue) -> Self {
|
|
||||||
Self {
|
|
||||||
songid,
|
|
||||||
tag_name,
|
|
||||||
tag_value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for AddTagIdRequest {
|
impl CommandRequest for AddTagIdRequest {
|
||||||
const COMMAND: &'static str = "addtagid";
|
const COMMAND: &'static str = "addtagid";
|
||||||
const MIN_ARGS: u32 = 3;
|
const MIN_ARGS: u32 = 3;
|
||||||
const MAX_ARGS: Option<u32> = Some(3);
|
const MAX_ARGS: Option<u32> = Some(3);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::AddTagId(self.songid, self.tag_name, self.tag_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::AddTagId(songid, tag_name, tag_value) => Some(AddTagIdRequest {
|
||||||
|
songid,
|
||||||
|
tag_name,
|
||||||
|
tag_value,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} {} {} {}\n",
|
"{} {} {} {}\n",
|
||||||
|
|||||||
@@ -14,17 +14,24 @@ pub struct ClearTagIdRequest {
|
|||||||
pub tag_name: TagName,
|
pub tag_name: TagName,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClearTagIdRequest {
|
|
||||||
pub fn new(songid: SongId, tag_name: TagName) -> Self {
|
|
||||||
Self { songid, tag_name }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for ClearTagIdRequest {
|
impl CommandRequest for ClearTagIdRequest {
|
||||||
const COMMAND: &'static str = "cleartagid";
|
const COMMAND: &'static str = "cleartagid";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::ClearTagId(self.songid, self.tag_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::ClearTagId(songid, tag_name) => {
|
||||||
|
Some(ClearTagIdRequest { songid, tag_name })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {} {}\n", Self::COMMAND, self.songid, self.tag_name)
|
format!("{} {} {}\n", Self::COMMAND, self.songid, self.tag_name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,17 +14,22 @@ pub struct MoveRequest {
|
|||||||
pub to: AbsouluteRelativeSongPosition,
|
pub to: AbsouluteRelativeSongPosition,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MoveRequest {
|
|
||||||
pub fn new(from_or_range: OneOrRange, to: AbsouluteRelativeSongPosition) -> Self {
|
|
||||||
Self { from_or_range, to }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for MoveRequest {
|
impl CommandRequest for MoveRequest {
|
||||||
const COMMAND: &'static str = "move";
|
const COMMAND: &'static str = "move";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Move(self.from_or_range, self.to)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Move(from_or_range, to) => Some(MoveRequest { from_or_range, to }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {} {}\n", Self::COMMAND, self.from_or_range, self.to)
|
format!("{} {} {}\n", Self::COMMAND, self.from_or_range, self.to)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,17 +14,22 @@ pub struct MoveIdRequest {
|
|||||||
pub to: AbsouluteRelativeSongPosition,
|
pub to: AbsouluteRelativeSongPosition,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MoveIdRequest {
|
|
||||||
pub fn new(id: SongId, to: AbsouluteRelativeSongPosition) -> Self {
|
|
||||||
Self { id, to }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for MoveIdRequest {
|
impl CommandRequest for MoveIdRequest {
|
||||||
const COMMAND: &'static str = "moveid";
|
const COMMAND: &'static str = "moveid";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::MoveId(self.id, self.to)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::MoveId(id, to) => Some(MoveIdRequest { id, to }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {} {}\n", Self::COMMAND, self.id, self.to)
|
format!("{} {} {}\n", Self::COMMAND, self.id, self.to)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,16 @@ empty_command_request!(Playlist, "playlist");
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PlaylistResponse(Vec<Uri>);
|
pub struct PlaylistResponse(Vec<Uri>);
|
||||||
|
|
||||||
impl PlaylistResponse {
|
|
||||||
pub fn new(items: Vec<Uri>) -> Self {
|
|
||||||
PlaylistResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for PlaylistResponse {
|
impl CommandResponse for PlaylistResponse {
|
||||||
fn parse(_parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
Response,
|
||||||
commands::{Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError},
|
commands::{Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError},
|
||||||
filter::Filter,
|
filter::Filter,
|
||||||
request_tokenizer::RequestTokenizer,
|
request_tokenizer::RequestTokenizer,
|
||||||
@@ -17,21 +18,26 @@ pub struct PlaylistFindRequest {
|
|||||||
window: Option<WindowRange>,
|
window: Option<WindowRange>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlaylistFindRequest {
|
|
||||||
pub fn new(filter: Filter, sort: Option<Sort>, window: Option<WindowRange>) -> Self {
|
|
||||||
Self {
|
|
||||||
filter,
|
|
||||||
sort,
|
|
||||||
window,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for PlaylistFindRequest {
|
impl CommandRequest for PlaylistFindRequest {
|
||||||
const COMMAND: &'static str = "playlistfind";
|
const COMMAND: &'static str = "playlistfind";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(3);
|
const MAX_ARGS: Option<u32> = Some(3);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::PlaylistFind(self.filter, self.sort, self.window)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::PlaylistFind(filter, sort, window) => Some(PlaylistFindRequest {
|
||||||
|
filter,
|
||||||
|
sort,
|
||||||
|
window,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
||||||
if let Some(sort) = &self.sort {
|
if let Some(sort) = &self.sort {
|
||||||
@@ -106,12 +112,6 @@ impl CommandRequest for PlaylistFindRequest {
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PlaylistFindResponse(Vec<PlaylistFindResponseEntry>);
|
pub struct PlaylistFindResponse(Vec<PlaylistFindResponseEntry>);
|
||||||
|
|
||||||
impl PlaylistFindResponse {
|
|
||||||
pub fn new(items: Vec<PlaylistFindResponseEntry>) -> Self {
|
|
||||||
PlaylistFindResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PlaylistFindResponseEntry {
|
pub struct PlaylistFindResponseEntry {
|
||||||
pub position: SongPosition,
|
pub position: SongPosition,
|
||||||
@@ -120,23 +120,15 @@ pub struct PlaylistFindResponseEntry {
|
|||||||
pub song_info: DbSongInfo,
|
pub song_info: DbSongInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlaylistFindResponseEntry {
|
|
||||||
pub fn new(
|
|
||||||
position: SongPosition,
|
|
||||||
id: SongId,
|
|
||||||
priority: Option<Priority>,
|
|
||||||
song_info: DbSongInfo,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
position,
|
|
||||||
id,
|
|
||||||
priority,
|
|
||||||
song_info,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for PlaylistFindResponse {
|
impl CommandResponse for PlaylistFindResponse {
|
||||||
|
fn into_response_enum(self) -> Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(_parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(_parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,6 @@ single_item_command_request!(PlaylistId, "playlistid", SongId);
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PlaylistIdResponse(Vec<PlaylistIdResponseEntry>);
|
pub struct PlaylistIdResponse(Vec<PlaylistIdResponseEntry>);
|
||||||
|
|
||||||
impl PlaylistIdResponse {
|
|
||||||
pub fn new(items: Vec<PlaylistIdResponseEntry>) -> Self {
|
|
||||||
PlaylistIdResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PlaylistIdResponseEntry {
|
pub struct PlaylistIdResponseEntry {
|
||||||
pub position: SongPosition,
|
pub position: SongPosition,
|
||||||
@@ -27,24 +21,16 @@ pub struct PlaylistIdResponseEntry {
|
|||||||
pub song_info: DbSongInfo,
|
pub song_info: DbSongInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlaylistIdResponseEntry {
|
|
||||||
pub fn new(
|
|
||||||
position: SongPosition,
|
|
||||||
id: SongId,
|
|
||||||
priority: Option<Priority>,
|
|
||||||
song_info: DbSongInfo,
|
|
||||||
) -> Self {
|
|
||||||
PlaylistIdResponseEntry {
|
|
||||||
position,
|
|
||||||
id,
|
|
||||||
priority,
|
|
||||||
song_info,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for PlaylistIdResponse {
|
impl CommandResponse for PlaylistIdResponse {
|
||||||
fn parse(_parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,6 @@ single_optional_item_command_request!(PlaylistInfo, "playlistinfo", OneOrRange);
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PlaylistInfoResponse(Vec<PlaylistInfoResponseEntry>);
|
pub struct PlaylistInfoResponse(Vec<PlaylistInfoResponseEntry>);
|
||||||
|
|
||||||
impl PlaylistInfoResponse {
|
|
||||||
pub fn new(items: Vec<PlaylistInfoResponseEntry>) -> Self {
|
|
||||||
PlaylistInfoResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PlaylistInfoResponseEntry {
|
pub struct PlaylistInfoResponseEntry {
|
||||||
pub position: SongPosition,
|
pub position: SongPosition,
|
||||||
@@ -29,23 +23,15 @@ pub struct PlaylistInfoResponseEntry {
|
|||||||
pub song_info: DbSongInfo,
|
pub song_info: DbSongInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlaylistInfoResponseEntry {
|
|
||||||
pub fn new(
|
|
||||||
position: SongPosition,
|
|
||||||
id: SongId,
|
|
||||||
priority: Option<Priority>,
|
|
||||||
song_info: DbSongInfo,
|
|
||||||
) -> Self {
|
|
||||||
PlaylistInfoResponseEntry {
|
|
||||||
position,
|
|
||||||
id,
|
|
||||||
priority,
|
|
||||||
song_info,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for PlaylistInfoResponse {
|
impl CommandResponse for PlaylistInfoResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(_parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(_parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,21 +17,26 @@ pub struct PlaylistSearchRequest {
|
|||||||
window: Option<WindowRange>,
|
window: Option<WindowRange>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlaylistSearchRequest {
|
|
||||||
pub fn new(filter: Filter, sort: Option<Sort>, window: Option<WindowRange>) -> Self {
|
|
||||||
Self {
|
|
||||||
filter,
|
|
||||||
sort,
|
|
||||||
window,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for PlaylistSearchRequest {
|
impl CommandRequest for PlaylistSearchRequest {
|
||||||
const COMMAND: &'static str = "playlistsearch";
|
const COMMAND: &'static str = "playlistsearch";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(3);
|
const MAX_ARGS: Option<u32> = Some(3);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::PlaylistSearch(self.filter, self.sort, self.window)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::PlaylistSearch(filter, sort, window) => Some(PlaylistSearchRequest {
|
||||||
|
filter,
|
||||||
|
sort,
|
||||||
|
window,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
||||||
if let Some(sort) = &self.sort {
|
if let Some(sort) = &self.sort {
|
||||||
@@ -106,12 +111,6 @@ impl CommandRequest for PlaylistSearchRequest {
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PlaylistSearchResponse(Vec<PlaylistSearchResponseEntry>);
|
pub struct PlaylistSearchResponse(Vec<PlaylistSearchResponseEntry>);
|
||||||
|
|
||||||
impl PlaylistSearchResponse {
|
|
||||||
pub fn new(items: Vec<PlaylistSearchResponseEntry>) -> Self {
|
|
||||||
PlaylistSearchResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PlaylistSearchResponseEntry {
|
pub struct PlaylistSearchResponseEntry {
|
||||||
pub position: SongPosition,
|
pub position: SongPosition,
|
||||||
@@ -120,24 +119,16 @@ pub struct PlaylistSearchResponseEntry {
|
|||||||
pub song_info: DbSongInfo,
|
pub song_info: DbSongInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlaylistSearchResponseEntry {
|
|
||||||
pub fn new(
|
|
||||||
position: SongPosition,
|
|
||||||
id: SongId,
|
|
||||||
priority: Option<Priority>,
|
|
||||||
song_info: DbSongInfo,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
position,
|
|
||||||
id,
|
|
||||||
priority,
|
|
||||||
song_info,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for PlaylistSearchResponse {
|
impl CommandResponse for PlaylistSearchResponse {
|
||||||
fn parse(_parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,17 +15,24 @@ pub struct PlChangesRequest {
|
|||||||
pub window: Option<WindowRange>,
|
pub window: Option<WindowRange>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlChangesRequest {
|
|
||||||
pub fn new(version: PlaylistVersion, window: Option<WindowRange>) -> Self {
|
|
||||||
Self { version, window }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for PlChangesRequest {
|
impl CommandRequest for PlChangesRequest {
|
||||||
const COMMAND: &'static str = "plchanges";
|
const COMMAND: &'static str = "plchanges";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::PlChanges(self.version, self.window)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::PlChanges(version, window) => {
|
||||||
|
Some(PlChangesRequest { version, window })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
match self.window.as_ref() {
|
match self.window.as_ref() {
|
||||||
Some(window) => format!("{} {} {}\n", Self::COMMAND, self.version, window),
|
Some(window) => format!("{} {} {}\n", Self::COMMAND, self.version, window),
|
||||||
@@ -64,12 +71,6 @@ impl CommandRequest for PlChangesRequest {
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PlChangesResponse(Vec<PlChangesResponseEntry>);
|
pub struct PlChangesResponse(Vec<PlChangesResponseEntry>);
|
||||||
|
|
||||||
impl PlChangesResponse {
|
|
||||||
pub fn new(items: Vec<PlChangesResponseEntry>) -> Self {
|
|
||||||
PlChangesResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PlChangesResponseEntry {
|
pub struct PlChangesResponseEntry {
|
||||||
pub position: SongPosition,
|
pub position: SongPosition,
|
||||||
@@ -78,24 +79,16 @@ pub struct PlChangesResponseEntry {
|
|||||||
pub song_info: DbSongInfo,
|
pub song_info: DbSongInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlChangesResponseEntry {
|
|
||||||
pub fn new(
|
|
||||||
position: SongPosition,
|
|
||||||
id: SongId,
|
|
||||||
priority: Option<Priority>,
|
|
||||||
song_info: DbSongInfo,
|
|
||||||
) -> Self {
|
|
||||||
PlChangesResponseEntry {
|
|
||||||
position,
|
|
||||||
id,
|
|
||||||
priority,
|
|
||||||
song_info,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for PlChangesResponse {
|
impl CommandResponse for PlChangesResponse {
|
||||||
fn parse(_parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,17 +15,24 @@ pub struct PlChangesPosIdRequest {
|
|||||||
pub window: Option<WindowRange>,
|
pub window: Option<WindowRange>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlChangesPosIdRequest {
|
|
||||||
pub fn new(version: PlaylistVersion, window: Option<WindowRange>) -> Self {
|
|
||||||
Self { version, window }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for PlChangesPosIdRequest {
|
impl CommandRequest for PlChangesPosIdRequest {
|
||||||
const COMMAND: &'static str = "plchangesposid";
|
const COMMAND: &'static str = "plchangesposid";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::PlChangesPosId(self.version, self.window)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::PlChangesPosId(version, window) => {
|
||||||
|
Some(PlChangesPosIdRequest { version, window })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
match self.window.as_ref() {
|
match self.window.as_ref() {
|
||||||
Some(window) => format!("{} {} {}\n", Self::COMMAND, self.version, window),
|
Some(window) => format!("{} {} {}\n", Self::COMMAND, self.version, window),
|
||||||
@@ -64,12 +71,6 @@ impl CommandRequest for PlChangesPosIdRequest {
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PlChangesPosIdResponse(Vec<PlChangesPosIdResponseEntry>);
|
pub struct PlChangesPosIdResponse(Vec<PlChangesPosIdResponseEntry>);
|
||||||
|
|
||||||
impl PlChangesPosIdResponse {
|
|
||||||
pub fn new(items: Vec<PlChangesPosIdResponseEntry>) -> Self {
|
|
||||||
PlChangesPosIdResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PlChangesPosIdResponseEntry {
|
pub struct PlChangesPosIdResponseEntry {
|
||||||
// 'cpos'
|
// 'cpos'
|
||||||
@@ -77,14 +78,16 @@ pub struct PlChangesPosIdResponseEntry {
|
|||||||
pub id: SongId,
|
pub id: SongId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlChangesPosIdResponseEntry {
|
|
||||||
pub fn new(position: SongPosition, id: SongId) -> Self {
|
|
||||||
PlChangesPosIdResponseEntry { position, id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for PlChangesPosIdResponse {
|
impl CommandResponse for PlChangesPosIdResponse {
|
||||||
fn parse(_parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,17 +14,22 @@ pub struct PrioRequest {
|
|||||||
pub window: WindowRange,
|
pub window: WindowRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrioRequest {
|
|
||||||
pub fn new(prio: Priority, window: WindowRange) -> Self {
|
|
||||||
Self { prio, window }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for PrioRequest {
|
impl CommandRequest for PrioRequest {
|
||||||
const COMMAND: &'static str = "prio";
|
const COMMAND: &'static str = "prio";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Prio(self.prio, self.window)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Prio(prio, window) => Some(PrioRequest { prio, window }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {} {}\n", Self::COMMAND, self.prio, self.window)
|
format!("{} {} {}\n", Self::COMMAND, self.prio, self.window)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,18 +14,23 @@ pub struct PrioIdRequest {
|
|||||||
pub songids: Vec<SongId>,
|
pub songids: Vec<SongId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrioIdRequest {
|
|
||||||
pub fn new(prio: Priority, songids: Vec<SongId>) -> Self {
|
|
||||||
Self { prio, songids }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for PrioIdRequest {
|
impl CommandRequest for PrioIdRequest {
|
||||||
const COMMAND: &'static str = "prioid";
|
const COMMAND: &'static str = "prioid";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
// TODO: should this be 2?
|
// TODO: should this be 2?
|
||||||
const MAX_ARGS: Option<u32> = None;
|
const MAX_ARGS: Option<u32> = None;
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::PrioId(self.prio, self.songids)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::PrioId(prio, songids) => Some(PrioIdRequest { prio, songids }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let songids = self
|
let songids = self
|
||||||
.songids
|
.songids
|
||||||
|
|||||||
@@ -14,20 +14,25 @@ pub struct RangeIdRequest {
|
|||||||
time_interval: TimeInterval,
|
time_interval: TimeInterval,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RangeIdRequest {
|
|
||||||
pub fn new(songid: SongId, time_interval: TimeInterval) -> Self {
|
|
||||||
Self {
|
|
||||||
songid,
|
|
||||||
time_interval,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for RangeIdRequest {
|
impl CommandRequest for RangeIdRequest {
|
||||||
const COMMAND: &'static str = "rangeid";
|
const COMMAND: &'static str = "rangeid";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::RangeId(self.songid, self.time_interval)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::RangeId(songid, time_interval) => Some(RangeIdRequest {
|
||||||
|
songid,
|
||||||
|
time_interval,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {} {}\n", Self::COMMAND, self.songid, self.time_interval)
|
format!("{} {} {}\n", Self::COMMAND, self.songid, self.time_interval)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,17 +14,22 @@ pub struct SwapRequest {
|
|||||||
pub songpos2: SongPosition,
|
pub songpos2: SongPosition,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SwapRequest {
|
|
||||||
pub fn new(songpos1: SongPosition, songpos2: SongPosition) -> Self {
|
|
||||||
Self { songpos1, songpos2 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for SwapRequest {
|
impl CommandRequest for SwapRequest {
|
||||||
const COMMAND: &'static str = "swap";
|
const COMMAND: &'static str = "swap";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Swap(self.songpos1, self.songpos2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Swap(songpos1, songpos2) => Some(SwapRequest { songpos1, songpos2 }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {} {}\n", Self::COMMAND, self.songpos1, self.songpos2)
|
format!("{} {} {}\n", Self::COMMAND, self.songpos1, self.songpos2)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,17 +14,22 @@ pub struct SwapIdRequest {
|
|||||||
pub songid2: SongId,
|
pub songid2: SongId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SwapIdRequest {
|
|
||||||
pub fn new(songid1: SongId, songid2: SongId) -> Self {
|
|
||||||
Self { songid1, songid2 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for SwapIdRequest {
|
impl CommandRequest for SwapIdRequest {
|
||||||
const COMMAND: &'static str = "swapid";
|
const COMMAND: &'static str = "swapid";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::SwapId(self.songid1, self.songid2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::SwapId(songid1, songid2) => Some(SwapIdRequest { songid1, songid2 }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {} {}\n", Self::COMMAND, self.songid1, self.songid2)
|
format!("{} {} {}\n", Self::COMMAND, self.songid1, self.songid2)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,17 +18,15 @@ pub struct ConfigResponse {
|
|||||||
pub pcre: bool,
|
pub pcre: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfigResponse {
|
|
||||||
pub fn new(music_directory: String, playlist_directory: String, pcre: bool) -> Self {
|
|
||||||
ConfigResponse {
|
|
||||||
music_directory,
|
|
||||||
playlist_directory,
|
|
||||||
pcre,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for ConfigResponse {
|
impl CommandResponse for ConfigResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: HashMap<_, _> = parts.into_map()?;
|
let parts: HashMap<_, _> = parts.into_map()?;
|
||||||
|
|
||||||
|
|||||||
@@ -16,26 +16,18 @@ pub struct Decoder {
|
|||||||
pub mime_types: Vec<String>,
|
pub mime_types: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decoder {
|
|
||||||
pub fn new(plugin: String, suffixes: Vec<String>, mime_types: Vec<String>) -> Self {
|
|
||||||
Decoder {
|
|
||||||
plugin,
|
|
||||||
suffixes,
|
|
||||||
mime_types,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct DecodersResponse(Vec<Decoder>);
|
pub struct DecodersResponse(Vec<Decoder>);
|
||||||
|
|
||||||
impl DecodersResponse {
|
|
||||||
pub fn new(items: Vec<Decoder>) -> Self {
|
|
||||||
DecodersResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for DecodersResponse {
|
impl CommandResponse for DecodersResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
let mut current_decoder: Option<Decoder> = None;
|
let mut current_decoder: Option<Decoder> = None;
|
||||||
|
|||||||
@@ -16,22 +16,27 @@ pub struct StickerDecRequest {
|
|||||||
pub value: usize,
|
pub value: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StickerDecRequest {
|
|
||||||
pub fn new(sticker_type: StickerType, uri: Uri, name: String, value: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
sticker_type,
|
|
||||||
uri,
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for StickerDecRequest {
|
impl CommandRequest for StickerDecRequest {
|
||||||
const COMMAND: &'static str = "sticker dec";
|
const COMMAND: &'static str = "sticker dec";
|
||||||
const MIN_ARGS: u32 = 4;
|
const MIN_ARGS: u32 = 4;
|
||||||
const MAX_ARGS: Option<u32> = Some(4);
|
const MAX_ARGS: Option<u32> = Some(4);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::StickerDec(self.sticker_type, self.uri, self.name, self.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::StickerDec(sticker_type, uri, name, value) => Some(StickerDecRequest {
|
||||||
|
sticker_type,
|
||||||
|
uri,
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} {} {} {} {}\n",
|
"{} {} {} {} {}\n",
|
||||||
|
|||||||
@@ -15,21 +15,26 @@ pub struct StickerDeleteRequest {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StickerDeleteRequest {
|
|
||||||
pub fn new(sticker_type: StickerType, uri: Uri, name: String) -> Self {
|
|
||||||
Self {
|
|
||||||
sticker_type,
|
|
||||||
uri,
|
|
||||||
name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for StickerDeleteRequest {
|
impl CommandRequest for StickerDeleteRequest {
|
||||||
const COMMAND: &'static str = "sticker delete";
|
const COMMAND: &'static str = "sticker delete";
|
||||||
const MIN_ARGS: u32 = 3;
|
const MIN_ARGS: u32 = 3;
|
||||||
const MAX_ARGS: Option<u32> = Some(3);
|
const MAX_ARGS: Option<u32> = Some(3);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::StickerDelete(self.sticker_type, self.uri, self.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::StickerDelete(sticker_type, uri, name) => Some(StickerDeleteRequest {
|
||||||
|
sticker_type,
|
||||||
|
uri,
|
||||||
|
name,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} {} {} {}\n",
|
"{} {} {} {}\n",
|
||||||
|
|||||||
@@ -18,29 +18,36 @@ pub struct StickerFindRequest {
|
|||||||
pub window: Option<WindowRange>,
|
pub window: Option<WindowRange>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StickerFindRequest {
|
|
||||||
pub fn new(
|
|
||||||
sticker_type: StickerType,
|
|
||||||
uri: Uri,
|
|
||||||
name: String,
|
|
||||||
sort: Option<Sort>,
|
|
||||||
window: Option<WindowRange>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
sticker_type,
|
|
||||||
uri,
|
|
||||||
name,
|
|
||||||
sort,
|
|
||||||
window,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for StickerFindRequest {
|
impl CommandRequest for StickerFindRequest {
|
||||||
const COMMAND: &'static str = "sticker find";
|
const COMMAND: &'static str = "sticker find";
|
||||||
const MIN_ARGS: u32 = 3;
|
const MIN_ARGS: u32 = 3;
|
||||||
const MAX_ARGS: Option<u32> = Some(5);
|
const MAX_ARGS: Option<u32> = Some(5);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::StickerFind(
|
||||||
|
self.sticker_type,
|
||||||
|
self.uri,
|
||||||
|
self.name,
|
||||||
|
self.sort,
|
||||||
|
self.window,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::StickerFind(sticker_type, uri, name, sort, window) => {
|
||||||
|
Some(StickerFindRequest {
|
||||||
|
sticker_type,
|
||||||
|
uri,
|
||||||
|
name,
|
||||||
|
sort,
|
||||||
|
window,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let mut cmd = format!(
|
let mut cmd = format!(
|
||||||
"{} {} {} {}",
|
"{} {} {} {}",
|
||||||
@@ -144,12 +151,6 @@ impl CommandRequest for StickerFindRequest {
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct StickerFindResponse(Vec<StickerFindResponseEntry>);
|
pub struct StickerFindResponse(Vec<StickerFindResponseEntry>);
|
||||||
|
|
||||||
impl StickerFindResponse {
|
|
||||||
pub fn new(items: Vec<StickerFindResponseEntry>) -> Self {
|
|
||||||
StickerFindResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct StickerFindResponseEntry {
|
pub struct StickerFindResponseEntry {
|
||||||
pub uri: String,
|
pub uri: String,
|
||||||
@@ -157,13 +158,15 @@ pub struct StickerFindResponseEntry {
|
|||||||
pub value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StickerFindResponseEntry {
|
|
||||||
pub fn new(uri: String, name: String, value: String) -> Self {
|
|
||||||
Self { uri, name, value }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for StickerFindResponse {
|
impl CommandResponse for StickerFindResponse {
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: Vec<_> = parts.into_vec()?;
|
let parts: Vec<_> = parts.into_vec()?;
|
||||||
let mut stickers = Vec::with_capacity(parts.len() / 2);
|
let mut stickers = Vec::with_capacity(parts.len() / 2);
|
||||||
|
|||||||
@@ -15,21 +15,26 @@ pub struct StickerGetRequest {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StickerGetRequest {
|
|
||||||
pub fn new(sticker_type: StickerType, uri: Uri, name: String) -> Self {
|
|
||||||
Self {
|
|
||||||
sticker_type,
|
|
||||||
uri,
|
|
||||||
name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for StickerGetRequest {
|
impl CommandRequest for StickerGetRequest {
|
||||||
const COMMAND: &'static str = "sticker get";
|
const COMMAND: &'static str = "sticker get";
|
||||||
const MIN_ARGS: u32 = 3;
|
const MIN_ARGS: u32 = 3;
|
||||||
const MAX_ARGS: Option<u32> = Some(3);
|
const MAX_ARGS: Option<u32> = Some(3);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::StickerGet(self.sticker_type, self.uri, self.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::StickerGet(sticker_type, uri, name) => Some(StickerGetRequest {
|
||||||
|
sticker_type,
|
||||||
|
uri,
|
||||||
|
name,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} {} {} {}\n",
|
"{} {} {} {}\n",
|
||||||
|
|||||||
@@ -16,22 +16,27 @@ pub struct StickerIncRequest {
|
|||||||
pub value: usize,
|
pub value: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StickerIncRequest {
|
|
||||||
pub fn new(sticker_type: StickerType, uri: Uri, name: String, value: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
sticker_type,
|
|
||||||
uri,
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for StickerIncRequest {
|
impl CommandRequest for StickerIncRequest {
|
||||||
const COMMAND: &'static str = "sticker inc";
|
const COMMAND: &'static str = "sticker inc";
|
||||||
const MIN_ARGS: u32 = 4;
|
const MIN_ARGS: u32 = 4;
|
||||||
const MAX_ARGS: Option<u32> = Some(4);
|
const MAX_ARGS: Option<u32> = Some(4);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::StickerInc(self.sticker_type, self.uri, self.name, self.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::StickerInc(sticker_type, uri, name, value) => Some(StickerIncRequest {
|
||||||
|
sticker_type,
|
||||||
|
uri,
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} {} {} {} {}\n",
|
"{} {} {} {} {}\n",
|
||||||
|
|||||||
@@ -17,17 +17,24 @@ pub struct StickerListRequest {
|
|||||||
pub uri: Uri,
|
pub uri: Uri,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StickerListRequest {
|
|
||||||
pub fn new(sticker_type: StickerType, uri: Uri) -> Self {
|
|
||||||
Self { sticker_type, uri }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for StickerListRequest {
|
impl CommandRequest for StickerListRequest {
|
||||||
const COMMAND: &'static str = "sticker list";
|
const COMMAND: &'static str = "sticker list";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::StickerList(self.sticker_type, self.uri)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::StickerList(sticker_type, uri) => {
|
||||||
|
Some(StickerListRequest { sticker_type, uri })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {} {}\n", Self::COMMAND, self.sticker_type, self.uri)
|
format!("{} {} {}\n", Self::COMMAND, self.sticker_type, self.uri)
|
||||||
}
|
}
|
||||||
@@ -61,13 +68,15 @@ impl CommandRequest for StickerListRequest {
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct StickerListResponse(HashMap<String, String>);
|
pub struct StickerListResponse(HashMap<String, String>);
|
||||||
|
|
||||||
impl StickerListResponse {
|
|
||||||
pub fn new(map: HashMap<String, String>) -> Self {
|
|
||||||
StickerListResponse(map)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for StickerListResponse {
|
impl CommandResponse for StickerListResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: Vec<_> = parts.into_vec()?;
|
let parts: Vec<_> = parts.into_vec()?;
|
||||||
if let Some((k, _)) = parts.iter().find(|(k, _)| *k != "sticker") {
|
if let Some((k, _)) = parts.iter().find(|(k, _)| *k != "sticker") {
|
||||||
|
|||||||
@@ -16,22 +16,27 @@ pub struct StickerSetRequest {
|
|||||||
pub value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StickerSetRequest {
|
|
||||||
pub fn new(sticker_type: StickerType, uri: Uri, name: String, value: String) -> Self {
|
|
||||||
Self {
|
|
||||||
sticker_type,
|
|
||||||
uri,
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for StickerSetRequest {
|
impl CommandRequest for StickerSetRequest {
|
||||||
const COMMAND: &'static str = "sticker set";
|
const COMMAND: &'static str = "sticker set";
|
||||||
const MIN_ARGS: u32 = 4;
|
const MIN_ARGS: u32 = 4;
|
||||||
const MAX_ARGS: Option<u32> = Some(4);
|
const MAX_ARGS: Option<u32> = Some(4);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::StickerSet(self.sticker_type, self.uri, self.name, self.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::StickerSet(sticker_type, uri, name, value) => Some(StickerSetRequest {
|
||||||
|
sticker_type,
|
||||||
|
uri,
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} {} {} {} {}\n",
|
"{} {} {} {} {}\n",
|
||||||
|
|||||||
@@ -14,17 +14,24 @@ pub struct StickerNamesTypes;
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct StickerNamesTypesRequest(Option<StickerType>);
|
pub struct StickerNamesTypesRequest(Option<StickerType>);
|
||||||
|
|
||||||
impl StickerNamesTypesRequest {
|
|
||||||
pub fn new(sticker_type: Option<StickerType>) -> Self {
|
|
||||||
Self(sticker_type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for StickerNamesTypesRequest {
|
impl CommandRequest for StickerNamesTypesRequest {
|
||||||
const COMMAND: &'static str = "stickernamestypes";
|
const COMMAND: &'static str = "stickernamestypes";
|
||||||
const MIN_ARGS: u32 = 0;
|
const MIN_ARGS: u32 = 0;
|
||||||
const MAX_ARGS: Option<u32> = Some(1);
|
const MAX_ARGS: Option<u32> = Some(1);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::StickerNamesTypes(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::StickerNamesTypes(sticker_type) => {
|
||||||
|
Some(StickerNamesTypesRequest(sticker_type))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
if let Some(sticker_type) = &self.0 {
|
if let Some(sticker_type) = &self.0 {
|
||||||
format!("{} {}\n", Self::COMMAND, sticker_type)
|
format!("{} {}\n", Self::COMMAND, sticker_type)
|
||||||
@@ -52,13 +59,15 @@ impl CommandRequest for StickerNamesTypesRequest {
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct StickerNamesTypesResponse(HashMap<String, Vec<String>>);
|
pub struct StickerNamesTypesResponse(HashMap<String, Vec<String>>);
|
||||||
|
|
||||||
impl StickerNamesTypesResponse {
|
|
||||||
pub fn new(map: HashMap<String, Vec<String>>) -> Self {
|
|
||||||
StickerNamesTypesResponse(map)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for StickerNamesTypesResponse {
|
impl CommandResponse for StickerNamesTypesResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: Vec<_> = parts.into_vec()?;
|
let parts: Vec<_> = parts.into_vec()?;
|
||||||
debug_assert!(parts.len() % 2 == 0);
|
debug_assert!(parts.len() % 2 == 0);
|
||||||
|
|||||||
@@ -20,17 +20,22 @@ pub struct ListPlaylistRequest {
|
|||||||
range: Option<WindowRange>,
|
range: Option<WindowRange>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListPlaylistRequest {
|
|
||||||
pub fn new(name: PlaylistName, range: Option<WindowRange>) -> Self {
|
|
||||||
Self { name, range }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for ListPlaylistRequest {
|
impl CommandRequest for ListPlaylistRequest {
|
||||||
const COMMAND: &'static str = "listplaylist";
|
const COMMAND: &'static str = "listplaylist";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::ListPlaylist(self.name, self.range)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::ListPlaylist(name, range) => Some(ListPlaylistRequest { name, range }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
if let Some(range) = &self.range {
|
if let Some(range) = &self.range {
|
||||||
format!("{} {} {}\n", Self::COMMAND, self.name, range)
|
format!("{} {} {}\n", Self::COMMAND, self.name, range)
|
||||||
|
|||||||
@@ -15,17 +15,24 @@ pub struct ListPlaylistInfoRequest {
|
|||||||
range: Option<WindowRange>,
|
range: Option<WindowRange>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListPlaylistInfoRequest {
|
|
||||||
pub fn new(name: PlaylistName, range: Option<WindowRange>) -> Self {
|
|
||||||
Self { name, range }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for ListPlaylistInfoRequest {
|
impl CommandRequest for ListPlaylistInfoRequest {
|
||||||
const COMMAND: &'static str = "listplaylistinfo";
|
const COMMAND: &'static str = "listplaylistinfo";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::ListPlaylistInfo(self.name, self.range)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::ListPlaylistInfo(name, range) => {
|
||||||
|
Some(ListPlaylistInfoRequest { name, range })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
match self.range.as_ref() {
|
match self.range.as_ref() {
|
||||||
Some(range) => format!("{} {} {}\n", Self::COMMAND, self.name, range),
|
Some(range) => format!("{} {} {}\n", Self::COMMAND, self.name, range),
|
||||||
@@ -56,14 +63,16 @@ impl CommandRequest for ListPlaylistInfoRequest {
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ListPlaylistInfoResponse(Vec<DbSongInfo>);
|
pub struct ListPlaylistInfoResponse(Vec<DbSongInfo>);
|
||||||
|
|
||||||
impl ListPlaylistInfoResponse {
|
|
||||||
pub fn new(items: Vec<DbSongInfo>) -> Self {
|
|
||||||
ListPlaylistInfoResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for ListPlaylistInfoResponse {
|
impl CommandResponse for ListPlaylistInfoResponse {
|
||||||
fn parse(_parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,6 @@ empty_command_request!(ListPlaylists, "listplaylists");
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ListPlaylistsResponse(Vec<ListPlaylistsResponseEntry>);
|
pub struct ListPlaylistsResponse(Vec<ListPlaylistsResponseEntry>);
|
||||||
|
|
||||||
impl ListPlaylistsResponse {
|
|
||||||
pub fn new(items: Vec<ListPlaylistsResponseEntry>) -> Self {
|
|
||||||
ListPlaylistsResponse(items)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ListPlaylistsResponseEntry {
|
pub struct ListPlaylistsResponseEntry {
|
||||||
pub playlist: PlaylistName,
|
pub playlist: PlaylistName,
|
||||||
@@ -26,16 +20,15 @@ pub struct ListPlaylistsResponseEntry {
|
|||||||
pub last_modified: Option<String>,
|
pub last_modified: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListPlaylistsResponseEntry {
|
|
||||||
pub fn new(playlist: PlaylistName, last_modified: Option<String>) -> Self {
|
|
||||||
ListPlaylistsResponseEntry {
|
|
||||||
playlist,
|
|
||||||
last_modified,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for ListPlaylistsResponse {
|
impl CommandResponse for ListPlaylistsResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let mut parts = parts.into_lazy_vec().into_iter().peekable();
|
let mut parts = parts.into_lazy_vec().into_iter().peekable();
|
||||||
// TODO: count instances of 'playlist' to preallocate
|
// TODO: count instances of 'playlist' to preallocate
|
||||||
|
|||||||
@@ -15,25 +15,26 @@ pub struct LoadRequest {
|
|||||||
position: Option<SongPosition>,
|
position: Option<SongPosition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LoadRequest {
|
|
||||||
pub fn new(
|
|
||||||
name: PlaylistName,
|
|
||||||
range: Option<WindowRange>,
|
|
||||||
position: Option<SongPosition>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
name,
|
|
||||||
range,
|
|
||||||
position,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for LoadRequest {
|
impl CommandRequest for LoadRequest {
|
||||||
const COMMAND: &'static str = "load";
|
const COMMAND: &'static str = "load";
|
||||||
const MIN_ARGS: u32 = 1;
|
const MIN_ARGS: u32 = 1;
|
||||||
const MAX_ARGS: Option<u32> = Some(3);
|
const MAX_ARGS: Option<u32> = Some(3);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Load(self.name, self.range, self.position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Load(name, range, position) => Some(LoadRequest {
|
||||||
|
name,
|
||||||
|
range,
|
||||||
|
position,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
match (self.range.as_ref(), self.position.as_ref()) {
|
match (self.range.as_ref(), self.position.as_ref()) {
|
||||||
(Some(range), Some(pos)) => {
|
(Some(range), Some(pos)) => {
|
||||||
|
|||||||
@@ -15,21 +15,26 @@ pub struct PlaylistAddRequest {
|
|||||||
pub position: Option<SongPosition>,
|
pub position: Option<SongPosition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlaylistAddRequest {
|
|
||||||
pub fn new(playlist_name: PlaylistName, uri: Uri, position: Option<SongPosition>) -> Self {
|
|
||||||
Self {
|
|
||||||
playlist_name,
|
|
||||||
uri,
|
|
||||||
position,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for PlaylistAddRequest {
|
impl CommandRequest for PlaylistAddRequest {
|
||||||
const COMMAND: &'static str = "playlistadd";
|
const COMMAND: &'static str = "playlistadd";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(3);
|
const MAX_ARGS: Option<u32> = Some(3);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::PlaylistAdd(self.playlist_name, self.uri, self.position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::PlaylistAdd(playlist_name, uri, position) => Some(PlaylistAddRequest {
|
||||||
|
playlist_name,
|
||||||
|
uri,
|
||||||
|
position,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
match self.position {
|
match self.position {
|
||||||
Some(pos) => {
|
Some(pos) => {
|
||||||
|
|||||||
@@ -14,20 +14,27 @@ pub struct PlaylistDeleteRequest {
|
|||||||
pub position: OneOrRange,
|
pub position: OneOrRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlaylistDeleteRequest {
|
|
||||||
pub fn new(playlist_name: PlaylistName, position: OneOrRange) -> Self {
|
|
||||||
Self {
|
|
||||||
playlist_name,
|
|
||||||
position,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for PlaylistDeleteRequest {
|
impl CommandRequest for PlaylistDeleteRequest {
|
||||||
const COMMAND: &'static str = "playlistdelete";
|
const COMMAND: &'static str = "playlistdelete";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::PlaylistDelete(self.playlist_name, self.position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::PlaylistDelete(playlist_name, position) => {
|
||||||
|
Some(PlaylistDeleteRequest {
|
||||||
|
playlist_name,
|
||||||
|
position,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} {} {}\n",
|
"{} {} {}\n",
|
||||||
|
|||||||
@@ -18,13 +18,15 @@ pub struct PlaylistLengthResponse {
|
|||||||
pub playtime: u64,
|
pub playtime: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlaylistLengthResponse {
|
|
||||||
pub fn new(songs: u64, playtime: u64) -> Self {
|
|
||||||
PlaylistLengthResponse { songs, playtime }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandResponse for PlaylistLengthResponse {
|
impl CommandResponse for PlaylistLengthResponse {
|
||||||
|
fn into_response_enum(self) -> crate::Response {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError> {
|
||||||
let parts: HashMap<_, _> = parts.into_map()?;
|
let parts: HashMap<_, _> = parts.into_map()?;
|
||||||
|
|
||||||
|
|||||||
@@ -15,21 +15,26 @@ pub struct PlaylistMoveRequest {
|
|||||||
pub to: SongPosition,
|
pub to: SongPosition,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlaylistMoveRequest {
|
|
||||||
pub fn new(playlist_name: PlaylistName, from: Option<OneOrRange>, to: SongPosition) -> Self {
|
|
||||||
Self {
|
|
||||||
playlist_name,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for PlaylistMoveRequest {
|
impl CommandRequest for PlaylistMoveRequest {
|
||||||
const COMMAND: &'static str = "playlistmove";
|
const COMMAND: &'static str = "playlistmove";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(3);
|
const MAX_ARGS: Option<u32> = Some(3);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::PlaylistMove(self.playlist_name, self.from, self.to)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::PlaylistMove(playlist_name, from, to) => Some(PlaylistMoveRequest {
|
||||||
|
playlist_name,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
match self.from.as_ref() {
|
match self.from.as_ref() {
|
||||||
Some(from) => {
|
Some(from) => {
|
||||||
|
|||||||
@@ -13,17 +13,24 @@ pub struct RenameRequest {
|
|||||||
pub new_name: String,
|
pub new_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenameRequest {
|
|
||||||
pub fn new(old_name: String, new_name: String) -> Self {
|
|
||||||
Self { old_name, new_name }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for RenameRequest {
|
impl CommandRequest for RenameRequest {
|
||||||
const COMMAND: &'static str = "rename";
|
const COMMAND: &'static str = "rename";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(2);
|
const MAX_ARGS: Option<u32> = Some(2);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Rename(self.old_name, self.new_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Rename(old_name, new_name) => {
|
||||||
|
Some(RenameRequest { old_name, new_name })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
format!("{} {} {}\n", Self::COMMAND, self.old_name, self.new_name)
|
format!("{} {} {}\n", Self::COMMAND, self.old_name, self.new_name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,20 +14,25 @@ pub struct SaveRequest {
|
|||||||
pub mode: Option<SaveMode>,
|
pub mode: Option<SaveMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SaveRequest {
|
|
||||||
pub fn new(playlist_name: PlaylistName, mode: Option<SaveMode>) -> Self {
|
|
||||||
Self {
|
|
||||||
playlist_name,
|
|
||||||
mode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for SaveRequest {
|
impl CommandRequest for SaveRequest {
|
||||||
const COMMAND: &'static str = "save";
|
const COMMAND: &'static str = "save";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(3);
|
const MAX_ARGS: Option<u32> = Some(3);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::Save(self.playlist_name, self.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::Save(playlist_name, mode) => Some(SaveRequest {
|
||||||
|
playlist_name,
|
||||||
|
mode,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
match self.mode.as_ref() {
|
match self.mode.as_ref() {
|
||||||
Some(mode) => {
|
Some(mode) => {
|
||||||
|
|||||||
@@ -16,21 +16,26 @@ pub struct SearchPlaylistRequest {
|
|||||||
pub range: Option<WindowRange>,
|
pub range: Option<WindowRange>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SearchPlaylistRequest {
|
|
||||||
pub fn new(name: PlaylistName, filter: Filter, range: Option<WindowRange>) -> Self {
|
|
||||||
Self {
|
|
||||||
name,
|
|
||||||
filter,
|
|
||||||
range,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRequest for SearchPlaylistRequest {
|
impl CommandRequest for SearchPlaylistRequest {
|
||||||
const COMMAND: &'static str = "searchplaylist";
|
const COMMAND: &'static str = "searchplaylist";
|
||||||
const MIN_ARGS: u32 = 2;
|
const MIN_ARGS: u32 = 2;
|
||||||
const MAX_ARGS: Option<u32> = Some(3);
|
const MAX_ARGS: Option<u32> = Some(3);
|
||||||
|
|
||||||
|
fn into_request_enum(self) -> crate::Request {
|
||||||
|
crate::Request::SearchPlaylist(self.name, self.filter, self.range)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||||
|
match request {
|
||||||
|
crate::Request::SearchPlaylist(name, filter, range) => Some(SearchPlaylistRequest {
|
||||||
|
name,
|
||||||
|
filter,
|
||||||
|
range,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize(&self) -> String {
|
fn serialize(&self) -> String {
|
||||||
let mut cmd = format!("{} {} {}", Self::COMMAND, self.name, self.filter);
|
let mut cmd = format!("{} {} {}", Self::COMMAND, self.name, self.filter);
|
||||||
if let Some(range) = &self.range {
|
if let Some(range) = &self.range {
|
||||||
|
|||||||
+1
-1
@@ -295,7 +295,7 @@ pub(super) fn unescape_string(s: &str) -> String {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
lalrpop_mod!(filter_grammar, "/src/filter_grammar.rs");
|
lalrpop_mod!(filter_grammar, "/filter_grammar.rs");
|
||||||
|
|
||||||
impl Filter {
|
impl Filter {
|
||||||
pub fn parse(input: &str) -> Result<Filter, RequestParserError> {
|
pub fn parse(input: &str) -> Result<Filter, RequestParserError> {
|
||||||
|
|||||||
+5
-1
@@ -4,13 +4,17 @@
|
|||||||
//! It does not provide any client or server implementation
|
//! It does not provide any client or server implementation
|
||||||
|
|
||||||
mod client;
|
mod client;
|
||||||
|
mod commands;
|
||||||
|
mod request;
|
||||||
mod request_tokenizer;
|
mod request_tokenizer;
|
||||||
mod response;
|
mod response;
|
||||||
mod response_tokenizer;
|
mod response_tokenizer;
|
||||||
|
mod server;
|
||||||
|
|
||||||
pub mod commands;
|
|
||||||
pub mod filter;
|
pub mod filter;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
pub use client::{MpdClient, MpdClientError};
|
pub use client::{MpdClient, MpdClientError};
|
||||||
|
pub use request::Request;
|
||||||
pub use response::Response;
|
pub use response::Response;
|
||||||
|
pub use server::MpdServer;
|
||||||
|
|||||||
+587
@@ -0,0 +1,587 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::commands::*;
|
||||||
|
use crate::types::*;
|
||||||
|
|
||||||
|
use crate::filter::Filter;
|
||||||
|
use crate::request_tokenizer::RequestTokenizer;
|
||||||
|
|
||||||
|
// TODO: SingleLineString
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum Request {
|
||||||
|
CommandList(Vec<Request>),
|
||||||
|
|
||||||
|
// -- Query Commands -- //
|
||||||
|
ClearError,
|
||||||
|
CurrentSong,
|
||||||
|
Idle(Option<Vec<SubSystem>>),
|
||||||
|
Status,
|
||||||
|
Stats,
|
||||||
|
|
||||||
|
// -- Playback Commands -- //
|
||||||
|
Consume(BoolOrOneshot),
|
||||||
|
Crossfade(Seconds),
|
||||||
|
MixRampDb(f32),
|
||||||
|
MixRampDelay(Seconds),
|
||||||
|
Random(bool),
|
||||||
|
Repeat(bool),
|
||||||
|
SetVol(VolumeValue),
|
||||||
|
GetVol,
|
||||||
|
Single(BoolOrOneshot),
|
||||||
|
ReplayGainMode(ReplayGainModeMode),
|
||||||
|
ReplayGainStatus,
|
||||||
|
Volume(VolumeValue),
|
||||||
|
|
||||||
|
// -- Playback Control Commands -- //
|
||||||
|
Next,
|
||||||
|
Pause(Option<bool>),
|
||||||
|
Play(Option<SongPosition>),
|
||||||
|
PlayId(Option<SongId>),
|
||||||
|
Previous,
|
||||||
|
Seek(SongPosition, TimeWithFractions),
|
||||||
|
SeekId(SongId, TimeWithFractions),
|
||||||
|
SeekCur(SeekMode, TimeWithFractions),
|
||||||
|
Stop,
|
||||||
|
|
||||||
|
// -- Queue Commands -- //
|
||||||
|
// TODO: relative mode
|
||||||
|
Add(String, Option<SongPosition>),
|
||||||
|
// TODO: relative mode
|
||||||
|
AddId(String, Option<SongPosition>),
|
||||||
|
Clear,
|
||||||
|
Delete(OneOrRange),
|
||||||
|
DeleteId(SongId),
|
||||||
|
// TODO: account for relative moves
|
||||||
|
Move(OneOrRange, AbsouluteRelativeSongPosition),
|
||||||
|
// TODO: account for relative moves
|
||||||
|
MoveId(SongId, AbsouluteRelativeSongPosition),
|
||||||
|
Playlist,
|
||||||
|
PlaylistFind(Filter, Option<Sort>, Option<WindowRange>),
|
||||||
|
PlaylistId(SongId),
|
||||||
|
PlaylistInfo(Option<OneOrRange>),
|
||||||
|
PlaylistSearch(Filter, Option<Sort>, Option<WindowRange>),
|
||||||
|
// TODO: which type of range?
|
||||||
|
PlChanges(PlaylistVersion, Option<WindowRange>),
|
||||||
|
// TODO: which type of range?
|
||||||
|
PlChangesPosId(PlaylistVersion, Option<WindowRange>),
|
||||||
|
// TODO: which type of range?
|
||||||
|
Prio(Priority, WindowRange),
|
||||||
|
PrioId(Priority, Vec<SongId>),
|
||||||
|
RangeId(SongId, TimeInterval),
|
||||||
|
Shuffle(Option<OneOrRange>),
|
||||||
|
Swap(SongPosition, SongPosition),
|
||||||
|
SwapId(SongId, SongId),
|
||||||
|
AddTagId(SongId, TagName, TagValue),
|
||||||
|
ClearTagId(SongId, TagName),
|
||||||
|
|
||||||
|
// -- Stored Playlist Commands -- //
|
||||||
|
ListPlaylist(PlaylistName, Option<WindowRange>),
|
||||||
|
ListPlaylistInfo(PlaylistName, Option<WindowRange>),
|
||||||
|
SearchPlaylist(PlaylistName, Filter, Option<WindowRange>),
|
||||||
|
ListPlaylists,
|
||||||
|
Load(PlaylistName, Option<WindowRange>, Option<SongPosition>),
|
||||||
|
PlaylistAdd(PlaylistName, Uri, Option<SongPosition>),
|
||||||
|
PlaylistClear(PlaylistName),
|
||||||
|
PlaylistDelete(PlaylistName, OneOrRange),
|
||||||
|
PlaylistLength(PlaylistName),
|
||||||
|
// TODO: which type of range?
|
||||||
|
PlaylistMove(PlaylistName, Option<OneOrRange>, SongPosition),
|
||||||
|
Rename(PlaylistName, PlaylistName),
|
||||||
|
Rm(PlaylistName),
|
||||||
|
Save(PlaylistName, Option<SaveMode>),
|
||||||
|
|
||||||
|
// -- Music Database Commands -- //
|
||||||
|
AlbumArt(Uri, Offset),
|
||||||
|
Count(Filter, Option<GroupType>),
|
||||||
|
GetFingerprint(Uri),
|
||||||
|
Find(Filter, Option<Sort>, Option<WindowRange>),
|
||||||
|
FindAdd(
|
||||||
|
Filter,
|
||||||
|
Option<Sort>,
|
||||||
|
Option<WindowRange>,
|
||||||
|
Option<SongPosition>,
|
||||||
|
),
|
||||||
|
List(TagName, Option<Filter>, Vec<GroupType>, Option<WindowRange>),
|
||||||
|
#[deprecated]
|
||||||
|
ListAll(Option<Uri>),
|
||||||
|
#[deprecated]
|
||||||
|
ListAllInfo(Option<Uri>),
|
||||||
|
ListFiles(Option<Uri>),
|
||||||
|
LsInfo(Option<Uri>),
|
||||||
|
ReadComments(Uri),
|
||||||
|
ReadPicture(Uri, Offset),
|
||||||
|
Search(Filter, Option<Sort>, Option<WindowRange>),
|
||||||
|
SearchAdd(
|
||||||
|
Filter,
|
||||||
|
Option<Sort>,
|
||||||
|
Option<WindowRange>,
|
||||||
|
Option<SongPosition>,
|
||||||
|
),
|
||||||
|
SearchAddPl(
|
||||||
|
PlaylistName,
|
||||||
|
Filter,
|
||||||
|
Option<Sort>,
|
||||||
|
Option<WindowRange>,
|
||||||
|
Option<SongPosition>,
|
||||||
|
),
|
||||||
|
SearchCount(Filter, Option<GroupType>),
|
||||||
|
Update(Option<Uri>),
|
||||||
|
Rescan(Option<Uri>),
|
||||||
|
|
||||||
|
// -- Mount and Neighbor Commands -- //
|
||||||
|
Mount(MountPath, Uri),
|
||||||
|
Unmount(MountPath),
|
||||||
|
ListMounts,
|
||||||
|
ListNeighbors,
|
||||||
|
|
||||||
|
// -- Sticker Commands -- //
|
||||||
|
StickerGet(StickerType, Uri, String),
|
||||||
|
StickerSet(StickerType, Uri, String, String),
|
||||||
|
StickerInc(StickerType, Uri, String, usize),
|
||||||
|
StickerDec(StickerType, Uri, String, usize),
|
||||||
|
StickerDelete(StickerType, Uri, String),
|
||||||
|
StickerList(StickerType, Uri),
|
||||||
|
StickerFind(StickerType, Uri, String, Option<Sort>, Option<WindowRange>),
|
||||||
|
StickerFindValue(
|
||||||
|
StickerType,
|
||||||
|
Uri,
|
||||||
|
String,
|
||||||
|
String,
|
||||||
|
Option<Sort>,
|
||||||
|
Option<WindowRange>,
|
||||||
|
),
|
||||||
|
StickerNames,
|
||||||
|
StickerTypes,
|
||||||
|
StickerNamesTypes(Option<StickerType>),
|
||||||
|
|
||||||
|
// -- Connection Commands -- //
|
||||||
|
Close,
|
||||||
|
Kill,
|
||||||
|
Password(String),
|
||||||
|
Ping,
|
||||||
|
BinaryLimit(u64),
|
||||||
|
TagTypes,
|
||||||
|
TagTypesDisable(Vec<TagName>),
|
||||||
|
TagTypesEnable(Vec<TagName>),
|
||||||
|
TagTypesClear,
|
||||||
|
TagTypesAll,
|
||||||
|
TagTypesAvailable,
|
||||||
|
TagTypesReset(Vec<TagName>),
|
||||||
|
Protocol,
|
||||||
|
ProtocolDisable(Vec<Feature>),
|
||||||
|
ProtocolEnable(Vec<Feature>),
|
||||||
|
ProtocolClear,
|
||||||
|
ProtocolAll,
|
||||||
|
ProtocolAvailable,
|
||||||
|
|
||||||
|
// -- Partition Commands -- //
|
||||||
|
Partition(PartitionName),
|
||||||
|
ListPartitions,
|
||||||
|
NewPartition(PartitionName),
|
||||||
|
DelPartition(PartitionName),
|
||||||
|
MoveOutput(String),
|
||||||
|
|
||||||
|
// -- Audio Output Commands -- //
|
||||||
|
DisableOutput(AudioOutputId),
|
||||||
|
EnableOutput(AudioOutputId),
|
||||||
|
ToggleOutput(AudioOutputId),
|
||||||
|
Outputs,
|
||||||
|
OutputSet(AudioOutputId, String, String),
|
||||||
|
|
||||||
|
// -- Reflection Commands -- //
|
||||||
|
Config,
|
||||||
|
Commands,
|
||||||
|
NotCommands,
|
||||||
|
UrlHandlers,
|
||||||
|
Decoders,
|
||||||
|
|
||||||
|
// -- Client to Client Commands -- //
|
||||||
|
Subscribe(ChannelName),
|
||||||
|
Unsubscribe(ChannelName),
|
||||||
|
Channels,
|
||||||
|
ReadMessages,
|
||||||
|
SendMessage(ChannelName, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! serialize_req {
|
||||||
|
($request_enum:expr, $request_struct:ty) => {
|
||||||
|
{
|
||||||
|
if let Some(request) = <$request_struct as CommandRequest>::from_request_enum($request_enum) {
|
||||||
|
return <$request_struct as CommandRequest>::serialize(&request);
|
||||||
|
} else {
|
||||||
|
panic!("Mismatched request enum and struct in serialize_request macro, this should never happen!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! parse_req {
|
||||||
|
($request_struct:ty, $parts:expr) => {
|
||||||
|
<$request_struct>::parse($parts).map(|req| req.into_request_enum())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Request {
|
||||||
|
pub fn serialize(self) -> String {
|
||||||
|
match self {
|
||||||
|
/* querying mpd status */
|
||||||
|
Request::ClearError => serialize_req!(self, ClearErrorRequest),
|
||||||
|
Request::CurrentSong => serialize_req!(self, CurrentSongRequest),
|
||||||
|
Request::Idle(_) => serialize_req!(self, IdleRequest),
|
||||||
|
Request::Status => serialize_req!(self, StatusRequest),
|
||||||
|
Request::Stats => serialize_req!(self, StatsRequest),
|
||||||
|
|
||||||
|
// /* playback options */
|
||||||
|
Request::Consume(_) => serialize_req!(self, ConsumeRequest),
|
||||||
|
Request::Crossfade(_) => serialize_req!(self, CrossfadeRequest),
|
||||||
|
Request::MixRampDb(_) => serialize_req!(self, MixRampDbRequest),
|
||||||
|
Request::MixRampDelay(_) => serialize_req!(self, MixRampDelayRequest),
|
||||||
|
Request::Random(_) => serialize_req!(self, RandomRequest),
|
||||||
|
Request::Repeat(_) => serialize_req!(self, RepeatRequest),
|
||||||
|
Request::SetVol(_) => serialize_req!(self, SetVolRequest),
|
||||||
|
Request::GetVol => serialize_req!(self, GetVolRequest),
|
||||||
|
Request::Single(_) => serialize_req!(self, SingleRequest),
|
||||||
|
Request::ReplayGainMode(_) => serialize_req!(self, ReplayGainModeRequest),
|
||||||
|
Request::ReplayGainStatus => serialize_req!(self, ReplayGainStatusRequest),
|
||||||
|
Request::Volume(_) => serialize_req!(self, VolumeRequest),
|
||||||
|
|
||||||
|
/* playback control */
|
||||||
|
Request::Next => serialize_req!(self, NextRequest),
|
||||||
|
Request::Pause(_) => serialize_req!(self, PauseRequest),
|
||||||
|
Request::Play(_) => serialize_req!(self, PlayRequest),
|
||||||
|
Request::PlayId(_) => serialize_req!(self, PlayIdRequest),
|
||||||
|
Request::Previous => serialize_req!(self, PreviousRequest),
|
||||||
|
Request::Seek(_, _) => serialize_req!(self, SeekRequest),
|
||||||
|
Request::SeekId(_, _) => serialize_req!(self, SeekIdRequest),
|
||||||
|
Request::SeekCur(_, _) => serialize_req!(self, SeekCurRequest),
|
||||||
|
Request::Stop => serialize_req!(self, StopRequest),
|
||||||
|
|
||||||
|
/* queue */
|
||||||
|
Request::Add(_, _) => serialize_req!(self, AddRequest),
|
||||||
|
Request::AddId(_, _) => serialize_req!(self, AddIdRequest),
|
||||||
|
Request::Clear => serialize_req!(self, ClearRequest),
|
||||||
|
Request::Delete(_) => serialize_req!(self, DeleteRequest),
|
||||||
|
Request::DeleteId(_) => serialize_req!(self, DeleteIdRequest),
|
||||||
|
Request::Move(_, _) => serialize_req!(self, MoveRequest),
|
||||||
|
Request::MoveId(_, _) => serialize_req!(self, MoveIdRequest),
|
||||||
|
Request::Playlist => serialize_req!(self, PlaylistRequest),
|
||||||
|
Request::PlaylistFind(_, _, _) => serialize_req!(self, PlaylistFindRequest),
|
||||||
|
Request::PlaylistId(_) => serialize_req!(self, PlaylistIdRequest),
|
||||||
|
Request::PlaylistInfo(_) => serialize_req!(self, PlaylistInfoRequest),
|
||||||
|
Request::PlaylistSearch(_, _, _) => serialize_req!(self, PlaylistSearchRequest),
|
||||||
|
Request::PlChanges(_, _) => serialize_req!(self, PlChangesRequest),
|
||||||
|
Request::PlChangesPosId(_, _) => serialize_req!(self, PlChangesPosIdRequest),
|
||||||
|
Request::Prio(_, _) => serialize_req!(self, PrioRequest),
|
||||||
|
Request::PrioId(_, _) => serialize_req!(self, PrioIdRequest),
|
||||||
|
Request::RangeId(_, _) => serialize_req!(self, RangeIdRequest),
|
||||||
|
Request::Shuffle(_) => serialize_req!(self, ShuffleRequest),
|
||||||
|
Request::Swap(_, _) => serialize_req!(self, SwapRequest),
|
||||||
|
Request::SwapId(_, _) => serialize_req!(self, SwapIdRequest),
|
||||||
|
Request::AddTagId(_, _, _) => serialize_req!(self, AddTagIdRequest),
|
||||||
|
Request::ClearTagId(_, _) => serialize_req!(self, ClearTagIdRequest),
|
||||||
|
|
||||||
|
/* stored playlists */
|
||||||
|
Request::ListPlaylist(_, _) => serialize_req!(self, ListPlaylistRequest),
|
||||||
|
Request::ListPlaylistInfo(_, _) => serialize_req!(self, ListPlaylistInfoRequest),
|
||||||
|
Request::SearchPlaylist(_, _, _) => serialize_req!(self, SearchPlaylistRequest),
|
||||||
|
Request::ListPlaylists => serialize_req!(self, ListPlaylistsRequest),
|
||||||
|
Request::Load(_, _, _) => serialize_req!(self, LoadRequest),
|
||||||
|
Request::PlaylistAdd(_, _, _) => serialize_req!(self, PlaylistAddRequest),
|
||||||
|
Request::PlaylistClear(_) => serialize_req!(self, PlaylistClearRequest),
|
||||||
|
Request::PlaylistDelete(_, _) => serialize_req!(self, PlaylistDeleteRequest),
|
||||||
|
Request::PlaylistLength(_) => serialize_req!(self, PlaylistLengthRequest),
|
||||||
|
Request::PlaylistMove(_, _, _) => serialize_req!(self, PlaylistMoveRequest),
|
||||||
|
Request::Rename(_, _) => serialize_req!(self, RenameRequest),
|
||||||
|
Request::Rm(_) => serialize_req!(self, RmRequest),
|
||||||
|
Request::Save(_, _) => serialize_req!(self, SaveRequest),
|
||||||
|
|
||||||
|
/* music database */
|
||||||
|
Request::AlbumArt(_, _) => serialize_req!(self, AlbumArtRequest),
|
||||||
|
Request::Count(_, _) => serialize_req!(self, CountRequest),
|
||||||
|
Request::GetFingerprint(_) => serialize_req!(self, GetFingerprintRequest),
|
||||||
|
Request::Find(_, _, _) => serialize_req!(self, FindRequest),
|
||||||
|
Request::FindAdd(_, _, _, _) => serialize_req!(self, FindAddRequest),
|
||||||
|
Request::List(_, _, _, _) => serialize_req!(self, ListRequest),
|
||||||
|
Request::ListAll(_) => serialize_req!(self, ListAllRequest),
|
||||||
|
Request::ListAllInfo(_) => serialize_req!(self, ListAllInfoRequest),
|
||||||
|
Request::ListFiles(_) => serialize_req!(self, ListFilesRequest),
|
||||||
|
Request::LsInfo(_) => serialize_req!(self, LsInfoRequest),
|
||||||
|
Request::ReadComments(_) => serialize_req!(self, ReadCommentsRequest),
|
||||||
|
Request::ReadPicture(_, _) => serialize_req!(self, ReadPictureRequest),
|
||||||
|
Request::Search(_, _, _) => serialize_req!(self, SearchRequest),
|
||||||
|
Request::SearchAdd(_, _, _, _) => serialize_req!(self, SearchAddRequest),
|
||||||
|
Request::SearchAddPl(_, _, _, _, _) => serialize_req!(self, SearchAddPlRequest),
|
||||||
|
Request::SearchCount(_, _) => serialize_req!(self, SearchCountRequest),
|
||||||
|
Request::Update(_) => serialize_req!(self, UpdateRequest),
|
||||||
|
Request::Rescan(_) => serialize_req!(self, RescanRequest),
|
||||||
|
|
||||||
|
/* mounts and neighbors */
|
||||||
|
Request::Mount(_, _) => serialize_req!(self, MountRequest),
|
||||||
|
Request::Unmount(_) => serialize_req!(self, UnmountRequest),
|
||||||
|
Request::ListMounts => serialize_req!(self, ListMountsRequest),
|
||||||
|
Request::ListNeighbors => serialize_req!(self, ListNeighborsRequest),
|
||||||
|
|
||||||
|
/* stickers */
|
||||||
|
Request::StickerGet(_, _, _) => serialize_req!(self, StickerGetRequest),
|
||||||
|
Request::StickerSet(_, _, _, _) => serialize_req!(self, StickerSetRequest),
|
||||||
|
Request::StickerInc(_, _, _, _) => serialize_req!(self, StickerIncRequest),
|
||||||
|
Request::StickerDec(_, _, _, _) => serialize_req!(self, StickerDecRequest),
|
||||||
|
Request::StickerDelete(_, _, _) => serialize_req!(self, StickerDeleteRequest),
|
||||||
|
Request::StickerList(_, _) => serialize_req!(self, StickerListRequest),
|
||||||
|
Request::StickerFind(_, _, _, _, _) => serialize_req!(self, StickerFindRequest),
|
||||||
|
Request::StickerNames => serialize_req!(self, StickerNamesRequest),
|
||||||
|
Request::StickerTypes => serialize_req!(self, StickerTypesRequest),
|
||||||
|
Request::StickerNamesTypes(_) => serialize_req!(self, StickerNamesTypesRequest),
|
||||||
|
|
||||||
|
/* connection settings */
|
||||||
|
Request::Close => serialize_req!(self, CloseRequest),
|
||||||
|
Request::Kill => serialize_req!(self, KillRequest),
|
||||||
|
Request::Password(_) => serialize_req!(self, PasswordRequest),
|
||||||
|
Request::Ping => serialize_req!(self, PingRequest),
|
||||||
|
Request::BinaryLimit(_) => serialize_req!(self, BinaryLimitRequest),
|
||||||
|
Request::TagTypes => serialize_req!(self, TagTypesRequest),
|
||||||
|
Request::TagTypesDisable(_) => serialize_req!(self, TagTypesDisableRequest),
|
||||||
|
Request::TagTypesEnable(_) => serialize_req!(self, TagTypesEnableRequest),
|
||||||
|
Request::TagTypesClear => serialize_req!(self, TagTypesClearRequest),
|
||||||
|
Request::TagTypesAll => serialize_req!(self, TagTypesAllRequest),
|
||||||
|
Request::TagTypesAvailable => serialize_req!(self, TagTypesAvailableRequest),
|
||||||
|
Request::TagTypesReset(_) => serialize_req!(self, TagTypesResetRequest),
|
||||||
|
Request::Protocol => serialize_req!(self, ProtocolRequest),
|
||||||
|
Request::ProtocolDisable(_) => serialize_req!(self, ProtocolDisableRequest),
|
||||||
|
Request::ProtocolEnable(_) => serialize_req!(self, ProtocolEnableRequest),
|
||||||
|
Request::ProtocolClear => serialize_req!(self, ProtocolClearRequest),
|
||||||
|
Request::ProtocolAll => serialize_req!(self, ProtocolAllRequest),
|
||||||
|
Request::ProtocolAvailable => serialize_req!(self, ProtocolAvailableRequest),
|
||||||
|
|
||||||
|
/* partition commands */
|
||||||
|
Request::Partition(_) => serialize_req!(self, PartitionRequest),
|
||||||
|
Request::ListPartitions => serialize_req!(self, ListPartitionsRequest),
|
||||||
|
Request::NewPartition(_) => serialize_req!(self, NewPartitionRequest),
|
||||||
|
Request::DelPartition(_) => serialize_req!(self, DelPartitionRequest),
|
||||||
|
Request::MoveOutput(_) => serialize_req!(self, MoveOutputRequest),
|
||||||
|
|
||||||
|
/* audio output devices */
|
||||||
|
Request::DisableOutput(_) => serialize_req!(self, DisableOutputRequest),
|
||||||
|
Request::EnableOutput(_) => serialize_req!(self, EnableOutputRequest),
|
||||||
|
Request::ToggleOutput(_) => serialize_req!(self, ToggleOutputRequest),
|
||||||
|
Request::Outputs => serialize_req!(self, OutputsRequest),
|
||||||
|
Request::OutputSet(_, _, _) => serialize_req!(self, OutputSetRequest),
|
||||||
|
|
||||||
|
/* reflection */
|
||||||
|
Request::Config => serialize_req!(self, ConfigRequest),
|
||||||
|
Request::Commands => serialize_req!(self, CommandsRequest),
|
||||||
|
Request::NotCommands => serialize_req!(self, NotCommandsRequest),
|
||||||
|
Request::UrlHandlers => serialize_req!(self, UrlHandlersRequest),
|
||||||
|
Request::Decoders => serialize_req!(self, DecodersRequest),
|
||||||
|
|
||||||
|
/* client to client */
|
||||||
|
Request::Subscribe(_) => serialize_req!(self, SubscribeRequest),
|
||||||
|
Request::Unsubscribe(_) => serialize_req!(self, UnsubscribeRequest),
|
||||||
|
Request::Channels => serialize_req!(self, ChannelsRequest),
|
||||||
|
Request::ReadMessages => serialize_req!(self, ReadMessagesRequest),
|
||||||
|
Request::SendMessage(_, _) => serialize_req!(self, SendMessageRequest),
|
||||||
|
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: upon encountering an error, there should be a function that lets you skip to the next OK,
|
||||||
|
// and continue execution. Maybe "parse_next_or_skip(&str) -> RequestParserResponse", which
|
||||||
|
// could skip stuff internally? Or do we want to report back the error with the entire command
|
||||||
|
// and let the library user decide what to do?
|
||||||
|
//
|
||||||
|
// TODO: should this return the remaining &str as well?
|
||||||
|
pub fn parse_next(raw: &str) -> Result<Self, RequestParserError> {
|
||||||
|
let (line, rest) = raw
|
||||||
|
.split_once('\n')
|
||||||
|
.ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let mut parts = RequestTokenizer::new(line);
|
||||||
|
|
||||||
|
match parts.next().ok_or(RequestParserError::EmptyLine)?.trim() {
|
||||||
|
"command_list_begin" => {
|
||||||
|
let mut commands = Vec::new();
|
||||||
|
let mut i = 1;
|
||||||
|
loop {
|
||||||
|
i += 1;
|
||||||
|
let (line, _rest) = rest
|
||||||
|
.split_once('\n')
|
||||||
|
.ok_or(RequestParserError::MissingCommandListEnd)?;
|
||||||
|
match line.trim() {
|
||||||
|
"command_list_begin" => {
|
||||||
|
return Err(RequestParserError::NestedCommandList { line: i });
|
||||||
|
}
|
||||||
|
"command_list_end" => {
|
||||||
|
return Ok(Request::CommandList(commands));
|
||||||
|
}
|
||||||
|
input => {
|
||||||
|
let command = Request::parse_next(input)?;
|
||||||
|
commands.push(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"command_list_end" => Err(RequestParserError::UnexpectedCommandListEnd),
|
||||||
|
|
||||||
|
/* querying mpd status */
|
||||||
|
ClearErrorRequest::COMMAND => parse_req!(ClearErrorRequest, parts),
|
||||||
|
CurrentSongRequest::COMMAND => parse_req!(CurrentSongRequest, parts),
|
||||||
|
IdleRequest::COMMAND => parse_req!(IdleRequest, parts),
|
||||||
|
StatusRequest::COMMAND => parse_req!(StatusRequest, parts),
|
||||||
|
StatsRequest::COMMAND => parse_req!(StatsRequest, parts),
|
||||||
|
|
||||||
|
/* playback options */
|
||||||
|
ConsumeRequest::COMMAND => parse_req!(ConsumeRequest, parts),
|
||||||
|
CrossfadeRequest::COMMAND => parse_req!(CrossfadeRequest, parts),
|
||||||
|
MixRampDbRequest::COMMAND => parse_req!(MixRampDbRequest, parts),
|
||||||
|
MixRampDelayRequest::COMMAND => parse_req!(MixRampDelayRequest, parts),
|
||||||
|
RandomRequest::COMMAND => parse_req!(RandomRequest, parts),
|
||||||
|
RepeatRequest::COMMAND => parse_req!(RepeatRequest, parts),
|
||||||
|
SetVolRequest::COMMAND => parse_req!(SetVolRequest, parts),
|
||||||
|
GetVolRequest::COMMAND => parse_req!(GetVolRequest, parts),
|
||||||
|
SingleRequest::COMMAND => parse_req!(SingleRequest, parts),
|
||||||
|
ReplayGainModeRequest::COMMAND => parse_req!(ReplayGainModeRequest, parts),
|
||||||
|
ReplayGainStatusRequest::COMMAND => parse_req!(ReplayGainStatusRequest, parts),
|
||||||
|
VolumeRequest::COMMAND => parse_req!(VolumeRequest, parts),
|
||||||
|
|
||||||
|
/* playback control */
|
||||||
|
NextRequest::COMMAND => parse_req!(NextRequest, parts),
|
||||||
|
PauseRequest::COMMAND => parse_req!(PauseRequest, parts),
|
||||||
|
PlayRequest::COMMAND => parse_req!(PlayRequest, parts),
|
||||||
|
PlayIdRequest::COMMAND => parse_req!(PlayIdRequest, parts),
|
||||||
|
PreviousRequest::COMMAND => parse_req!(PreviousRequest, parts),
|
||||||
|
SeekRequest::COMMAND => parse_req!(SeekRequest, parts),
|
||||||
|
SeekIdRequest::COMMAND => parse_req!(SeekIdRequest, parts),
|
||||||
|
SeekCurRequest::COMMAND => parse_req!(SeekCurRequest, parts),
|
||||||
|
StopRequest::COMMAND => parse_req!(StopRequest, parts),
|
||||||
|
|
||||||
|
/* queue */
|
||||||
|
AddRequest::COMMAND => parse_req!(AddRequest, parts),
|
||||||
|
AddIdRequest::COMMAND => parse_req!(AddIdRequest, parts),
|
||||||
|
ClearRequest::COMMAND => parse_req!(ClearRequest, parts),
|
||||||
|
DeleteRequest::COMMAND => parse_req!(DeleteRequest, parts),
|
||||||
|
DeleteIdRequest::COMMAND => parse_req!(DeleteIdRequest, parts),
|
||||||
|
MoveRequest::COMMAND => parse_req!(MoveRequest, parts),
|
||||||
|
MoveIdRequest::COMMAND => parse_req!(MoveIdRequest, parts),
|
||||||
|
PlaylistRequest::COMMAND => parse_req!(PlaylistRequest, parts),
|
||||||
|
PlaylistFindRequest::COMMAND => parse_req!(PlaylistFindRequest, parts),
|
||||||
|
PlaylistIdRequest::COMMAND => parse_req!(PlaylistIdRequest, parts),
|
||||||
|
PlaylistInfoRequest::COMMAND => parse_req!(PlaylistInfoRequest, parts),
|
||||||
|
PlaylistSearchRequest::COMMAND => parse_req!(PlaylistSearchRequest, parts),
|
||||||
|
PlChangesRequest::COMMAND => parse_req!(PlChangesRequest, parts),
|
||||||
|
PlChangesPosIdRequest::COMMAND => parse_req!(PlChangesPosIdRequest, parts),
|
||||||
|
PrioRequest::COMMAND => parse_req!(PrioRequest, parts),
|
||||||
|
PrioIdRequest::COMMAND => parse_req!(PrioIdRequest, parts),
|
||||||
|
RangeIdRequest::COMMAND => parse_req!(RangeIdRequest, parts),
|
||||||
|
ShuffleRequest::COMMAND => parse_req!(ShuffleRequest, parts),
|
||||||
|
SwapRequest::COMMAND => parse_req!(SwapRequest, parts),
|
||||||
|
SwapIdRequest::COMMAND => parse_req!(SwapIdRequest, parts),
|
||||||
|
AddTagIdRequest::COMMAND => parse_req!(AddTagIdRequest, parts),
|
||||||
|
ClearTagIdRequest::COMMAND => parse_req!(ClearTagIdRequest, parts),
|
||||||
|
|
||||||
|
/* stored playlists */
|
||||||
|
ListPlaylistRequest::COMMAND => parse_req!(ListPlaylistRequest, parts),
|
||||||
|
ListPlaylistInfoRequest::COMMAND => parse_req!(ListPlaylistInfoRequest, parts),
|
||||||
|
SearchPlaylistRequest::COMMAND => parse_req!(SearchPlaylistRequest, parts),
|
||||||
|
ListPlaylistsRequest::COMMAND => parse_req!(ListPlaylistsRequest, parts),
|
||||||
|
LoadRequest::COMMAND => parse_req!(LoadRequest, parts),
|
||||||
|
PlaylistAddRequest::COMMAND => parse_req!(PlaylistAddRequest, parts),
|
||||||
|
PlaylistClearRequest::COMMAND => parse_req!(PlaylistClearRequest, parts),
|
||||||
|
PlaylistDeleteRequest::COMMAND => parse_req!(PlaylistDeleteRequest, parts),
|
||||||
|
PlaylistLengthRequest::COMMAND => parse_req!(PlaylistLengthRequest, parts),
|
||||||
|
PlaylistMoveRequest::COMMAND => parse_req!(PlaylistMoveRequest, parts),
|
||||||
|
RenameRequest::COMMAND => parse_req!(RenameRequest, parts),
|
||||||
|
RmRequest::COMMAND => parse_req!(RmRequest, parts),
|
||||||
|
SaveRequest::COMMAND => parse_req!(SaveRequest, parts),
|
||||||
|
|
||||||
|
/* music database */
|
||||||
|
AlbumArtRequest::COMMAND => parse_req!(AlbumArtRequest, parts),
|
||||||
|
CountRequest::COMMAND => parse_req!(CountRequest, parts),
|
||||||
|
GetFingerprintRequest::COMMAND => parse_req!(GetFingerprintRequest, parts),
|
||||||
|
FindRequest::COMMAND => parse_req!(FindRequest, parts),
|
||||||
|
FindAddRequest::COMMAND => parse_req!(FindAddRequest, parts),
|
||||||
|
ListRequest::COMMAND => parse_req!(ListRequest, parts),
|
||||||
|
ListAllRequest::COMMAND => parse_req!(ListAllRequest, parts),
|
||||||
|
ListAllInfoRequest::COMMAND => parse_req!(ListAllInfoRequest, parts),
|
||||||
|
ListFilesRequest::COMMAND => parse_req!(ListFilesRequest, parts),
|
||||||
|
LsInfoRequest::COMMAND => parse_req!(LsInfoRequest, parts),
|
||||||
|
ReadCommentsRequest::COMMAND => parse_req!(ReadCommentsRequest, parts),
|
||||||
|
ReadPictureRequest::COMMAND => parse_req!(ReadPictureRequest, parts),
|
||||||
|
SearchRequest::COMMAND => parse_req!(SearchRequest, parts),
|
||||||
|
SearchAddRequest::COMMAND => parse_req!(SearchAddRequest, parts),
|
||||||
|
SearchAddPlRequest::COMMAND => parse_req!(SearchAddPlRequest, parts),
|
||||||
|
SearchCountRequest::COMMAND => parse_req!(SearchCountRequest, parts),
|
||||||
|
UpdateRequest::COMMAND => parse_req!(UpdateRequest, parts),
|
||||||
|
RescanRequest::COMMAND => parse_req!(RescanRequest, parts),
|
||||||
|
|
||||||
|
/* mounts and neighbors */
|
||||||
|
MountRequest::COMMAND => parse_req!(MountRequest, parts),
|
||||||
|
UnmountRequest::COMMAND => parse_req!(UnmountRequest, parts),
|
||||||
|
ListMountsRequest::COMMAND => parse_req!(ListMountsRequest, parts),
|
||||||
|
ListNeighborsRequest::COMMAND => parse_req!(ListNeighborsRequest, parts),
|
||||||
|
|
||||||
|
/* stickers */
|
||||||
|
StickerGetRequest::COMMAND => parse_req!(StickerGetRequest, parts),
|
||||||
|
StickerSetRequest::COMMAND => parse_req!(StickerSetRequest, parts),
|
||||||
|
StickerIncRequest::COMMAND => parse_req!(StickerIncRequest, parts),
|
||||||
|
StickerDecRequest::COMMAND => parse_req!(StickerDecRequest, parts),
|
||||||
|
StickerDeleteRequest::COMMAND => parse_req!(StickerDeleteRequest, parts),
|
||||||
|
StickerListRequest::COMMAND => parse_req!(StickerListRequest, parts),
|
||||||
|
StickerFindRequest::COMMAND => parse_req!(StickerFindRequest, parts),
|
||||||
|
StickerNamesRequest::COMMAND => parse_req!(StickerNamesRequest, parts),
|
||||||
|
StickerTypesRequest::COMMAND => parse_req!(StickerTypesRequest, parts),
|
||||||
|
StickerNamesTypesRequest::COMMAND => parse_req!(StickerNamesTypesRequest, parts),
|
||||||
|
|
||||||
|
/* connection settings */
|
||||||
|
CloseRequest::COMMAND => parse_req!(CloseRequest, parts),
|
||||||
|
KillRequest::COMMAND => parse_req!(KillRequest, parts),
|
||||||
|
PasswordRequest::COMMAND => parse_req!(PasswordRequest, parts),
|
||||||
|
PingRequest::COMMAND => parse_req!(PingRequest, parts),
|
||||||
|
BinaryLimitRequest::COMMAND => parse_req!(BinaryLimitRequest, parts),
|
||||||
|
TagTypesRequest::COMMAND => parse_req!(TagTypesRequest, parts),
|
||||||
|
TagTypesDisableRequest::COMMAND => parse_req!(TagTypesDisableRequest, parts),
|
||||||
|
TagTypesEnableRequest::COMMAND => parse_req!(TagTypesEnableRequest, parts),
|
||||||
|
TagTypesClearRequest::COMMAND => parse_req!(TagTypesClearRequest, parts),
|
||||||
|
TagTypesAllRequest::COMMAND => parse_req!(TagTypesAllRequest, parts),
|
||||||
|
TagTypesAvailableRequest::COMMAND => parse_req!(TagTypesAvailableRequest, parts),
|
||||||
|
TagTypesResetRequest::COMMAND => parse_req!(TagTypesResetRequest, parts),
|
||||||
|
ProtocolRequest::COMMAND => parse_req!(ProtocolRequest, parts),
|
||||||
|
ProtocolDisableRequest::COMMAND => parse_req!(ProtocolDisableRequest, parts),
|
||||||
|
ProtocolEnableRequest::COMMAND => parse_req!(ProtocolEnableRequest, parts),
|
||||||
|
ProtocolClearRequest::COMMAND => parse_req!(ProtocolClearRequest, parts),
|
||||||
|
ProtocolAllRequest::COMMAND => parse_req!(ProtocolAllRequest, parts),
|
||||||
|
ProtocolAvailableRequest::COMMAND => parse_req!(ProtocolAvailableRequest, parts),
|
||||||
|
|
||||||
|
/* partition commands */
|
||||||
|
PartitionRequest::COMMAND => parse_req!(PartitionRequest, parts),
|
||||||
|
ListPartitionsRequest::COMMAND => parse_req!(ListPartitionsRequest, parts),
|
||||||
|
NewPartitionRequest::COMMAND => parse_req!(NewPartitionRequest, parts),
|
||||||
|
DelPartitionRequest::COMMAND => parse_req!(DelPartitionRequest, parts),
|
||||||
|
MoveOutputRequest::COMMAND => parse_req!(MoveOutputRequest, parts),
|
||||||
|
|
||||||
|
/* audio output devices */
|
||||||
|
DisableOutputRequest::COMMAND => parse_req!(DisableOutputRequest, parts),
|
||||||
|
EnableOutputRequest::COMMAND => parse_req!(EnableOutputRequest, parts),
|
||||||
|
ToggleOutputRequest::COMMAND => parse_req!(ToggleOutputRequest, parts),
|
||||||
|
OutputsRequest::COMMAND => parse_req!(OutputsRequest, parts),
|
||||||
|
OutputSetRequest::COMMAND => parse_req!(OutputSetRequest, parts),
|
||||||
|
|
||||||
|
/* reflection */
|
||||||
|
ConfigRequest::COMMAND => parse_req!(ConfigRequest, parts),
|
||||||
|
CommandsRequest::COMMAND => parse_req!(CommandsRequest, parts),
|
||||||
|
NotCommandsRequest::COMMAND => parse_req!(NotCommandsRequest, parts),
|
||||||
|
UrlHandlersRequest::COMMAND => parse_req!(UrlHandlersRequest, parts),
|
||||||
|
DecodersRequest::COMMAND => parse_req!(DecodersRequest, parts),
|
||||||
|
|
||||||
|
/* client to client */
|
||||||
|
SubscribeRequest::COMMAND => parse_req!(SubscribeRequest, parts),
|
||||||
|
UnsubscribeRequest::COMMAND => parse_req!(UnsubscribeRequest, parts),
|
||||||
|
ChannelsRequest::COMMAND => parse_req!(ChannelsRequest, parts),
|
||||||
|
ReadMessagesRequest::COMMAND => parse_req!(ReadMessagesRequest, parts),
|
||||||
|
SendMessageRequest::COMMAND => parse_req!(SendMessageRequest, parts),
|
||||||
|
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ use std::fmt::Display;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
// See https://github.com/MusicPlayerDaemon/MPD/blob/7774c3369e1484dc5dec6d7d9572e0a57e9c5302/src/command/AllCommands.cxx#L67-L209
|
||||||
pub type Response = Result<(), MpdError>;
|
pub type Response = Result<(), MpdError>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
|||||||
+89
-81
@@ -69,97 +69,105 @@ impl<'a> Iterator for ResponseAttributes<'a> {
|
|||||||
type Item = Result<(&'a str, GenericResponseValue<'a>), ResponseParserError>;
|
type Item = Result<(&'a str, GenericResponseValue<'a>), ResponseParserError>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
loop {
|
if self.cursor >= self.bytestring.len() {
|
||||||
if self.cursor >= self.bytestring.len() {
|
return Some(Err(ResponseParserError::UnexpectedEOF));
|
||||||
|
}
|
||||||
|
if self.bytestring[self.cursor..].starts_with(b"OK") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let remaining = &self.bytestring[self.cursor..];
|
||||||
|
let newline_pos = remaining
|
||||||
|
.iter()
|
||||||
|
.position(|&b| b == b'\n')
|
||||||
|
.unwrap_or(remaining.len());
|
||||||
|
let line = &remaining[..newline_pos];
|
||||||
|
|
||||||
|
// Skip empty lines
|
||||||
|
if line.is_empty() {
|
||||||
|
self.cursor += newline_pos + 1;
|
||||||
|
return self.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: it is important that this happens before any None returns,
|
||||||
|
// so that the iterator advances despite errors.
|
||||||
|
self.cursor += newline_pos + 1;
|
||||||
|
|
||||||
|
let mut keyval = line.splitn(2, |&b| b == b':');
|
||||||
|
let key_bytes = keyval.next()?;
|
||||||
|
|
||||||
|
// TODO: should this be a proper runtime error?
|
||||||
|
debug_assert!(!key_bytes.is_empty());
|
||||||
|
debug_assert!(std::str::from_utf8(key_bytes).is_ok());
|
||||||
|
let key = std::str::from_utf8(key_bytes).ok()?;
|
||||||
|
|
||||||
|
// In the case of binary data, the following value will be the byte count
|
||||||
|
// in decimal, and the actual binary data will follow in the next N bytes,
|
||||||
|
// followed by a newline.
|
||||||
|
//
|
||||||
|
// We parse the number and assign the binary data to the "binary" key.
|
||||||
|
if key == "binary" {
|
||||||
|
let byte_count = match keyval.next() {
|
||||||
|
Some(count) => count.trim_ascii_start(),
|
||||||
|
None => {
|
||||||
|
// TODO: throw more specific error
|
||||||
|
return Some(Err(ResponseParserError::UnexpectedEOF));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let byte_count_str = match std::str::from_utf8(byte_count) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => {
|
||||||
|
// TODO: throw more specific error
|
||||||
|
return Some(Err(ResponseParserError::SyntaxError(
|
||||||
|
0,
|
||||||
|
"Invalid byte count".to_string(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let byte_count: usize = match byte_count_str.parse() {
|
||||||
|
Ok(n) => n,
|
||||||
|
Err(_) => {
|
||||||
|
// TODO: throw more specific error
|
||||||
|
return Some(Err(ResponseParserError::SyntaxError(
|
||||||
|
0,
|
||||||
|
"Invalid byte count".to_string(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let value_start = self.cursor;
|
||||||
|
let value_end = self.cursor + byte_count;
|
||||||
|
if value_end > self.bytestring.len() {
|
||||||
return Some(Err(ResponseParserError::UnexpectedEOF));
|
return Some(Err(ResponseParserError::UnexpectedEOF));
|
||||||
}
|
}
|
||||||
|
let value_bytes = &self.bytestring[value_start..value_end];
|
||||||
|
|
||||||
if self.bytestring[self.cursor..].starts_with(b"OK") {
|
debug_assert!(
|
||||||
return None;
|
self.bytestring[value_end..]
|
||||||
}
|
.iter()
|
||||||
|
.next()
|
||||||
|
.is_none_or(|&b| b == b'\n')
|
||||||
|
);
|
||||||
|
|
||||||
let remaining = &self.bytestring[self.cursor..];
|
// Skip the binary data and the following newline
|
||||||
let newline_pos = remaining
|
self.cursor = value_end + 1;
|
||||||
.iter()
|
|
||||||
.position(|&b| b == b'\n')
|
|
||||||
.unwrap_or(remaining.len());
|
|
||||||
|
|
||||||
let line = &remaining[..newline_pos];
|
Some(Ok((key, GenericResponseValue::Binary(value_bytes))))
|
||||||
|
} else {
|
||||||
|
let value_bytes = match keyval.next() {
|
||||||
|
Some(v) => v.trim_ascii_start(),
|
||||||
|
None => b"",
|
||||||
|
};
|
||||||
|
// TODO: this should be a proper runtime error, the specification
|
||||||
|
// declares that all string values are UTF-8.
|
||||||
|
debug_assert!(std::str::from_utf8(value_bytes).is_ok());
|
||||||
|
let value_str = std::str::from_utf8(value_bytes).ok()?;
|
||||||
|
|
||||||
// NOTE: it is important that this happens before any further None returns,
|
Some(Ok((key, GenericResponseValue::Text(value_str))))
|
||||||
// so that the iterator advances despite errors.
|
|
||||||
self.cursor += newline_pos + 1;
|
|
||||||
|
|
||||||
if line.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(parse_line(line, self));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_line<'a>(
|
|
||||||
line: &'a [u8],
|
|
||||||
state: &mut ResponseAttributes<'a>,
|
|
||||||
) -> Result<(&'a str, GenericResponseValue<'a>), ResponseParserError> {
|
|
||||||
let mut parts = line.splitn(2, |&b| b == b':');
|
|
||||||
|
|
||||||
let key = parts
|
|
||||||
.next()
|
|
||||||
.filter(|k| !k.is_empty())
|
|
||||||
.and_then(|k| std::str::from_utf8(k).ok())
|
|
||||||
.ok_or_else(|| ResponseParserError::SyntaxError(0, "Invalid key".into()))?;
|
|
||||||
|
|
||||||
match key {
|
|
||||||
"binary" => parse_binary(parts.next(), state).map(|v| (key, v)),
|
|
||||||
_ => {
|
|
||||||
let value = parts.next().unwrap_or(b"").trim_ascii_start();
|
|
||||||
|
|
||||||
let text = std::str::from_utf8(value)
|
|
||||||
.map_err(|_| ResponseParserError::SyntaxError(0, "Invalid UTF-8".into()))?;
|
|
||||||
|
|
||||||
Ok((key, GenericResponseValue::Text(text)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_binary<'a>(
|
|
||||||
count_bytes: Option<&[u8]>,
|
|
||||||
state: &mut ResponseAttributes<'a>,
|
|
||||||
) -> Result<GenericResponseValue<'a>, ResponseParserError> {
|
|
||||||
// In the case of binary data, the following value will be the byte count
|
|
||||||
// in decimal, and the actual binary data will follow in the next N bytes,
|
|
||||||
// followed by a newline.
|
|
||||||
//
|
|
||||||
// We parse the number and assign the binary data to the "binary" key.
|
|
||||||
let count = count_bytes
|
|
||||||
.map(|b| b.trim_ascii_start())
|
|
||||||
.and_then(|b| std::str::from_utf8(b).ok())
|
|
||||||
.and_then(|s| s.parse::<usize>().ok())
|
|
||||||
.ok_or_else(|| ResponseParserError::SyntaxError(0, "Invalid byte count".into()))?;
|
|
||||||
|
|
||||||
let start = state.cursor;
|
|
||||||
let end = start + count;
|
|
||||||
|
|
||||||
if end > state.bytestring.len() {
|
|
||||||
return Err(ResponseParserError::UnexpectedEOF);
|
|
||||||
}
|
|
||||||
|
|
||||||
let bytes = &state.bytestring[start..end];
|
|
||||||
|
|
||||||
if state.bytestring.get(end).is_some_and(|&b| b != b'\n') {
|
|
||||||
return Err(ResponseParserError::SyntaxError(
|
|
||||||
0,
|
|
||||||
"Missing newline".into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
state.cursor = end + 1;
|
|
||||||
|
|
||||||
Ok(GenericResponseValue::Binary(bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<ResponseAttributes<'a>>
|
impl<'a> From<ResponseAttributes<'a>>
|
||||||
for Result<HashMap<&'a str, GenericResponseValue<'a>>, ResponseParserError>
|
for Result<HashMap<&'a str, GenericResponseValue<'a>>, ResponseParserError>
|
||||||
{
|
{
|
||||||
|
|||||||
+246
@@ -0,0 +1,246 @@
|
|||||||
|
use crate::{Request, Response, types::SubSystem};
|
||||||
|
|
||||||
|
pub trait MpdServer {
|
||||||
|
type Error;
|
||||||
|
|
||||||
|
fn route_request(&mut self, request: Request) -> Result<Response, Self::Error> {
|
||||||
|
match request {
|
||||||
|
Request::ClearError => self.handle_clear_error().map(|_| Ok(())),
|
||||||
|
Request::CurrentSong => self.handle_current_song().map(|_| Ok(())),
|
||||||
|
Request::Idle(subsystems) => self.handle_idle(subsystems).map(|_| Ok(())),
|
||||||
|
Request::Status => self.handle_status().map(|_| Ok(())),
|
||||||
|
Request::Stats => self.handle_stats().map(|_| Ok(())),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_unimplemented(&mut self) -> Result<(), Self::Error> {
|
||||||
|
// fn handle_unimplemented(&mut self, name: &str) -> Result<(), Self::Error> {
|
||||||
|
// return Err("a".into());
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- Query Commands -- //
|
||||||
|
fn handle_clear_error(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self.handle_unimplemented()
|
||||||
|
}
|
||||||
|
fn handle_current_song(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self.handle_unimplemented()
|
||||||
|
}
|
||||||
|
fn handle_idle(&mut self, _: Option<Vec<SubSystem>>) -> Result<(), Self::Error> {
|
||||||
|
self.handle_unimplemented()
|
||||||
|
}
|
||||||
|
fn handle_status(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self.handle_unimplemented()
|
||||||
|
}
|
||||||
|
fn handle_stats(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self.handle_unimplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- Playback Commands -- //
|
||||||
|
// handle_consume(ConsumeState),
|
||||||
|
// handle_crossfade(Seconds),
|
||||||
|
// handle_mix_ramp_db(f32),
|
||||||
|
// handle_mix_ramp_delay(Seconds),
|
||||||
|
// handle_random(bool),
|
||||||
|
// handle_repeat(bool),
|
||||||
|
// handle_set_vol(Volume),
|
||||||
|
// handle_get_vol,
|
||||||
|
// handle_single(SingleState),
|
||||||
|
// handle_replay_gain_mode(ReplayGainMode),
|
||||||
|
// handle_replay_gain_status,
|
||||||
|
// handle_volume(Volume),
|
||||||
|
|
||||||
|
// // -- Playback Control Commands -- //
|
||||||
|
// next,
|
||||||
|
// pause(Option<bool>),
|
||||||
|
// play(SongPosition),
|
||||||
|
// play_id(SongId),
|
||||||
|
// previous,
|
||||||
|
// seek(SongPosition, TimeWithFractions),
|
||||||
|
// seek_id(SongId, TimeWithFractions),
|
||||||
|
// seek_cur(SeekMode, TimeWithFractions),
|
||||||
|
// stop,
|
||||||
|
|
||||||
|
// // -- Queue Commands -- //
|
||||||
|
// handle_add(String, Option<SongPosition>),
|
||||||
|
// handle_add_id(String, Option<SongPosition>),
|
||||||
|
// handle_clear,
|
||||||
|
// handle_delete(OneOrRange),
|
||||||
|
// handle_delete_id(SongId),
|
||||||
|
// handle_move(OneOrRange, SongPosition),
|
||||||
|
// handle_move_id(SongId, SongPosition),
|
||||||
|
// handle_playlist,
|
||||||
|
// handle_playlist_find(Filter, Option<Sort>, Option<WindowRange>),
|
||||||
|
// handle_playlist_id(SongId),
|
||||||
|
// handle_playlist_info(OneOrRange),
|
||||||
|
// handle_playlist_search(Filter, Option<Sort>, Option<WindowRange>),
|
||||||
|
// handle_pl_changes(Version, Option<WindowRange>),
|
||||||
|
// handle_pl_changes_pos_id(Version, Option<WindowRange>),
|
||||||
|
// handle_prio(Priority, WindowRange),
|
||||||
|
// handle_prio_id(Priority, Vec<SongId>),
|
||||||
|
// handle_range_id(SongId, WindowRange),
|
||||||
|
// handle_shuffle(Option<OneOrRange>),
|
||||||
|
// handle_swap(SongPosition, SongPosition),
|
||||||
|
// handle_swap_id(SongId, SongId),
|
||||||
|
// handle_add_tag_id(SongId, TagName, TagValue),
|
||||||
|
// handle_clear_tag_id(SongId, TagName),
|
||||||
|
|
||||||
|
// // -- Stored Playlist Commands -- //
|
||||||
|
// ListPlaylist(PlaylistName, Option<WindowRange>),
|
||||||
|
// ListPlaylistInfo(PlaylistName, Option<WindowRange>),
|
||||||
|
// SearchPlaylist(PlaylistName, Filter, Option<WindowRange>),
|
||||||
|
// ListPlaylists,
|
||||||
|
// Load(PlaylistName, Option<WindowRange>, SongPosition),
|
||||||
|
// PlaylistAdd(PlaylistName, Uri, SongPosition),
|
||||||
|
// PlaylistClear(PlaylistName),
|
||||||
|
// PlaylistDelete(PlaylistName, OneOrRange),
|
||||||
|
// PlaylistLength(PlaylistName),
|
||||||
|
// // TODO: which type of range?
|
||||||
|
// PlaylistMove(PlaylistName, OneOrRange, SongPosition),
|
||||||
|
// Rename(PlaylistName, PlaylistName),
|
||||||
|
// Rm(PlaylistName),
|
||||||
|
// Save(PlaylistName, Option<SaveMode>),
|
||||||
|
|
||||||
|
// // -- Music Database Commands -- //
|
||||||
|
// AlbumArt(Uri, Offset),
|
||||||
|
// Count(Filter, Option<GroupType>),
|
||||||
|
// GetFingerprint(Uri),
|
||||||
|
// Find(Filter, Option<Sort>, Option<WindowRange>),
|
||||||
|
// FindAdd(Filter, Option<Sort>, Option<WindowRange>, Option<SongPosition>),
|
||||||
|
// List(Tag, Filter, Option<GroupType>),
|
||||||
|
// #[deprecated]
|
||||||
|
// ListAll(Option<Uri>),
|
||||||
|
// #[deprecated]
|
||||||
|
// ListAllInfo(Option<Uri>),
|
||||||
|
// ListFiles(Uri),
|
||||||
|
// LsInfo(Option<Uri>),
|
||||||
|
// ReadComments(Uri),
|
||||||
|
// ReadPicture(Uri, Offset),
|
||||||
|
// Search(Filter, Option<Sort>, Option<WindowRange>),
|
||||||
|
// SearchAdd(Filter, Option<Sort>, Option<WindowRange>, Option<SongPosition>),
|
||||||
|
// SearchAddPl(Filter, Option<Sort>, Option<WindowRange>, Option<SongPosition>),
|
||||||
|
// SearchCount(Filter, Option<GroupType>),
|
||||||
|
// Update(Option<Uri>),
|
||||||
|
// Rescan(Option<Uri>),
|
||||||
|
|
||||||
|
// // -- Mount and Neighbor Commands -- //
|
||||||
|
// Mount(Option<Path>, Option<Uri>),
|
||||||
|
// Unmount(Path),
|
||||||
|
// ListMounts,
|
||||||
|
// ListNeighbors,
|
||||||
|
|
||||||
|
// // -- Sticker Commands -- //
|
||||||
|
// StickerGet(StickerType, Uri, String),
|
||||||
|
// StickerSet(StickerType, Uri, String, String),
|
||||||
|
// StickerDelete(StickerType, Uri, String),
|
||||||
|
// StickerList(StickerType, Uri),
|
||||||
|
// StickerFind(StickerType, Uri, String, Option<Sort>, Option<WindowRange>),
|
||||||
|
// StickerFindValue(StickerType, Uri, String, String, Option<Sort>, Option<WindowRange>),
|
||||||
|
// StickerNames,
|
||||||
|
// StickerTypes,
|
||||||
|
// StickerNamesTypes(Option<StickerType>),
|
||||||
|
|
||||||
|
// // -- Connection Commands -- //
|
||||||
|
// Close,
|
||||||
|
// Kill,
|
||||||
|
// Password(String),
|
||||||
|
// Ping,
|
||||||
|
// BinaryLimit(u64),
|
||||||
|
// TagTypes,
|
||||||
|
// TagTypesDisable(Vec<Tag>),
|
||||||
|
// TagTypesEnable(Vec<Tag>),
|
||||||
|
// TagTypesClear,
|
||||||
|
// TagTypesAll,
|
||||||
|
// TagTypesAvailable,
|
||||||
|
// TagTypesReset(Vec<Tag>),
|
||||||
|
// Protocol,
|
||||||
|
// ProtocolDisable(Vec<Feature>),
|
||||||
|
// ProtocolEnable(Vec<Feature>),
|
||||||
|
// ProtocolClear,
|
||||||
|
// ProtocolAll,
|
||||||
|
// ProtocolAvailable,
|
||||||
|
|
||||||
|
// // -- Partition Commands -- //
|
||||||
|
// Partition(PartitionName),
|
||||||
|
// ListPartitions,
|
||||||
|
// NewPartition(PartitionName),
|
||||||
|
// DelPartition(PartitionName),
|
||||||
|
// MoveOutput(String),
|
||||||
|
|
||||||
|
// // -- Audio Output Commands -- //
|
||||||
|
// DisableOutput(AudioOutputId),
|
||||||
|
// EnableOutput(AudioOutputId),
|
||||||
|
// ToggleOutput(AudioOutputId),
|
||||||
|
// Outputs,
|
||||||
|
// OutputSet(AudioOutputId, String, String),
|
||||||
|
|
||||||
|
// // -- Reflection Commands -- //
|
||||||
|
// Config,
|
||||||
|
// Commands,
|
||||||
|
// NotCommands,
|
||||||
|
// UrlHandlers,
|
||||||
|
// Decoders,
|
||||||
|
|
||||||
|
// // -- Client to Client Commands -- //
|
||||||
|
// Subscribe(ChannelName),
|
||||||
|
// Unsubscribe(ChannelName),
|
||||||
|
// Channels,
|
||||||
|
// ReadMessages,
|
||||||
|
// SendMessage(ChannelName, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl Into<Vec<u8>> for Request {
|
||||||
|
// fn into(self) -> Vec<u8> {
|
||||||
|
// todo!()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
// pub enum SaveMode {
|
||||||
|
// Create,
|
||||||
|
// Append,
|
||||||
|
// Replace,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
// pub enum SeekMode {
|
||||||
|
// Relative,
|
||||||
|
// RelativeReverse,
|
||||||
|
// Absolute,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
// pub enum SubSystem {
|
||||||
|
// /// The song database has been modified after update.
|
||||||
|
// Database,
|
||||||
|
// /// A database update has started or finished. If the database was modified during the update, the database event is also emitted.
|
||||||
|
// Update,
|
||||||
|
// /// A stored playlist has been modified, renamed, created or deleted
|
||||||
|
// StoredPlaylist,
|
||||||
|
// /// The queue (i.e. the current playlist) has been modified
|
||||||
|
// Playlist,
|
||||||
|
// /// The player has been started, stopped or seeked or tags of the currently playing song have changed (e.g. received from stream)
|
||||||
|
// Player,
|
||||||
|
// /// The volume has been changed
|
||||||
|
// Mixer,
|
||||||
|
// /// An audio output has been added, removed or modified (e.g. renamed, enabled or disabled)
|
||||||
|
// Output,
|
||||||
|
// /// Options like repeat, random, crossfade, replay gain
|
||||||
|
// Options,
|
||||||
|
// /// A partition was added, removed or changed
|
||||||
|
// Partition,
|
||||||
|
// /// The sticker database has been modified.
|
||||||
|
// Sticker,
|
||||||
|
// /// A client has subscribed or unsubscribed to a channel
|
||||||
|
// Subscription,
|
||||||
|
// /// A message was received on a channel this client is subscribed to; this event is only emitted when the client’s message queue is empty
|
||||||
|
// Message,
|
||||||
|
// /// A neighbor was found or lost
|
||||||
|
// Neighbor,
|
||||||
|
// /// The mount list has changed
|
||||||
|
// Mount,
|
||||||
|
|
||||||
|
// /// Other subsystems not covered by the above
|
||||||
|
// Other(String),
|
||||||
|
// }
|
||||||
Reference in New Issue
Block a user