diff options
| -rw-r--r-- | Cargo.lock | 242 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/bin/quassel-client.rs | 8 | ||||
| -rw-r--r-- | src/client/mod.rs | 17 | ||||
| -rw-r--r-- | src/message/mod.rs | 2 | ||||
| -rw-r--r-- | src/message/signalproxy.rs | 309 | ||||
| -rw-r--r-- | src/primitive/datetime.rs | 171 | ||||
| -rw-r--r-- | src/primitive/variant.rs | 13 | ||||
| -rw-r--r-- | src/tests/mod.rs | 1 | ||||
| -rw-r--r-- | src/util.rs | 5 |
10 files changed, 697 insertions, 72 deletions
@@ -54,11 +54,21 @@ dependencies = [ ] [[package]] +name = "base-x" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "bumpalo" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -110,6 +120,11 @@ dependencies = [ ] [[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "either" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -313,6 +328,11 @@ dependencies = [ ] [[package]] +name = "itoa" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -345,6 +365,7 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-test 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -629,6 +650,19 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "schannel" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -659,6 +693,49 @@ dependencies = [ ] [[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_derive" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sha1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "signal-hook-registry" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -684,6 +761,56 @@ dependencies = [ ] [[package]] +name = "standback" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb-derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb-internal-macros 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb-internal-runtime 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base-x 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "syn" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -734,6 +861,41 @@ dependencies = [ ] [[package]] +name = "time" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "standback 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", + "time-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", + "time-macros-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "standback 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "tokio" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -819,11 +981,65 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "version_check" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "wasm-bindgen" +version = "0.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bumpalo 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro-support 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -877,7 +1093,9 @@ dependencies = [ "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum backtrace 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e" "checksum backtrace-sys 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "78848718ee1255a2485d1309ad9cdecfc2e7d0362dd11c6829364c6b35ae1bc7" +"checksum base-x 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b20b618342cf9891c292c4f5ac2cde7287cc5c87e87e9c769d617793607dec1" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum bumpalo 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" @@ -886,6 +1104,7 @@ dependencies = [ "checksum core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" "checksum core-foundation-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +"checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" "checksum failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" @@ -910,6 +1129,7 @@ dependencies = [ "checksum hermit-abi 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8a0d737e0f947a1864e93d33fdef4af8445a00d1ed8dc0c8ddb73139ea6abf15" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005" @@ -946,17 +1166,33 @@ dependencies = [ "checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum ryu 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" "checksum schannel 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "039c25b130bd8c1321ee2d7de7fde2659fa9c2744e4bb29711cfc852ea53cd19" "checksum security-framework 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3f331b9025654145cd425b9ded0caf8f5ae0df80d418b326e2dc1c3dc5eb0620" "checksum security-framework-sys 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "17bf11d99252f512695eb468de5516e5cf75455521e69dfe343f3b74e4748405" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" +"checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" +"checksum serde_json 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)" = "a7894c8ed05b7a3a279aeb79025fdec1d3158080b75b98a08faf2806bb799edd" +"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +"checksum standback 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "47e4b8c631c998468961a9ea159f064c5c8499b95b5e4a34b77849d45949d540" +"checksum stdweb 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +"checksum stdweb-derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +"checksum stdweb-internal-macros 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +"checksum stdweb-internal-runtime 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" "checksum syn 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213" "checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +"checksum time 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "a6b5580a7510e7f3c6f199c1cd448515063f7056f026fe42e930c11d97c83e83" +"checksum time-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ae9b6e9f095bc105e183e3cd493d72579be3181ad4004fceb01adbe9eecab2d" +"checksum time-macros-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" "checksum tokio 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "7d9c43f1bb96970e153bcbae39a65e249ccb942bd9d36dbdf086024920417c9c" "checksum tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" "checksum tokio-macros 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" @@ -965,7 +1201,13 @@ dependencies = [ "checksum tokio-util 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "571da51182ec208780505a32528fc5512a8fe1443ab960b3f2f3ef093cd16930" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" +"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +"checksum wasm-bindgen 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "e3c7d40d09cdbf0f4895ae58cf57d92e1e57a9dd8ed2e8390514b54a47cc5551" +"checksum wasm-bindgen-backend 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "c3972e137ebf830900db522d6c8fd74d1900dcfc733462e9a12e942b00b4ac94" +"checksum wasm-bindgen-macro 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "2cd85aa2c579e8892442954685f0d801f9129de24fa2136b2c6a539c76b65776" +"checksum wasm-bindgen-macro-support 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "8eb197bd3a47553334907ffd2f16507b4f4f01bbec3ac921a7719e0decdfe72a" +"checksum wasm-bindgen-shared 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "a91c2916119c17a8e316507afaaa2dd94b47646048014bbdf6bef098c1bb58ad" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" @@ -12,6 +12,7 @@ log = "0.4" byteorder = "1.3.2" failure = "0.1" either = "1.5" +time = "0.2" bytes = { version = "0.5" } flate2 = { version = "1.0", features = ["tokio"], optional = true } diff --git a/src/bin/quassel-client.rs b/src/bin/quassel-client.rs index 9d25088..233d3ae 100644 --- a/src/bin/quassel-client.rs +++ b/src/bin/quassel-client.rs @@ -16,10 +16,18 @@ async fn main() -> Result<(), Error> { // true, // ).await.unwrap(); + let username = std::env::args().nth(1).expect("no username given"); + let password = std::env::args().nth(2).expect("no password given"); + + let mut client = client::Client::<tokio_tls::TlsStream<tokio::net::TcpStream>>::connect_tls( "cocaine.farm", 4242, true, + client::User { + name: username, + password: password, + } ).await.unwrap(); client.run().await; diff --git a/src/client/mod.rs b/src/client/mod.rs index b43115b..9f0d66c 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -30,6 +30,12 @@ pub struct Client<T: AsyncRead + AsyncWrite + Unpin> { pub tls: bool, pub compression: bool, pub state: ClientState, + pub user: User, +} + +pub struct User { + pub name: String, + pub password: String, } pub enum ClientState { @@ -69,7 +75,7 @@ impl <T: AsyncRead + AsyncWrite + Unpin> Client<T> { }; } - pub async fn connect(address: &'static str, port: u64, compression: bool) -> Result<Client<TcpStream>, Error> { + pub async fn connect(address: &'static str, port: u64, compression: bool, user: User) -> Result<Client<TcpStream>, Error> { let mut stream = TcpStream::connect(format!("{}:{}", address, port)).await?; info!(target: "init", "Establishing Connection"); @@ -90,10 +96,11 @@ impl <T: AsyncRead + AsyncWrite + Unpin> Client<T> { tls: false, compression, state: ClientState::Handshake, + user, }); } - pub async fn connect_tls(address: &'static str, port: u64, compression: bool) -> Result<Client<TlsStream<TcpStream>>, Error> { + pub async fn connect_tls(address: &'static str, port: u64, compression: bool, user: User) -> Result<Client<TlsStream<TcpStream>>, Error> { let mut stream: TcpStream = TcpStream::connect(format!("{}:{}", address, port)).await?; info!(target: "init", "Establishing Connection"); @@ -118,6 +125,7 @@ impl <T: AsyncRead + AsyncWrite + Unpin> Client<T> { tls: true, compression, state: ClientState::Handshake, + user, }); } @@ -137,7 +145,7 @@ pub async fn handle_login_message<T: AsyncRead + AsyncWrite + Unpin>(client: &mu "ClientInitAck" => { info!(target: "init", "Initialization successfull"); info!(target: "login", "Starting Login"); - let login = ClientLogin {user: "audron".to_string(), password: "audron".to_string()}; + let login = ClientLogin {user: client.user.name.clone(), password: client.user.password.clone()}; client.stream.send(login.serialize()?).await?; }, "ClientInitReject" => { @@ -162,12 +170,13 @@ pub async fn handle_login_message<T: AsyncRead + AsyncWrite + Unpin>(client: &mu } pub async fn handle_message<T: AsyncRead + AsyncWrite + Unpin>(client: &mut Client<T>, buf: &[u8]) -> Result<(), Error> { + use crate::message::Message; use crate::primitive::VariantList; use crate::Deserialize; use crate::Serialize; trace!(target: "message", "Received bytes: {:x?}", buf); - let (_, res) = VariantList::parse(buf)?; + let (_, res) = Message::parse(buf)?; debug!(target: "init", "Received Messsage: {:#?}", res); return Ok(()); diff --git a/src/message/mod.rs b/src/message/mod.rs index 16f2088..96cc910 100644 --- a/src/message/mod.rs +++ b/src/message/mod.rs @@ -1,3 +1,5 @@ mod handshake; +mod signalproxy; pub use handshake::*; +pub use signalproxy::*; diff --git a/src/message/signalproxy.rs b/src/message/signalproxy.rs new file mode 100644 index 0000000..22a498a --- /dev/null +++ b/src/message/signalproxy.rs @@ -0,0 +1,309 @@ +use crate::primitive::{DateTime, Variant, VariantList}; +use crate::{Deserialize, Serialize}; + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub enum Message { + /// Bidirectional + SyncMessage(SyncMessage), + /// Bidirectional + RpcCall(RpcCall), + InitRequest(InitRequest), + InitData(InitData), + /// Bidirectional + HeartBeat(HeartBeat), + /// Bidirectional + HeartBeatReply(HeartBeatReply), +} + +impl Serialize for Message { + fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { + match &self { + Message::SyncMessage(value) => value.serialize(), + Message::RpcCall(value) => value.serialize(), + Message::InitRequest(value) => value.serialize(), + Message::InitData(value) => value.serialize(), + Message::HeartBeat(value) => value.serialize(), + Message::HeartBeatReply(value) => value.serialize(), + } + } +} + +impl Deserialize for Message { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { + let (_, message_type) = i32::parse(&b[9..13])?; + + match MessageType::from(message_type) { + MessageType::SyncMessage => { + let (size, res) = SyncMessage::parse(&b)?; + + Ok((size, Message::SyncMessage(res))) + } + MessageType::RpcCall => { + let (size, res) = RpcCall::parse(&b)?; + + Ok((size, Message::RpcCall(res))) + } + MessageType::InitRequest => { + let (size, res) = InitRequest::parse(&b)?; + + Ok((size, Message::InitRequest(res))) + } + MessageType::InitData => { + let (size, res) = InitData::parse(&b)?; + + Ok((size, Message::InitData(res))) + } + MessageType::HeartBeat => { + let (size, res) = HeartBeat::parse(&b)?; + + Ok((size, Message::HeartBeat(res))) + } + MessageType::HeartBeatReply => { + let (size, res) = HeartBeatReply::parse(&b)?; + + Ok((size, Message::HeartBeatReply(res))) + } + } + } +} + +/// Type of an SignalProxy Message +/// The first element in the VariantList that is received +#[repr(i32)] +#[derive(Copy, Clone, Debug, std::cmp::PartialEq)] +pub enum MessageType { + /// Bidirectional + SyncMessage = 0x00000001, + /// Bidirectional + RpcCall = 0x00000002, + InitRequest = 0x00000003, + InitData = 0x00000004, + /// Bidirectional + HeartBeat = 0x00000005, + /// Bidirectional + HeartBeatReply = 0x00000006, +} + +impl From<i32> for MessageType { + fn from(val: i32) -> Self { + match val { + 0x00000001 => MessageType::SyncMessage, + 0x00000002 => MessageType::RpcCall, + 0x00000003 => MessageType::InitRequest, + 0x00000004 => MessageType::InitData, + 0x00000005 => MessageType::HeartBeat, + 0x00000006 => MessageType::HeartBeatReply, + _ => unimplemented!(), + } + } +} + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct SyncMessage { + class_name: String, + object_name: String, + slot_name: String, + params: VariantList, +} + +impl Serialize for SyncMessage { + fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { + let mut res = VariantList::new(); + + res.push(Variant::i32(MessageType::SyncMessage as i32)); + res.push(Variant::StringUTF8(self.class_name.clone())); + res.push(Variant::StringUTF8(self.object_name.clone())); + res.push(Variant::StringUTF8(self.slot_name.clone())); + + res.append(&mut self.params.clone()); + + res.serialize() + } +} + +impl Deserialize for SyncMessage { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { + let (size, mut res) = VariantList::parse(&b)?; + + res.remove(0); + + Ok(( + size, + Self { + class_name: match_variant!(res.remove(0), Variant::StringUTF8), + object_name: match_variant!(res.remove(0), Variant::StringUTF8), + slot_name: match_variant!(res.remove(0), Variant::StringUTF8), + params: res, + }, + )) + } +} + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct RpcCall { + slot_name: String, + params: VariantList, +} + +impl Serialize for RpcCall { + fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { + let mut res = VariantList::new(); + + res.push(Variant::i32(MessageType::RpcCall as i32)); + res.push(Variant::StringUTF8(self.slot_name.clone())); + + res.append(&mut self.params.clone()); + + res.serialize() + } +} + +impl Deserialize for RpcCall { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { + let (size, mut res) = VariantList::parse(&b)?; + + res.remove(0); + + Ok(( + size, + Self { + slot_name: match_variant!(res.remove(0), Variant::StringUTF8), + params: res, + }, + )) + } +} + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct InitRequest { + class_name: String, + object_name: String, +} + +impl Serialize for InitRequest { + fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { + let mut res = VariantList::new(); + + res.push(Variant::i32(MessageType::InitRequest as i32)); + res.push(Variant::StringUTF8(self.class_name.clone())); + res.push(Variant::StringUTF8(self.object_name.clone())); + + res.serialize() + } +} + +impl Deserialize for InitRequest { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { + let (size, mut res) = VariantList::parse(&b)?; + + res.remove(0); + + Ok(( + size, + Self { + class_name: match_variant!(res.remove(0), Variant::StringUTF8), + object_name: match_variant!(res.remove(0), Variant::StringUTF8), + }, + )) + } +} + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct InitData { + class_name: String, + object_name: String, + init_data: VariantList, +} + +impl Serialize for InitData { + fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { + let mut res = VariantList::new(); + + res.push(Variant::i32(MessageType::InitData as i32)); + res.push(Variant::StringUTF8(self.class_name.clone())); + res.push(Variant::StringUTF8(self.object_name.clone())); + + res.append(&mut self.init_data.clone()); + + res.serialize() + } +} + +impl Deserialize for InitData { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { + let (size, mut res) = VariantList::parse(&b)?; + + res.remove(0); + + Ok(( + size, + Self { + class_name: match_variant!(res.remove(0), Variant::StringUTF8), + object_name: match_variant!(res.remove(0), Variant::StringUTF8), + init_data: res, + }, + )) + } +} + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct HeartBeat { + timestamp: DateTime, +} + +impl Serialize for HeartBeat { + fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { + let mut res = VariantList::new(); + + res.push(Variant::i32(MessageType::HeartBeat as i32)); + res.push(Variant::DateTime(self.timestamp.clone())); + + res.serialize() + } +} + +impl Deserialize for HeartBeat { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { + let (size, mut res) = VariantList::parse(&b)?; + + res.remove(0); + + Ok(( + size, + Self { + timestamp: match_variant!(res.remove(0), Variant::DateTime), + }, + )) + } +} + +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct HeartBeatReply { + timestamp: DateTime, +} + +impl Serialize for HeartBeatReply { + fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { + let mut res = VariantList::new(); + + res.push(Variant::i32(MessageType::HeartBeatReply as i32)); + res.push(Variant::DateTime(self.timestamp.clone())); + + res.serialize() + } +} + +impl Deserialize for HeartBeatReply { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { + let (size, mut res) = VariantList::parse(&b)?; + + res.remove(0); + + Ok(( + size, + Self { + timestamp: match_variant!(res.remove(0), Variant::DateTime), + }, + )) + } +} diff --git a/src/primitive/datetime.rs b/src/primitive/datetime.rs index e6946b9..cbcdd51 100644 --- a/src/primitive/datetime.rs +++ b/src/primitive/datetime.rs @@ -1,107 +1,160 @@ use crate::Deserialize; use crate::Serialize; -/// The DateTime struct represents a DateTime as received in IRC -/// -/// DateTime is, like all other struct based types, serialized sequentially. -#[derive(Clone, Debug, std::cmp::PartialEq)] -pub struct DateTime { - /// Day in Julian calendar, unknown if signed or unsigned - julian_day: i32, - /// Milliseconds since start of day - millis_of_day: i32, - /// Timezone of DateTime, 0x00 is local, 0x01 is UTC - zone: u8, +use time::{OffsetDateTime, PrimitiveDateTime, UtcOffset}; + +// The DateTime struct represents a DateTime as received in IRC +// +// DateTime is, like all other struct based types, serialized sequentially. +// #[derive(Clone, Debug, std::cmp::PartialEq)] +// pub struct DateTime { +// /// Day in Julian calendar, unknown if signed or unsigned +// julian_day: i32, +// /// Milliseconds since start of day +// millis_of_day: i32, +// /// Timezone of DateTime, 0x00 is local, 0x01 is UTC +// zone: u8, +// } + +pub type DateTime = OffsetDateTime; +pub use time::{Date, Time}; + +/// TimeSpec specifies whether the time is a local time, daylightsaving local time or a form of UTC Offset +#[repr(i8)] +#[derive(Copy, Clone, Debug, std::cmp::PartialEq)] +pub enum TimeSpec { + LocalUnknown = -0x01, + LocalStandard = 0x00, + LocalDST = 0x01, + UTC = 0x02, + OffsetFromUTC = 0x03, } -impl Serialize for DateTime { - fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { +impl From<i8> for TimeSpec { + fn from(val: i8) -> Self { + match val { + -0x01 => TimeSpec::LocalUnknown, + 0x00 => TimeSpec::LocalStandard, + 0x01 => TimeSpec::LocalDST, + 0x02 => TimeSpec::UTC, + 0x03 => TimeSpec::OffsetFromUTC, + _ => unimplemented!(), + } + } +} + +impl Serialize for OffsetDateTime { + fn serialize(&self) -> Result<Vec<u8>, failure::Error> { let mut values: Vec<u8> = Vec::new(); - values.append(&mut i32::serialize(&self.julian_day)?); - values.append(&mut i32::serialize(&self.millis_of_day)?); - values.append(&mut u8::serialize(&(self.zone))?); + values.extend(i32::serialize(&(self.date().julian_day() as i32))?); + + let time: i32 = { + let hour: i32 = self.time().hour() as i32; + let minute: i32 = self.time().minute() as i32; + let second: i32 = self.time().second() as i32; + let milli: i32 = self.time().millisecond() as i32; + + milli + (second * 1000) + (minute * 60000) + (hour * 60 * 60000) + }; + + values.extend(i32::serialize(&time)?); + values.extend(u8::serialize(&(TimeSpec::OffsetFromUTC as u8))?); + values.extend(i32::serialize(&self.offset().as_seconds())?); Ok(values) } } -impl Deserialize for DateTime { - fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> - where - Self: Sized, - { +impl Deserialize for OffsetDateTime { + fn parse(b: &[u8]) -> Result<(usize, Self), failure::Error> { let (_, julian_day) = i32::parse(&b[0..4])?; let (_, millis_of_day) = i32::parse(&b[4..8])?; let (_, zone) = u8::parse(&b[8..9])?; - return Ok(( - 9, - DateTime { - julian_day, - millis_of_day, - zone, - }, - )); - } -} + let mut pos = 9; + + let zone = TimeSpec::from(zone as i8); + + let offset: UtcOffset; + match zone { + TimeSpec::LocalUnknown | TimeSpec::LocalStandard | TimeSpec::LocalDST => { + offset = UtcOffset::current_local_offset() + } + TimeSpec::UTC => offset = UtcOffset::UTC, + TimeSpec::OffsetFromUTC => { + let (_, tmp_offset) = i32::parse(&b[9..13])?; + pos += 4; + offset = UtcOffset::seconds(tmp_offset) + } + } -/// The Date struct represents a Date as received in IRC -/// -/// Date is, like all other struct based types, serialized sequentially. -#[derive(Clone, Debug, std::cmp::PartialEq)] -pub struct Date { - /// Day in Julian calendar, unknown if signed or unsigned - julian_day: i32, + let date = Date::from_julian_day(julian_day as i64); + + let hour = millis_of_day / 60 / 60000; + let minute = (millis_of_day - (hour * 60 * 60000)) / 60000; + let seconds = (millis_of_day - (hour * 60 * 60000) - (minute * 60000)) / 1000; + let millis = millis_of_day - (hour * 60 * 60000) - (minute * 60000) - (seconds * 1000); + + let time = + Time::try_from_hms_milli(hour as u8, minute as u8, seconds as u8, millis as u16)?; + let primitivedatetime = PrimitiveDateTime::new(date, time); + let datetime = primitivedatetime.assume_offset(offset); + + Ok((pos, datetime)) + } } impl Serialize for Date { fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { let mut values: Vec<u8> = Vec::new(); - values.append(&mut i32::serialize(&self.julian_day)?); + values.extend(i32::serialize(&(self.julian_day() as i32))?); Ok(values) } } impl Deserialize for Date { - fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> - where - Self: Sized, - { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { let (_, julian_day) = i32::parse(&b[0..4])?; + let date = Date::from_julian_day(julian_day as i64); - return Ok((9, Date { julian_day })); + Ok((4, date)) } } -/// The Time struct represents a Time as received in IRC -/// -/// Time is, like all other struct based types, serialized sequentially. -#[derive(Clone, Debug, std::cmp::PartialEq)] -pub struct Time { - /// Milliseconds since start of day - millis_of_day: i32, -} - impl Serialize for Time { fn serialize(&self) -> Result<Vec<std::primitive::u8>, failure::Error> { let mut values: Vec<u8> = Vec::new(); - values.append(&mut i32::serialize(&self.millis_of_day)?); + let time: i32 = { + let hour: i32 = self.hour() as i32; + let minute: i32 = self.minute() as i32; + let second: i32 = self.second() as i32; + let milli: i32 = self.millisecond() as i32; + + milli + (second * 1000) + (minute * 60000) + (hour * 60 * 60000) + }; + + values.extend(i32::serialize(&time)?); Ok(values) } } impl Deserialize for Time { - fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> - where - Self: Sized, - { + fn parse(b: &[std::primitive::u8]) -> Result<(std::primitive::usize, Self), failure::Error> { let (_, millis_of_day) = i32::parse(&b[0..4])?; - return Ok((4, Time { millis_of_day })); + let hour = millis_of_day / 60 / 60000; + let minute = (millis_of_day - (hour * 60 * 60000)) / 60000; + let seconds = (millis_of_day - (hour * 60 * 60000) - (minute * 60000)) / 1000; + let millis = millis_of_day - (hour * 60 * 60000) - (minute * 60000) - (seconds * 1000); + + let time = + Time::try_from_hms_milli(hour as u8, minute as u8, seconds as u8, millis as u16)?; + + Ok((4, time)) } } diff --git a/src/primitive/variant.rs b/src/primitive/variant.rs index 71ddc4a..9242d90 100644 --- a/src/primitive/variant.rs +++ b/src/primitive/variant.rs @@ -12,9 +12,7 @@ use crate::{Serialize, SerializeUTF8}; extern crate bytes; -use crate::primitive::{ - BufferInfo, Date, DateTime, Message, Time, VariantList, VariantMap, -}; +use crate::primitive::{BufferInfo, Date, DateTime, Message, Time, VariantList, VariantMap}; /// Variant represents the possible types we can receive /// @@ -204,17 +202,18 @@ impl Deserialize for Variant { } primitive::QDATETIME => { trace!(target: "primitive::Variant", "Parsing Variant: Date"); - let (vlen, value) = Date::parse(&b[len..])?; - return Ok((len + vlen, Variant::Date(value.clone()))); + // let (vlen, value) = DateTime::parse(&b[len..])?; + let (vlen, value): (usize, DateTime) = Deserialize::parse(&b[len..])?; + return Ok((len + vlen, Variant::DateTime(value.clone()))); } primitive::QDATE => { trace!(target: "primitive::Variant", "Parsing Variant: Date"); - let (vlen, value) = Date::parse(&b[len..])?; + let (vlen, value): (usize, Date) = Deserialize::parse(&b[len..])?; return Ok((len + vlen, Variant::Date(value.clone()))); } primitive::QTIME => { trace!(target: "primitive::Variant", "Parsing Variant: Time"); - let (vlen, value) = Time::parse(&b[len..])?; + let (vlen, value): (usize, Time) = Deserialize::parse(&b[len..])?; return Ok((len + vlen, Variant::Time(value.clone()))); } primitive::BOOL => { diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 16fd124..1e99bfe 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,4 +1,5 @@ pub mod base_types; +pub mod datetime; #[allow(unused_imports)] #[allow(unused_macros)] diff --git a/src/util.rs b/src/util.rs index 192e270..eeeda4e 100644 --- a/src/util.rs +++ b/src/util.rs @@ -3,9 +3,10 @@ /// # Example /// /// ``` +/// use libquassel::match_variant; /// use libquassel::primitive::{VariantMap, Variant}; /// -/// let var = Variant::String("test string"); +/// let var = Variant::String("test string".to_string()); /// let result = match_variant!(var, Variant::String); /// ``` #[macro_export] @@ -13,7 +14,7 @@ macro_rules! match_variant { ( $values:expr, $x:path ) => { match &$values { $x(x) => Ok(x.clone()), - _ => Err(""), + err => Err(err), } .unwrap(); }; |
