benchmark and improve method parsing

This commit is contained in:
nora 2022-02-20 16:24:11 +01:00
parent 186f744715
commit 45196c722c
10 changed files with 593 additions and 210 deletions

413
Cargo.lock generated
View file

@ -49,6 +49,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"amqp_core", "amqp_core",
"anyhow", "anyhow",
"criterion",
"nom", "nom",
"once_cell", "once_cell",
"rand", "rand",
@ -85,6 +86,23 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "axum" name = "axum"
version = "0.4.5" version = "0.4.5"
@ -136,18 +154,158 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bstr"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
dependencies = [
"lazy_static",
"memchr",
"regex-automata",
"serde",
]
[[package]]
name = "bumpalo"
version = "3.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.1.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
[[package]]
name = "cast"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a"
dependencies = [
"rustc_version",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"bitflags",
"textwrap",
"unicode-width",
]
[[package]]
name = "criterion"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
dependencies = [
"atty",
"cast",
"clap",
"criterion-plot",
"csv",
"itertools",
"lazy_static",
"num-traits",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_cbor",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
dependencies = [
"cast",
"itertools",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9"
dependencies = [
"cfg-if",
"crossbeam-utils",
"lazy_static",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6"
dependencies = [
"cfg-if",
"lazy_static",
]
[[package]]
name = "csv"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
dependencies = [
"bstr",
"csv-core",
"itoa 0.4.8",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "either" name = "either"
version = "1.6.1" version = "1.6.1"
@ -220,6 +378,12 @@ dependencies = [
"wasi", "wasi",
] ]
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.0" version = "0.4.0"
@ -243,7 +407,7 @@ checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03"
dependencies = [ dependencies = [
"bytes", "bytes",
"fnv", "fnv",
"itoa", "itoa 1.0.1",
] ]
[[package]] [[package]]
@ -289,7 +453,7 @@ dependencies = [
"http-body", "http-body",
"httparse", "httparse",
"httpdate", "httpdate",
"itoa", "itoa 1.0.1",
"pin-project-lite", "pin-project-lite",
"socket2", "socket2",
"tokio", "tokio",
@ -307,6 +471,12 @@ dependencies = [
"either", "either",
] ]
[[package]]
name = "itoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.1" version = "1.0.1"
@ -319,6 +489,15 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9447923c57a8a2d5c1b0875cdf96a6324275df728b498f2ede0e5cbde088a15" checksum = "c9447923c57a8a2d5c1b0875cdf96a6324275df728b498f2ede0e5cbde088a15"
[[package]]
name = "js-sys"
version = "0.3.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04"
dependencies = [
"wasm-bindgen",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@ -367,6 +546,15 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "mime" name = "mime"
version = "0.3.16" version = "0.3.16"
@ -421,6 +609,15 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.13.1" version = "1.13.1"
@ -437,6 +634,12 @@ version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
[[package]]
name = "oorandom"
version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.0" version = "0.12.0"
@ -498,6 +701,34 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "plotters"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c"
[[package]]
name = "plotters-svg"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9"
dependencies = [
"plotters-backend",
]
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.16" version = "0.2.16"
@ -562,6 +793,31 @@ dependencies = [
"rand_core", "rand_core",
] ]
[[package]]
name = "rayon"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
dependencies = [
"autocfg",
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"lazy_static",
"num_cpus",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.2.10" version = "0.2.10"
@ -582,24 +838,54 @@ dependencies = [
"regex-syntax", "regex-syntax",
] ]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.25" version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.9" version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "semver"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.136" version = "1.0.136"
@ -609,6 +895,16 @@ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]]
name = "serde_cbor"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
dependencies = [
"half",
"serde",
]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.136" version = "1.0.136"
@ -626,7 +922,7 @@ version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
dependencies = [ dependencies = [
"itoa", "itoa 1.0.1",
"ryu", "ryu",
"serde", "serde",
] ]
@ -638,7 +934,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [ dependencies = [
"form_urlencoded", "form_urlencoded",
"itoa", "itoa 1.0.1",
"ryu", "ryu",
"serde", "serde",
] ]
@ -718,6 +1014,15 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8"
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.30" version = "1.0.30"
@ -747,6 +1052,16 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.17.0" version = "1.17.0"
@ -918,6 +1233,12 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "unicode-width"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.2" version = "0.2.2"
@ -942,6 +1263,17 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",
"winapi-util",
]
[[package]] [[package]]
name = "want" name = "want"
version = "0.3.0" version = "0.3.0"
@ -958,6 +1290,70 @@ version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2"
[[package]]
name = "web-sys"
version = "0.3.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@ -974,6 +1370,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"

View file

@ -18,3 +18,10 @@ tracing = "0.1.30"
uuid = "0.8.2" uuid = "0.8.2"
[features] [features]
[dev-dependencies]
criterion = "0.3.5"
[[bench]]
name = "parser"
harness = false

View file

@ -0,0 +1,39 @@
use amqp_transport::methods;
use amqp_transport::methods::{Method, RandomMethod};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use rand::SeedableRng;
fn random_method_from_seed(seed: u128) -> Method {
let mut rng = rand::rngs::StdRng::from_seed(
[seed.to_be_bytes(), seed.to_be_bytes()]
.concat()
.try_into()
.unwrap(),
);
Method::random(&mut rng)
}
fn serialize_method(method: Method) -> Vec<u8> {
let mut writer = Vec::new();
methods::write::write_method(method, &mut writer).unwrap();
writer
}
fn parse_method(c: &mut Criterion) {
let methods = (0..10000)
.map(random_method_from_seed)
.map(serialize_method)
.collect::<Vec<_>>();
c.bench_function("parse random methods", |b| {
b.iter(|| {
for data in &methods {
let result = methods::parse_method(black_box(data)).unwrap();
black_box(result);
}
})
});
}
criterion_group!(benches, parse_method);
criterion_main!(benches);

View file

@ -3,11 +3,12 @@
mod connection; mod connection;
mod error; mod error;
mod frame; mod frame;
mod methods; pub mod methods;
mod sasl; mod sasl;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use crate::connection::Connection; use crate::connection::Connection;
use amqp_core::GlobalData; use amqp_core::GlobalData;
use anyhow::Result; use anyhow::Result;

View file

@ -887,8 +887,7 @@ pub mod parse {
table(input) table(input)
} }
fn connection(input: &[u8]) -> IResult<'_, Method> { fn connection(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = tag(10_u16.to_be_bytes())(input) let (input, _) = tag(10_u16.to_be_bytes())(input)?;
.map_err(fail_err("invalid tag for class connection"))?;
alt(( alt((
connection_start, connection_start,
connection_start_ok, connection_start_ok,
@ -904,8 +903,7 @@ pub mod parse {
.map_err(fail_err("class connection")) .map_err(fail_err("class connection"))
} }
fn connection_start(input: &[u8]) -> IResult<'_, Method> { fn connection_start(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(10_u16.to_be_bytes())(input)?;
tag(10_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, version_major) = let (input, version_major) =
domain_octet(input).map_err(fail_err("field version-major in method start"))?; domain_octet(input).map_err(fail_err("field version-major in method start"))?;
let (input, version_minor) = let (input, version_minor) =
@ -934,8 +932,7 @@ pub mod parse {
)) ))
} }
fn connection_start_ok(input: &[u8]) -> IResult<'_, Method> { fn connection_start_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(11_u16.to_be_bytes())(input)?;
tag(11_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, client_properties) = domain_peer_properties(input) let (input, client_properties) = domain_peer_properties(input)
.map_err(fail_err("field client-properties in method start-ok"))?; .map_err(fail_err("field client-properties in method start-ok"))?;
let (input, mechanism) = let (input, mechanism) =
@ -964,15 +961,13 @@ pub mod parse {
)) ))
} }
fn connection_secure(input: &[u8]) -> IResult<'_, Method> { fn connection_secure(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(20_u16.to_be_bytes())(input)?;
tag(20_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, challenge) = let (input, challenge) =
domain_longstr(input).map_err(fail_err("field challenge in method secure"))?; domain_longstr(input).map_err(fail_err("field challenge in method secure"))?;
Ok((input, Method::ConnectionSecure { challenge })) Ok((input, Method::ConnectionSecure { challenge }))
} }
fn connection_secure_ok(input: &[u8]) -> IResult<'_, Method> { fn connection_secure_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(21_u16.to_be_bytes())(input)?;
tag(21_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, response) = let (input, response) =
domain_longstr(input).map_err(fail_err("field response in method secure-ok"))?; domain_longstr(input).map_err(fail_err("field response in method secure-ok"))?;
if response.is_empty() { if response.is_empty() {
@ -981,8 +976,7 @@ pub mod parse {
Ok((input, Method::ConnectionSecureOk { response })) Ok((input, Method::ConnectionSecureOk { response }))
} }
fn connection_tune(input: &[u8]) -> IResult<'_, Method> { fn connection_tune(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(30_u16.to_be_bytes())(input)?;
tag(30_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, channel_max) = let (input, channel_max) =
domain_short(input).map_err(fail_err("field channel-max in method tune"))?; domain_short(input).map_err(fail_err("field channel-max in method tune"))?;
let (input, frame_max) = let (input, frame_max) =
@ -999,8 +993,7 @@ pub mod parse {
)) ))
} }
fn connection_tune_ok(input: &[u8]) -> IResult<'_, Method> { fn connection_tune_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(31_u16.to_be_bytes())(input)?;
tag(31_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, channel_max) = let (input, channel_max) =
domain_short(input).map_err(fail_err("field channel-max in method tune-ok"))?; domain_short(input).map_err(fail_err("field channel-max in method tune-ok"))?;
if channel_max == 0 { if channel_max == 0 {
@ -1020,8 +1013,7 @@ pub mod parse {
)) ))
} }
fn connection_open(input: &[u8]) -> IResult<'_, Method> { fn connection_open(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(40_u16.to_be_bytes())(input)?;
tag(40_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, virtual_host) = let (input, virtual_host) =
domain_path(input).map_err(fail_err("field virtual-host in method open"))?; domain_path(input).map_err(fail_err("field virtual-host in method open"))?;
let (input, reserved_1) = let (input, reserved_1) =
@ -1038,15 +1030,13 @@ pub mod parse {
)) ))
} }
fn connection_open_ok(input: &[u8]) -> IResult<'_, Method> { fn connection_open_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(41_u16.to_be_bytes())(input)?;
tag(41_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reserved_1) = let (input, reserved_1) =
domain_shortstr(input).map_err(fail_err("field reserved-1 in method open-ok"))?; domain_shortstr(input).map_err(fail_err("field reserved-1 in method open-ok"))?;
Ok((input, Method::ConnectionOpenOk { reserved_1 })) Ok((input, Method::ConnectionOpenOk { reserved_1 }))
} }
fn connection_close(input: &[u8]) -> IResult<'_, Method> { fn connection_close(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(50_u16.to_be_bytes())(input)?;
tag(50_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reply_code) = let (input, reply_code) =
domain_reply_code(input).map_err(fail_err("field reply-code in method close"))?; domain_reply_code(input).map_err(fail_err("field reply-code in method close"))?;
let (input, reply_text) = let (input, reply_text) =
@ -1066,13 +1056,11 @@ pub mod parse {
)) ))
} }
fn connection_close_ok(input: &[u8]) -> IResult<'_, Method> { fn connection_close_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(51_u16.to_be_bytes())(input)?;
tag(51_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
Ok((input, Method::ConnectionCloseOk {})) Ok((input, Method::ConnectionCloseOk {}))
} }
fn channel(input: &[u8]) -> IResult<'_, Method> { fn channel(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(20_u16.to_be_bytes())(input)?;
tag(20_u16.to_be_bytes())(input).map_err(fail_err("invalid tag for class channel"))?;
alt(( alt((
channel_open, channel_open,
channel_open_ok, channel_open_ok,
@ -1084,36 +1072,31 @@ pub mod parse {
.map_err(fail_err("class channel")) .map_err(fail_err("class channel"))
} }
fn channel_open(input: &[u8]) -> IResult<'_, Method> { fn channel_open(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(10_u16.to_be_bytes())(input)?;
tag(10_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reserved_1) = let (input, reserved_1) =
domain_shortstr(input).map_err(fail_err("field reserved-1 in method open"))?; domain_shortstr(input).map_err(fail_err("field reserved-1 in method open"))?;
Ok((input, Method::ChannelOpen { reserved_1 })) Ok((input, Method::ChannelOpen { reserved_1 }))
} }
fn channel_open_ok(input: &[u8]) -> IResult<'_, Method> { fn channel_open_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(11_u16.to_be_bytes())(input)?;
tag(11_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reserved_1) = let (input, reserved_1) =
domain_longstr(input).map_err(fail_err("field reserved-1 in method open-ok"))?; domain_longstr(input).map_err(fail_err("field reserved-1 in method open-ok"))?;
Ok((input, Method::ChannelOpenOk { reserved_1 })) Ok((input, Method::ChannelOpenOk { reserved_1 }))
} }
fn channel_flow(input: &[u8]) -> IResult<'_, Method> { fn channel_flow(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(20_u16.to_be_bytes())(input)?;
tag(20_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, bits) = bit(input, 1).map_err(fail_err("field active in method flow"))?; let (input, bits) = bit(input, 1).map_err(fail_err("field active in method flow"))?;
let active = bits[0]; let active = bits[0];
Ok((input, Method::ChannelFlow { active })) Ok((input, Method::ChannelFlow { active }))
} }
fn channel_flow_ok(input: &[u8]) -> IResult<'_, Method> { fn channel_flow_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(21_u16.to_be_bytes())(input)?;
tag(21_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, bits) = bit(input, 1).map_err(fail_err("field active in method flow-ok"))?; let (input, bits) = bit(input, 1).map_err(fail_err("field active in method flow-ok"))?;
let active = bits[0]; let active = bits[0];
Ok((input, Method::ChannelFlowOk { active })) Ok((input, Method::ChannelFlowOk { active }))
} }
fn channel_close(input: &[u8]) -> IResult<'_, Method> { fn channel_close(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(40_u16.to_be_bytes())(input)?;
tag(40_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reply_code) = let (input, reply_code) =
domain_reply_code(input).map_err(fail_err("field reply-code in method close"))?; domain_reply_code(input).map_err(fail_err("field reply-code in method close"))?;
let (input, reply_text) = let (input, reply_text) =
@ -1133,13 +1116,11 @@ pub mod parse {
)) ))
} }
fn channel_close_ok(input: &[u8]) -> IResult<'_, Method> { fn channel_close_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(41_u16.to_be_bytes())(input)?;
tag(41_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
Ok((input, Method::ChannelCloseOk {})) Ok((input, Method::ChannelCloseOk {}))
} }
fn exchange(input: &[u8]) -> IResult<'_, Method> { fn exchange(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(40_u16.to_be_bytes())(input)?;
tag(40_u16.to_be_bytes())(input).map_err(fail_err("invalid tag for class exchange"))?;
alt(( alt((
exchange_declare, exchange_declare,
exchange_declare_ok, exchange_declare_ok,
@ -1149,8 +1130,7 @@ pub mod parse {
.map_err(fail_err("class exchange")) .map_err(fail_err("class exchange"))
} }
fn exchange_declare(input: &[u8]) -> IResult<'_, Method> { fn exchange_declare(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(10_u16.to_be_bytes())(input)?;
tag(10_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reserved_1) = let (input, reserved_1) =
domain_short(input).map_err(fail_err("field reserved-1 in method declare"))?; domain_short(input).map_err(fail_err("field reserved-1 in method declare"))?;
let (input, exchange) = let (input, exchange) =
@ -1184,13 +1164,11 @@ pub mod parse {
)) ))
} }
fn exchange_declare_ok(input: &[u8]) -> IResult<'_, Method> { fn exchange_declare_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(11_u16.to_be_bytes())(input)?;
tag(11_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
Ok((input, Method::ExchangeDeclareOk {})) Ok((input, Method::ExchangeDeclareOk {}))
} }
fn exchange_delete(input: &[u8]) -> IResult<'_, Method> { fn exchange_delete(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(20_u16.to_be_bytes())(input)?;
tag(20_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reserved_1) = let (input, reserved_1) =
domain_short(input).map_err(fail_err("field reserved-1 in method delete"))?; domain_short(input).map_err(fail_err("field reserved-1 in method delete"))?;
let (input, exchange) = let (input, exchange) =
@ -1212,13 +1190,11 @@ pub mod parse {
)) ))
} }
fn exchange_delete_ok(input: &[u8]) -> IResult<'_, Method> { fn exchange_delete_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(21_u16.to_be_bytes())(input)?;
tag(21_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
Ok((input, Method::ExchangeDeleteOk {})) Ok((input, Method::ExchangeDeleteOk {}))
} }
fn queue(input: &[u8]) -> IResult<'_, Method> { fn queue(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(50_u16.to_be_bytes())(input)?;
tag(50_u16.to_be_bytes())(input).map_err(fail_err("invalid tag for class queue"))?;
alt(( alt((
queue_declare, queue_declare,
queue_declare_ok, queue_declare_ok,
@ -1234,8 +1210,7 @@ pub mod parse {
.map_err(fail_err("class queue")) .map_err(fail_err("class queue"))
} }
fn queue_declare(input: &[u8]) -> IResult<'_, Method> { fn queue_declare(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(10_u16.to_be_bytes())(input)?;
tag(10_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reserved_1) = let (input, reserved_1) =
domain_short(input).map_err(fail_err("field reserved-1 in method declare"))?; domain_short(input).map_err(fail_err("field reserved-1 in method declare"))?;
let (input, queue) = let (input, queue) =
@ -1263,8 +1238,7 @@ pub mod parse {
)) ))
} }
fn queue_declare_ok(input: &[u8]) -> IResult<'_, Method> { fn queue_declare_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(11_u16.to_be_bytes())(input)?;
tag(11_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, queue) = let (input, queue) =
domain_queue_name(input).map_err(fail_err("field queue in method declare-ok"))?; domain_queue_name(input).map_err(fail_err("field queue in method declare-ok"))?;
if queue.is_empty() { if queue.is_empty() {
@ -1284,8 +1258,7 @@ pub mod parse {
)) ))
} }
fn queue_bind(input: &[u8]) -> IResult<'_, Method> { fn queue_bind(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(20_u16.to_be_bytes())(input)?;
tag(20_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reserved_1) = let (input, reserved_1) =
domain_short(input).map_err(fail_err("field reserved-1 in method bind"))?; domain_short(input).map_err(fail_err("field reserved-1 in method bind"))?;
let (input, queue) = let (input, queue) =
@ -1311,13 +1284,11 @@ pub mod parse {
)) ))
} }
fn queue_bind_ok(input: &[u8]) -> IResult<'_, Method> { fn queue_bind_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(21_u16.to_be_bytes())(input)?;
tag(21_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
Ok((input, Method::QueueBindOk {})) Ok((input, Method::QueueBindOk {}))
} }
fn queue_unbind(input: &[u8]) -> IResult<'_, Method> { fn queue_unbind(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(50_u16.to_be_bytes())(input)?;
tag(50_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reserved_1) = let (input, reserved_1) =
domain_short(input).map_err(fail_err("field reserved-1 in method unbind"))?; domain_short(input).map_err(fail_err("field reserved-1 in method unbind"))?;
let (input, queue) = let (input, queue) =
@ -1340,13 +1311,11 @@ pub mod parse {
)) ))
} }
fn queue_unbind_ok(input: &[u8]) -> IResult<'_, Method> { fn queue_unbind_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(51_u16.to_be_bytes())(input)?;
tag(51_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
Ok((input, Method::QueueUnbindOk {})) Ok((input, Method::QueueUnbindOk {}))
} }
fn queue_purge(input: &[u8]) -> IResult<'_, Method> { fn queue_purge(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(30_u16.to_be_bytes())(input)?;
tag(30_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reserved_1) = let (input, reserved_1) =
domain_short(input).map_err(fail_err("field reserved-1 in method purge"))?; domain_short(input).map_err(fail_err("field reserved-1 in method purge"))?;
let (input, queue) = let (input, queue) =
@ -1363,15 +1332,13 @@ pub mod parse {
)) ))
} }
fn queue_purge_ok(input: &[u8]) -> IResult<'_, Method> { fn queue_purge_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(31_u16.to_be_bytes())(input)?;
tag(31_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, message_count) = domain_message_count(input) let (input, message_count) = domain_message_count(input)
.map_err(fail_err("field message-count in method purge-ok"))?; .map_err(fail_err("field message-count in method purge-ok"))?;
Ok((input, Method::QueuePurgeOk { message_count })) Ok((input, Method::QueuePurgeOk { message_count }))
} }
fn queue_delete(input: &[u8]) -> IResult<'_, Method> { fn queue_delete(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(40_u16.to_be_bytes())(input)?;
tag(40_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reserved_1) = let (input, reserved_1) =
domain_short(input).map_err(fail_err("field reserved-1 in method delete"))?; domain_short(input).map_err(fail_err("field reserved-1 in method delete"))?;
let (input, queue) = let (input, queue) =
@ -1392,15 +1359,13 @@ pub mod parse {
)) ))
} }
fn queue_delete_ok(input: &[u8]) -> IResult<'_, Method> { fn queue_delete_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(41_u16.to_be_bytes())(input)?;
tag(41_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, message_count) = domain_message_count(input) let (input, message_count) = domain_message_count(input)
.map_err(fail_err("field message-count in method delete-ok"))?; .map_err(fail_err("field message-count in method delete-ok"))?;
Ok((input, Method::QueueDeleteOk { message_count })) Ok((input, Method::QueueDeleteOk { message_count }))
} }
fn basic(input: &[u8]) -> IResult<'_, Method> { fn basic(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(60_u16.to_be_bytes())(input)?;
tag(60_u16.to_be_bytes())(input).map_err(fail_err("invalid tag for class basic"))?;
alt(( alt((
basic_qos, basic_qos,
basic_qos_ok, basic_qos_ok,
@ -1423,8 +1388,7 @@ pub mod parse {
.map_err(fail_err("class basic")) .map_err(fail_err("class basic"))
} }
fn basic_qos(input: &[u8]) -> IResult<'_, Method> { fn basic_qos(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(10_u16.to_be_bytes())(input)?;
tag(10_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, prefetch_size) = let (input, prefetch_size) =
domain_long(input).map_err(fail_err("field prefetch-size in method qos"))?; domain_long(input).map_err(fail_err("field prefetch-size in method qos"))?;
let (input, prefetch_count) = let (input, prefetch_count) =
@ -1441,13 +1405,11 @@ pub mod parse {
)) ))
} }
fn basic_qos_ok(input: &[u8]) -> IResult<'_, Method> { fn basic_qos_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(11_u16.to_be_bytes())(input)?;
tag(11_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
Ok((input, Method::BasicQosOk {})) Ok((input, Method::BasicQosOk {}))
} }
fn basic_consume(input: &[u8]) -> IResult<'_, Method> { fn basic_consume(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(20_u16.to_be_bytes())(input)?;
tag(20_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reserved_1) = let (input, reserved_1) =
domain_short(input).map_err(fail_err("field reserved-1 in method consume"))?; domain_short(input).map_err(fail_err("field reserved-1 in method consume"))?;
let (input, queue) = let (input, queue) =
@ -1476,15 +1438,13 @@ pub mod parse {
)) ))
} }
fn basic_consume_ok(input: &[u8]) -> IResult<'_, Method> { fn basic_consume_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(21_u16.to_be_bytes())(input)?;
tag(21_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, consumer_tag) = domain_consumer_tag(input) let (input, consumer_tag) = domain_consumer_tag(input)
.map_err(fail_err("field consumer-tag in method consume-ok"))?; .map_err(fail_err("field consumer-tag in method consume-ok"))?;
Ok((input, Method::BasicConsumeOk { consumer_tag })) Ok((input, Method::BasicConsumeOk { consumer_tag }))
} }
fn basic_cancel(input: &[u8]) -> IResult<'_, Method> { fn basic_cancel(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(30_u16.to_be_bytes())(input)?;
tag(30_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, consumer_tag) = let (input, consumer_tag) =
domain_consumer_tag(input).map_err(fail_err("field consumer-tag in method cancel"))?; domain_consumer_tag(input).map_err(fail_err("field consumer-tag in method cancel"))?;
let (input, bits) = bit(input, 1).map_err(fail_err("field no-wait in method cancel"))?; let (input, bits) = bit(input, 1).map_err(fail_err("field no-wait in method cancel"))?;
@ -1498,15 +1458,13 @@ pub mod parse {
)) ))
} }
fn basic_cancel_ok(input: &[u8]) -> IResult<'_, Method> { fn basic_cancel_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(31_u16.to_be_bytes())(input)?;
tag(31_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, consumer_tag) = domain_consumer_tag(input) let (input, consumer_tag) = domain_consumer_tag(input)
.map_err(fail_err("field consumer-tag in method cancel-ok"))?; .map_err(fail_err("field consumer-tag in method cancel-ok"))?;
Ok((input, Method::BasicCancelOk { consumer_tag })) Ok((input, Method::BasicCancelOk { consumer_tag }))
} }
fn basic_publish(input: &[u8]) -> IResult<'_, Method> { fn basic_publish(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(40_u16.to_be_bytes())(input)?;
tag(40_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reserved_1) = let (input, reserved_1) =
domain_short(input).map_err(fail_err("field reserved-1 in method publish"))?; domain_short(input).map_err(fail_err("field reserved-1 in method publish"))?;
let (input, exchange) = let (input, exchange) =
@ -1528,8 +1486,7 @@ pub mod parse {
)) ))
} }
fn basic_return(input: &[u8]) -> IResult<'_, Method> { fn basic_return(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(50_u16.to_be_bytes())(input)?;
tag(50_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reply_code) = let (input, reply_code) =
domain_reply_code(input).map_err(fail_err("field reply-code in method return"))?; domain_reply_code(input).map_err(fail_err("field reply-code in method return"))?;
let (input, reply_text) = let (input, reply_text) =
@ -1549,8 +1506,7 @@ pub mod parse {
)) ))
} }
fn basic_deliver(input: &[u8]) -> IResult<'_, Method> { fn basic_deliver(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(60_u16.to_be_bytes())(input)?;
tag(60_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, consumer_tag) = let (input, consumer_tag) =
domain_consumer_tag(input).map_err(fail_err("field consumer-tag in method deliver"))?; domain_consumer_tag(input).map_err(fail_err("field consumer-tag in method deliver"))?;
let (input, delivery_tag) = let (input, delivery_tag) =
@ -1574,8 +1530,7 @@ pub mod parse {
)) ))
} }
fn basic_get(input: &[u8]) -> IResult<'_, Method> { fn basic_get(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(70_u16.to_be_bytes())(input)?;
tag(70_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reserved_1) = let (input, reserved_1) =
domain_short(input).map_err(fail_err("field reserved-1 in method get"))?; domain_short(input).map_err(fail_err("field reserved-1 in method get"))?;
let (input, queue) = let (input, queue) =
@ -1592,8 +1547,7 @@ pub mod parse {
)) ))
} }
fn basic_get_ok(input: &[u8]) -> IResult<'_, Method> { fn basic_get_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(71_u16.to_be_bytes())(input)?;
tag(71_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, delivery_tag) = let (input, delivery_tag) =
domain_delivery_tag(input).map_err(fail_err("field delivery-tag in method get-ok"))?; domain_delivery_tag(input).map_err(fail_err("field delivery-tag in method get-ok"))?;
let (input, bits) = let (input, bits) =
@ -1617,15 +1571,13 @@ pub mod parse {
)) ))
} }
fn basic_get_empty(input: &[u8]) -> IResult<'_, Method> { fn basic_get_empty(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(72_u16.to_be_bytes())(input)?;
tag(72_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, reserved_1) = let (input, reserved_1) =
domain_shortstr(input).map_err(fail_err("field reserved-1 in method get-empty"))?; domain_shortstr(input).map_err(fail_err("field reserved-1 in method get-empty"))?;
Ok((input, Method::BasicGetEmpty { reserved_1 })) Ok((input, Method::BasicGetEmpty { reserved_1 }))
} }
fn basic_ack(input: &[u8]) -> IResult<'_, Method> { fn basic_ack(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(80_u16.to_be_bytes())(input)?;
tag(80_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, delivery_tag) = let (input, delivery_tag) =
domain_delivery_tag(input).map_err(fail_err("field delivery-tag in method ack"))?; domain_delivery_tag(input).map_err(fail_err("field delivery-tag in method ack"))?;
let (input, bits) = bit(input, 1).map_err(fail_err("field multiple in method ack"))?; let (input, bits) = bit(input, 1).map_err(fail_err("field multiple in method ack"))?;
@ -1639,8 +1591,7 @@ pub mod parse {
)) ))
} }
fn basic_reject(input: &[u8]) -> IResult<'_, Method> { fn basic_reject(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(90_u16.to_be_bytes())(input)?;
tag(90_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, delivery_tag) = let (input, delivery_tag) =
domain_delivery_tag(input).map_err(fail_err("field delivery-tag in method reject"))?; domain_delivery_tag(input).map_err(fail_err("field delivery-tag in method reject"))?;
let (input, bits) = bit(input, 1).map_err(fail_err("field requeue in method reject"))?; let (input, bits) = bit(input, 1).map_err(fail_err("field requeue in method reject"))?;
@ -1654,28 +1605,24 @@ pub mod parse {
)) ))
} }
fn basic_recover_async(input: &[u8]) -> IResult<'_, Method> { fn basic_recover_async(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(100_u16.to_be_bytes())(input)?;
tag(100_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, bits) = let (input, bits) =
bit(input, 1).map_err(fail_err("field requeue in method recover-async"))?; bit(input, 1).map_err(fail_err("field requeue in method recover-async"))?;
let requeue = bits[0]; let requeue = bits[0];
Ok((input, Method::BasicRecoverAsync { requeue })) Ok((input, Method::BasicRecoverAsync { requeue }))
} }
fn basic_recover(input: &[u8]) -> IResult<'_, Method> { fn basic_recover(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(110_u16.to_be_bytes())(input)?;
tag(110_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
let (input, bits) = bit(input, 1).map_err(fail_err("field requeue in method recover"))?; let (input, bits) = bit(input, 1).map_err(fail_err("field requeue in method recover"))?;
let requeue = bits[0]; let requeue = bits[0];
Ok((input, Method::BasicRecover { requeue })) Ok((input, Method::BasicRecover { requeue }))
} }
fn basic_recover_ok(input: &[u8]) -> IResult<'_, Method> { fn basic_recover_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(111_u16.to_be_bytes())(input)?;
tag(111_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
Ok((input, Method::BasicRecoverOk {})) Ok((input, Method::BasicRecoverOk {}))
} }
fn tx(input: &[u8]) -> IResult<'_, Method> { fn tx(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(90_u16.to_be_bytes())(input)?;
tag(90_u16.to_be_bytes())(input).map_err(fail_err("invalid tag for class tx"))?;
alt(( alt((
tx_select, tx_select,
tx_select_ok, tx_select_ok,
@ -1687,33 +1634,27 @@ pub mod parse {
.map_err(fail_err("class tx")) .map_err(fail_err("class tx"))
} }
fn tx_select(input: &[u8]) -> IResult<'_, Method> { fn tx_select(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(10_u16.to_be_bytes())(input)?;
tag(10_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
Ok((input, Method::TxSelect {})) Ok((input, Method::TxSelect {}))
} }
fn tx_select_ok(input: &[u8]) -> IResult<'_, Method> { fn tx_select_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(11_u16.to_be_bytes())(input)?;
tag(11_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
Ok((input, Method::TxSelectOk {})) Ok((input, Method::TxSelectOk {}))
} }
fn tx_commit(input: &[u8]) -> IResult<'_, Method> { fn tx_commit(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(20_u16.to_be_bytes())(input)?;
tag(20_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
Ok((input, Method::TxCommit {})) Ok((input, Method::TxCommit {}))
} }
fn tx_commit_ok(input: &[u8]) -> IResult<'_, Method> { fn tx_commit_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(21_u16.to_be_bytes())(input)?;
tag(21_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
Ok((input, Method::TxCommitOk {})) Ok((input, Method::TxCommitOk {}))
} }
fn tx_rollback(input: &[u8]) -> IResult<'_, Method> { fn tx_rollback(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(30_u16.to_be_bytes())(input)?;
tag(30_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
Ok((input, Method::TxRollback {})) Ok((input, Method::TxRollback {}))
} }
fn tx_rollback_ok(input: &[u8]) -> IResult<'_, Method> { fn tx_rollback_ok(input: &[u8]) -> IResult<'_, Method> {
let (input, _) = let (input, _) = tag(31_u16.to_be_bytes())(input)?;
tag(31_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;
Ok((input, Method::TxRollbackOk {})) Ok((input, Method::TxRollbackOk {}))
} }
} }
@ -2134,10 +2075,10 @@ pub mod write {
Ok(()) Ok(())
} }
} }
#[cfg(test)]
mod random { mod random {
use super::*; use super::*;
use crate::methods::tests::RandomMethod; use crate::methods::RandomMethod;
use rand::Rng; use rand::Rng;
impl<R: Rng> RandomMethod<R> for Method { impl<R: Rng> RandomMethod<R> for Method {

View file

@ -1,4 +1,5 @@
use crate::error::{ConException, TransError}; use crate::error::{ConException, TransError};
use rand::Rng;
use std::collections::HashMap; use std::collections::HashMap;
mod generated; mod generated;
@ -56,3 +57,70 @@ pub fn parse_method(payload: &[u8]) -> Result<generated::Method, TransError> {
Err(nom::Err::Failure(err) | nom::Err::Error(err)) => Err(err), Err(nom::Err::Failure(err) | nom::Err::Error(err)) => Err(err),
} }
} }
/// Allows the creation of a random instance of that type
pub trait RandomMethod<R: Rng> {
fn random(rng: &mut R) -> Self;
}
impl<R: Rng> RandomMethod<R> for String {
fn random(rng: &mut R) -> Self {
let n = rng.gen_range(0_u16..9999);
format!("string{n}")
}
}
impl<R: Rng, T: RandomMethod<R>> RandomMethod<R> for Vec<T> {
fn random(rng: &mut R) -> Self {
let len = rng.gen_range(1_usize..10);
let mut vec = Vec::with_capacity(len);
(0..len).for_each(|_| vec.push(RandomMethod::random(rng)));
vec
}
}
macro_rules! rand_random_method {
($($ty:ty),+) => {
$(
impl<R: Rng> RandomMethod<R> for $ty {
fn random(rng: &mut R) -> Self {
rng.gen()
}
})+
};
}
rand_random_method!(bool, u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
impl<R: Rng> RandomMethod<R> for HashMap<String, FieldValue> {
fn random(rng: &mut R) -> Self {
let len = rng.gen_range(0..3);
HashMap::from_iter((0..len).map(|_| (String::random(rng), FieldValue::random(rng))))
}
}
impl<R: Rng> RandomMethod<R> for FieldValue {
fn random(rng: &mut R) -> Self {
let index = rng.gen_range(0_u32..17);
match index {
0 => FieldValue::Boolean(RandomMethod::random(rng)),
1 => FieldValue::ShortShortInt(RandomMethod::random(rng)),
2 => FieldValue::ShortShortUInt(RandomMethod::random(rng)),
3 => FieldValue::ShortInt(RandomMethod::random(rng)),
4 => FieldValue::ShortUInt(RandomMethod::random(rng)),
5 => FieldValue::LongInt(RandomMethod::random(rng)),
6 => FieldValue::LongUInt(RandomMethod::random(rng)),
7 => FieldValue::LongLongInt(RandomMethod::random(rng)),
8 => FieldValue::LongLongUInt(RandomMethod::random(rng)),
9 => FieldValue::Float(RandomMethod::random(rng)),
10 => FieldValue::Double(RandomMethod::random(rng)),
11 => FieldValue::ShortString(RandomMethod::random(rng)),
12 => FieldValue::LongString(RandomMethod::random(rng)),
13 => FieldValue::FieldArray(RandomMethod::random(rng)),
14 => FieldValue::Timestamp(RandomMethod::random(rng)),
15 => FieldValue::FieldTable(RandomMethod::random(rng)),
16 => FieldValue::Void,
_ => unreachable!(),
}
}
}

View file

@ -12,9 +12,6 @@ use nom::number::Endianness::Big;
use nom::Err; use nom::Err;
use std::collections::HashMap; use std::collections::HashMap;
// todo: remove the debug machinery or change it in a way that actually does what it should lmao
// I'm probably misusing nom hard
impl<T> nom::error::ParseError<T> for TransError { impl<T> nom::error::ParseError<T> for TransError {
fn from_error_kind(_input: T, _kind: ErrorKind) -> Self { fn from_error_kind(_input: T, _kind: ErrorKind) -> Self {
ConException::SyntaxError(vec![]).into_trans() ConException::SyntaxError(vec![]).into_trans()
@ -27,12 +24,6 @@ impl<T> nom::error::ParseError<T> for TransError {
pub fn fail_err<S: Into<String>>(msg: S) -> impl FnOnce(Err<TransError>) -> Err<TransError> { pub fn fail_err<S: Into<String>>(msg: S) -> impl FnOnce(Err<TransError>) -> Err<TransError> {
move |err| { move |err| {
let error_level = if matches!(err, nom::Err::Failure(_)) {
Err::Failure
} else {
Err::Error
};
let msg = msg.into(); let msg = msg.into();
let stack = match err { let stack = match err {
Err::Error(e) | Err::Failure(e) => match e { Err::Error(e) | Err::Failure(e) => match e {
@ -46,7 +37,7 @@ pub fn fail_err<S: Into<String>>(msg: S) -> impl FnOnce(Err<TransError>) -> Err<
}, },
_ => vec![msg], _ => vec![msg],
}; };
error_level(ConException::SyntaxError(stack).into_trans()) Err::Failure(ConException::SyntaxError(stack).into_trans())
} }
} }
pub fn err_other<E, S: Into<String>>(msg: S) -> impl FnOnce(E) -> Err<TransError> { pub fn err_other<E, S: Into<String>>(msg: S) -> impl FnOnce(E) -> Err<TransError> {

View file

@ -1,77 +1,10 @@
// create random methods to test the ser/de code together. if they diverge, we have a bug // create random methods to test the ser/de code together. if they diverge, we have a bug
// this is not perfect, if they both have the same bug it won't be found, but tha's an ok tradeoff // this is not perfect, if they both have the same bug it won't be found, but tha's an ok tradeoff
use crate::methods::{FieldValue, Method}; use crate::methods::{FieldValue, Method, RandomMethod};
use rand::{Rng, SeedableRng}; use rand::SeedableRng;
use std::collections::HashMap; use std::collections::HashMap;
/// Allows the creation of a random instance of that type
pub(crate) trait RandomMethod<R: Rng> {
fn random(rng: &mut R) -> Self;
}
impl<R: Rng> RandomMethod<R> for String {
fn random(rng: &mut R) -> Self {
let n = rng.gen_range(0_u16..9999);
format!("string{n}")
}
}
impl<R: Rng, T: RandomMethod<R>> RandomMethod<R> for Vec<T> {
fn random(rng: &mut R) -> Self {
let len = rng.gen_range(1_usize..10);
let mut vec = Vec::with_capacity(len);
(0..len).for_each(|_| vec.push(RandomMethod::random(rng)));
vec
}
}
macro_rules! rand_random_method {
($($ty:ty),+) => {
$(
impl<R: Rng> RandomMethod<R> for $ty {
fn random(rng: &mut R) -> Self {
rng.gen()
}
})+
};
}
rand_random_method!(bool, u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
impl<R: Rng> RandomMethod<R> for HashMap<String, FieldValue> {
fn random(rng: &mut R) -> Self {
let len = rng.gen_range(0..3);
HashMap::from_iter((0..len).map(|_| (String::random(rng), FieldValue::random(rng))))
}
}
impl<R: Rng> RandomMethod<R> for FieldValue {
fn random(rng: &mut R) -> Self {
let index = rng.gen_range(0_u32..17);
match index {
0 => FieldValue::Boolean(RandomMethod::random(rng)),
1 => FieldValue::ShortShortInt(RandomMethod::random(rng)),
2 => FieldValue::ShortShortUInt(RandomMethod::random(rng)),
3 => FieldValue::ShortInt(RandomMethod::random(rng)),
4 => FieldValue::ShortUInt(RandomMethod::random(rng)),
5 => FieldValue::LongInt(RandomMethod::random(rng)),
6 => FieldValue::LongUInt(RandomMethod::random(rng)),
7 => FieldValue::LongLongInt(RandomMethod::random(rng)),
8 => FieldValue::LongLongUInt(RandomMethod::random(rng)),
9 => FieldValue::Float(RandomMethod::random(rng)),
10 => FieldValue::Double(RandomMethod::random(rng)),
11 => FieldValue::ShortString(RandomMethod::random(rng)),
12 => FieldValue::LongString(RandomMethod::random(rng)),
13 => FieldValue::FieldArray(RandomMethod::random(rng)),
14 => FieldValue::Timestamp(RandomMethod::random(rng)),
15 => FieldValue::FieldTable(RandomMethod::random(rng)),
16 => FieldValue::Void,
_ => unreachable!(),
}
}
}
#[test] #[test]
fn pack_few_bits() { fn pack_few_bits() {
let bits = [true, false, true]; let bits = [true, false, true];

View file

@ -56,7 +56,7 @@ pub type IResult<'a, T> = nom::IResult<&'a [u8], T, TransError>;
.join(", "); .join(", ");
let class_name_raw = &class.name; let class_name_raw = &class.name;
println!( println!(
r#" let (input, _) = tag({class_index}_u16.to_be_bytes())(input).map_err(fail_err("invalid tag for class {class_name_raw}"))?; r#" let (input, _) = tag({class_index}_u16.to_be_bytes())(input)?;
alt(({all_methods}))(input).map_err(fail_err("class {class_name_raw}"))"# alt(({all_methods}))(input).map_err(fail_err("class {class_name_raw}"))"#
); );
}); });
@ -96,9 +96,7 @@ fn method_parser(amqp: &Amqp, class: &Class, method: &Method) {
let function_name = method_function_name(&class_name)(method); let function_name = method_function_name(&class_name)(method);
function(&function_name, "Method", || { function(&function_name, "Method", || {
let method_index = method.index; let method_index = method.index;
println!( println!(r#" let (input, _) = tag({method_index}_u16.to_be_bytes())(input)?;"#);
r#" let (input, _) = tag({method_index}_u16.to_be_bytes())(input).map_err(fail_err("parsing method index"))?;"#
);
let mut iter = method.fields.iter().peekable(); let mut iter = method.fields.iter().peekable();
while let Some(field) = iter.next() { while let Some(field) = iter.next() {
let field_name_raw = &field.name; let field_name_raw = &field.name;

View file

@ -3,10 +3,10 @@ use heck::ToUpperCamelCase;
pub(super) fn codegen_random(amqp: &Amqp) { pub(super) fn codegen_random(amqp: &Amqp) {
println!( println!(
"#[cfg(test)] "
mod random {{ mod random {{
use rand::Rng; use rand::Rng;
use crate::methods::tests::RandomMethod; use crate::methods::RandomMethod;
use super::*; use super::*;
" "
); );