Compare commits
39 Commits
syndicate-
...
main
Author | SHA1 | Date |
---|---|---|
Tony Garnock-Jones | 6468e16790 | |
Tony Garnock-Jones | 65101e900e | |
Tony Garnock-Jones | 581886835a | |
Tony Garnock-Jones | dcb1aec142 | |
Tony Garnock-Jones | c0239cf322 | |
Tony Garnock-Jones | 9cc4175f24 | |
Tony Garnock-Jones | 70f42dd931 | |
Tony Garnock-Jones | ef1ebe6412 | |
Tony Garnock-Jones | deec008c66 | |
Tony Garnock-Jones | 008671d0b2 | |
Tony Garnock-Jones | 9fcf22e1b5 | |
Tony Garnock-Jones | ca18ca08df | |
Tony Garnock-Jones | 40ca168eac | |
Tony Garnock-Jones | 5a73e8d4c3 | |
Tony Garnock-Jones | 91b26001d8 | |
Tony Garnock-Jones | b83b39515d | |
Tony Garnock-Jones | d9fa6362af | |
Tony Garnock-Jones | 94598a574b | |
Tony Garnock-Jones | 80ad0914ed | |
Tony Garnock-Jones | bdb0cc1023 | |
Tony Garnock-Jones | 710ff91a64 | |
Tony Garnock-Jones | d3748a286b | |
Tony Garnock-Jones | a56aec2c30 | |
Tony Garnock-Jones | 0c06ae9601 | |
Tony Garnock-Jones | 1f0c9d2883 | |
Tony Garnock-Jones | 615830f799 | |
Tony Garnock-Jones | 3c44768a72 | |
Tony Garnock-Jones | 04bb8c2f23 | |
Tony Garnock-Jones | 9084c1781e | |
Tony Garnock-Jones | 8a817fcb4f | |
Tony Garnock-Jones | 2ed2b38edc | |
Tony Garnock-Jones | 5090625f47 | |
Tony Garnock-Jones | a7ede65bad | |
Tony Garnock-Jones | c59e044695 | |
Tony Garnock-Jones | ef98217a3a | |
Tony Garnock-Jones | bf0d47f1b7 | |
Tony Garnock-Jones | fef41f39eb | |
Tony Garnock-Jones | 0b72b4029b | |
Tony Garnock-Jones | 7797a3cd09 |
|
@ -54,9 +54,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -152,15 +152,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.69"
|
||||
version = "0.3.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
||||
checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
|
@ -185,9 +185,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.2"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
|
||||
[[package]]
|
||||
name = "blake2"
|
||||
|
@ -209,9 +209,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.15.4"
|
||||
version = "3.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
|
@ -221,9 +221,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.5.0"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
|
@ -233,9 +233,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.90"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
|
||||
checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -276,9 +276,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.35"
|
||||
version = "0.4.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
|
||||
checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
|
@ -314,9 +314,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.2"
|
||||
version = "4.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651"
|
||||
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -331,28 +331,28 @@ dependencies = [
|
|||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim 0.11.0",
|
||||
"strsim 0.11.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete"
|
||||
version = "4.5.1"
|
||||
version = "4.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "885e4d7d5af40bfb99ae6f9433e292feac98d452dcb3ec3d25dfe7552b77da8c"
|
||||
checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e"
|
||||
dependencies = [
|
||||
"clap 4.5.2",
|
||||
"clap 4.5.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.0"
|
||||
version = "4.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47"
|
||||
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -673,7 +673,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -729,9 +729,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.12"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
||||
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
|
@ -777,9 +777,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
|
@ -956,9 +956,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.10"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
|
@ -1024,9 +1024,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.1"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
|
@ -1120,7 +1120,7 @@ dependencies = [
|
|||
"aes-gcm",
|
||||
"blake2",
|
||||
"chacha20poly1305",
|
||||
"getrandom 0.2.12",
|
||||
"getrandom 0.2.14",
|
||||
"noise-protocol",
|
||||
"sha2",
|
||||
"x25519-dalek",
|
||||
|
@ -1263,7 +1263,7 @@ version = "0.10.64"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"bitflags 2.5.0",
|
||||
"cfg-if 1.0.0",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
|
@ -1280,7 +1280,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1294,9 +1294,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.101"
|
||||
version = "0.9.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff"
|
||||
checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
@ -1376,14 +1376,14 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.13"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
|
@ -1456,9 +1456,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
|||
|
||||
[[package]]
|
||||
name = "preserves"
|
||||
version = "4.995.0"
|
||||
version = "4.995.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19005106ee00c4f20bf88d5ed27dc73ff33a3f14e4ec6803fe853250afdd6e8e"
|
||||
checksum = "bdc22936ee042b69240f80bac422262b1b514e537e8f40a7adb8eded2b80788f"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"dtoa",
|
||||
|
@ -1471,9 +1471,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "preserves-schema"
|
||||
version = "5.995.0"
|
||||
version = "5.995.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b554f32fe5e2a829cf48d9c41a7e4ef1d6d021e13afd2daf44b8fce052514aa0"
|
||||
checksum = "56e7f701ce176a21b37abf14c3fcd461106c362e1a090150e29bec7768104679"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"glob",
|
||||
|
@ -1510,18 +1510,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.78"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.35"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -1562,14 +1562,14 @@ version = "0.6.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.12",
|
||||
"getrandom 0.2.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.9.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd"
|
||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
|
@ -1605,14 +1605,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.3"
|
||||
version = "1.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
|
||||
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata 0.4.6",
|
||||
"regex-syntax 0.8.2",
|
||||
"regex-syntax 0.8.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1632,7 +1632,7 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
|||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax 0.8.2",
|
||||
"regex-syntax 0.8.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1643,9 +1643,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
|||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
|
@ -1710,14 +1710,14 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.114"
|
||||
version = "1.0.115"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
|
||||
checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -1775,9 +1775,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.1"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
|
@ -1797,9 +1797,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
|||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
|
@ -1844,9 +1844,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.52"
|
||||
version = "2.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
|
||||
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1855,13 +1855,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syndicate"
|
||||
version = "0.36.0"
|
||||
version = "0.40.0"
|
||||
dependencies = [
|
||||
"blake2",
|
||||
"bytes",
|
||||
"criterion",
|
||||
"futures",
|
||||
"getrandom 0.2.12",
|
||||
"getrandom 0.2.14",
|
||||
"hmac",
|
||||
"lazy_static",
|
||||
"openssl",
|
||||
|
@ -1877,7 +1877,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syndicate-macros"
|
||||
version = "0.29.0"
|
||||
version = "0.32.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1889,7 +1889,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syndicate-schema-plugin"
|
||||
version = "0.6.0"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"preserves-schema",
|
||||
"syndicate",
|
||||
|
@ -1897,7 +1897,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syndicate-server"
|
||||
version = "0.42.0"
|
||||
version = "0.45.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"futures",
|
||||
|
@ -1924,9 +1924,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syndicate-tools"
|
||||
version = "0.15.0"
|
||||
version = "0.18.0"
|
||||
dependencies = [
|
||||
"clap 4.5.2",
|
||||
"clap 4.5.4",
|
||||
"clap_complete",
|
||||
"noise-protocol",
|
||||
"noise-rust-crypto",
|
||||
|
@ -1945,22 +1945,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.57"
|
||||
version = "1.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
|
||||
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.57"
|
||||
version = "1.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
|
||||
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2020,9 +2020,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.36.0"
|
||||
version = "1.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
|
||||
checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
|
@ -2044,14 +2044,14 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.14"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
|
||||
checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
|
@ -2109,7 +2109,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2348,7 +2348,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
@ -2370,7 +2370,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
@ -2613,5 +2613,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
|
|
@ -1,2 +1,7 @@
|
|||
#!/bin/sh
|
||||
make -C ../syndicate-server binary && exec taskset -c 0,1 ../target/release/syndicate-server -c benchmark-config.pr "$@"
|
||||
TASKSET='taskset -c 0,1'
|
||||
if [ $(uname -s) = 'Darwin' ]
|
||||
then
|
||||
TASKSET=
|
||||
fi
|
||||
make -C ../syndicate-server binary && exec $TASKSET ../target/release/syndicate-server -c benchmark-config.pr "$@"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "syndicate-macros"
|
||||
version = "0.29.0"
|
||||
version = "0.32.0"
|
||||
authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
@ -13,7 +13,7 @@ license = "Apache-2.0"
|
|||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syndicate = { path = "../syndicate", version = "0.36.0"}
|
||||
syndicate = { path = "../syndicate", version = "0.40.0"}
|
||||
|
||||
proc-macro2 = { version = "^1.0", features = ["span-locations"] }
|
||||
quote = "^1.0"
|
||||
|
|
|
@ -36,7 +36,7 @@ enum SymbolVariant<'a> {
|
|||
fn compile_sequence_members(vs: &[IOValue]) -> Vec<TokenStream> {
|
||||
vs.iter().enumerate().map(|(i, f)| {
|
||||
let p = compile_pattern(f);
|
||||
quote!((#i .into(), #p))
|
||||
quote!((syndicate::value::Value::from(#i).wrap(), #p))
|
||||
}).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
|
@ -151,16 +151,14 @@ fn compile_pattern(v: &IOValue) -> TokenStream {
|
|||
#[allow(non_snake_case)]
|
||||
let V_: TokenStream = quote!(syndicate::value);
|
||||
#[allow(non_snake_case)]
|
||||
let MapFromIterator_: TokenStream = quote!(<#V_::Map<_, _> as std::iter::FromIterator<_>>::from_iter);
|
||||
let MapFrom_: TokenStream = quote!(<#V_::Map<_, _>>::from);
|
||||
|
||||
match v.value() {
|
||||
Value::Symbol(s) => match analyze_symbol(&s, true) {
|
||||
SymbolVariant::Binder(_) =>
|
||||
quote!(#P_::Pattern::DBind(Box::new(#P_::DBind {
|
||||
pattern: #P_::Pattern::DDiscard(Box::new(#P_::DDiscard))
|
||||
}))),
|
||||
quote!(#P_::Pattern::Bind{ pattern: Box::new(#P_::Pattern::Discard) }),
|
||||
SymbolVariant::Discard =>
|
||||
quote!(#P_::Pattern::DDiscard(Box::new(#P_::DDiscard))),
|
||||
quote!(#P_::Pattern::Discard),
|
||||
SymbolVariant::Substitution(s) =>
|
||||
lit(Ident::new(s, Span::call_site())),
|
||||
SymbolVariant::Normal(_) =>
|
||||
|
@ -172,9 +170,7 @@ fn compile_pattern(v: &IOValue) -> TokenStream {
|
|||
Some(label) =>
|
||||
if label.starts_with("$") && r.arity() == 1 {
|
||||
let nested = compile_pattern(&r.fields()[0]);
|
||||
quote!(#P_::Pattern::DBind(Box::new(#P_::DBind {
|
||||
pattern: #nested
|
||||
})))
|
||||
quote!(#P_::Pattern::Bind{ pattern: Box::new(#nested) })
|
||||
} else {
|
||||
let label_stx = if label.starts_with("=") {
|
||||
let id = Ident::new(&label[1..], Span::call_site());
|
||||
|
@ -183,18 +179,19 @@ fn compile_pattern(v: &IOValue) -> TokenStream {
|
|||
quote!(#V_::Value::symbol(#label).wrap())
|
||||
};
|
||||
let members = compile_sequence_members(r.fields());
|
||||
quote!(#P_::Pattern::DCompound(Box::new(#P_::DCompound::Rec {
|
||||
label: #label_stx,
|
||||
fields: vec![#(#members),*],
|
||||
})))
|
||||
quote!(#P_::Pattern::Group {
|
||||
type_: Box::new(#P_::GroupType::Rec { label: #label_stx }),
|
||||
entries: #MapFrom_([#(#members),*]),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Sequence(vs) => {
|
||||
let members = compile_sequence_members(vs);
|
||||
quote!(#P_::Pattern::DCompound(Box::new(#P_::DCompound::Arr {
|
||||
items: vec![#(#members),*],
|
||||
})))
|
||||
quote!(#P_::Pattern::Group {
|
||||
type_: Box::new(#P_::GroupType::Arr),
|
||||
entries: #MapFrom_([#(#members),*]),
|
||||
})
|
||||
}
|
||||
Value::Set(_) =>
|
||||
panic!("Cannot match sets in patterns"),
|
||||
|
@ -204,9 +201,10 @@ fn compile_pattern(v: &IOValue) -> TokenStream {
|
|||
let v = compile_pattern(v);
|
||||
quote!((#k, #v))
|
||||
}).collect::<Vec<_>>();
|
||||
quote!(#P_::Pattern::DCompound(Box::new(#P_::DCompound::Dict {
|
||||
entries: #MapFromIterator_(vec![#(#members),*])
|
||||
})))
|
||||
quote!(#P_::Pattern::Group {
|
||||
type_: Box::new(#P_::GroupType::Dict),
|
||||
entries: #MapFrom_([#(#members),*]),
|
||||
})
|
||||
}
|
||||
_ => lit(ValueCompiler::for_patterns().compile(v)),
|
||||
}
|
||||
|
|
|
@ -15,10 +15,9 @@ pub fn lit<T: ToTokens>(e: T) -> TokenStream2 {
|
|||
}
|
||||
|
||||
fn compile_sequence_members(stxs: &Vec<Stx>) -> Result<Vec<TokenStream2>, &'static str> {
|
||||
stxs.iter().map(|stx| {
|
||||
// let p = to_pattern_expr(stx)?;
|
||||
// Ok(quote!(#p))
|
||||
to_pattern_expr(stx)
|
||||
stxs.iter().enumerate().map(|(i, stx)| {
|
||||
let p = to_pattern_expr(stx)?;
|
||||
Ok(quote!((syndicate::value::Value::from(#i).wrap(), #p)))
|
||||
}).collect()
|
||||
}
|
||||
|
||||
|
@ -28,7 +27,7 @@ pub fn to_pattern_expr(stx: &Stx) -> Result<TokenStream2, &'static str> {
|
|||
#[allow(non_snake_case)]
|
||||
let V_: TokenStream2 = quote!(syndicate::value);
|
||||
#[allow(non_snake_case)]
|
||||
let MapFromIterator_: TokenStream2 = quote!(<#V_::Map<_, _> as std::iter::FromIterator<_>>::from_iter);
|
||||
let MapFrom_: TokenStream2 = quote!(<#V_::Map<_, _>>::from);
|
||||
|
||||
match stx {
|
||||
Stx::Atom(v) =>
|
||||
|
@ -41,26 +40,27 @@ pub fn to_pattern_expr(stx: &Stx) -> Result<TokenStream2, &'static str> {
|
|||
None => to_pattern_expr(&Stx::Discard)?,
|
||||
}
|
||||
};
|
||||
Ok(quote!(#P_::Pattern::DBind(Box::new(#P_::DBind { pattern: #inner_pat_expr }))))
|
||||
Ok(quote!(#P_::Pattern::Bind { pattern: Box::new(#inner_pat_expr) }))
|
||||
}
|
||||
Stx::Subst(e) =>
|
||||
Ok(lit(e)),
|
||||
Stx::Discard =>
|
||||
Ok(quote!(#P_::Pattern::DDiscard(Box::new(#P_::DDiscard)))),
|
||||
Ok(quote!(#P_::Pattern::Discard)),
|
||||
|
||||
Stx::Rec(l, fs) => {
|
||||
let label = to_value_expr(&*l)?;
|
||||
let members = compile_sequence_members(fs)?;
|
||||
Ok(quote!(#P_::Pattern::DCompound(Box::new(#P_::DCompound::Rec {
|
||||
label: #label,
|
||||
fields: vec![#(#members),*],
|
||||
}))))
|
||||
Ok(quote!(#P_::Pattern::Group {
|
||||
type_: Box::new(#P_::GroupType::Rec { label: #label }),
|
||||
entries: #MapFrom_([#(#members),*]),
|
||||
}))
|
||||
},
|
||||
Stx::Seq(stxs) => {
|
||||
let members = compile_sequence_members(stxs)?;
|
||||
Ok(quote!(#P_::Pattern::DCompound(Box::new(#P_::DCompound::Arr {
|
||||
items: vec![#(#members),*],
|
||||
}))))
|
||||
Ok(quote!(#P_::Pattern::Group {
|
||||
type_: Box::new(#P_::GroupType::Arr),
|
||||
entries: #MapFrom_([#(#members),*]),
|
||||
}))
|
||||
}
|
||||
Stx::Set(_stxs) =>
|
||||
Err("Set literals not supported in patterns"),
|
||||
|
@ -70,9 +70,10 @@ pub fn to_pattern_expr(stx: &Stx) -> Result<TokenStream2, &'static str> {
|
|||
let v = to_pattern_expr(v)?;
|
||||
Ok(quote!((#k, #v)))
|
||||
}).collect::<Result<Vec<_>, &'static str>>()?;
|
||||
Ok(quote!(#P_::Pattern::DCompound(Box::new(#P_::DCompound::Dict {
|
||||
entries: #MapFromIterator_(vec![#(#members),*])
|
||||
}))))
|
||||
Ok(quote!(#P_::Pattern::Group {
|
||||
type_: Box::new(#P_::GroupType::Dict),
|
||||
entries: #MapFrom_([#(#members),*])
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
},
|
||||
{
|
||||
"path": "../syndicate-protocols"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"files.exclude": {
|
||||
"target": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "syndicate-schema-plugin"
|
||||
version = "0.6.0"
|
||||
version = "0.9.0"
|
||||
authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
@ -13,7 +13,7 @@ license = "Apache-2.0"
|
|||
|
||||
[dependencies]
|
||||
preserves-schema = "5.995"
|
||||
syndicate = { path = "../syndicate", version = "0.36.0"}
|
||||
syndicate = { path = "../syndicate", version = "0.40.0"}
|
||||
|
||||
[package.metadata.workspaces]
|
||||
independent = true
|
||||
|
|
|
@ -61,7 +61,7 @@ impl Plugin for PatternPlugin {
|
|||
}
|
||||
|
||||
fn discard() -> P::Pattern {
|
||||
P::Pattern::DDiscard(Box::new(P::DDiscard))
|
||||
P::Pattern::Discard
|
||||
}
|
||||
|
||||
trait WildcardPattern {
|
||||
|
@ -94,33 +94,34 @@ fn from_io(v: &IOValue) -> Option<P::_Any> {
|
|||
impl WildcardPattern for CompoundPattern {
|
||||
fn wc(&self, s: &mut WalkState) -> Option<P::Pattern> {
|
||||
match self {
|
||||
CompoundPattern::Tuple { patterns } =>
|
||||
Some(P::Pattern::DCompound(Box::new(P::DCompound::Arr {
|
||||
items: patterns.iter()
|
||||
.map(|p| unname(p).wc(s))
|
||||
.collect::<Option<Vec<P::Pattern>>>()?,
|
||||
}))),
|
||||
CompoundPattern::TuplePrefix { .. } =>
|
||||
Some(discard()),
|
||||
CompoundPattern::Tuple { patterns } |
|
||||
CompoundPattern::TuplePrefix { fixed: patterns, .. }=>
|
||||
Some(P::Pattern::Group {
|
||||
type_: Box::new(P::GroupType::Arr),
|
||||
entries: patterns.iter().enumerate()
|
||||
.map(|(i, p)| Some((P::_Any::new(i), unname(p).wc(s)?)))
|
||||
.collect::<Option<Map<P::_Any, P::Pattern>>>()?,
|
||||
}),
|
||||
CompoundPattern::Dict { entries } =>
|
||||
Some(P::Pattern::DCompound(Box::new(P::DCompound::Dict {
|
||||
Some(P::Pattern::Group {
|
||||
type_: Box::new(P::GroupType::Dict),
|
||||
entries: Map::from_iter(
|
||||
entries.0.iter()
|
||||
.map(|(k, p)| Some((from_io(k)?, unname_simple(p).wc(s)?)))
|
||||
.filter(|e| discard() != e.as_ref().unwrap().1)
|
||||
.collect::<Option<Vec<(P::_Any, P::Pattern)>>>()?
|
||||
.into_iter()),
|
||||
}))),
|
||||
}),
|
||||
CompoundPattern::Rec { label, fields } => match (unname(label), unname(fields)) {
|
||||
(Pattern::SimplePattern(label), Pattern::CompoundPattern(fields)) =>
|
||||
match (*label, *fields) {
|
||||
(SimplePattern::Lit { value }, CompoundPattern::Tuple { patterns }) =>
|
||||
Some(P::Pattern::DCompound(Box::new(P::DCompound::Rec {
|
||||
label: from_io(&value)?,
|
||||
fields: patterns.iter()
|
||||
.map(|p| unname(p).wc(s))
|
||||
.collect::<Option<Vec<P::Pattern>>>()?,
|
||||
}))),
|
||||
Some(P::Pattern::Group{
|
||||
type_: Box::new(P::GroupType::Rec { label: from_io(&value)? }),
|
||||
entries: patterns.iter().enumerate()
|
||||
.map(|(i, p)| Some((P::_Any::new(i), unname(p).wc(s)?)))
|
||||
.collect::<Option<Map<P::_Any, P::Pattern>>>()?,
|
||||
}),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "syndicate-server"
|
||||
version = "0.42.0"
|
||||
version = "0.45.0"
|
||||
authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
@ -14,13 +14,13 @@ jemalloc = ["dep:tikv-jemallocator"]
|
|||
|
||||
[build-dependencies]
|
||||
preserves-schema = "5.995"
|
||||
syndicate = { path = "../syndicate", version = "0.36.0"}
|
||||
syndicate-schema-plugin = { path = "../syndicate-schema-plugin", version = "0.6.0"}
|
||||
syndicate = { path = "../syndicate", version = "0.40.0"}
|
||||
syndicate-schema-plugin = { path = "../syndicate-schema-plugin", version = "0.9.0"}
|
||||
|
||||
[dependencies]
|
||||
preserves-schema = "5.995"
|
||||
syndicate = { path = "../syndicate", version = "0.36.0"}
|
||||
syndicate-macros = { path = "../syndicate-macros", version = "0.29.0"}
|
||||
syndicate = { path = "../syndicate", version = "0.40.0"}
|
||||
syndicate-macros = { path = "../syndicate-macros", version = "0.32.0"}
|
||||
|
||||
chrono = "0.4"
|
||||
futures = "0.3"
|
||||
|
|
|
@ -267,18 +267,18 @@ fn await_bind_noise(
|
|||
ds: &mut Arc<Cap>,
|
||||
t: &mut Activation,
|
||||
service_selector: AnyValue,
|
||||
initiator_session: Arc<Cap>,
|
||||
observer: Arc<Cap>,
|
||||
direct_resolution_facet: FacetId,
|
||||
) -> ActorResult {
|
||||
let handler = syndicate::entity(())
|
||||
.on_asserted_facet(move |_state, t, a: AnyValue| {
|
||||
t.stop_facet(direct_resolution_facet);
|
||||
let initiator_session = Arc::clone(&initiator_session);
|
||||
let observer = Arc::clone(&observer);
|
||||
t.spawn_link(None, move |t| {
|
||||
let bindings = a.value().to_sequence()?;
|
||||
let spec = validate_noise_spec(language().parse(&bindings[0])?)?;
|
||||
let service = bindings[1].value().to_embedded()?;
|
||||
run_noise_responder(t, spec, initiator_session, Arc::clone(service))
|
||||
run_noise_responder(t, spec, observer, Arc::clone(service))
|
||||
});
|
||||
Ok(())
|
||||
})
|
||||
|
@ -293,25 +293,50 @@ fn await_bind_noise(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
struct ResponderDetails {
|
||||
initiator_session: Arc<Cap>,
|
||||
service: Arc<Cap>,
|
||||
}
|
||||
|
||||
struct ResponderTransport {
|
||||
relay_input: Arc<Mutex<Option<TunnelRelay>>>,
|
||||
c_recv: CipherState<ChaCha20Poly1305>
|
||||
}
|
||||
type HandshakeState = noise_protocol::HandshakeState<X25519, ChaCha20Poly1305, Blake2s>;
|
||||
|
||||
enum ResponderState {
|
||||
Handshake(ResponderDetails, noise_protocol::HandshakeState<X25519, ChaCha20Poly1305, Blake2s>),
|
||||
Transport(ResponderTransport),
|
||||
Invalid, // used during state transitions
|
||||
Introduction {
|
||||
service: Arc<Cap>,
|
||||
hs: HandshakeState,
|
||||
},
|
||||
Handshake {
|
||||
initiator_session: Arc<Cap>,
|
||||
service: Arc<Cap>,
|
||||
hs: HandshakeState,
|
||||
},
|
||||
Transport {
|
||||
relay_input: Arc<Mutex<Option<TunnelRelay>>>,
|
||||
c_recv: CipherState<ChaCha20Poly1305>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Entity<noise::Packet> for ResponderState {
|
||||
fn message(&mut self, t: &mut Activation, p: noise::Packet) -> ActorResult {
|
||||
impl Entity<noise::SessionItem> for ResponderState {
|
||||
fn assert(&mut self, _t: &mut Activation, item: noise::SessionItem, _handle: Handle) -> ActorResult {
|
||||
let initiator_session = match item {
|
||||
noise::SessionItem::Initiator(i_box) => i_box.initiator_session,
|
||||
noise::SessionItem::Packet(_) => Err("Unexpected Packet assertion")?,
|
||||
};
|
||||
match std::mem::replace(self, ResponderState::Invalid) {
|
||||
ResponderState::Introduction { service, hs } => {
|
||||
*self = ResponderState::Handshake { initiator_session, service, hs };
|
||||
Ok(())
|
||||
}
|
||||
_ =>
|
||||
Err("Received second Initiator")?,
|
||||
}
|
||||
}
|
||||
|
||||
fn message(&mut self, t: &mut Activation, item: noise::SessionItem) -> ActorResult {
|
||||
let p = match item {
|
||||
noise::SessionItem::Initiator(_) => Err("Unexpected Initiator message")?,
|
||||
noise::SessionItem::Packet(p_box) => *p_box,
|
||||
};
|
||||
match self {
|
||||
ResponderState::Handshake(details, hs) => match p {
|
||||
ResponderState::Invalid | ResponderState::Introduction { .. } =>
|
||||
Err("Received Packet in invalid ResponderState")?,
|
||||
ResponderState::Handshake { initiator_session, service, hs } => match p {
|
||||
noise::Packet::Complete(bs) => {
|
||||
if bs.len() < hs.get_next_message_overhead() {
|
||||
Err("Invalid handshake message for pattern")?;
|
||||
|
@ -322,14 +347,13 @@ impl Entity<noise::Packet> for ResponderState {
|
|||
hs.read_message(&bs, &mut [])?;
|
||||
let mut reply = vec![0u8; hs.get_next_message_overhead()];
|
||||
hs.write_message(&[], &mut reply[..])?;
|
||||
details.initiator_session.message(t, language(), &noise::Packet::Complete(reply.into()));
|
||||
initiator_session.message(t, language(), &noise::Packet::Complete(reply.into()));
|
||||
if hs.completed() {
|
||||
let (c_recv, mut c_send) = hs.get_ciphers();
|
||||
let (_, relay_input, mut relay_output) =
|
||||
TunnelRelay::_run(t, Some(Arc::clone(&details.service)), None, false);
|
||||
TunnelRelay::_run(t, Some(Arc::clone(service)), None, false);
|
||||
let trace_collector = t.trace_collector();
|
||||
let transport = ResponderTransport { relay_input, c_recv };
|
||||
let initiator_session = Arc::clone(&details.initiator_session);
|
||||
let initiator_session = Arc::clone(initiator_session);
|
||||
let relay_output_name = Some(AnyValue::symbol("relay_output"));
|
||||
let transport_facet = t.facet_ref();
|
||||
t.linked_task(relay_output_name.clone(), async move {
|
||||
|
@ -360,25 +384,25 @@ impl Entity<noise::Packet> for ResponderState {
|
|||
}
|
||||
Ok(LinkedTaskTermination::Normal)
|
||||
});
|
||||
*self = ResponderState::Transport(transport);
|
||||
*self = ResponderState::Transport { relay_input, c_recv };
|
||||
}
|
||||
}
|
||||
_ => Err("Fragmented handshake is not allowed")?,
|
||||
},
|
||||
ResponderState::Transport(transport) => {
|
||||
ResponderState::Transport { relay_input, c_recv } => {
|
||||
let bs = match p {
|
||||
noise::Packet::Complete(bs) =>
|
||||
transport.c_recv.decrypt_vec(&bs[..]).map_err(|_| "Cannot decrypt packet")?,
|
||||
c_recv.decrypt_vec(&bs[..]).map_err(|_| "Cannot decrypt packet")?,
|
||||
noise::Packet::Fragmented(pieces) => {
|
||||
let mut result = Vec::with_capacity(1024);
|
||||
for piece in pieces {
|
||||
result.extend(transport.c_recv.decrypt_vec(&piece[..])
|
||||
result.extend(c_recv.decrypt_vec(&piece[..])
|
||||
.map_err(|_| "Cannot decrypt packet fragment")?);
|
||||
}
|
||||
result
|
||||
}
|
||||
};
|
||||
let mut g = transport.relay_input.lock();
|
||||
let mut g = relay_input.lock();
|
||||
let tr = g.as_mut().expect("initialized");
|
||||
tr.handle_inbound_datagram(t, &bs[..])?;
|
||||
}
|
||||
|
@ -446,7 +470,7 @@ fn lookup_pattern(name: &str) -> Option<HandshakePattern> {
|
|||
fn run_noise_responder(
|
||||
t: &mut Activation,
|
||||
spec: ValidatedNoiseSpec,
|
||||
initiator_session: Arc<Cap>,
|
||||
observer: Arc<Cap>,
|
||||
service: Arc<Cap>,
|
||||
) -> ActorResult {
|
||||
let hs = {
|
||||
|
@ -469,13 +493,8 @@ fn run_noise_responder(
|
|||
hs
|
||||
};
|
||||
|
||||
let details = ResponderDetails {
|
||||
initiator_session: initiator_session.clone(),
|
||||
service,
|
||||
};
|
||||
|
||||
let responder_session =
|
||||
Cap::guard(crate::Language::arc(), t.create(ResponderState::Handshake(details, hs)));
|
||||
initiator_session.assert(t, language(), &gatekeeper::Resolved::Accepted { responder_session });
|
||||
Cap::guard(crate::Language::arc(), t.create(ResponderState::Introduction{ service, hs }));
|
||||
observer.assert(t, language(), &gatekeeper::Resolved::Accepted { responder_session });
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -32,13 +32,9 @@ pub fn empty_response(code: StatusCode) -> Response<Body> {
|
|||
|
||||
type ChunkItem = Result<body::Bytes, Box<dyn std::error::Error + Send + Sync>>;
|
||||
|
||||
enum ResponseCollector {
|
||||
Pending {
|
||||
tx: oneshot::Sender<Response<Body>>,
|
||||
body_tx: UnboundedSender<ChunkItem>,
|
||||
res: Response<Body>,
|
||||
},
|
||||
Done
|
||||
struct ResponseCollector {
|
||||
tx_res: Option<(oneshot::Sender<Response<Body>>, Response<Body>)>,
|
||||
body_tx: Option<UnboundedSender<ChunkItem>>,
|
||||
}
|
||||
|
||||
impl ResponseCollector {
|
||||
|
@ -46,43 +42,50 @@ impl ResponseCollector {
|
|||
let (body_tx, body_rx) = unbounded_channel();
|
||||
let body_stream: Box<dyn futures::Stream<Item = ChunkItem> + Send> =
|
||||
Box::new(UnboundedReceiverStream::new(body_rx));
|
||||
ResponseCollector::Pending {
|
||||
tx,
|
||||
body_tx,
|
||||
res: Response::new(body_stream.into()),
|
||||
let mut res = Response::new(body_stream.into());
|
||||
*res.status_mut() = StatusCode::OK;
|
||||
ResponseCollector {
|
||||
tx_res: Some((tx, res)),
|
||||
body_tx: Some(body_tx),
|
||||
}
|
||||
}
|
||||
|
||||
fn with_res<F: FnOnce(&mut Response<Body>) -> ActorResult>(&mut self, f: F) -> ActorResult {
|
||||
if let ResponseCollector::Pending { res, .. } = self {
|
||||
if let Some((_, res)) = &mut self.tx_res {
|
||||
f(res)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn deliver_res(&mut self) {
|
||||
if let Some((tx, res)) = std::mem::replace(&mut self.tx_res, None) {
|
||||
let _ = tx.send(res);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_chunk(&mut self, value: http::Chunk) -> ActorResult {
|
||||
if let ResponseCollector::Pending { body_tx, .. } = self {
|
||||
self.deliver_res();
|
||||
|
||||
if let Some(body_tx) = self.body_tx.as_mut() {
|
||||
body_tx.send(Ok(match value {
|
||||
http::Chunk::Bytes(bs) => bs.into(),
|
||||
http::Chunk::String(s) => s.as_bytes().to_vec().into(),
|
||||
}))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn finish(&mut self) -> ActorResult {
|
||||
match std::mem::replace(self, ResponseCollector::Done) {
|
||||
ResponseCollector::Pending { tx, res, .. } => {
|
||||
let _ = tx.send(res);
|
||||
}
|
||||
ResponseCollector::Done => (),
|
||||
}
|
||||
fn finish(&mut self, t: &mut Activation) -> ActorResult {
|
||||
self.deliver_res();
|
||||
self.body_tx = None;
|
||||
t.stop();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Entity<http::HttpResponse> for ResponseCollector {
|
||||
fn message(&mut self, _turn: &mut Activation, message: http::HttpResponse) -> ActorResult {
|
||||
fn message(&mut self, t: &mut Activation, message: http::HttpResponse) -> ActorResult {
|
||||
match message {
|
||||
http::HttpResponse::Status { code, .. } => self.with_res(|r| {
|
||||
*r.status_mut() = StatusCode::from_u16(
|
||||
|
@ -94,10 +97,12 @@ impl Entity<http::HttpResponse> for ResponseCollector {
|
|||
HeaderValue::from_str(value.as_str())?);
|
||||
Ok(())
|
||||
}),
|
||||
http::HttpResponse::Chunk { chunk } => self.add_chunk(*chunk),
|
||||
http::HttpResponse::Chunk { chunk } => {
|
||||
self.add_chunk(*chunk)
|
||||
}
|
||||
http::HttpResponse::Done { chunk } => {
|
||||
self.add_chunk(*chunk)?;
|
||||
self.finish()
|
||||
self.finish(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,11 +116,11 @@ pub async fn serve(
|
|||
port: u16,
|
||||
) -> Result<Response<Body>, Error> {
|
||||
let host = match req.headers().get("host").and_then(|v| v.to_str().ok()) {
|
||||
None => return Ok(empty_response(StatusCode::BAD_REQUEST)),
|
||||
Some(h) => match h.rsplit_once(':') {
|
||||
None => http::RequestHost::Absent,
|
||||
Some(h) => http::RequestHost::Present(match h.rsplit_once(':') {
|
||||
None => h.to_string(),
|
||||
Some((h, _port)) => h.to_string(),
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let uri = req.uri();
|
||||
|
@ -160,34 +165,29 @@ pub async fn serve(
|
|||
let account = Account::new(Some(AnyValue::symbol("http")), trace_collector);
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let mut req_handle: Option<Handle> = None;
|
||||
|
||||
facet.activate(&account, Some(trace::TurnCause::external("http")), |t| {
|
||||
let sreq = http::HttpRequest {
|
||||
sequence_number: NEXT_SEQ.fetch_add(1, Ordering::Relaxed).into(),
|
||||
host,
|
||||
port: port.into(),
|
||||
method: req.method().to_string().to_lowercase(),
|
||||
path,
|
||||
headers: http::Headers(headers),
|
||||
query,
|
||||
body,
|
||||
};
|
||||
tracing::debug!(?sreq);
|
||||
let srep = Cap::guard(&language().syndicate, t.create(ResponseCollector::new(tx)));
|
||||
req_handle = httpd.assert(t, language(), &http::HttpContext { req: sreq, res: srep });
|
||||
t.facet(move |t| {
|
||||
let sreq = http::HttpRequest {
|
||||
sequence_number: NEXT_SEQ.fetch_add(1, Ordering::Relaxed).into(),
|
||||
host,
|
||||
port: port.into(),
|
||||
method: req.method().to_string().to_lowercase(),
|
||||
path,
|
||||
headers: http::Headers(headers),
|
||||
query,
|
||||
body,
|
||||
};
|
||||
tracing::debug!(?sreq);
|
||||
let srep = Cap::guard(&language().syndicate, t.create(ResponseCollector::new(tx)));
|
||||
httpd.assert(t, language(), &http::HttpContext { req: sreq, res: srep });
|
||||
Ok(())
|
||||
})?;
|
||||
Ok(())
|
||||
});
|
||||
|
||||
let response_result = rx.await;
|
||||
|
||||
facet.activate(&account, Some(trace::TurnCause::external("http")), |t| {
|
||||
if let Some(h) = req_handle {
|
||||
t.retract(h);
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
match response_result {
|
||||
Ok(response) => Ok(response),
|
||||
Err(_ /* sender dropped */) => Ok(empty_response(StatusCode::INTERNAL_SERVER_ERROR)),
|
||||
|
|
|
@ -9,7 +9,7 @@ use syndicate::actor::*;
|
|||
use syndicate::dataspace::Dataspace;
|
||||
use syndicate::during;
|
||||
use syndicate::enclose;
|
||||
use syndicate::pattern::{lift_literal, drop_literal};
|
||||
use syndicate::pattern::{lift_literal, drop_literal, pattern_seq_from_dictionary};
|
||||
use syndicate::schemas::dataspace;
|
||||
use syndicate::schemas::dataspace_patterns as P;
|
||||
use syndicate::schemas::sturdy;
|
||||
|
@ -173,7 +173,7 @@ fn bad_instruction(message: &str) -> io::Error {
|
|||
}
|
||||
|
||||
fn discard() -> P::Pattern {
|
||||
P::Pattern::DDiscard(Box::new(P::DDiscard))
|
||||
P::Pattern::Discard
|
||||
}
|
||||
|
||||
fn dlit(value: AnyValue) -> P::Pattern {
|
||||
|
@ -272,7 +272,7 @@ impl<'env> PatternInstantiator<'env> {
|
|||
Symbolic::Discard => discard(),
|
||||
Symbolic::Binder(s) => {
|
||||
self.binding_names.push(s);
|
||||
P::Pattern::DBind(Box::new(P::DBind { pattern: discard() }))
|
||||
P::Pattern::Bind { pattern: Box::new(discard()) }
|
||||
}
|
||||
Symbolic::Reference(s) =>
|
||||
dlit(self.env.lookup(&s, "pattern-template variable")?.clone()),
|
||||
|
@ -287,43 +287,47 @@ impl<'env> PatternInstantiator<'env> {
|
|||
Some(pat) => pat,
|
||||
None => {
|
||||
let label = self.instantiate_pattern(r.label())?;
|
||||
let fields = r.fields().iter().map(|p| self.instantiate_pattern(p))
|
||||
.collect::<io::Result<Vec<P::Pattern>>>()?;
|
||||
P::Pattern::DCompound(Box::new(P::DCompound::Rec {
|
||||
label: drop_literal(&label)
|
||||
.ok_or(bad_instruction("Record pattern must have literal label"))?,
|
||||
fields,
|
||||
}))
|
||||
let entries = r.fields().iter().enumerate()
|
||||
.map(|(i, p)| Ok((AnyValue::new(i), self.instantiate_pattern(p)?)))
|
||||
.collect::<io::Result<Map<AnyValue, P::Pattern>>>()?;
|
||||
P::Pattern::Group {
|
||||
type_: Box::new(P::GroupType::Rec {
|
||||
label: drop_literal(&label)
|
||||
.ok_or(bad_instruction("Record pattern must have literal label"))?,
|
||||
}),
|
||||
entries,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Value::Sequence(v) =>
|
||||
P::Pattern::DCompound(Box::new(P::DCompound::Arr {
|
||||
items: v.iter()
|
||||
.map(|p| self.instantiate_pattern(p))
|
||||
.collect::<io::Result<Vec<P::Pattern>>>()?,
|
||||
})),
|
||||
P::Pattern::Group {
|
||||
type_: Box::new(P::GroupType::Arr),
|
||||
entries: v.iter().enumerate()
|
||||
.map(|(i, p)| Ok((AnyValue::new(i), self.instantiate_pattern(p)?)))
|
||||
.collect::<io::Result<Map<AnyValue, P::Pattern>>>()?,
|
||||
},
|
||||
Value::Set(_) =>
|
||||
Err(bad_instruction(&format!("Sets not permitted in patterns: {:?}", template)))?,
|
||||
Value::Dictionary(v) =>
|
||||
P::Pattern::DCompound(Box::new(P::DCompound::Dict {
|
||||
P::Pattern::Group {
|
||||
type_: Box::new(P::GroupType::Dict),
|
||||
entries: v.iter()
|
||||
.map(|(a, b)| Ok((a.clone(), self.instantiate_pattern(b)?)))
|
||||
.collect::<io::Result<Map<AnyValue, P::Pattern>>>()?,
|
||||
})),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn maybe_binder_with_pattern(&mut self, r: &Record<AnyValue>) -> io::Result<Option<P::Pattern>> {
|
||||
match r.label().value().as_symbol().map(|s| analyze(&s)) {
|
||||
Some(Symbolic::Binder(formal)) => if r.fields().len() == 1 {
|
||||
Some(Symbolic::Binder(formal)) if r.fields().len() == 1 => {
|
||||
let pattern = self.instantiate_pattern(&r.fields()[0])?;
|
||||
self.binding_names.push(formal);
|
||||
return Ok(Some(P::Pattern::DBind(Box::new(P::DBind { pattern }))));
|
||||
Ok(Some(P::Pattern::Bind { pattern: Box::new(pattern) }))
|
||||
},
|
||||
_ => (),
|
||||
_ => Ok(None),
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -553,7 +557,7 @@ impl Env {
|
|||
RewriteTemplate::Accept { pattern_template } => {
|
||||
let (_binding_names, pattern) = self.instantiate_pattern(pattern_template)?;
|
||||
Ok(sturdy::Rewrite {
|
||||
pattern: embed_pattern(&P::Pattern::DBind(Box::new(P::DBind { pattern }))),
|
||||
pattern: embed_pattern(&P::Pattern::Bind { pattern: Box::new(pattern) }),
|
||||
template: sturdy::Template::TRef(Box::new(sturdy::TRef { binding: 0.into() })),
|
||||
})
|
||||
}
|
||||
|
@ -674,24 +678,26 @@ impl Env {
|
|||
|
||||
fn embed_pattern(p: &P::Pattern) -> sturdy::Pattern {
|
||||
match p {
|
||||
P::Pattern::DDiscard(_) => sturdy::Pattern::PDiscard(Box::new(sturdy::PDiscard)),
|
||||
P::Pattern::DBind(b) => sturdy::Pattern::PBind(Box::new(sturdy::PBind {
|
||||
pattern: embed_pattern(&b.pattern),
|
||||
P::Pattern::Discard => sturdy::Pattern::PDiscard(Box::new(sturdy::PDiscard)),
|
||||
P::Pattern::Bind { pattern } => sturdy::Pattern::PBind(Box::new(sturdy::PBind {
|
||||
pattern: embed_pattern(&**pattern),
|
||||
})),
|
||||
P::Pattern::DLit(b) => sturdy::Pattern::Lit(Box::new(sturdy::Lit {
|
||||
value: language().unparse(&b.value),
|
||||
P::Pattern::Lit { value } => sturdy::Pattern::Lit(Box::new(sturdy::Lit {
|
||||
value: language().unparse(&**value),
|
||||
})),
|
||||
P::Pattern::DCompound(b) => sturdy::Pattern::PCompound(Box::new(match &**b {
|
||||
P::DCompound::Rec { label, fields } =>
|
||||
P::Pattern::Group { type_, entries } => sturdy::Pattern::PCompound(Box::new(match &**type_ {
|
||||
P::GroupType::Rec { label } =>
|
||||
sturdy::PCompound::Rec {
|
||||
label: label.clone(),
|
||||
fields: fields.iter().map(embed_pattern).collect(),
|
||||
fields: pattern_seq_from_dictionary(entries).expect("correct field entries")
|
||||
.into_iter().map(embed_pattern).collect(),
|
||||
},
|
||||
P::DCompound::Arr { items } =>
|
||||
P::GroupType::Arr =>
|
||||
sturdy::PCompound::Arr {
|
||||
items: items.iter().map(embed_pattern).collect(),
|
||||
items: pattern_seq_from_dictionary(entries).expect("correct element entries")
|
||||
.into_iter().map(embed_pattern).collect(),
|
||||
},
|
||||
P::DCompound::Dict { entries } =>
|
||||
P::GroupType::Dict =>
|
||||
sturdy::PCompound::Dict {
|
||||
entries: entries.iter().map(|(k, v)| (k.clone(), embed_pattern(v))).collect(),
|
||||
},
|
||||
|
|
|
@ -10,7 +10,6 @@ use syndicate::error::Error;
|
|||
use syndicate::preserves::rec;
|
||||
use syndicate::preserves::value::Map;
|
||||
use syndicate::preserves::value::NestedValue;
|
||||
use syndicate::preserves::value::Set;
|
||||
use syndicate::schemas::http;
|
||||
use syndicate::value::signed_integer::SignedInteger;
|
||||
|
||||
|
@ -22,7 +21,7 @@ use crate::schemas::internal_services::HttpStaticFileServer;
|
|||
use syndicate_macros::during;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref MIME_TABLE: Map<String, String> = load_mime_table("/etc/mime.types").expect("MIME table");
|
||||
pub static ref MIME_TABLE: Map<String, String> = load_mime_table("/etc/mime.types").unwrap_or_default();
|
||||
}
|
||||
|
||||
pub fn load_mime_table(path: &str) -> Result<Map<String, String>, std::io::Error> {
|
||||
|
@ -56,10 +55,22 @@ pub fn on_demand(t: &mut Activation, ds: Arc<Cap>) {
|
|||
});
|
||||
}
|
||||
|
||||
type MethodTable = Map<http::MethodPattern, Set<Arc<Cap>>>;
|
||||
#[derive(Debug, Clone)]
|
||||
struct ActiveHandler {
|
||||
cap: Arc<Cap>,
|
||||
terminated: Arc<Field<bool>>,
|
||||
}
|
||||
type MethodTable = Map<http::MethodPattern, Vec<ActiveHandler>>;
|
||||
type HostTable = Map<http::HostPattern, Map<http::PathPattern, MethodTable>>;
|
||||
type RoutingTable = Map<SignedInteger, HostTable>;
|
||||
|
||||
fn request_host(value: &http::RequestHost) -> Option<String> {
|
||||
match value {
|
||||
http::RequestHost::Present(h) => Some(h.to_owned()),
|
||||
http::RequestHost::Absent => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn run(t: &mut Activation, ds: Arc<Cap>, spec: HttpRouter) -> ActorResult {
|
||||
ds.assert(t, language(), &lifecycle::started(&spec));
|
||||
ds.assert(t, language(), &lifecycle::ready(&spec));
|
||||
|
@ -72,25 +83,35 @@ fn run(t: &mut Activation, ds: Arc<Cap>, spec: HttpRouter) -> ActorResult {
|
|||
enclose!((httpd, routes) during!(t, httpd, language(), <http-listener #(&port1)>, enclose!((routes, port) |t: &mut Activation| {
|
||||
let port2 = port.clone();
|
||||
during!(t, httpd, language(), <http-bind $host #(&port2) $method $path $handler>, |t: &mut Activation| {
|
||||
tracing::debug!("+HTTP binding {:?} {:?} {:?} {:?} {:?}", host, port, method, path, handler);
|
||||
let port = port.value().to_signedinteger()?;
|
||||
let host = language().parse::<http::HostPattern>(&host)?;
|
||||
let path = language().parse::<http::PathPattern>(&path)?;
|
||||
let method = language().parse::<http::MethodPattern>(&method)?;
|
||||
let handler = handler.value().to_embedded()?;
|
||||
let handler_cap = handler.value().to_embedded()?.clone();
|
||||
let handler_terminated = t.named_field("handler-terminated", false);
|
||||
t.get_mut(&routes)
|
||||
.entry(port.clone()).or_default()
|
||||
.entry(host.clone()).or_default()
|
||||
.entry(path.clone()).or_default()
|
||||
.entry(method.clone()).or_default()
|
||||
.insert(handler.clone());
|
||||
t.on_stop(enclose!((routes, handler, method, path, host, port) move |t| {
|
||||
.push(ActiveHandler {
|
||||
cap: handler_cap.clone(),
|
||||
terminated: handler_terminated,
|
||||
});
|
||||
t.on_stop(enclose!((routes, method, path, host, port) move |t| {
|
||||
tracing::debug!("-HTTP binding {:?} {:?} {:?} {:?} {:?}", host, port, method, path, handler);
|
||||
let port_map = t.get_mut(&routes);
|
||||
let host_map = port_map.entry(port.clone()).or_default();
|
||||
let path_map = host_map.entry(host.clone()).or_default();
|
||||
let method_map = path_map.entry(path.clone()).or_default();
|
||||
let handler_set = method_map.entry(method.clone()).or_default();
|
||||
handler_set.remove(&handler);
|
||||
if handler_set.is_empty() {
|
||||
let handler_vec = method_map.entry(method.clone()).or_default();
|
||||
let handler = {
|
||||
let i = handler_vec.iter().position(|a| a.cap == handler_cap)
|
||||
.expect("Expected an index of an active handler to remove");
|
||||
handler_vec.swap_remove(i)
|
||||
};
|
||||
if handler_vec.is_empty() {
|
||||
method_map.remove(&method);
|
||||
}
|
||||
if method_map.is_empty() {
|
||||
|
@ -102,6 +123,7 @@ fn run(t: &mut Activation, ds: Arc<Cap>, spec: HttpRouter) -> ActorResult {
|
|||
if host_map.is_empty() {
|
||||
port_map.remove(&port);
|
||||
}
|
||||
*t.get_mut(&handler.terminated) = true;
|
||||
Ok(())
|
||||
}));
|
||||
Ok(())
|
||||
|
@ -115,12 +137,14 @@ fn run(t: &mut Activation, ds: Arc<Cap>, spec: HttpRouter) -> ActorResult {
|
|||
let req = match language().parse::<http::HttpRequest>(&req) { Ok(v) => v, Err(_) => return Ok(()) };
|
||||
let res = match res.value().to_embedded() { Ok(v) => v, Err(_) => return Ok(()) };
|
||||
|
||||
tracing::trace!("Looking up handler for {:#?} in {:#?}", &req, &t.get(&routes));
|
||||
|
||||
let host_map = match t.get(&routes).get(&req.port) {
|
||||
Some(host_map) => host_map,
|
||||
None => return send_empty(t, res, 404, "Not found"),
|
||||
};
|
||||
|
||||
let methods = match try_hostname(host_map, http::HostPattern::Host(req.host.clone()), &req.path)? {
|
||||
let methods = match request_host(&req.host).and_then(|h| try_hostname(host_map, http::HostPattern::Host(h), &req.path).transpose()).transpose()? {
|
||||
Some(methods) => methods,
|
||||
None => match try_hostname(host_map, http::HostPattern::Any, &req.path)? {
|
||||
Some(methods) => methods,
|
||||
|
@ -141,9 +165,7 @@ fn run(t: &mut Activation, ds: Arc<Cap>, spec: HttpRouter) -> ActorResult {
|
|||
code: 405.into(), message: "Method Not Allowed".into() });
|
||||
res.message(t, language(), &http::HttpResponse::Header {
|
||||
name: "allow".into(), value: allowed });
|
||||
res.message(t, language(), &http::HttpResponse::Done {
|
||||
chunk: Box::new(http::Chunk::Bytes(vec![])) });
|
||||
return Ok(())
|
||||
return send_done(t, res);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -151,21 +173,33 @@ fn run(t: &mut Activation, ds: Arc<Cap>, spec: HttpRouter) -> ActorResult {
|
|||
if handlers.len() > 1 {
|
||||
tracing::warn!(?req, "Too many handlers available");
|
||||
}
|
||||
let handler = handlers.first().expect("Nonempty handler set").clone();
|
||||
handler.assert(t, language(), &http::HttpContext { req, res: res.clone() });
|
||||
let ActiveHandler { cap, terminated } = handlers.first().expect("Nonempty handler set").clone();
|
||||
tracing::trace!("Handler for {:?} is {:?}", &req, &cap);
|
||||
|
||||
t.dataflow(enclose!((terminated, req, res) move |t| {
|
||||
if *t.get(&terminated) {
|
||||
tracing::trace!("Handler for {:?} terminated", &req);
|
||||
send_empty(t, &res, 500, "Internal Server Error")?;
|
||||
}
|
||||
Ok(())
|
||||
}))?;
|
||||
|
||||
cap.assert(t, language(), &http::HttpContext { req, res: res.clone() });
|
||||
Ok(())
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_done(t: &mut Activation, res: &Arc<Cap>) -> ActorResult {
|
||||
res.message(t, language(), &http::HttpResponse::Done {
|
||||
chunk: Box::new(http::Chunk::Bytes(vec![])) });
|
||||
Ok(())
|
||||
}
|
||||
fn send_empty(t: &mut Activation, res: &Arc<Cap>, code: u16, message: &str) -> ActorResult {
|
||||
res.message(t, language(), &http::HttpResponse::Status {
|
||||
code: code.into(), message: message.into() });
|
||||
res.message(t, language(), &http::HttpResponse::Done {
|
||||
chunk: Box::new(http::Chunk::Bytes(vec![])) });
|
||||
return Ok(())
|
||||
send_done(t, res)
|
||||
}
|
||||
|
||||
fn path_pattern_matches(path_pat: &http::PathPattern, path: &Vec<String>) -> bool {
|
||||
|
@ -187,7 +221,10 @@ fn path_pattern_matches(path_pat: &http::PathPattern, path: &Vec<String>) -> boo
|
|||
http::PathPatternElement::Rest => return true,
|
||||
}
|
||||
}
|
||||
true
|
||||
match path_iter.next() {
|
||||
Some(_more) => false,
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_hostname<'table>(
|
||||
|
@ -199,6 +236,7 @@ fn try_hostname<'table>(
|
|||
None => Ok(None),
|
||||
Some(path_table) => {
|
||||
for (path_pat, method_table) in path_table.iter() {
|
||||
tracing::trace!("Checking path {:?} against pattern {:?}", &path, &path_pat);
|
||||
if path_pattern_matches(path_pat, path) {
|
||||
return Ok(Some(method_table));
|
||||
}
|
||||
|
@ -263,9 +301,7 @@ impl HttpStaticFileServer {
|
|||
code: 301.into(), message: "Moved permanently".into() });
|
||||
res.message(t, language(), &http::HttpResponse::Header {
|
||||
name: "location".into(), value: format!("/{}/", req.path.join("/")) });
|
||||
res.message(t, language(), &http::HttpResponse::Done {
|
||||
chunk: Box::new(http::Chunk::Bytes(vec![])) });
|
||||
return Ok(())
|
||||
return send_done(t, res);
|
||||
} else {
|
||||
let mut buf = Vec::new();
|
||||
fh.read_to_end(&mut buf)?;
|
||||
|
@ -286,6 +322,7 @@ impl HttpStaticFileServer {
|
|||
}
|
||||
res.message(t, language(), &http::HttpResponse::Done {
|
||||
chunk: Box::new(http::Chunk::Bytes(body)) });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,24 +15,20 @@ use tokio::net::TcpListener;
|
|||
use crate::language::language;
|
||||
use crate::lifecycle;
|
||||
use crate::protocol::detect_protocol;
|
||||
use crate::schemas::internal_services::{TcpWithHttp, TcpWithoutHttp, TcpRelayListener};
|
||||
use crate::schemas::internal_services::TcpWithoutHttp;
|
||||
|
||||
use syndicate_macros::during;
|
||||
|
||||
pub fn on_demand(t: &mut Activation, ds: Arc<Cap>) {
|
||||
t.spawn(Some(AnyValue::symbol("tcp_relay_listener")), move |t| {
|
||||
enclose!((ds) during!(t, ds, language(), <run-service $spec: TcpWithHttp::<AnyValue>>, |t: &mut Activation| {
|
||||
spec.httpd.assert(t, language(), &syndicate::schemas::http::HttpListener { port: spec.addr.port.clone() });
|
||||
run_supervisor(t, ds.clone(), TcpRelayListener::TcpWithHttp(Box::new(spec)))
|
||||
}));
|
||||
enclose!((ds) during!(t, ds, language(), <run-service $spec: TcpWithoutHttp::<AnyValue>>, |t| {
|
||||
run_supervisor(t, ds.clone(), TcpRelayListener::TcpWithoutHttp(Box::new(spec)))
|
||||
run_supervisor(t, ds.clone(), spec)
|
||||
}));
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
fn run_supervisor(t: &mut Activation, ds: Arc<Cap>, spec: TcpRelayListener) -> ActorResult {
|
||||
fn run_supervisor(t: &mut Activation, ds: Arc<Cap>, spec: TcpWithoutHttp) -> ActorResult {
|
||||
Supervisor::start(
|
||||
t,
|
||||
Some(rec![AnyValue::symbol("relay"), language().unparse(&spec)]),
|
||||
|
@ -41,18 +37,32 @@ fn run_supervisor(t: &mut Activation, ds: Arc<Cap>, spec: TcpRelayListener) -> A
|
|||
enclose!((ds) move |t| enclose!((ds, spec) run(t, ds, spec))))
|
||||
}
|
||||
|
||||
fn run(t: &mut Activation, ds: Arc<Cap>, spec: TcpRelayListener) -> ActorResult {
|
||||
fn run(t: &mut Activation, ds: Arc<Cap>, spec: TcpWithoutHttp) -> ActorResult {
|
||||
lifecycle::terminate_on_service_restart(t, &ds, &spec);
|
||||
let (addr, gatekeeper, httpd) = match spec.clone() {
|
||||
TcpRelayListener::TcpWithHttp(b) => {
|
||||
let TcpWithHttp { addr, gatekeeper, httpd } = *b;
|
||||
(addr, gatekeeper, Some(httpd))
|
||||
}
|
||||
TcpRelayListener::TcpWithoutHttp(b) => {
|
||||
let TcpWithoutHttp { addr, gatekeeper } = *b;
|
||||
(addr, gatekeeper, None)
|
||||
}
|
||||
};
|
||||
|
||||
let httpd = t.named_field("httpd", None::<Arc<Cap>>);
|
||||
|
||||
{
|
||||
let ad = spec.addr.clone();
|
||||
let ad2 = ad.clone();
|
||||
let gk = spec.gatekeeper.clone();
|
||||
enclose!((ds, httpd) during!(t, ds, language(),
|
||||
<run-service <relay-listener #(&language().unparse(&ad)) #(&AnyValue::domain(gk)) $h>>, |t: &mut Activation| {
|
||||
if let Some(h) = h.value().as_embedded().cloned() {
|
||||
h.assert(t, language(), &syndicate::schemas::http::HttpListener { port: ad2.port.clone() });
|
||||
*t.get_mut(&httpd) = Some(h.clone());
|
||||
t.on_stop(enclose!((httpd) move |t| {
|
||||
let f = t.get_mut(&httpd);
|
||||
if *f == Some(h.clone()) { *f = None; }
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
|
||||
let TcpWithoutHttp { addr, gatekeeper } = spec.clone();
|
||||
|
||||
let host = addr.host.clone();
|
||||
let port = u16::try_from(&addr.port).map_err(|_| "Invalid TCP port number")?;
|
||||
let facet = t.facet_ref();
|
||||
|
@ -83,6 +93,7 @@ fn run(t: &mut Activation, ds: Arc<Cap>, spec: TcpRelayListener) -> ActorResult
|
|||
let account = Account::new(name.clone(), trace_collector.clone());
|
||||
if !facet.activate(
|
||||
&account, cause, enclose!((trace_collector, httpd) move |t| {
|
||||
let httpd = t.get(&httpd).clone();
|
||||
t.spawn(name, move |t| {
|
||||
Ok(t.linked_task(None, {
|
||||
let facet = t.facet_ref();
|
||||
|
@ -91,7 +102,7 @@ fn run(t: &mut Activation, ds: Arc<Cap>, spec: TcpRelayListener) -> ActorResult
|
|||
facet,
|
||||
stream,
|
||||
gatekeeper,
|
||||
httpd.map(|r| r.clone()),
|
||||
httpd,
|
||||
addr,
|
||||
port).await?;
|
||||
Ok(LinkedTaskTermination::KeepFacet)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "syndicate-tools"
|
||||
version = "0.15.0"
|
||||
version = "0.18.0"
|
||||
authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
@ -11,7 +11,7 @@ license = "Apache-2.0"
|
|||
|
||||
[dependencies]
|
||||
preserves = "4.995"
|
||||
syndicate = { path = "../syndicate", version = "0.36.0"}
|
||||
syndicate = { path = "../syndicate", version = "0.40.0"}
|
||||
|
||||
clap = { version = "^4.0", features = ["derive"] }
|
||||
clap_complete = "^4.0"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "syndicate"
|
||||
version = "0.36.0"
|
||||
version = "0.40.0"
|
||||
authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
@ -19,7 +19,7 @@ preserves-schema = "5.995"
|
|||
preserves = "4.995"
|
||||
preserves-schema = "5.995"
|
||||
|
||||
tokio = { version = "1.10", features = ["io-util", "macros", "rt", "rt-multi-thread", "time"] }
|
||||
tokio = { version = "1.10", features = ["io-std", "io-util", "macros", "rt", "rt-multi-thread", "time"] }
|
||||
tokio-util = "0.6"
|
||||
bytes = "1.0"
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ use syndicate::during::entity;
|
|||
use syndicate::dataspace::Dataspace;
|
||||
use syndicate::schemas::dataspace::Observe;
|
||||
use syndicate::schemas::dataspace_patterns as p;
|
||||
use syndicate::value::Map;
|
||||
use syndicate::value::NestedValue;
|
||||
use syndicate::value::Value;
|
||||
|
||||
|
@ -88,11 +89,11 @@ pub fn bench_pub(c: &mut Criterion) {
|
|||
.create_cap(t);
|
||||
|
||||
ds.assert(t, language(), &Observe {
|
||||
pattern: p::Pattern::DBind(Box::new(p::DBind {
|
||||
pattern: p::Pattern::DLit(Box::new(p::DLit {
|
||||
value: p::AnyAtom::Symbol("consumer".to_owned()),
|
||||
})),
|
||||
})),
|
||||
pattern: p::Pattern::Bind {
|
||||
pattern: Box::new(p::Pattern::Lit {
|
||||
value: Box::new(p::AnyAtom::Symbol("consumer".to_owned())),
|
||||
}),
|
||||
},
|
||||
observer: shutdown,
|
||||
});
|
||||
|
||||
|
@ -110,24 +111,27 @@ pub fn bench_pub(c: &mut Criterion) {
|
|||
|
||||
ds.assert(t, &(), &AnyValue::symbol("consumer"));
|
||||
ds.assert(t, language(), &Observe {
|
||||
pattern: p::Pattern::DCompound(Box::new(p::DCompound::Rec {
|
||||
label: AnyValue::symbol("Says"),
|
||||
fields: vec![
|
||||
p::Pattern::DLit(Box::new(p::DLit {
|
||||
value: p::AnyAtom::String("bench_pub".to_owned()),
|
||||
})),
|
||||
p::Pattern::DBind(Box::new(p::DBind {
|
||||
pattern: p::Pattern::DDiscard(Box::new(p::DDiscard)),
|
||||
})),
|
||||
]})),
|
||||
pattern: p::Pattern::Group {
|
||||
type_: Box::new(p::GroupType::Rec {
|
||||
label: AnyValue::symbol("Says"),
|
||||
}),
|
||||
entries: Map::from([
|
||||
(p::_Any::new(0), p::Pattern::Lit {
|
||||
value: Box::new(p::AnyAtom::String("bench_pub".to_owned())),
|
||||
}),
|
||||
(p::_Any::new(1), p::Pattern::Bind {
|
||||
pattern: Box::new(p::Pattern::Discard),
|
||||
}),
|
||||
]),
|
||||
},
|
||||
observer: receiver,
|
||||
});
|
||||
ds.assert(t, language(), &Observe {
|
||||
pattern: p::Pattern::DBind(Box::new(p::DBind {
|
||||
pattern: p::Pattern::DLit(Box::new(p::DLit {
|
||||
value: p::AnyAtom::Bool(true),
|
||||
})),
|
||||
})),
|
||||
pattern: p::Pattern::Bind {
|
||||
pattern: Box::new(p::Pattern::Lit {
|
||||
value: Box::new(p::AnyAtom::Bool(true)),
|
||||
}),
|
||||
},
|
||||
observer: shutdown,
|
||||
});
|
||||
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
tcp-remote„´³tupleµ´³named³host´³atom³String„„´³named³port´³atom³
SignedInteger„„„„„³TcpPeerInfo´³rec´³lit³tcp-peer„´³tupleµ´³named³handle´³embedded³any„„´³named³local´³refµ„³TcpLocal„„´³named³remote´³refµ„³ TcpRemote„„„„„„³embeddedType´³refµ³ EntityRef„³Cap„„„µ³http„´³schema·³version°³definitions·³Chunk´³orµµ±string´³atom³String„„µ±bytes´³atom³
|
||||
ByteString„„„„³Headers´³dictof´³atom³Symbol„´³atom³String„„³MimeType´³atom³Symbol„³
|
||||
QueryValue´³orµµ±string´³atom³String„„µ±file´³rec´³lit³file„´³tupleµ´³named³filename´³atom³String„„´³named³headers´³refµ„³Headers„„´³named³body´³atom³
|
||||
ByteString„„„„„„„„³HostPattern´³orµµ±host´³atom³String„„µ±any´³lit€„„„„³HttpBinding´³rec´³lit³ http-bind„´³tupleµ´³named³host´³refµ„³HostPattern„„´³named³port´³atom³
SignedInteger„„´³named³method´³refµ„³
MethodPattern„„´³named³path´³refµ„³PathPattern„„´³named³handler´³embedded´³refµ„³HttpRequest„„„„„„³HttpContext´³rec´³lit³request„´³tupleµ´³named³req´³refµ„³HttpRequest„„´³named³res´³embedded´³refµ„³HttpResponse„„„„„„³HttpRequest´³rec´³lit³http-request„´³tupleµ´³named³sequenceNumber´³atom³
SignedInteger„„´³named³host´³atom³String„„´³named³port´³atom³
SignedInteger„„´³named³method´³atom³Symbol„„´³named³path´³seqof´³atom³String„„„´³named³headers´³refµ„³Headers„„´³named³query´³dictof´³atom³Symbol„´³seqof´³refµ„³
|
||||
ByteString„„„„„„„„³HostPattern´³orµµ±host´³atom³String„„µ±any´³lit€„„„„³HttpBinding´³rec´³lit³ http-bind„´³tupleµ´³named³host´³refµ„³HostPattern„„´³named³port´³atom³
SignedInteger„„´³named³method´³refµ„³
MethodPattern„„´³named³path´³refµ„³PathPattern„„´³named³handler´³embedded´³refµ„³HttpRequest„„„„„„³HttpContext´³rec´³lit³request„´³tupleµ´³named³req´³refµ„³HttpRequest„„´³named³res´³embedded´³refµ„³HttpResponse„„„„„„³HttpRequest´³rec´³lit³http-request„´³tupleµ´³named³sequenceNumber´³atom³
SignedInteger„„´³named³host´³refµ„³RequestHost„„´³named³port´³atom³
SignedInteger„„´³named³method´³atom³Symbol„„´³named³path´³seqof´³atom³String„„„´³named³headers´³refµ„³Headers„„´³named³query´³dictof´³atom³Symbol„´³seqof´³refµ„³
|
||||
QueryValue„„„„´³named³body´³refµ„³RequestBody„„„„„³HttpService´³rec´³lit³http-service„´³tupleµ´³named³host´³refµ„³HostPattern„„´³named³port´³atom³
SignedInteger„„´³named³method´³refµ„³
MethodPattern„„´³named³path´³refµ„³PathPattern„„„„„³PathPattern´³seqof´³refµ„³PathPatternElement„„³RequestBody´³orµµ±present´³atom³
|
||||
ByteString„„µ±absent´³lit€„„„„³HttpListener´³rec´³lit³
http-listener„´³tupleµ´³named³port´³atom³
SignedInteger„„„„„³HttpResponse´³orµµ±status´³rec´³lit³status„´³tupleµ´³named³code´³atom³
SignedInteger„„´³named³message´³atom³String„„„„„„µ±header´³rec´³lit³header„´³tupleµ´³named³name´³atom³Symbol„„´³named³value´³atom³String„„„„„„µ±chunk´³rec´³lit³chunk„´³tupleµ´³named³chunk´³refµ„³Chunk„„„„„„µ±done´³rec´³lit³done„´³tupleµ´³named³chunk´³refµ„³Chunk„„„„„„„„³
MethodPattern´³orµµ±any´³lit€„„µ±specific´³atom³Symbol„„„„³PathPatternElement´³orµµ±label´³atom³String„„µ±wildcard´³lit³_„„µ±rest´³lit³...„„„„„³embeddedType€„„µ³noise„´³schema·³version°³definitions·³Packet´³orµµ±complete´³atom³
|
||||
ByteString„„µ±absent´³lit€„„„„³RequestHost´³orµµ±present´³atom³String„„µ±absent´³lit€„„„„³HttpListener´³rec´³lit³
http-listener„´³tupleµ´³named³port´³atom³
SignedInteger„„„„„³HttpResponse´³orµµ±status´³rec´³lit³status„´³tupleµ´³named³code´³atom³
SignedInteger„„´³named³message´³atom³String„„„„„„µ±header´³rec´³lit³header„´³tupleµ´³named³name´³atom³Symbol„„´³named³value´³atom³String„„„„„„µ±chunk´³rec´³lit³chunk„´³tupleµ´³named³chunk´³refµ„³Chunk„„„„„„µ±done´³rec´³lit³done„´³tupleµ´³named³chunk´³refµ„³Chunk„„„„„„„„³
MethodPattern´³orµµ±any´³lit€„„µ±specific´³atom³Symbol„„„„³PathPatternElement´³orµµ±label´³atom³String„„µ±wildcard´³lit³_„„µ±rest´³lit³...„„„„„³embeddedType€„„µ³noise„´³schema·³version°³definitions·³Packet´³orµµ±complete´³atom³
|
||||
ByteString„„µ±
|
||||
fragmented´³seqof´³atom³
|
||||
ByteString„„„„„³ NoiseSpec´³andµ´³dict·³key´³named³key´³atom³
|
||||
ByteString„„³service´³named³service´³refµ„³ServiceSelector„„„„´³named³protocol´³refµ„³
NoiseProtocol„„´³named³
preSharedKeys´³refµ„³NoisePreSharedKeys„„„„³
NoiseProtocol´³orµµ±present´³dict·³protocol´³named³protocol´³atom³String„„„„„µ±invalid´³dict·³protocol´³named³protocol³any„„„„µ±absent´³dict·„„„„„³
NoiseStepType´³lit³noise„³SecretKeyField´³orµµ±present´³dict·³ secretKey´³named³ secretKey´³atom³
|
||||
ByteString„„„„„³ Initiator´³rec´³lit³ initiator„´³tupleµ´³named³initiatorSession´³embedded´³refµ„³Packet„„„„„„³ NoiseSpec´³andµ´³dict·³key´³named³key´³atom³
|
||||
ByteString„„³service´³named³service´³refµ„³ServiceSelector„„„„´³named³protocol´³refµ„³
NoiseProtocol„„´³named³
preSharedKeys´³refµ„³NoisePreSharedKeys„„„„³SessionItem´³orµµ± Initiator´³refµ„³ Initiator„„µ±Packet´³refµ„³Packet„„„„³
NoiseProtocol´³orµµ±present´³dict·³protocol´³named³protocol´³atom³String„„„„„µ±invalid´³dict·³protocol´³named³protocol³any„„„„µ±absent´³dict·„„„„„³
NoiseStepType´³lit³noise„³SecretKeyField´³orµµ±present´³dict·³ secretKey´³named³ secretKey´³atom³
|
||||
ByteString„„„„„µ±invalid´³dict·³ secretKey´³named³ secretKey³any„„„„µ±absent´³dict·„„„„„³DefaultProtocol´³lit±!Noise_NK_25519_ChaChaPoly_BLAKE2s„³NoiseStepDetail´³refµ„³ServiceSelector„³ServiceSelector³any³NoiseServiceSpec´³andµ´³named³base´³refµ„³ NoiseSpec„„´³named³ secretKey´³refµ„³SecretKeyField„„„„³NoisePreSharedKeys´³orµµ±present´³dict·³
preSharedKeys´³named³
preSharedKeys´³seqof´³atom³
|
||||
ByteString„„„„„„µ±invalid´³dict·³
preSharedKeys´³named³
preSharedKeys³any„„„„µ±absent´³dict·„„„„„³NoisePathStepDetail´³refµ„³ NoiseSpec„³NoiseDescriptionDetail´³refµ„³NoiseServiceSpec„„³embeddedType€„„µ³timer„´³schema·³version°³definitions·³SetTimer´³rec´³lit³ set-timer„´³tupleµ´³named³label³any„´³named³seconds´³atom³Double„„´³named³kind´³refµ„³ TimerKind„„„„„³ LaterThan´³rec´³lit³
|
||||
ByteString„„„„„„µ±invalid´³dict·³
preSharedKeys´³named³
preSharedKeys³any„„„„µ±absent´³dict·„„„„„³NoisePathStepDetail´³refµ„³ NoiseSpec„³NoiseDescriptionDetail´³refµ„³NoiseServiceSpec„„³embeddedType´³refµ³ EntityRef„³Cap„„„µ³timer„´³schema·³version°³definitions·³SetTimer´³rec´³lit³ set-timer„´³tupleµ´³named³label³any„´³named³seconds´³atom³Double„„´³named³kind´³refµ„³ TimerKind„„„„„³ LaterThan´³rec´³lit³
|
||||
later-than„´³tupleµ´³named³seconds´³atom³Double„„„„„³ TimerKind´³orµµ±relative´³lit³relative„„µ±absolute´³lit³absolute„„µ±clear´³lit³clear„„„„³TimerExpired´³rec´³lit³
timer-expired„´³tupleµ´³named³label³any„´³named³seconds´³atom³Double„„„„„„³embeddedType€„„µ³trace„´³schema·³version°³definitions·³Oid³any³Name´³orµµ± anonymous´³rec´³lit³ anonymous„´³tupleµ„„„„µ±named´³rec´³lit³named„´³tupleµ´³named³name³any„„„„„„„³Target´³rec´³lit³entity„´³tupleµ´³named³actor´³refµ„³ActorId„„´³named³facet´³refµ„³FacetId„„´³named³oid´³refµ„³Oid„„„„„³TaskId³any³TurnId³any³ActorId³any³FacetId³any³ TurnCause´³orµµ±turn´³rec´³lit³ caused-by„´³tupleµ´³named³id´³refµ„³TurnId„„„„„„µ±cleanup´³rec´³lit³cleanup„´³tupleµ„„„„µ±linkedTaskRelease´³rec´³lit³linked-task-release„´³tupleµ´³named³id´³refµ„³TaskId„„´³named³reason´³refµ„³LinkedTaskReleaseReason„„„„„„µ±periodicActivation´³rec´³lit³periodic-activation„´³tupleµ´³named³period´³atom³Double„„„„„„µ±delay´³rec´³lit³delay„´³tupleµ´³named³causingTurn´³refµ„³TurnId„„´³named³amount´³atom³Double„„„„„„µ±external´³rec´³lit³external„´³tupleµ´³named³description³any„„„„„„„³ TurnEvent´³orµµ±assert´³rec´³lit³assert„´³tupleµ´³named³ assertion´³refµ„³AssertionDescription„„´³named³handle´³refµ³protocol„³Handle„„„„„„µ±retract´³rec´³lit³retract„´³tupleµ´³named³handle´³refµ³protocol„³Handle„„„„„„µ±message´³rec´³lit³message„´³tupleµ´³named³body´³refµ„³AssertionDescription„„„„„„µ±sync´³rec´³lit³sync„´³tupleµ´³named³peer´³refµ„³Target„„„„„„µ± breakLink´³rec´³lit³
|
||||
break-link„´³tupleµ´³named³source´³refµ„³ActorId„„´³named³handle´³refµ³protocol„³Handle„„„„„„„„³
|
||||
ExitStatus´³orµµ±ok´³lit³ok„„µ±Error´³refµ³protocol„³Error„„„„³
|
||||
|
@ -40,5 +40,5 @@ ByteString
|
|||
RunService´³rec´³lit³run-service„´³tupleµ´³named³serviceName³any„„„„³ServiceState´³rec´³lit³
service-state„´³tupleµ´³named³serviceName³any„´³named³state´³refµ„³State„„„„„³
ServiceObject´³rec´³lit³service-object„´³tupleµ´³named³serviceName³any„´³named³object³any„„„„³RequireService´³rec´³lit³require-service„´³tupleµ´³named³serviceName³any„„„„³RestartService´³rec´³lit³restart-service„´³tupleµ´³named³serviceName³any„„„„³ServiceDependency´³rec´³lit³
|
||||
depends-on„´³tupleµ´³named³depender³any„´³named³dependee´³refµ„³ServiceState„„„„„„³embeddedType´³refµ³ EntityRef„³Cap„„„µ³protocol„´³schema·³version°³definitions·³Oid´³atom³
SignedInteger„³Sync´³rec´³lit³S„´³tupleµ´³named³peer´³embedded´³lit<69>„„„„„„³Turn´³seqof´³refµ„³ TurnEvent„„³Error´³rec´³lit³error„´³tupleµ´³named³message´³atom³String„„´³named³detail³any„„„„³Event´³orµµ±Assert´³refµ„³Assert„„µ±Retract´³refµ„³Retract„„µ±Message´³refµ„³Message„„µ±Sync´³refµ„³Sync„„„„³Assert´³rec´³lit³A„´³tupleµ´³named³ assertion´³refµ„³ Assertion„„´³named³handle´³refµ„³Handle„„„„„³Handle´³atom³
SignedInteger„³Packet´³orµµ±Turn´³refµ„³Turn„„µ±Error´³refµ„³Error„„µ± Extension´³refµ„³ Extension„„„„³Message´³rec´³lit³M„´³tupleµ´³named³body´³refµ„³ Assertion„„„„„³Retract´³rec´³lit³R„´³tupleµ´³named³handle´³refµ„³Handle„„„„„³ Assertion³any³ Extension´³rec´³named³label³any„´³named³fields´³seqof³any„„„³ TurnEvent´³tupleµ´³named³oid´³refµ„³Oid„„´³named³event´³refµ„³Event„„„„„³embeddedType€„„µ³ dataspace„´³schema·³version°³definitions·³Observe´³rec´³lit³Observe„´³tupleµ´³named³pattern´³refµ³dataspacePatterns„³Pattern„„´³named³observer´³embedded³any„„„„„„³embeddedType´³refµ³ EntityRef„³Cap„„„µ³
|
||||
gatekeeper„´³schema·³version°³definitions·³Bind´³rec´³lit³bind„´³tupleµ´³named³description´³refµ„³Description„„´³named³target´³embedded³any„„´³named³observer´³refµ„³BindObserver„„„„„³Step´³rec´³named³stepType´³atom³Symbol„„´³tupleµ´³named³detail³any„„„„³Bound´³orµµ±bound´³rec´³lit³bound„´³tupleµ´³named³pathStep´³refµ„³PathStep„„„„„„µ±Rejected´³refµ„³Rejected„„„„³Route´³rec´³lit³route„´³tuplePrefixµ´³named³
|
||||
transports´³seqof³any„„„´³named³ pathSteps´³seqof´³refµ„³PathStep„„„„„³Resolve´³rec´³lit³resolve„´³tupleµ´³named³step´³refµ„³Step„„´³named³observer´³embedded´³refµ„³Resolved„„„„„„³PathStep´³rec´³named³stepType´³atom³Symbol„„´³tupleµ´³named³detail³any„„„„³Rejected´³rec´³lit³rejected„´³tupleµ´³named³detail³any„„„„³Resolved´³orµµ±accepted´³rec´³lit³accepted„´³tupleµ´³named³responderSession´³embedded³any„„„„„„µ±Rejected´³refµ„³Rejected„„„„³Description´³rec´³named³stepType´³atom³Symbol„„´³tupleµ´³named³detail³any„„„„³ResolvePath´³rec´³lit³resolve-path„´³tupleµ´³named³route´³refµ„³Route„„´³named³addr³any„´³named³control´³embedded´³refµ„³TransportControl„„„´³named³resolved´³refµ„³Resolved„„„„„³BindObserver´³orµµ±present´³embedded´³refµ„³Bound„„„µ±absent´³lit€„„„„³ForceDisconnect´³rec´³lit³force-disconnect„´³tupleµ„„„³ResolvedPathStep´³rec´³lit³ path-step„´³tupleµ´³named³origin´³embedded´³refµ„³Resolve„„„´³named³pathStep´³refµ„³PathStep„„´³named³resolved´³refµ„³Resolved„„„„„³TransportControl´³refµ„³ForceDisconnect„³TransportConnection´³rec´³lit³connect-transport„´³tupleµ´³named³addr³any„´³named³control´³embedded´³refµ„³TransportControl„„„´³named³resolved´³refµ„³Resolved„„„„„„³embeddedType´³refµ³ EntityRef„³Cap„„„µ³transportAddress„´³schema·³version°³definitions·³Tcp´³rec´³lit³tcp„´³tupleµ´³named³host´³atom³String„„´³named³port´³atom³
SignedInteger„„„„„³Unix´³rec´³lit³unix„´³tupleµ´³named³path´³atom³String„„„„„³Stdio´³rec´³lit³stdio„´³tupleµ„„„³ WebSocket´³rec´³lit³ws„´³tupleµ´³named³url´³atom³String„„„„„„³embeddedType€„„µ³dataspacePatterns„´³schema·³version°³definitions·³DLit´³rec´³lit³lit„´³tupleµ´³named³value´³refµ„³AnyAtom„„„„„³DBind´³rec´³lit³bind„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„³AnyAtom´³orµµ±bool´³atom³Boolean„„µ±double´³atom³Double„„µ±int´³atom³
SignedInteger„„µ±string´³atom³String„„µ±bytes´³atom³
|
||||
ByteString„„µ±symbol´³atom³Symbol„„µ±embedded´³embedded³any„„„„³Pattern´³orµµ±DDiscard´³refµ„³DDiscard„„µ±DBind´³refµ„³DBind„„µ±DLit´³refµ„³DLit„„µ± DCompound´³refµ„³ DCompound„„„„³DDiscard´³rec´³lit³_„´³tupleµ„„„³ DCompound´³orµµ±rec´³rec´³lit³rec„´³tupleµ´³named³label³any„´³named³fields´³seqof´³refµ„³Pattern„„„„„„„µ±arr´³rec´³lit³arr„´³tupleµ´³named³items´³seqof´³refµ„³Pattern„„„„„„„µ±dict´³rec´³lit³dict„´³tupleµ´³named³entries´³dictof³any´³refµ„³Pattern„„„„„„„„„„³embeddedType´³refµ³ EntityRef„³Cap„„„„„
|
||||
transports´³seqof³any„„„´³named³ pathSteps´³seqof´³refµ„³PathStep„„„„„³Resolve´³rec´³lit³resolve„´³tupleµ´³named³step´³refµ„³Step„„´³named³observer´³embedded´³refµ„³Resolved„„„„„„³PathStep´³rec´³named³stepType´³atom³Symbol„„´³tupleµ´³named³detail³any„„„„³Rejected´³rec´³lit³rejected„´³tupleµ´³named³detail³any„„„„³Resolved´³orµµ±accepted´³rec´³lit³accepted„´³tupleµ´³named³responderSession´³embedded³any„„„„„„µ±Rejected´³refµ„³Rejected„„„„³Description´³rec´³named³stepType´³atom³Symbol„„´³tupleµ´³named³detail³any„„„„³ResolvePath´³rec´³lit³resolve-path„´³tupleµ´³named³route´³refµ„³Route„„´³named³addr³any„´³named³control´³embedded´³refµ„³TransportControl„„„´³named³resolved´³refµ„³Resolved„„„„„³BindObserver´³orµµ±present´³embedded´³refµ„³Bound„„„µ±absent´³lit€„„„„³ForceDisconnect´³rec´³lit³force-disconnect„´³tupleµ„„„³ResolvedPathStep´³rec´³lit³ path-step„´³tupleµ´³named³origin´³embedded´³refµ„³Resolve„„„´³named³pathStep´³refµ„³PathStep„„´³named³resolved´³refµ„³Resolved„„„„„³TransportControl´³refµ„³ForceDisconnect„³TransportConnection´³rec´³lit³connect-transport„´³tupleµ´³named³addr³any„´³named³control´³embedded´³refµ„³TransportControl„„„´³named³resolved´³refµ„³Resolved„„„„„„³embeddedType´³refµ³ EntityRef„³Cap„„„µ³transportAddress„´³schema·³version°³definitions·³Tcp´³rec´³lit³tcp„´³tupleµ´³named³host´³atom³String„„´³named³port´³atom³
SignedInteger„„„„„³Unix´³rec´³lit³unix„´³tupleµ´³named³path´³atom³String„„„„„³Stdio´³rec´³lit³stdio„´³tupleµ„„„³ WebSocket´³rec´³lit³ws„´³tupleµ´³named³url´³atom³String„„„„„„³embeddedType€„„µ³dataspacePatterns„´³schema·³version°³definitions·³AnyAtom´³orµµ±bool´³atom³Boolean„„µ±double´³atom³Double„„µ±int´³atom³
SignedInteger„„µ±string´³atom³String„„µ±bytes´³atom³
|
||||
ByteString„„µ±symbol´³atom³Symbol„„µ±embedded´³embedded³any„„„„³Pattern´³orµµ±discard´³rec´³lit³_„´³tupleµ„„„„µ±bind´³rec´³lit³bind„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„„µ±lit´³rec´³lit³lit„´³tupleµ´³named³value´³refµ„³AnyAtom„„„„„„µ±group´³rec´³lit³group„´³tupleµ´³named³type´³refµ„³ GroupType„„´³named³entries´³dictof³any´³refµ„³Pattern„„„„„„„„„³ GroupType´³orµµ±rec´³rec´³lit³rec„´³tupleµ´³named³label³any„„„„„µ±arr´³rec´³lit³arr„´³tupleµ„„„„µ±dict´³rec´³lit³dict„´³tupleµ„„„„„„„³embeddedType´³refµ³ EntityRef„³Cap„„„„„
|
|
@ -1,15 +1,23 @@
|
|||
version 1 .
|
||||
embeddedType EntityRef.Cap .
|
||||
|
||||
# Dataspace patterns: a sublanguage of attenuation patterns.
|
||||
Pattern = DDiscard / DBind / DLit / DCompound .
|
||||
# Dataspace patterns: *almost* a sublanguage of attenuation patterns.
|
||||
#
|
||||
# One key difference is that Dataspace patterns are extensible, in that
|
||||
# they ignore fields not mentioned in group patterns.
|
||||
|
||||
DDiscard = <_>.
|
||||
DBind = <bind @pattern Pattern>.
|
||||
DLit = <lit @value AnyAtom>.
|
||||
DCompound = <rec @label any @fields [Pattern ...]>
|
||||
/ <arr @items [Pattern ...]>
|
||||
/ <dict @entries { any: Pattern ...:... }> .
|
||||
Pattern =
|
||||
/ @discard <_>
|
||||
/ <bind @pattern Pattern>
|
||||
/ <lit @value AnyAtom>
|
||||
/ <group @type GroupType @entries { any: Pattern ...:... }>
|
||||
.
|
||||
|
||||
GroupType =
|
||||
/ <rec @label any>
|
||||
/ <arr>
|
||||
/ <dict>
|
||||
.
|
||||
|
||||
AnyAtom =
|
||||
/ @bool bool
|
||||
|
|
|
@ -13,8 +13,37 @@ Step = <<rec> @stepType symbol [@detail any]> .
|
|||
# ---------------------------------------------------------------------------
|
||||
# Protocol at dataspaces *associated* with gatekeeper entities
|
||||
|
||||
# Assertion. Gatekeeper will compute an appropriate PathStep from `description` pointing at
|
||||
# `target`, and will respond with a `Bound` to `observer` (if supplied).
|
||||
# ## Handling `Resolve` requests
|
||||
#
|
||||
# When the gatekeeper entity receives a `Resolve` assertion (call it R1), it
|
||||
#
|
||||
# 1. asserts a `Resolve` (call it R2) into its associated dataspace that
|
||||
# is the same as R1 except it has a different `observer`; and
|
||||
#
|
||||
# 2. observes a `Bind` with `description` matching the `step` of R1/R2
|
||||
# according to `stepType` (e.g. treatment of SturdyStepType is not the
|
||||
# same as treatment of NoiseStepType).
|
||||
#
|
||||
# Normally, an appropriate `Bind` is expected to exist. If the gatekeeper
|
||||
# sees the `Bind` first, it takes the `target` from it and does whatever
|
||||
# `stepType` mandates before replying to R1's observer.
|
||||
#
|
||||
# However, if a `Resolved` is asserted to R2's observer before a `Bind`
|
||||
# appears, that resolution is relayed on to R1's observer directly, be it
|
||||
# positive or negative, and the gatekeeper stops waiting for a `Bind`.
|
||||
#
|
||||
# This way, entities can keep an eye out for `Resolve` requests that will
|
||||
# never complete, and answer `Rejected` to them even when no matching
|
||||
# `Bind` exists. Entities could also use `Resolve` requests to synthesize a
|
||||
# `Bind` in a "just-in-time" fashion.
|
||||
#
|
||||
# ## General treatment of `Bind` assertions
|
||||
#
|
||||
# When the gatekeeper sees a `Bind`, independently of any potential
|
||||
# `Resolve` requests, it computes an appropriate PathStep from
|
||||
# `description` pointing at `target`, and responds with a `Bound` to
|
||||
# `observer` (if supplied).
|
||||
#
|
||||
Bind = <bind @description Description @target #:any @observer BindObserver> .
|
||||
Description = <<rec> @stepType symbol [@detail any]> .
|
||||
BindObserver = @present #:Bound / @absent #f .
|
||||
|
|
|
@ -21,7 +21,7 @@ MethodPattern = @any #f / @specific @"Lowercase" symbol .
|
|||
# Assertion in driver DS
|
||||
HttpRequest = <http-request
|
||||
@sequenceNumber int
|
||||
@host string
|
||||
@host RequestHost
|
||||
@port int
|
||||
@method @"Lowercase" symbol
|
||||
@path [string ...]
|
||||
|
@ -32,13 +32,24 @@ HttpRequest = <http-request
|
|||
Headers = {@"Lowercase" symbol: string ...:...} .
|
||||
QueryValue = @string string / <file @filename string @headers Headers @body bytes> .
|
||||
RequestBody = @present bytes / @absent #f .
|
||||
RequestHost = @present string / @absent #f .
|
||||
|
||||
# Assertion to handler entity
|
||||
HttpContext = <request @req HttpRequest @res #:HttpResponse> .
|
||||
|
||||
# HttpResponse protocol. Delivered to the `res` ref in `HttpContext`.
|
||||
#
|
||||
# (status | header)* . chunk* . done
|
||||
#
|
||||
# Done triggers completion of the response and retraction of the frame by the peer. If the
|
||||
# HttpBinding responsible for the request is withdrawn mid-way through a response (i.e. when
|
||||
# chunked transfer is used and at least one chunk has been sent) the request is abruptly
|
||||
# closed; if it is withdrawn at any other moment in the lifetime of the request, a 500 Internal
|
||||
# Server Error is send to the client.
|
||||
#
|
||||
@<TODO "trailers?">
|
||||
# Messages
|
||||
HttpResponse =
|
||||
# Messages.
|
||||
/ <status @code int @message string>
|
||||
/ <header @name symbol @value string>
|
||||
/ <chunk @chunk Chunk>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
version 1 .
|
||||
embeddedType EntityRef.Cap .
|
||||
|
||||
# https://noiseprotocol.org/
|
||||
|
||||
|
@ -42,13 +43,30 @@ DefaultProtocol = "Noise_NK_25519_ChaChaPoly_BLAKE2s" .
|
|||
# sequence is exhausted or not supplied, an all-zeros key is used each time a PSK is needed.
|
||||
NoisePreSharedKeys = @present { preSharedKeys: [bytes ...] } / @invalid { preSharedKeys: any } / @absent {} .
|
||||
|
||||
# Sessions proceed by sending Packets to the initiatorSession and responderSession according to
|
||||
# the Noise protocol definition. Each Packet represents a complete logical unit of
|
||||
# ---------------------------------------------------------------------------
|
||||
# Handshaking and running a session
|
||||
|
||||
# 1. initiator asserts <resolve <noise ServiceSelector> #:A> at Gatekeeper
|
||||
# 2. gatekeeper asserts <accepted #:B> at #:A
|
||||
# 3. initiator asserts <initiator #:C> at #:B and then sends `Packet`s to #:B
|
||||
# 4. responder sends `Packet`s to #:C
|
||||
#
|
||||
# Sessions begin with introduction of initiator (#:C) and responder (#:B) to each other, and
|
||||
# then proceed by sending `Packet`s (from #:C) to #:B and (from #:B) to #:C according to
|
||||
# the Noise protocol definition. Each `Packet` represents a complete logical unit of
|
||||
# communication; for example, a complete Turn when layering the Syndicate protocol over Noise.
|
||||
# Note well the restriction on Noise messages: no individual complete packet or packet fragment
|
||||
# may exceed 65535 bytes (N.B. not 65536!). When `fragmented`, each portion of a Packet is a
|
||||
# may exceed 65535 bytes (N.B. not 65536!). When `fragmented`, each portion of a `Packet` is a
|
||||
# complete Noise "transport message"; when `complete`, the whole thing is likewise a complete
|
||||
# "transport message".
|
||||
#
|
||||
# Retraction of the `Initiator` ends the session from the initiator-side; retraction of the
|
||||
# `<accepted ...>` assertion ends the session from the responder-side.
|
||||
|
||||
SessionItem = Initiator / Packet .
|
||||
# Assertion
|
||||
Initiator = <initiator @initiatorSession #:Packet> .
|
||||
# Message
|
||||
Packet = @complete bytes / @fragmented [bytes ...] .
|
||||
|
||||
# When layering Syndicate protocol over noise,
|
||||
|
|
|
@ -1214,6 +1214,8 @@ impl Activation {
|
|||
// just drop 'em so they don't run next time
|
||||
std::mem::take(&mut self.commit_actions);
|
||||
}
|
||||
self.single_queue = None;
|
||||
self.multiple_queues = None;
|
||||
tracing::trace!("Activation::rollback complete");
|
||||
}
|
||||
|
||||
|
@ -1837,7 +1839,16 @@ impl Activation {
|
|||
) {
|
||||
match &*exit_status {
|
||||
ExitStatus::Normal => assert!(self.get_facet(self.root).is_none()),
|
||||
ExitStatus::Dropped | ExitStatus::Error(_) => (),
|
||||
ExitStatus::Dropped => {
|
||||
// If we panicked, facet_id will be Some(_), but leaving it this way as we
|
||||
// enter take_turn causes a nested panic, so we clear it here.
|
||||
if self.facet_id.is_some() {
|
||||
tracing::debug!(actor_id=?self.actor_id, facet_id=?self.facet_id,
|
||||
"clearing facet_id (we must have panicked mid-Turn)");
|
||||
self.facet_id = None;
|
||||
}
|
||||
}
|
||||
ExitStatus::Error(_) => (),
|
||||
}
|
||||
|
||||
let cause = Some(trace::TurnCause::Cleanup);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::schemas::dataspace_patterns::*;
|
||||
|
||||
use super::language;
|
||||
|
@ -8,23 +10,25 @@ use preserves::value::Record;
|
|||
use preserves::value::Value;
|
||||
use preserves_schema::Codec;
|
||||
|
||||
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub enum PathStep {
|
||||
Index(usize),
|
||||
Key(_Any),
|
||||
}
|
||||
|
||||
pub type PathStep = _Any;
|
||||
pub type Path = Vec<PathStep>;
|
||||
pub type Paths = Vec<Path>;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct ConstantPositions {
|
||||
pub with_values: Paths,
|
||||
pub required_to_exist: Paths,
|
||||
}
|
||||
|
||||
struct Analyzer {
|
||||
pub const_paths: Paths,
|
||||
pub const_values: Vec<_Any>,
|
||||
pub checked_paths: Paths,
|
||||
pub capture_paths: Paths,
|
||||
}
|
||||
|
||||
pub struct PatternAnalysis {
|
||||
pub const_paths: Paths,
|
||||
pub const_positions: Arc<ConstantPositions>,
|
||||
pub const_values: _Any,
|
||||
pub capture_paths: Paths,
|
||||
}
|
||||
|
@ -38,11 +42,15 @@ impl PatternAnalysis {
|
|||
let mut analyzer = Analyzer {
|
||||
const_paths: Vec::new(),
|
||||
const_values: Vec::new(),
|
||||
checked_paths: Vec::new(),
|
||||
capture_paths: Vec::new(),
|
||||
};
|
||||
analyzer.walk(&mut Vec::new(), p);
|
||||
PatternAnalysis {
|
||||
const_paths: analyzer.const_paths,
|
||||
const_positions: Arc::new(ConstantPositions {
|
||||
with_values: analyzer.const_paths,
|
||||
required_to_exist: analyzer.checked_paths,
|
||||
}),
|
||||
const_values: _Any::new(analyzer.const_values),
|
||||
capture_paths: analyzer.capture_paths,
|
||||
}
|
||||
|
@ -58,34 +66,21 @@ impl Analyzer {
|
|||
|
||||
fn walk(&mut self, path: &mut Path, p: &Pattern) {
|
||||
match p {
|
||||
Pattern::DCompound(b) => match &**b {
|
||||
DCompound::Rec { fields, .. } => {
|
||||
for (i, p) in fields.iter().enumerate() {
|
||||
self.walk_step(path, PathStep::Index(i), p);
|
||||
}
|
||||
}
|
||||
DCompound::Arr { items, .. } => {
|
||||
for (i, p) in items.iter().enumerate() {
|
||||
self.walk_step(path, PathStep::Index(i), p);
|
||||
}
|
||||
}
|
||||
DCompound::Dict { entries, .. } => {
|
||||
for (k, p) in entries {
|
||||
self.walk_step(path, PathStep::Key(k.clone()), p);
|
||||
}
|
||||
Pattern::Group { entries, .. } => {
|
||||
for (k, p) in entries {
|
||||
self.walk_step(path, k.clone(), p)
|
||||
}
|
||||
}
|
||||
Pattern::DBind(b) => {
|
||||
let DBind { pattern, .. } = &**b;
|
||||
Pattern::Bind { pattern } => {
|
||||
self.capture_paths.push(path.clone());
|
||||
self.walk(path, pattern)
|
||||
self.walk(path, &**pattern);
|
||||
}
|
||||
Pattern::DDiscard(_) =>
|
||||
(),
|
||||
Pattern::DLit(b) => {
|
||||
let DLit { value } = &**b;
|
||||
Pattern::Discard => {
|
||||
self.checked_paths.push(path.clone());
|
||||
}
|
||||
Pattern::Lit { value } => {
|
||||
self.const_paths.push(path.clone());
|
||||
self.const_values.push(language().unparse(value));
|
||||
self.const_values.push(language().unparse(&**value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,52 +104,47 @@ impl PatternMatcher {
|
|||
}
|
||||
}
|
||||
|
||||
fn run_seq<'a, F: 'a + Fn(usize) -> &'a _Any>(&mut self, entries: &Map<_Any, Pattern<_Any>>, values: F) -> bool {
|
||||
for (k, p) in entries {
|
||||
match k.value().as_usize() {
|
||||
None => return false,
|
||||
Some(i) => if !self.run(p, values(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn run(&mut self, pattern: &Pattern<_Any>, value: &_Any) -> bool {
|
||||
match pattern {
|
||||
Pattern::DDiscard(_) => true,
|
||||
Pattern::DBind(b) => {
|
||||
Pattern::Discard => true,
|
||||
Pattern::Bind { pattern } => {
|
||||
self.captures.push(value.clone());
|
||||
self.run(&b.pattern, value)
|
||||
self.run(&**pattern, value)
|
||||
}
|
||||
Pattern::DLit(b) => value == &language().unparse(&b.value),
|
||||
Pattern::DCompound(b) => match &**b {
|
||||
DCompound::Rec { label, fields } => {
|
||||
match value.value().as_record(Some(fields.len())) {
|
||||
Pattern::Lit { value: expected } => value == &language().unparse(&**expected),
|
||||
Pattern::Group { type_, entries } => match &**type_ {
|
||||
GroupType::Rec { label } => {
|
||||
match value.value().as_record(None) {
|
||||
None => false,
|
||||
Some(r) => {
|
||||
if r.label() != label {
|
||||
return false;
|
||||
}
|
||||
for (i, p) in fields.iter().enumerate() {
|
||||
if !self.run(p, &r.fields()[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
Some(r) =>
|
||||
r.label() == label &&
|
||||
self.run_seq(entries, |i| &r.fields()[i])
|
||||
}
|
||||
}
|
||||
DCompound::Arr { items } => {
|
||||
GroupType::Arr => {
|
||||
match value.value().as_sequence() {
|
||||
None => false,
|
||||
Some(vs) => {
|
||||
if vs.len() != items.len() {
|
||||
return false;
|
||||
}
|
||||
for (i, p) in items.iter().enumerate() {
|
||||
if !self.run(p, &vs[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
Some(vs) =>
|
||||
self.run_seq(entries, |i| &vs[i])
|
||||
}
|
||||
}
|
||||
DCompound::Dict { entries: expected_entries } => {
|
||||
GroupType::Dict => {
|
||||
match value.value().as_dictionary() {
|
||||
None => false,
|
||||
Some(actual_entries) => {
|
||||
for (k, p) in expected_entries.iter() {
|
||||
for (k, p) in entries {
|
||||
if !actual_entries.get(k).map(|v| self.run(p, v)).unwrap_or(false) {
|
||||
return false;
|
||||
}
|
||||
|
@ -170,42 +160,68 @@ impl PatternMatcher {
|
|||
|
||||
pub fn lift_literal(v: &_Any) -> Pattern {
|
||||
match v.value() {
|
||||
Value::Record(r) => Pattern::DCompound(Box::new(DCompound::Rec {
|
||||
label: r.label().clone(),
|
||||
fields: r.fields().iter().map(lift_literal).collect(),
|
||||
})),
|
||||
Value::Sequence(items) => Pattern::DCompound(Box::new(DCompound::Arr {
|
||||
items: items.iter().map(lift_literal).collect(),
|
||||
})),
|
||||
Value::Record(r) => Pattern::Group {
|
||||
type_: Box::new(GroupType::Rec { label: r.label().clone() }),
|
||||
entries: r.fields().iter().enumerate()
|
||||
.map(|(i, v)| (_Any::new(i), lift_literal(v)))
|
||||
.collect(),
|
||||
},
|
||||
Value::Sequence(items) => Pattern::Group {
|
||||
type_: Box::new(GroupType::Arr),
|
||||
entries: items.iter().enumerate()
|
||||
.map(|(i, v)| (_Any::new(i), lift_literal(v)))
|
||||
.collect(),
|
||||
},
|
||||
Value::Set(_members) => panic!("Cannot express literal set in pattern"),
|
||||
Value::Dictionary(entries) => Pattern::DCompound(Box::new(DCompound::Dict {
|
||||
entries: entries.iter().map(|(k, v)| (k.clone(), lift_literal(v))).collect(),
|
||||
})),
|
||||
_other => Pattern::DLit(Box::new(DLit {
|
||||
value: language().parse(v).expect("Non-compound datum can be converted to AnyAtom"),
|
||||
})),
|
||||
Value::Dictionary(entries) => Pattern::Group {
|
||||
type_: Box::new(GroupType::Dict),
|
||||
entries: entries.iter()
|
||||
.map(|(k, v)| (k.clone(), lift_literal(v)))
|
||||
.collect(),
|
||||
},
|
||||
_other => Pattern::Lit {
|
||||
value: Box::new(language().parse(v).expect("Non-compound datum can be converted to AnyAtom")),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const DISCARD: Pattern = Pattern::Discard;
|
||||
|
||||
pub fn pattern_seq_from_dictionary(entries: &Map<_Any, Pattern>) -> Option<Vec<&Pattern>> {
|
||||
let mut max_k: Option<usize> = None;
|
||||
for k in entries.keys() {
|
||||
max_k = max_k.max(Some(k.value().as_usize()?));
|
||||
}
|
||||
let mut seq = vec![];
|
||||
if let Some(max_k) = max_k {
|
||||
seq.reserve(max_k + 1);
|
||||
for i in 0..=max_k {
|
||||
seq.push(entries.get(&_Any::new(i)).unwrap_or(&DISCARD));
|
||||
}
|
||||
}
|
||||
return Some(seq);
|
||||
}
|
||||
|
||||
fn drop_literal_entries_seq(mut seq: Vec<_Any>, entries: &Map<_Any, Pattern>) -> Option<Vec<_Any>> {
|
||||
for p in pattern_seq_from_dictionary(entries)?.into_iter() {
|
||||
seq.push(drop_literal(p)?);
|
||||
}
|
||||
Some(seq)
|
||||
}
|
||||
|
||||
pub fn drop_literal(p: &Pattern) -> Option<_Any> {
|
||||
match p {
|
||||
Pattern::DCompound(b) => match &**b {
|
||||
DCompound::Rec { label, fields } => {
|
||||
let mut r = vec![label.clone()];
|
||||
for f in fields.iter() {
|
||||
r.push(drop_literal(f)?);
|
||||
}
|
||||
Some(Value::Record(Record(r)).wrap())
|
||||
}
|
||||
DCompound::Arr { items } =>
|
||||
Some(Value::Sequence(items.iter().map(drop_literal)
|
||||
.collect::<Option<Vec<_Any>>>()?).wrap()),
|
||||
DCompound::Dict { entries } =>
|
||||
Some(Value::Dictionary(entries.iter()
|
||||
.map(|(k, p)| Some((k.clone(), drop_literal(p)?)))
|
||||
.collect::<Option<Map<_Any, _Any>>>()?).wrap()),
|
||||
Pattern::Group { type_, entries } => match &**type_ {
|
||||
GroupType::Rec { label } =>
|
||||
Some(Value::Record(Record(drop_literal_entries_seq(vec![label.clone()], entries)?)).wrap()),
|
||||
GroupType::Arr =>
|
||||
Some(Value::Sequence(drop_literal_entries_seq(vec![], entries)?).wrap()),
|
||||
GroupType::Dict =>
|
||||
Some(Value::Dictionary(entries.iter()
|
||||
.map(|(k, p)| Some((k.clone(), drop_literal(p)?)))
|
||||
.collect::<Option<Map<_Any, _Any>>>()?).wrap()),
|
||||
},
|
||||
Pattern::DLit(b) => Some(language().unparse(&b.value)),
|
||||
Pattern::Lit { value } => Some(language().unparse(&**value)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ use preserves::value::Map;
|
|||
use preserves::value::NestedValue;
|
||||
use preserves::value::NoEmbeddedDomainCodec;
|
||||
use preserves::value::PackedWriter;
|
||||
use preserves::value::Set;
|
||||
use preserves::value::TextWriter;
|
||||
use preserves::value::ViaCodec;
|
||||
use preserves::value::Writer;
|
||||
|
@ -76,6 +77,7 @@ struct Membranes {
|
|||
exported: Membrane,
|
||||
imported: Membrane,
|
||||
next_export_oid: usize,
|
||||
reimported_attenuations: Map<sturdy::Oid, Set<Arc<Cap>>>,
|
||||
}
|
||||
|
||||
pub enum Input {
|
||||
|
@ -172,6 +174,11 @@ impl Membrane {
|
|||
ws
|
||||
}
|
||||
|
||||
fn remove(&mut self, ws: &Arc<WireSymbol>) {
|
||||
self.oid_map.remove(&ws.oid);
|
||||
self.ref_map.remove(&ws.obj);
|
||||
}
|
||||
|
||||
fn insert_inert_entity(&mut self, t: &mut Activation, oid: sturdy::Oid) -> Arc<WireSymbol> {
|
||||
self.insert(oid, Cap::new(&t.inert_entity()))
|
||||
}
|
||||
|
@ -221,7 +228,57 @@ impl std::fmt::Debug for Membrane {
|
|||
macro_rules! dump_membranes { ($e:expr) => { tracing::trace!("membranes: {:#?}", $e); } }
|
||||
// macro_rules! dump_membranes { ($e:expr) => { (); } }
|
||||
|
||||
/// Main entry point for stdio-based Syndicate services.
|
||||
pub async fn stdio_service<F>(f: F) -> !
|
||||
where
|
||||
F: 'static + Send + FnOnce(&mut Activation) -> Result<Arc<Cap>, ActorError>
|
||||
{
|
||||
let result = Actor::top(None, move |t| {
|
||||
let service = f(t)?;
|
||||
Ok(TunnelRelay::stdio_service(t, service))
|
||||
}).await;
|
||||
|
||||
// Because we're currently using tokio::io::stdin(), which can prevent shutdown of the
|
||||
// runtime, this routine uses std::process::exit directly as a special case. It's a
|
||||
// stopgap: eventually, we'd like to do things Properly, as indicated in the comment
|
||||
// attached (at the time of writing) to tokio::io::stdin(), which reads in part:
|
||||
//
|
||||
// This handle is best used for non-interactive uses, such as when a file
|
||||
// is piped into the application. For technical reasons, `stdin` is
|
||||
// implemented by using an ordinary blocking read on a separate thread, and
|
||||
// it is impossible to cancel that read. This can make shutdown of the
|
||||
// runtime hang until the user presses enter.
|
||||
//
|
||||
// For interactive uses, it is recommended to spawn a thread dedicated to
|
||||
// user input and use blocking IO directly in that thread.
|
||||
//
|
||||
// TODO: Revisit this.
|
||||
|
||||
match result {
|
||||
Ok(Ok(())) => {
|
||||
std::process::exit(0);
|
||||
}
|
||||
Ok(Err(e)) => {
|
||||
tracing::error!("Main stdio_service actor failed: {}", e);
|
||||
std::process::exit(1);
|
||||
},
|
||||
Err(e) => {
|
||||
tracing::error!("Join of main stdio_service actor failed: {}", e);
|
||||
std::process::exit(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TunnelRelay {
|
||||
pub fn stdio_service(t: &mut Activation, service: Arc<Cap>) -> () {
|
||||
TunnelRelay::run(t,
|
||||
Input::Bytes(Box::pin(tokio::io::stdin())),
|
||||
Output::Bytes(Box::pin(tokio::io::stdout())),
|
||||
Some(service),
|
||||
None,
|
||||
false);
|
||||
}
|
||||
|
||||
pub fn run(
|
||||
t: &mut Activation,
|
||||
i: Input,
|
||||
|
@ -259,6 +316,7 @@ impl TunnelRelay {
|
|||
exported: Membrane::new(WireSymbolSide::Exported),
|
||||
imported: Membrane::new(WireSymbolSide::Imported),
|
||||
next_export_oid: 0,
|
||||
reimported_attenuations: Map::new(),
|
||||
},
|
||||
pending_outbound: Vec::new(),
|
||||
};
|
||||
|
@ -550,9 +608,10 @@ impl Membranes {
|
|||
#[inline]
|
||||
fn release_one(&mut self, ws: Arc<WireSymbol>) -> bool {
|
||||
if ws.dec_ref() {
|
||||
let membrane = self.membrane(ws.side);
|
||||
membrane.oid_map.remove(&ws.oid);
|
||||
membrane.ref_map.remove(&ws.obj);
|
||||
if let WireSymbolSide::Exported = ws.side {
|
||||
self.reimported_attenuations.remove(&ws.oid);
|
||||
}
|
||||
self.membrane(ws.side).remove(&ws);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
@ -573,34 +632,43 @@ impl Membranes {
|
|||
src: &'src mut S,
|
||||
_read_annotations: bool,
|
||||
) -> io::Result<Arc<Cap>> {
|
||||
let ws = match sturdy::WireRef::deserialize(&mut src.packed(NoEmbeddedDomainCodec))? {
|
||||
match sturdy::WireRef::deserialize(&mut src.packed(NoEmbeddedDomainCodec))? {
|
||||
sturdy::WireRef::Mine{ oid: b } => {
|
||||
let oid = *b;
|
||||
self.imported.oid_map.get(&oid).map(Arc::clone)
|
||||
.unwrap_or_else(|| self.import_oid(t, relay_ref, oid))
|
||||
let ws = self.imported.oid_map.get(&oid).map(Arc::clone)
|
||||
.unwrap_or_else(|| self.import_oid(t, relay_ref, oid));
|
||||
Ok(Arc::clone(&ws.inc_ref().obj))
|
||||
}
|
||||
sturdy::WireRef::Yours { oid: b, attenuation } => {
|
||||
let oid = *b;
|
||||
let ws = self.exported.oid_map.get(&oid).map(Arc::clone)
|
||||
.unwrap_or_else(|| self.exported.insert_inert_entity(t, oid.clone()));
|
||||
|
||||
if attenuation.is_empty() {
|
||||
self.exported.oid_map.get(&oid).map(Arc::clone).unwrap_or_else(
|
||||
|| self.exported.insert_inert_entity(t, oid))
|
||||
Ok(Arc::clone(&ws.inc_ref().obj))
|
||||
} else {
|
||||
match self.exported.oid_map.get(&oid) {
|
||||
None => self.exported.insert_inert_entity(t, oid),
|
||||
Some(ws) => {
|
||||
let attenuated_obj = ws.obj.attenuate(&attenuation)
|
||||
.map_err(|e| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
format!("Invalid capability attenuation: {:?}", e))
|
||||
})?;
|
||||
self.exported.insert(oid, attenuated_obj)
|
||||
let attenuated_obj = ws.obj.attenuate(&attenuation)
|
||||
.map_err(|e| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
format!("Invalid capability attenuation: {:?}", e))
|
||||
})?;
|
||||
|
||||
ws.inc_ref();
|
||||
|
||||
let variations = self.reimported_attenuations.entry(oid).or_default();
|
||||
match variations.get(&attenuated_obj) {
|
||||
None => {
|
||||
variations.insert(Arc::clone(&attenuated_obj));
|
||||
self.exported.ref_map.insert(Arc::clone(&attenuated_obj), Arc::clone(&ws));
|
||||
Ok(attenuated_obj)
|
||||
}
|
||||
Some(existing) =>
|
||||
Ok(Arc::clone(existing))
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(Arc::clone(&ws.inc_ref().obj))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,19 +16,12 @@ use crate::actor::Activation;
|
|||
use crate::actor::Handle;
|
||||
use crate::actor::Cap;
|
||||
use crate::schemas::dataspace_patterns as ds;
|
||||
use crate::pattern::{self, PathStep, Path, Paths};
|
||||
use crate::pattern::{self, ConstantPositions, PathStep, Path, Paths};
|
||||
|
||||
type Bag<A> = bag::BTreeBag<A>;
|
||||
|
||||
type Captures = AnyValue;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
|
||||
enum Guard {
|
||||
Rec(AnyValue, usize),
|
||||
Seq(usize),
|
||||
Map,
|
||||
}
|
||||
|
||||
/// Index of assertions and [`Observe`rs][crate::schemas::dataspace::Observe].
|
||||
///
|
||||
/// Generally speaking, you will not need to use this structure;
|
||||
|
@ -44,13 +37,13 @@ pub struct Index {
|
|||
#[derive(Debug)]
|
||||
struct Node {
|
||||
continuation: Continuation,
|
||||
edges: Map<Selector, Map<Guard, Node>>,
|
||||
edges: Map<Selector, Map<ds::GroupType, Node>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Continuation {
|
||||
cached_assertions: Set<AnyValue>,
|
||||
leaf_map: Map<Paths, Map<Captures, Leaf>>,
|
||||
leaf_map: Map<Arc<ConstantPositions>, Map<Captures, Leaf>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
@ -205,7 +198,7 @@ impl Node {
|
|||
}
|
||||
|
||||
fn extend(&mut self, pat: &ds::Pattern) -> &mut Continuation {
|
||||
let (_pop_count, final_node) = self.extend_walk(&mut Vec::new(), 0, PathStep::Index(0), pat);
|
||||
let (_pop_count, final_node) = self.extend_walk(&mut Vec::new(), 0, PathStep::new(0), pat);
|
||||
&mut final_node.continuation
|
||||
}
|
||||
|
||||
|
@ -216,23 +209,13 @@ impl Node {
|
|||
step: PathStep,
|
||||
pat: &ds::Pattern,
|
||||
) -> (usize, &mut Node) {
|
||||
let (guard, members): (Guard, Vec<(PathStep, &ds::Pattern)>) = match pat {
|
||||
ds::Pattern::DCompound(b) => match &**b {
|
||||
ds::DCompound::Arr { items } =>
|
||||
(Guard::Seq(items.len()),
|
||||
items.iter().enumerate().map(|(i, p)| (PathStep::Index(i), p)).collect()),
|
||||
ds::DCompound::Rec { label, fields } =>
|
||||
(Guard::Rec(label.clone(), fields.len()),
|
||||
fields.iter().enumerate().map(|(i, p)| (PathStep::Index(i), p)).collect()),
|
||||
ds::DCompound::Dict { entries, .. } =>
|
||||
(Guard::Map,
|
||||
entries.iter().map(|(k, p)| (PathStep::Key(k.clone()), p)).collect()),
|
||||
}
|
||||
ds::Pattern::DBind(b) => {
|
||||
let ds::DBind { pattern, .. } = &**b;
|
||||
return self.extend_walk(path, pop_count, step, pattern);
|
||||
}
|
||||
ds::Pattern::DDiscard(_) | ds::Pattern::DLit(_) =>
|
||||
let (guard, members): (ds::GroupType, Vec<(PathStep, &ds::Pattern)>) = match pat {
|
||||
ds::Pattern::Group { type_, entries } =>
|
||||
((&**type_).clone(),
|
||||
entries.iter().map(|(k, p)| (k.clone(), p)).collect()),
|
||||
ds::Pattern::Bind { pattern } =>
|
||||
return self.extend_walk(path, pop_count, step, &**pattern),
|
||||
ds::Pattern::Discard | ds::Pattern::Lit { .. } =>
|
||||
return (pop_count, self),
|
||||
};
|
||||
|
||||
|
@ -336,41 +319,46 @@ where FCont: FnMut(&mut Continuation, &AnyValue) -> (),
|
|||
|
||||
fn continuation(&mut self, c: &mut Continuation) {
|
||||
(self.m_cont)(c, self.outer_value);
|
||||
let mut empty_const_paths = Vec::new();
|
||||
for (const_paths, const_val_map) in &mut c.leaf_map {
|
||||
if let Some(const_vals) = project_paths(self.outer_value, const_paths) {
|
||||
let leaf_opt = if self.create_leaf_if_absent {
|
||||
Some(const_val_map.entry(const_vals.clone()).or_insert_with(Leaf::new))
|
||||
} else {
|
||||
const_val_map.get_mut(&const_vals)
|
||||
};
|
||||
if let Some(leaf) = leaf_opt {
|
||||
(self.m_leaf)(leaf, self.outer_value);
|
||||
for (capture_paths, endpoints) in &mut leaf.endpoints_map {
|
||||
if let Some(cs) = project_paths(self.outer_value, &capture_paths) {
|
||||
(self.m_endpoints)(endpoints, cs);
|
||||
}
|
||||
let mut empty_const_positions = Vec::new();
|
||||
for (const_positions, const_val_map) in &mut c.leaf_map {
|
||||
if project_paths(self.outer_value, &const_positions.required_to_exist).is_none() {
|
||||
continue;
|
||||
}
|
||||
let const_vals = match project_paths(self.outer_value, &const_positions.with_values) {
|
||||
Some(vs) => vs,
|
||||
None => continue,
|
||||
};
|
||||
let leaf_opt = if self.create_leaf_if_absent {
|
||||
Some(const_val_map.entry(const_vals.clone()).or_insert_with(Leaf::new))
|
||||
} else {
|
||||
const_val_map.get_mut(&const_vals)
|
||||
};
|
||||
if let Some(leaf) = leaf_opt {
|
||||
(self.m_leaf)(leaf, self.outer_value);
|
||||
for (capture_paths, endpoints) in &mut leaf.endpoints_map {
|
||||
if let Some(cs) = project_paths(self.outer_value, &capture_paths) {
|
||||
(self.m_endpoints)(endpoints, cs);
|
||||
}
|
||||
if leaf.is_empty() {
|
||||
const_val_map.remove(&const_vals);
|
||||
if const_val_map.is_empty() {
|
||||
empty_const_paths.push(const_paths.clone());
|
||||
}
|
||||
}
|
||||
if leaf.is_empty() {
|
||||
const_val_map.remove(&const_vals);
|
||||
if const_val_map.is_empty() {
|
||||
empty_const_positions.push(const_positions.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for const_paths in empty_const_paths {
|
||||
c.leaf_map.remove(&const_paths);
|
||||
for const_positions in empty_const_positions {
|
||||
c.leaf_map.remove(&const_positions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn class_of(v: &AnyValue) -> Option<Guard> {
|
||||
fn class_of(v: &AnyValue) -> Option<ds::GroupType> {
|
||||
match v.value() {
|
||||
Value::Sequence(vs) => Some(Guard::Seq(vs.len())),
|
||||
Value::Record(r) => Some(Guard::Rec(r.label().clone(), r.arity())),
|
||||
Value::Dictionary(_) => Some(Guard::Map),
|
||||
Value::Sequence(_) => Some(ds::GroupType::Arr),
|
||||
Value::Record(r) => Some(ds::GroupType::Rec { label: r.label().clone() }),
|
||||
Value::Dictionary(_) => Some(ds::GroupType::Dict),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -398,15 +386,17 @@ fn project_paths<'a>(v: &'a AnyValue, ps: &Paths) -> Option<Captures> {
|
|||
}
|
||||
|
||||
fn step<'a>(v: &'a AnyValue, s: &PathStep) -> Option<&'a AnyValue> {
|
||||
match (v.value(), s) {
|
||||
(Value::Sequence(vs), PathStep::Index(i)) =>
|
||||
if *i < vs.len() { Some(&vs[*i]) } else { None },
|
||||
(Value::Record(r), PathStep::Index(i)) =>
|
||||
if *i < r.arity() { Some(&r.fields()[*i]) } else { None },
|
||||
(Value::Dictionary(m), PathStep::Key(k)) =>
|
||||
m.get(k),
|
||||
_ =>
|
||||
None,
|
||||
match v.value() {
|
||||
Value::Sequence(vs) => {
|
||||
let i = s.value().as_usize()?;
|
||||
if i < vs.len() { Some(&vs[i]) } else { None }
|
||||
}
|
||||
Value::Record(r) => {
|
||||
let i = s.value().as_usize()?;
|
||||
if i < r.arity() { Some(&r.fields()[i]) } else { None }
|
||||
}
|
||||
Value::Dictionary(m) => m.get(s),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,11 +413,14 @@ impl Continuation {
|
|||
) {
|
||||
let cached_assertions = &self.cached_assertions;
|
||||
let const_val_map =
|
||||
self.leaf_map.entry(analysis.const_paths.clone()).or_insert_with({
|
||||
self.leaf_map.entry(analysis.const_positions.clone()).or_insert_with({
|
||||
|| {
|
||||
let mut cvm = Map::new();
|
||||
for a in cached_assertions {
|
||||
if let Some(key) = project_paths(a, &analysis.const_paths) {
|
||||
if project_paths(a, &analysis.const_positions.required_to_exist).is_none() {
|
||||
continue;
|
||||
}
|
||||
if let Some(key) = project_paths(a, &analysis.const_positions.with_values) {
|
||||
cvm.entry(key).or_insert_with(Leaf::new)
|
||||
.cached_assertions.insert(a.clone());
|
||||
}
|
||||
|
@ -462,7 +455,7 @@ impl Continuation {
|
|||
observer: &Arc<Cap>,
|
||||
) {
|
||||
if let Entry::Occupied(mut const_val_map_entry)
|
||||
= self.leaf_map.entry(analysis.const_paths)
|
||||
= self.leaf_map.entry(analysis.const_positions)
|
||||
{
|
||||
let const_val_map = const_val_map_entry.get_mut();
|
||||
if let Entry::Occupied(mut leaf_entry)
|
||||
|
|
Loading…
Reference in New Issue