New:Socket for Asana Is Now Available.Learn more
Get Started

combine

Package Overview
Dependencies
Maintainers
1
Versions
82
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

combine - cargo Package Compare versions

Comparing version
4.6.7
to
4.6.8
+1
-1
.cargo_vcs_info.json
{
"git": {
"sha1": "f726b8f943f44d258686911907c0324771a2d09f"
"sha1": "678a1b8c9311c4323d7289d7caba8ee9b607100e"
},
"path_in_vcs": ""
}
+389
-795
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "addr2line"
version = "0.21.0"
name = "aho-corasick"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
dependencies = [
"gimli",
"memchr",
]
[[package]]
name = "adler"
version = "1.0.2"
name = "anes"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "aho-corasick"
version = "1.1.2"
name = "anstyle"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"

@@ -42,11 +39,10 @@ [[package]]

name = "async-channel"
version = "2.1.1"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c"
checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2"
dependencies = [
"concurrent-queue",
"event-listener 4.0.0",
"event-listener-strategy",
"futures-core",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.17",
]

@@ -56,11 +52,11 @@

name = "async-executor"
version = "1.8.0"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c"
checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a"
dependencies = [
"async-lock 3.2.0",
"async-task",
"concurrent-queue",
"fastrand 2.0.1",
"futures-lite 2.1.0",
"fastrand",
"futures-lite",
"pin-project-lite 0.2.17",
"slab",

@@ -75,8 +71,8 @@ ]

dependencies = [
"async-channel 2.1.1",
"async-channel 2.5.0",
"async-executor",
"async-io 2.2.2",
"async-lock 3.2.0",
"async-io",
"async-lock",
"blocking",
"futures-lite 2.1.0",
"futures-lite",
"once_cell",

@@ -87,37 +83,16 @@ ]

name = "async-io"
version = "1.13.0"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
dependencies = [
"async-lock 2.8.0",
"autocfg",
"cfg-if 1.0.0",
"cfg-if 1.0.4",
"concurrent-queue",
"futures-lite 1.13.0",
"log",
"parking",
"polling 2.8.0",
"rustix 0.37.27",
"slab",
"socket2",
"waker-fn",
]
[[package]]
name = "async-io"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6afaa937395a620e33dc6a742c593c01aced20aa376ffb0f628121198578ccc7"
dependencies = [
"async-lock 3.2.0",
"cfg-if 1.0.0",
"concurrent-queue",
"futures-io",
"futures-lite 2.1.0",
"futures-lite",
"parking",
"polling 3.3.1",
"rustix 0.38.28",
"polling",
"rustix",
"slab",
"tracing",
"windows-sys 0.52.0",
"windows-sys",
]

@@ -127,18 +102,9 @@

name = "async-lock"
version = "2.8.0"
version = "3.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311"
dependencies = [
"event-listener 2.5.3",
]
[[package]]
name = "async-lock"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7125e42787d53db9dd54261812ef17e937c95a51e4d291373b670342fa44310c"
dependencies = [
"event-listener 4.0.0",
"event-listener 5.4.2",
"event-listener-strategy",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.17",
]

@@ -148,10 +114,10 @@

name = "async-std"
version = "1.12.0"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b"
dependencies = [
"async-channel 1.9.0",
"async-global-executor",
"async-io 1.13.0",
"async-lock 2.8.0",
"async-io",
"async-lock",
"crossbeam-utils",

@@ -161,3 +127,3 @@ "futures-channel",

"futures-io",
"futures-lite 1.13.0",
"futures-lite",
"gloo-timers",

@@ -168,3 +134,3 @@ "kv-log-macro",

"once_cell",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.17",
"pin-utils",

@@ -177,5 +143,5 @@ "slab",

name = "async-task"
version = "4.5.0"
version = "4.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1"
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"

@@ -189,34 +155,8 @@ [[package]]

[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi 0.3.9",
]
[[package]]
name = "autocfg"
version = "1.1.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "backtrace"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
dependencies = [
"addr2line",
"cc",
"cfg-if 1.0.0",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "bitflags"

@@ -229,20 +169,17 @@ version = "1.3.2"

name = "bitflags"
version = "2.4.1"
version = "2.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
[[package]]
name = "blocking"
version = "1.5.1"
version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118"
checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21"
dependencies = [
"async-channel 2.1.1",
"async-lock 3.2.0",
"async-channel 2.5.0",
"async-task",
"fastrand 2.0.1",
"futures-io",
"futures-lite 2.1.0",
"futures-lite",
"piper",
"tracing",
]

@@ -252,24 +189,8 @@

name = "bumpalo"
version = "3.14.0"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
dependencies = [
"byteorder",
"iovec",
]
[[package]]
name = "bytes"
version = "0.5.6"

@@ -281,5 +202,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index"

name = "bytes"
version = "1.5.0"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"

@@ -293,42 +214,74 @@ [[package]]

[[package]]
name = "cc"
version = "1.0.83"
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "ciborium"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
dependencies = [
"libc",
"ciborium-io",
"ciborium-ll",
"serde",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
name = "ciborium-io"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
[[package]]
name = "cfg-if"
version = "1.0.0"
name = "ciborium-ll"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
dependencies = [
"ciborium-io",
"half",
]
[[package]]
name = "clap"
version = "2.34.0"
version = "4.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca"
dependencies = [
"bitflags 1.3.2",
"textwrap",
"unicode-width",
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889"
dependencies = [
"anstyle",
"clap_lex",
]
[[package]]
name = "clap_lex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]]
name = "combine"
version = "4.6.7"
version = "4.6.8"
dependencies = [
"async-std",
"bytes 0.5.6",
"bytes 1.5.0",
"bytes 1.12.1",
"criterion",
"futures 0.3.29",
"futures",
"futures-core",

@@ -339,3 +292,3 @@ "futures-io",

"partial-io",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.17",
"quick-error",

@@ -346,3 +299,3 @@ "quickcheck",

"tokio 0.3.7",
"tokio 1.35.0",
"tokio 1.53.1",
"tokio-util",

@@ -353,5 +306,5 @@ ]

name = "concurrent-queue"
version = "2.4.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363"
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
dependencies = [

@@ -363,21 +316,16 @@ "crossbeam-utils",

name = "criterion"
version = "0.3.6"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f"
checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928"
dependencies = [
"atty",
"anes",
"cast",
"ciborium",
"clap",
"criterion-plot",
"csv",
"itertools",
"lazy_static",
"num-traits",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_cbor",
"serde_derive",
"serde_json",

@@ -390,5 +338,5 @@ "tinytemplate",

name = "criterion-plot"
version = "0.4.5"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876"
checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338"
dependencies = [

@@ -400,72 +348,37 @@ "cast",

[[package]]
name = "crossbeam-deque"
version = "0.8.3"
name = "crossbeam-utils"
version = "0.8.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-epoch",
"crossbeam-utils",
]
checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17"
[[package]]
name = "crossbeam-epoch"
version = "0.9.15"
name = "crunchy"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
dependencies = [
"autocfg",
"cfg-if 1.0.0",
"crossbeam-utils",
"memoffset",
"scopeguard",
]
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
[[package]]
name = "crossbeam-utils"
version = "0.8.16"
name = "either"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
dependencies = [
"cfg-if 1.0.0",
]
checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d"
[[package]]
name = "csv"
version = "1.3.0"
name = "env_filter"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe"
checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217"
dependencies = [
"csv-core",
"itoa",
"ryu",
"serde",
"log",
"regex",
]
[[package]]
name = "csv-core"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
dependencies = [
"memchr",
]
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "env_logger"
version = "0.5.13"
version = "0.11.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38"
checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6"
dependencies = [
"atty",
"humantime",
"env_filter",
"log",
"regex",
"termcolor",
]

@@ -475,8 +388,8 @@

name = "errno"
version = "0.3.8"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys",
]

@@ -492,9 +405,8 @@

name = "event-listener"
version = "4.0.0"
version = "5.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae"
checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2"
dependencies = [
"concurrent-queue",
"parking",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.17",
]

@@ -504,8 +416,8 @@

name = "event-listener-strategy"
version = "0.4.0"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3"
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
dependencies = [
"event-listener 4.0.0",
"pin-project-lite 0.2.13",
"event-listener 5.4.2",
"pin-project-lite 0.2.17",
]

@@ -515,22 +427,7 @@

name = "fastrand"
version = "1.9.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
dependencies = [
"instant",
]
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
[[package]]
name = "fastrand"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "fuchsia-zircon"

@@ -553,11 +450,5 @@ version = "0.3.3"

name = "futures"
version = "0.1.31"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
[[package]]
name = "futures"
version = "0.3.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335"
checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3"
dependencies = [

@@ -575,5 +466,5 @@ "futures-channel",

name = "futures-channel"
version = "0.3.29"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4"
dependencies = [

@@ -586,11 +477,11 @@ "futures-core",

name = "futures-core"
version = "0.3.29"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
[[package]]
name = "futures-executor"
version = "0.3.29"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432"
dependencies = [

@@ -604,43 +495,28 @@ "futures-core",

name = "futures-io"
version = "0.3.29"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed"
[[package]]
name = "futures-lite"
version = "1.13.0"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
dependencies = [
"fastrand 1.9.0",
"fastrand",
"futures-core",
"futures-io",
"memchr",
"parking",
"pin-project-lite 0.2.13",
"waker-fn",
"pin-project-lite 0.2.17",
]
[[package]]
name = "futures-lite"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aeee267a1883f7ebef3700f262d2d54de95dfaf38189015a74fdc4e0c7ad8143"
dependencies = [
"fastrand 2.0.1",
"futures-core",
"futures-io",
"parking",
"pin-project-lite 0.2.13",
]
[[package]]
name = "futures-macro"
version = "0.3.29"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 3.0.3",
]

@@ -650,17 +526,17 @@

name = "futures-sink"
version = "0.3.29"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d"
[[package]]
name = "futures-task"
version = "0.3.29"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
[[package]]
name = "futures-util"
version = "0.3.29"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
dependencies = [

@@ -674,4 +550,3 @@ "futures-channel",

"memchr",
"pin-project-lite 0.2.13",
"pin-utils",
"pin-project-lite 0.2.17",
"slab",

@@ -681,68 +556,52 @@ ]

[[package]]
name = "gimli"
version = "0.28.1"
name = "getrandom"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "gloo-timers"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"futures-channel",
"futures-core",
"js-sys",
"wasm-bindgen",
"cfg-if 1.0.4",
"libc",
"wasi",
]
[[package]]
name = "half"
version = "1.8.2"
name = "getrandom"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
dependencies = [
"cfg-if 1.0.4",
"libc",
"r-efi",
"rand_core 0.10.1",
]
[[package]]
name = "hermit-abi"
version = "0.3.3"
name = "gloo-timers"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
dependencies = [
"quick-error",
"futures-channel",
"futures-core",
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "instant"
version = "0.1.12"
name = "half"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
dependencies = [
"cfg-if 1.0.0",
"cfg-if 1.0.4",
"crunchy",
"zerocopy",
]
[[package]]
name = "io-lifetimes"
version = "1.0.11"
name = "hermit-abi"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi 0.3.3",
"libc",
"windows-sys 0.48.0",
]
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"

@@ -760,5 +619,5 @@ [[package]]

name = "itertools"
version = "0.10.5"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [

@@ -770,12 +629,14 @@ "either",

name = "itoa"
version = "1.0.10"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "js-sys"
version = "0.3.66"
version = "0.3.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a"
dependencies = [
"cfg-if 1.0.4",
"futures-util",
"wasm-bindgen",

@@ -805,29 +666,23 @@ ]

name = "lazy_static"
version = "1.4.0"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.151"
version = "0.2.189"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
[[package]]
name = "linux-raw-sys"
version = "0.3.8"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
name = "linux-raw-sys"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
[[package]]
name = "log"
version = "0.4.20"
version = "0.4.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
dependencies = [

@@ -839,25 +694,7 @@ "value-bag",

name = "memchr"
version = "2.6.4"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
[[package]]
name = "memoffset"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]]
name = "miniz_oxide"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
[[package]]
name = "mio"

@@ -906,5 +743,5 @@ version = "0.6.23"

name = "num-traits"
version = "0.2.17"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [

@@ -916,7 +753,7 @@ "autocfg",

name = "num_cpus"
version = "1.16.0"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
dependencies = [
"hermit-abi 0.3.3",
"hermit-abi",
"libc",

@@ -926,37 +763,28 @@ ]

[[package]]
name = "object"
version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.19.0"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "oorandom"
version = "11.1.3"
version = "11.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]]
name = "parking"
version = "2.2.0"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
[[package]]
name = "partial-io"
version = "0.3.1"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "682cf88dcd93492e8d17723b7ccc1ae2eeffd1d312ea3533c942aa8af7122a2d"
checksum = "af95cf22649f58b48309da6d05caeb5fab4bb335eba4a3f9ac7c3a8e176d0e16"
dependencies = [
"futures 0.1.31",
"quickcheck",
"tokio-io",
"rand 0.8.7",
"tokio 1.53.1",
]

@@ -972,5 +800,5 @@

name = "pin-project-lite"
version = "0.2.13"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"

@@ -985,8 +813,8 @@ [[package]]

name = "piper"
version = "0.2.1"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4"
checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1"
dependencies = [
"atomic-waker",
"fastrand 2.0.1",
"fastrand",
"futures-io",

@@ -996,57 +824,22 @@ ]

[[package]]
name = "plotters"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
[[package]]
name = "plotters-svg"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
dependencies = [
"plotters-backend",
]
[[package]]
name = "polling"
version = "2.8.0"
version = "3.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
dependencies = [
"autocfg",
"bitflags 1.3.2",
"cfg-if 1.0.0",
"cfg-if 1.0.4",
"concurrent-queue",
"libc",
"log",
"pin-project-lite 0.2.13",
"windows-sys 0.48.0",
"hermit-abi",
"pin-project-lite 0.2.17",
"rustix",
"windows-sys",
]
[[package]]
name = "polling"
version = "3.3.1"
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"cfg-if 1.0.0",
"concurrent-queue",
"pin-project-lite 0.2.13",
"rustix 0.38.28",
"tracing",
"windows-sys 0.52.0",
"zerocopy",
]

@@ -1056,5 +849,5 @@

name = "proc-macro2"
version = "1.0.70"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
dependencies = [

@@ -1066,15 +859,15 @@ "unicode-ident",

name = "quick-error"
version = "1.2.3"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
name = "quickcheck"
version = "0.6.2"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c01babc5ffd48a2a83744b3024814bb46dfd4f2a4705ccb44b1b60e644fdcab7"
checksum = "95c589f335db0f6aaa168a7cd27b1fc6920f5e1470c804f814d9cd6e62a0f70b"
dependencies = [
"env_logger",
"log",
"rand",
"rand 0.10.2",
]

@@ -1084,5 +877,5 @@

name = "quote"
version = "1.0.33"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
dependencies = [

@@ -1093,63 +886,58 @@ "proc-macro2",

[[package]]
name = "r-efi"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]]
name = "rand"
version = "0.4.6"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a"
dependencies = [
"fuchsia-cprng",
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi 0.3.9",
"rand_chacha",
"rand_core 0.6.4",
]
[[package]]
name = "rand_core"
version = "0.3.1"
name = "rand"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80"
dependencies = [
"rand_core 0.4.2",
"getrandom 0.4.3",
"rand_core 0.10.1",
]
[[package]]
name = "rand_core"
version = "0.4.2"
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rayon"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"either",
"rayon-core",
"ppv-lite86",
"rand_core 0.6.4",
]
[[package]]
name = "rayon-core"
version = "1.12.0"
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
"getrandom 0.2.17",
]
[[package]]
name = "rdrand"
version = "0.4.0"
name = "rand_core"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]]
name = "regex"
version = "1.10.2"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
dependencies = [

@@ -1164,5 +952,5 @@ "aho-corasick",

name = "regex-automata"
version = "0.4.3"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
dependencies = [

@@ -1176,46 +964,26 @@ "aho-corasick",

name = "regex-syntax"
version = "0.8.2"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]]
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustix"
version = "0.37.27"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2"
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
dependencies = [
"bitflags 1.3.2",
"bitflags 2.13.1",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys 0.3.8",
"windows-sys 0.48.0",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "rustix"
version = "0.38.28"
name = "rustversion"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
dependencies = [
"bitflags 2.4.1",
"errno",
"libc",
"linux-raw-sys 0.4.12",
"windows-sys 0.52.0",
]
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
[[package]]
name = "ryu"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
[[package]]
name = "same-file"

@@ -1230,13 +998,8 @@ version = "1.0.6"

[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.193"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
dependencies = [
"serde_core",
"serde_derive",

@@ -1246,9 +1009,8 @@ ]

[[package]]
name = "serde_cbor"
version = "0.11.2"
name = "serde_core"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
dependencies = [
"half",
"serde",
"serde_derive",
]

@@ -1258,9 +1020,9 @@

name = "serde_derive"
version = "1.0.193"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 3.0.3",
]

@@ -1270,9 +1032,11 @@

name = "serde_json"
version = "1.0.108"
version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
dependencies = [
"itoa",
"ryu",
"memchr",
"serde",
"serde_core",
"zmij",
]

@@ -1282,20 +1046,7 @@

name = "slab"
version = "0.4.9"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
]
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "socket2"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
dependencies = [
"libc",
"winapi 0.3.9",
]
[[package]]
name = "syn"

@@ -1313,5 +1064,5 @@ version = "1.0.109"

name = "syn"
version = "2.0.40"
version = "2.0.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e"
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
dependencies = [

@@ -1324,20 +1075,13 @@ "proc-macro2",

[[package]]
name = "termcolor"
version = "1.4.0"
name = "syn"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
dependencies = [
"winapi-util",
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "tinytemplate"

@@ -1375,3 +1119,3 @@ version = "1.2.1"

"num_cpus",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.17",
"slab",

@@ -1383,25 +1127,12 @@ "tokio-macros 0.3.2",

name = "tokio"
version = "1.35.0"
version = "1.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c"
checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
dependencies = [
"backtrace",
"bytes 1.5.0",
"num_cpus",
"pin-project-lite 0.2.13",
"tokio-macros 2.2.0",
"bytes 1.12.1",
"pin-project-lite 0.2.17",
"tokio-macros 2.7.2",
]
[[package]]
name = "tokio-io"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674"
dependencies = [
"bytes 0.4.12",
"futures 0.1.31",
"log",
]
[[package]]
name = "tokio-macros"

@@ -1430,9 +1161,9 @@ version = "0.2.6"

name = "tokio-macros"
version = "2.2.0"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.40",
"syn 3.0.3",
]

@@ -1442,62 +1173,31 @@

name = "tokio-util"
version = "0.7.10"
version = "0.7.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52"
dependencies = [
"bytes 1.5.0",
"bytes 1.12.1",
"futures-core",
"futures-sink",
"pin-project-lite 0.2.13",
"tokio 1.35.0",
"tracing",
"libc",
"pin-project-lite 0.2.17",
"tokio 1.53.1",
]
[[package]]
name = "tracing"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
"pin-project-lite 0.2.13",
"tracing-core",
]
[[package]]
name = "tracing-core"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [
"once_cell",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-width"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "value-bag"
version = "1.4.2"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a72e1902dde2bd6441347de2b70b7f5d59bf157c6c62f0c44572607a1d55bbe"
checksum = "068e763e8279de7ab94b6afebded2cb701678af094feb1c12ccb061b4783c1be"
[[package]]
name = "waker-fn"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690"
[[package]]
name = "walkdir"
version = "2.4.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [

@@ -1509,23 +1209,17 @@ "same-file",

[[package]]
name = "wasm-bindgen"
version = "0.2.89"
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen-macro",
]
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.89"
name = "wasm-bindgen"
version = "0.2.127"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70"
dependencies = [
"bumpalo",
"log",
"cfg-if 1.0.4",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.40",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",

@@ -1536,10 +1230,8 @@ ]

name = "wasm-bindgen-futures"
version = "0.4.39"
version = "0.4.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12"
checksum = "6b7777d5cc23d0e91404e53ce2d5e8ec7acae3026b16233dba62cd3246457950"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
]

@@ -1549,5 +1241,5 @@

name = "wasm-bindgen-macro"
version = "0.2.89"
version = "0.2.127"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1"
dependencies = [

@@ -1560,10 +1252,10 @@ "quote",

name = "wasm-bindgen-macro-support"
version = "0.2.89"
version = "0.2.127"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn 2.0.40",
"wasm-bindgen-backend",
"syn 2.0.119",
"wasm-bindgen-shared",

@@ -1574,14 +1266,7 @@ ]

name = "wasm-bindgen-shared"
version = "0.2.89"
version = "0.2.127"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
[[package]]
name = "web-sys"
version = "0.3.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f"
checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf"
dependencies = [
"js-sys",
"wasm-bindgen",
"unicode-ident",
]

@@ -1619,7 +1304,7 @@

name = "winapi-util"
version = "0.1.6"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"winapi 0.3.9",
"windows-sys",
]

@@ -1634,141 +1319,50 @@

[[package]]
name = "windows-sys"
version = "0.48.0"
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.52.0"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-targets 0.52.0",
"windows-link",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
"winapi 0.2.8",
"winapi-build",
]
[[package]]
name = "windows-targets"
version = "0.52.0"
name = "zerocopy"
version = "0.8.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb"
dependencies = [
"windows_aarch64_gnullvm 0.52.0",
"windows_aarch64_msvc 0.52.0",
"windows_i686_gnu 0.52.0",
"windows_i686_msvc 0.52.0",
"windows_x86_64_gnu 0.52.0",
"windows_x86_64_gnullvm 0.52.0",
"windows_x86_64_msvc 0.52.0",
"zerocopy-derive",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
name = "zerocopy-derive"
version = "0.8.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
name = "zmij"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
dependencies = [
"winapi 0.2.8",
"winapi-build",
]
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"

@@ -15,4 +15,17 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO

name = "combine"
version = "4.6.7"
version = "4.6.8"
authors = ["Markus Westerlind <marwes91@gmail.com>"]
build = false
include = [
"Cargo.toml",
"README.md",
"CHANGELOG.md",
"LICENSE",
"src/**/*.rs",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Fast parser combinators on arbitrary streams with zero-copy support."

@@ -41,5 +54,40 @@ documentation = "https://docs.rs/combine"

[profile.bench]
lto = true
codegen-units = 1
[features]
alloc = []
default = ["std"]
futures-03 = [
"pin-project",
"std",
"futures-core-03",
"futures-io-03",
"pin-project-lite",
]
mp4 = []
pin-project = ["pin-project-lite"]
std = [
"memchr/std",
"bytes",
"alloc",
]
tokio = [
"tokio-dep",
"tokio-util/io",
"futures-core-03",
"pin-project-lite",
]
tokio-02 = [
"pin-project",
"std",
"tokio-02-dep",
"futures-core-03",
"pin-project-lite",
"bytes_05",
]
tokio-03 = [
"pin-project",
"std",
"tokio-03-dep",
"futures-core-03",
"pin-project-lite",
]

@@ -50,48 +98,2 @@ [lib]

[[example]]
name = "async"
required-features = [
"std",
"tokio",
]
[[example]]
name = "date"
[[example]]
name = "number"
[[example]]
name = "readme"
[[example]]
name = "ini"
[[test]]
name = "async"
required-features = [
"tokio-02",
"futures-io-03",
]
[[bench]]
name = "json"
harness = false
required-features = ["std"]
[[bench]]
name = "http"
harness = false
required-features = ["std"]
[[bench]]
name = "mp4"
harness = false
required-features = ["mp4"]
[[bench]]
name = "buffers"
harness = false
required-features = ["std"]
[dependencies.bytes]

@@ -166,3 +168,3 @@ version = "1"

[dev-dependencies.criterion]
version = "0.3"
version = "0.7"
default-features = false

@@ -178,13 +180,13 @@

[dev-dependencies.partial-io]
version = "0.3"
version = "0.5"
features = [
"tokio",
"quickcheck",
"quickcheck1",
]
[dev-dependencies.quick-error]
version = "1.0"
version = "2.0"
[dev-dependencies.quickcheck]
version = "0.6"
version = "1"

@@ -221,39 +223,4 @@ [dev-dependencies.tokio-02-dep]

[features]
alloc = []
default = ["std"]
futures-03 = [
"pin-project",
"std",
"futures-core-03",
"futures-io-03",
"pin-project-lite",
]
mp4 = []
pin-project = ["pin-project-lite"]
std = [
"memchr/std",
"bytes",
"alloc",
]
tokio = [
"tokio-dep",
"tokio-util/io",
"futures-core-03",
"pin-project-lite",
]
tokio-02 = [
"pin-project",
"std",
"tokio-02-dep",
"futures-core-03",
"pin-project-lite",
"bytes_05",
]
tokio-03 = [
"pin-project",
"std",
"tokio-03-dep",
"futures-core-03",
"pin-project-lite",
]
[profile.bench]
lto = true
codegen-units = 1

@@ -0,1 +1,16 @@

## [4.6.8](https://github.com/gluon-lang/gluon/compare/v4.6.7..4.6.8) - 2026-08-25
### Bug Fixes
- usage of `BytesMut` in `extend_buf_sync` - ([b705882](https://github.com/gluon-lang/gluon/commit/b705882f725c18b4c767864a2e7830c5551083ad)) - Paolo Barbolini
### Documentation
- Add documentation to no_partial - ([b3c770f](https://github.com/gluon-lang/gluon/commit/b3c770f9bd43db7b4197225566bf9d951887c2b3)) - Markus Westerlind
- Use from_str in examples/async.rs - ([8068d6c](https://github.com/gluon-lang/gluon/commit/8068d6c472d390fd129cd7da631125bcfe2d3cc5)) - Markus Westerlind
### Parser/combinator
- Drop superfluous semicolon in `opaque` - ([6a3701d](https://github.com/gluon-lang/gluon/commit/6a3701d742a80d40cf7907f336c34599821a3353)) - Christian Aistleitner
<a name="v4.6.7"></a>

@@ -622,3 +637,3 @@ ### v4.6.7 (2024-04-10)

* Remove depreceated items ([9107342a](https://github.com/Marwes/combine/commit/9107342a89a5efc664bac9c2919a93a992ca6809), breaks [#](https://github.com/Marwes/combine/issues/))
* Remove deprecated items ([9107342a](https://github.com/Marwes/combine/commit/9107342a89a5efc664bac9c2919a93a992ca6809), breaks [#](https://github.com/Marwes/combine/issues/))
* Don't forward tuple parsers to frunk to prevent a performance loss ([7e27c523](https://github.com/Marwes/combine/commit/7e27c523da46828b254ee4fc7c1f9750623e5aff))

@@ -625,0 +640,0 @@ * Add the correct errors after sequencing has returned EmptyOk ([54fecc62](https://github.com/Marwes/combine/commit/54fecc62938445aae15373a6b1ec7c4419582025), closes [#95](https://github.com/Marwes/combine/issues/95))

@@ -76,3 +76,3 @@ use crate::lib::fmt;

type Format = &'s F;
fn into_info(&'s self) -> Info<T, R, <Self as ErrorInfo<'_, T, R>>::Format> {
fn into_info(&'s self) -> Info<T, R, <Self as ErrorInfo<'s, T, R>>::Format> {
match self {

@@ -79,0 +79,0 @@ Info::Token(b) => Info::Token(b.clone()),

@@ -498,2 +498,3 @@ //! Combinators which take one or more parsers and attempts to parse successfully with at least one

#[allow(dead_code)] // this needs to be there for rust 1.85
#[inline]

@@ -500,0 +501,0 @@ fn parse_mode_choice<M>(

@@ -667,2 +667,26 @@ //! Various combinators which do not fit anywhere else.

/// Wraps a parser `p` and disables partial parsing for it (changing the `PartialState` to `()`)
///
/// Partial parsing lets a parser accept incomplete (partial) input resume parsing when more input is available without re-parsing any part of the input.
/// By disabling partial parsing for a parser it will need to restart its parse from the beginning once more input is available (no_partial ONLY affects the wrapped parser,
/// any parsers calling the `no_partial` parser will still employ partial parsing).
///
/// If you are not using partial parsing this has no effect (except changing the typing of the parser).
///
/// ```
/// # #[macro_use]
/// # extern crate combine;
/// # use combine::parser::combinator::no_partial;
/// # use combine::parser::char::letter;
/// # use combine::*;
///
/// # fn main() {
///
/// assert_eq!(
/// (no_partial(letter()), letter()).easy_parse("ab"),
/// Ok((('a', 'b'), ""))
/// );
///
/// # }
/// ```
pub fn no_partial<Input, P>(p: P) -> NoPartial<P>

@@ -1414,3 +1438,3 @@ where

($e: expr) => {
$crate::opaque!($e,);
$crate::opaque!($e,)
};

@@ -1417,0 +1441,0 @@ ($e: expr,) => {

@@ -845,2 +845,4 @@ //! A collection of both concrete parsers as well as parser combinators.

/// {
/// // Using no_partial here we do not need to name the type of `PartialState`
/// // (though it disables partial parsing, if partial parsing is used `any_partial_state` can be used instead)
/// combine::parser::combinator::no_partial((token(c), satisfy(f))).boxed()

@@ -847,0 +849,0 @@ /// }

@@ -126,4 +126,2 @@ //! Module containing regex parsers on streams returning ranges of `&str` or `&[u8]`.

pub use self::regex::*;
impl<'t> MatchFind for regex::Match<'t> {

@@ -130,0 +128,0 @@ type Range = &'t str;

@@ -361,3 +361,3 @@ use std::io::{self, BufRead, Read};

let size = 8 * 1024;
if !buf.has_remaining_mut() {
if buf.capacity() == buf.len() {
buf.reserve(size);

@@ -368,9 +368,8 @@ }

let n = {
let bs = buf.chunk_mut();
let bs = buf.spare_capacity_mut();
let initial_size = bs.len().min(size);
let bs = &mut bs[..initial_size];
for i in 0..bs.len() {
bs.write_byte(i, 0);
}
// SAFETY: the above slicing operation guarantees `bs.len() == initial_size`
unsafe { bs.as_mut_ptr().cast::<u8>().write_bytes(0, initial_size) }

@@ -377,0 +376,0 @@ // Convert to `&mut [u8]`

@@ -249,3 +249,3 @@ use crate::{

/// Struct which represents a position in a source file.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub struct SourcePosition {

@@ -252,0 +252,0 @@ /// Current line of the input

[clog]
repository = "https://github.com/Marwes/combine"
changelog = "CHANGELOG.md"
from-latest-tag = true
name: Rust
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
matrix:
rust: [1.61.0, stable, beta, nightly]
env:
CARGO_INCREMENTAL: 0 # Incremental compilation is slower and bloats the cache
RUST_BACKTRACE: 1
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
- name: Build
run: cargo build
- name: Check 1.61
if: ${{ matrix.rust == '1.61.0' }}
run: |
cargo "$@" check
cargo "$@" check --no-default-features
- name: Run tests
if: ${{ matrix.rust != '1.61.0' }}
run: ./ci.sh
- name: Check docs
if: ${{ matrix.rust == 'stable' }}
run: cargo doc
/target
#vim temporary files
*.swp
*.swo
/.vscode
/benches/small.mp4
#![cfg(feature = "std")]
use {
combine::{
parser::{
byte::take_until_bytes,
combinator::{any_send_sync_partial_state, recognize, AnySendSyncPartialState},
},
Parser, RangeStream,
},
criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion},
partial_io::{PartialOp, PartialRead},
std::io::Cursor,
};
fn test_data() -> Vec<u8> {
let mut input = vec![b' '; 5_000_000];
input.push(b'1');
input
}
fn parser<'a, I>() -> impl combine::Parser<I, Output = usize, PartialState = AnySendSyncPartialState>
where
I: RangeStream<Token = u8, Range = &'a [u8]>,
I::Error: combine::ParseError<u8, &'a [u8], I::Position>,
{
any_send_sync_partial_state(
recognize(take_until_bytes(&b"1"[..])).map(|spaces: Vec<u8>| spaces.len()),
)
}
fn bench_small_buf(bencher: &mut Bencher<'_>) {
let input = test_data();
let mut decoder = combine::stream::decoder::Decoder::new();
bencher.iter(|| {
let cursor = Cursor::new(&input);
let mut partial_read =
PartialRead::new(cursor, std::iter::repeat(PartialOp::Limited(1000)));
let mut ref_decoder = &mut decoder;
let result = combine::decode!(ref_decoder, partial_read, parser(), |input, _position| {
combine::easy::Stream::from(input)
},);
match result {
Ok(usize) => black_box(usize),
Err(err) => {
println!("{:?}", err);
panic!();
}
};
});
}
fn bench_big_buf(bencher: &mut Bencher<'_>) {
let input = test_data();
let mut decoder = combine::stream::decoder::Decoder::new();
bencher.iter(|| {
let cursor = Cursor::new(&input);
let mut partial_read = PartialRead::new(cursor, std::iter::repeat(PartialOp::Unlimited));
let mut ref_decoder = &mut decoder;
let result = combine::decode!(ref_decoder, partial_read, parser(), |input, _position| {
combine::easy::Stream::from(input)
},);
match result {
Ok(usize) => black_box(usize),
Err(err) => {
println!("{:?}", err);
panic!();
}
};
});
}
fn bench(c: &mut Criterion) {
c.bench_function("buffers_small", bench_small_buf);
c.bench_function("buffers_big", bench_big_buf);
}
criterion_group!(buffers, bench);
criterion_main!(buffers);
[
{
"_id": "54d38af178bf1fbfe80a59e5",
"index": 0,
"guid": "cc631fea-7bf2-4595-950c-097880a818bc",
"isActive": false,
"balance": "$3,397.06",
"picture": "http://placehold.it/32x32",
"age": 39,
"eyeColor": "brown",
"name": "Corina Tyler",
"gender": "female",
"company": "GEEKOL",
"email": "corinatyler@geekol.com",
"phone": "+1 (899) 452-2754",
"address": "608 Leonard Street, Yettem, Connecticut, 6707",
"about": "Ea dolore pariatur aliqua veniam officia est et fugiat ipsum do sunt mollit id aute. Nisi ad elit ut et et. Duis in aliquip id labore ex et laboris anim magna proident Lorem est ut. Consectetur sint aliqua eu exercitation anim cupidatat fugiat. Enim exercitation amet ex irure quis anim est fugiat et laborum.\r\n",
"registered": "2014-03-27T05:29:11 -01:00",
"latitude": -57.157547,
"longitude": -23.548119,
"tags": [
"est",
"est",
"exercitation",
"ipsum",
"tempor",
"id",
"aliqua"
],
"friends": [
{
"id": 0,
"name": "Bates Lynch"
},
{
"id": 1,
"name": "Duffy Townsend"
},
{
"id": 2,
"name": "Nelson Good"
}
],
"greeting": "Hello, Corina Tyler! You have 8 unread messages.",
"favoriteFruit": "apple"
},
{
"_id": "54d38af1c9a8d04d5e35f211",
"index": 1,
"guid": "d8dd5231-048f-4a5a-b392-8f7c3492ad15",
"isActive": false,
"balance": "$1,646.89",
"picture": "http://placehold.it/32x32",
"age": 22,
"eyeColor": "brown",
"name": "Santos Boyd",
"gender": "male",
"company": "AUTOGRATE",
"email": "santosboyd@autograte.com",
"phone": "+1 (872) 545-2605",
"address": "428 Homecrest Avenue, Century, Kentucky, 1905",
"about": "Quis cillum mollit adipisicing duis sunt. Eiusmod culpa reprehenderit proident magna laborum voluptate incididunt et ipsum in laboris consectetur. Nostrud consequat excepteur nisi magna officia.\r\n",
"registered": "2015-02-03T03:03:32 -01:00",
"latitude": 47.505093,
"longitude": -138.153509,
"tags": [
"aliquip",
"et",
"eu",
"minim",
"non",
"eiusmod",
"deserunt"
],
"friends": [
{
"id": 0,
"name": "Annmarie Larson"
},
{
"id": 1,
"name": "Cherie Potts"
},
{
"id": 2,
"name": "Catalina Bass"
}
],
"greeting": "Hello, Santos Boyd! You have 1 unread messages.",
"favoriteFruit": "apple"
},
{
"_id": "54d38af171fedb95c2841d64",
"index": 2,
"guid": "f4b131d7-871f-4503-8674-275c4c8e3121",
"isActive": false,
"balance": "$3,311.55",
"picture": "http://placehold.it/32x32",
"age": 23,
"eyeColor": "green",
"name": "Jeannie Daugherty",
"gender": "female",
"company": "COMTRAK",
"email": "jeanniedaugherty@comtrak.com",
"phone": "+1 (853) 445-3806",
"address": "189 Narrows Avenue, Cascades, Arkansas, 5738",
"about": "Velit labore mollit in sint culpa dolor consequat voluptate cupidatat ut. Laborum dolore incididunt deserunt adipisicing aliquip nisi cupidatat. Aliqua cillum consequat voluptate nulla velit deserunt cillum do reprehenderit cupidatat quis labore anim nulla. Irure do nisi et ea excepteur culpa mollit aliqua occaecat id dolore ullamco ad. Magna enim consectetur ea ullamco tempor magna eu consequat sint irure. In Lorem est id est do anim ex.\r\n",
"registered": "2014-01-29T22:48:53 -01:00",
"latitude": 72.451611,
"longitude": -89.847471,
"tags": [
"consequat",
"deserunt",
"ipsum",
"commodo",
"magna",
"ut",
"ut"
],
"friends": [
{
"id": 0,
"name": "Kenya Alford"
},
{
"id": 1,
"name": "Francesca Carpenter"
},
{
"id": 2,
"name": "Celina Petty"
}
],
"greeting": "Hello, Jeannie Daugherty! You have 3 unread messages.",
"favoriteFruit": "strawberry"
},
{
"_id": "54d38af16b1001dc2ee7f7b0",
"index": 3,
"guid": "c905d47f-8e7a-488d-a1a0-df61bf1af2eb",
"isActive": true,
"balance": "$2,311.19",
"picture": "http://placehold.it/32x32",
"age": 39,
"eyeColor": "green",
"name": "Jordan Horton",
"gender": "female",
"company": "ENERSOL",
"email": "jordanhorton@enersol.com",
"phone": "+1 (910) 467-2211",
"address": "123 Harwood Place, Northchase, Guam, 5138",
"about": "Cupidatat aliqua nisi minim ad culpa cupidatat proident fugiat veniam aliquip minim anim et. Ullamco consequat consequat aute exercitation aliqua eiusmod sunt ea. Et laborum dolor ex proident do non adipisicing nostrud voluptate qui reprehenderit elit ad nostrud. Excepteur exercitation laborum nulla laboris incididunt. Est sunt nisi eu id fugiat excepteur. In sunt laborum aliquip aute ipsum.\r\n",
"registered": "2014-10-08T23:32:53 -02:00",
"latitude": -52.78747,
"longitude": -121.825343,
"tags": [
"voluptate",
"non",
"dolor",
"nisi",
"minim",
"mollit",
"minim"
],
"friends": [
{
"id": 0,
"name": "Fields Ballard"
},
{
"id": 1,
"name": "Peterson Reese"
},
{
"id": 2,
"name": "Montoya Mccullough"
}
],
"greeting": "Hello, Jordan Horton! You have 3 unread messages.",
"favoriteFruit": "banana"
},
{
"_id": "54d38af1ae98fd5f8860a1a0",
"index": 4,
"guid": "d6f73551-9672-4f4a-b832-1d2942a53203",
"isActive": false,
"balance": "$1,178.62",
"picture": "http://placehold.it/32x32",
"age": 36,
"eyeColor": "green",
"name": "Mae Roy",
"gender": "female",
"company": "BUGSALL",
"email": "maeroy@bugsall.com",
"phone": "+1 (859) 452-3883",
"address": "266 Berriman Street, Logan, Rhode Island, 2566",
"about": "Adipisicing id incididunt ut excepteur officia incididunt enim quis dolor incididunt esse esse. Nulla laboris pariatur eiusmod veniam duis ipsum Lorem ex cupidatat do sunt commodo cillum. Laboris enim aute irure qui officia laborum. Veniam ullamco ad laboris nulla minim laboris ut ad minim non duis.\r\n",
"registered": "2014-07-31T12:08:03 -02:00",
"latitude": 49.234132,
"longitude": -86.652077,
"tags": [
"ut",
"mollit",
"duis",
"ea",
"cillum",
"in",
"ut"
],
"friends": [
{
"id": 0,
"name": "Acevedo Kent"
},
{
"id": 1,
"name": "Wood Edwards"
},
{
"id": 2,
"name": "Kris Brennan"
}
],
"greeting": "Hello, Mae Roy! You have 3 unread messages.",
"favoriteFruit": "strawberry"
},
{
"_id": "54d38af1638743947b6d15c2",
"index": 5,
"guid": "db331420-0216-4a92-93eb-23aa0f69a533",
"isActive": true,
"balance": "$2,375.71",
"picture": "http://placehold.it/32x32",
"age": 20,
"eyeColor": "blue",
"name": "Mooney Manning",
"gender": "male",
"company": "HOMELUX",
"email": "mooneymanning@homelux.com",
"phone": "+1 (865) 585-2829",
"address": "833 Madison Street, Mulino, Iowa, 249",
"about": "Et ex irure magna culpa fugiat magna exercitation laborum velit quis nostrud et minim in. Sint nulla laboris non non. Do excepteur dolor ipsum proident anim.\r\n",
"registered": "2014-12-23T16:46:55 -01:00",
"latitude": -37.873914,
"longitude": 11.797406,
"tags": [
"cupidatat",
"labore",
"culpa",
"esse",
"amet",
"nostrud",
"irure"
],
"friends": [
{
"id": 0,
"name": "Avila Lawrence"
},
{
"id": 1,
"name": "Wright Stokes"
},
{
"id": 2,
"name": "Joann Ramirez"
}
],
"greeting": "Hello, Mooney Manning! You have 8 unread messages.",
"favoriteFruit": "banana"
},
{
"_id": "54d38af187f8159129b215ef",
"index": 6,
"guid": "0a7a0751-3ed3-480e-8b87-082f440d4bde",
"isActive": false,
"balance": "$2,258.43",
"picture": "http://placehold.it/32x32",
"age": 26,
"eyeColor": "brown",
"name": "Sylvia Roberts",
"gender": "female",
"company": "ZOLARITY",
"email": "sylviaroberts@zolarity.com",
"phone": "+1 (852) 580-3720",
"address": "604 Boardwalk , Greensburg, Pennsylvania, 9876",
"about": "Amet mollit mollit nostrud dolor ut et. Eiusmod amet id nulla commodo qui ullamco pariatur nulla magna nisi proident. Irure aliquip eu excepteur incididunt nisi consectetur.\r\n",
"registered": "2014-09-20T02:58:52 -02:00",
"latitude": 3.989497,
"longitude": -111.05834,
"tags": [
"culpa",
"quis",
"commodo",
"laboris",
"consectetur",
"pariatur",
"enim"
],
"friends": [
{
"id": 0,
"name": "Logan Rivas"
},
{
"id": 1,
"name": "Bryan Sullivan"
},
{
"id": 2,
"name": "Bobbie Cleveland"
}
],
"greeting": "Hello, Sylvia Roberts! You have 9 unread messages.",
"favoriteFruit": "banana"
}
]
GET / HTTP/1.1
Host: www.reddit.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
GET /reddit.v_EZwRzV-Ns.css HTTP/1.1
Host: www.redditstatic.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/css,*/*;q=0.1
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /reddit-init.en-us.O1zuMqOOQvY.js HTTP/1.1
Host: www.redditstatic.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /reddit.en-us.31yAfSoTsfo.js HTTP/1.1
Host: www.redditstatic.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /kill.png HTTP/1.1
Host: www.redditstatic.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /icon.png HTTP/1.1
Host: www.redditstatic.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
GET /favicon.ico HTTP/1.1
Host: www.redditstatic.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
GET /AMZM4CWd6zstSC8y.jpg HTTP/1.1
Host: b.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /jz1d5Nm0w97-YyNm.jpg HTTP/1.1
Host: b.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /aWGO99I6yOcNUKXB.jpg HTTP/1.1
Host: a.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /rZ_rD5TjrJM0E9Aj.css HTTP/1.1
Host: e.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/css,*/*;q=0.1
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /tmsPwagFzyTvrGRx.jpg HTTP/1.1
Host: a.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /KYgUaLvXCK3TCEJx.jpg HTTP/1.1
Host: a.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /81pzxT5x2ozuEaxX.jpg HTTP/1.1
Host: e.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /MFqCUiUVPO5V8t6x.jpg HTTP/1.1
Host: a.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /TFpYTiAO5aEowokv.jpg HTTP/1.1
Host: e.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /eMWMpmm9APNeNqcF.jpg HTTP/1.1
Host: e.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /S-IpsJrOKuaK9GZ8.jpg HTTP/1.1
Host: c.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /3V6dj9PDsNnheDXn.jpg HTTP/1.1
Host: c.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /wQ3-VmNXhv8sg4SJ.jpg HTTP/1.1
Host: c.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /ixd1C1njpczEWC22.jpg HTTP/1.1
Host: c.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /nGsQj15VyOHMwmq8.jpg HTTP/1.1
Host: c.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /zT4yQmDxQLbIxK1b.jpg HTTP/1.1
Host: c.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /L5e1HcZLv1iu4nrG.jpg HTTP/1.1
Host: f.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /WJFFPxD8X4JO_lIG.jpg HTTP/1.1
Host: f.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /hVMVTDdjuY3bQox5.jpg HTTP/1.1
Host: f.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /rnWf8CjBcyPQs5y_.jpg HTTP/1.1
Host: f.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /gZJL1jNylKbGV4d-.jpg HTTP/1.1
Host: d.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /aNd2zNRLXiMnKUFh.jpg HTTP/1.1
Host: c.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /droparrowgray.gif HTTP/1.1
Host: www.redditstatic.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.redditstatic.com/reddit.v_EZwRzV-Ns.css
GET /sprite-reddit.an0Lnf61Ap4.png HTTP/1.1
Host: www.redditstatic.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.redditstatic.com/reddit.v_EZwRzV-Ns.css
GET /ga.js HTTP/1.1
Host: www.google-analytics.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
If-Modified-Since: Tue, 29 Oct 2013 19:33:51 GMT
GET /reddit/ads.html?sr=-reddit.com&bust2 HTTP/1.1
Host: static.adzerk.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /pixel/of_destiny.png?v=hOlmDALJCWWdjzfBV4ZxJPmrdCLWB%2Ftq7Z%2Ffp4Q%2FxXbVPPREuMJMVGzKraTuhhNWxCCwi6yFEZg%3D&r=783333388 HTTP/1.1
Host: pixel.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /UNcO-h_QcS9PD-Gn.jpg HTTP/1.1
Host: c.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://e.thumbs.redditmedia.com/rZ_rD5TjrJM0E9Aj.css
GET /welcome-lines.png HTTP/1.1
Host: www.redditstatic.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.redditstatic.com/reddit.v_EZwRzV-Ns.css
GET /welcome-upvote.png HTTP/1.1
Host: www.redditstatic.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.redditstatic.com/reddit.v_EZwRzV-Ns.css
GET /__utm.gif?utmwv=5.5.1&utms=1&utmn=720496082&utmhn=www.reddit.com&utme=8(site*srpath*usertype*uitype)9(%20reddit.com*%20reddit.com-GET_listing*guest*web)11(3!2)&utmcs=UTF-8&utmsr=2560x1600&utmvp=1288x792&utmsc=24-bit&utmul=en-us&utmje=1&utmfl=13.0%20r0&utmdt=reddit%3A%20the%20front%20page%20of%20the%20internet&utmhid=2129416330&utmr=-&utmp=%2F&utmht=1400862512705&utmac=UA-12131688-1&utmcc=__utma%3D55650728.585571751.1400862513.1400862513.1400862513.1%3B%2B__utmz%3D55650728.1400862513.1.1.utmcsr%3D(direct)%7Cutmccn%3D(direct)%7Cutmcmd%3D(none)%3B&utmu=qR~ HTTP/1.1
Host: www.google-analytics.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /ImnpOQhbXUPkwceN.png HTTP/1.1
Host: a.thumbs.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /ajax/libs/jquery/1.7.1/jquery.min.js HTTP/1.1
Host: ajax.googleapis.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2
GET /__utm.gif?utmwv=5.5.1&utms=2&utmn=1493472678&utmhn=www.reddit.com&utmt=event&utme=5(AdBlock*enabled*false)(0)8(site*srpath*usertype*uitype)9(%20reddit.com*%20reddit.com-GET_listing*guest*web)11(3!2)&utmcs=UTF-8&utmsr=2560x1600&utmvp=1288x792&utmsc=24-bit&utmul=en-us&utmje=1&utmfl=13.0%20r0&utmdt=reddit%3A%20the%20front%20page%20of%20the%20internet&utmhid=2129416330&utmr=-&utmp=%2F&utmht=1400862512708&utmac=UA-12131688-1&utmni=1&utmcc=__utma%3D55650728.585571751.1400862513.1400862513.1400862513.1%3B%2B__utmz%3D55650728.1400862513.1.1.utmcsr%3D(direct)%7Cutmccn%3D(direct)%7Cutmcmd%3D(none)%3B&utmu=6R~ HTTP/1.1
Host: www.google-analytics.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /ados.js?q=43 HTTP/1.1
Host: secure.adzerk.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2
GET /fetch-trackers?callback=jQuery111005268222517967478_1400862512407&ids%5B%5D=t3_25jzeq-t8_k2ii&_=1400862512408 HTTP/1.1
Host: tracker.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /ados?t=1400862512892&request={%22Placements%22:[{%22A%22:5146,%22S%22:24950,%22D%22:%22main%22,%22AT%22:5},{%22A%22:5146,%22S%22:24950,%22D%22:%22sponsorship%22,%22AT%22:8}],%22Keywords%22:%22-reddit.com%22,%22Referrer%22:%22http%3A%2F%2Fwww.reddit.com%2F%22,%22IsAsync%22:true,%22WriteResults%22:true} HTTP/1.1
Host: engine.adzerk.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2
GET /pixel/of_doom.png?id=t3_25jzeq-t8_k2ii&hash=da31d967485cdbd459ce1e9a5dde279fef7fc381&r=1738649500 HTTP/1.1
Host: pixel.redditmedia.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /Extensions/adFeedback.js HTTP/1.1
Host: static.adzrk.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2
GET /Extensions/adFeedback.css HTTP/1.1
Host: static.adzrk.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/css,*/*;q=0.1
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2
GET /reddit/ads-load.html?bust2 HTTP/1.1
Host: static.adzerk.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.reddit.com/
GET /Advertisers/a774d7d6148046efa89403a8db635a81.jpg HTTP/1.1
Host: static.adzerk.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2
GET /i.gif?e=eyJhdiI6NjIzNTcsImF0Ijo1LCJjbSI6MTE2MzUxLCJjaCI6Nzk4NCwiY3IiOjMzNzAxNSwiZGkiOiI4NmI2Y2UzYWM5NDM0MjhkOTk2ZTg4MjYwZDE5ZTE1YyIsImRtIjoxLCJmYyI6NDE2MTI4LCJmbCI6MjEwNDY0LCJrdyI6Ii1yZWRkaXQuY29tIiwibWsiOiItcmVkZGl0LmNvbSIsIm53Ijo1MTQ2LCJwYyI6MCwicHIiOjIwMzYyLCJydCI6MSwicmYiOiJodHRwOi8vd3d3LnJlZGRpdC5jb20vIiwic3QiOjI0OTUwLCJ1ayI6InVlMS01ZWIwOGFlZWQ5YTc0MDFjOTE5NWNiOTMzZWI3Yzk2NiIsInRzIjoxNDAwODYyNTkzNjQ1fQ&s=lwlbFf2Uywt7zVBFRj_qXXu7msY HTTP/1.1
Host: engine.adzerk.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2
Cookie: azk=ue1-5eb08aeed9a7401c9195cb933eb7c966
GET /BurstingPipe/adServer.bs?cn=tf&c=19&mc=imp&pli=9994987&PluID=0&ord=1400862593644&rtu=-1 HTTP/1.1
Host: bs.serving-sys.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2
GET /Advertisers/63cfd0044ffd49c0a71a6626f7a1d8f0.jpg HTTP/1.1
Host: static.adzerk.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://static.adzerk.net/reddit/ads-load.html?bust2
GET /BurstingPipe/adServer.bs?cn=tf&c=19&mc=imp&pli=9962555&PluID=0&ord=1400862593645&rtu=-1 HTTP/1.1
Host: bs.serving-sys.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://static.adzerk.net/reddit/ads-load.html?bust2
Cookie: S_9994987=6754579095859875029; A4=01fmFvgRnI09SF00000; u2=d1263d39-874b-4a89-86cd-a2ab0860ed4e3Zl040
GET /i.gif?e=eyJhdiI6NjIzNTcsImF0Ijo4LCJjbSI6MTE2MzUxLCJjaCI6Nzk4NCwiY3IiOjMzNzAxOCwiZGkiOiI3OTdlZjU3OWQ5NjE0ODdiODYyMGMyMGJkOTE4YzNiMSIsImRtIjoxLCJmYyI6NDE2MTMxLCJmbCI6MjEwNDY0LCJrdyI6Ii1yZWRkaXQuY29tIiwibWsiOiItcmVkZGl0LmNvbSIsIm53Ijo1MTQ2LCJwYyI6MCwicHIiOjIwMzYyLCJydCI6MSwicmYiOiJodHRwOi8vd3d3LnJlZGRpdC5jb20vIiwic3QiOjI0OTUwLCJ1ayI6InVlMS01ZWIwOGFlZWQ5YTc0MDFjOTE5NWNiOTMzZWI3Yzk2NiIsInRzIjoxNDAwODYyNTkzNjQ2fQ&s=OjzxzXAgQksbdQOHNm-bjZcnZPA HTTP/1.1
Host: engine.adzerk.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://static.adzerk.net/reddit/ads-load.html?bust2
Cookie: azk=ue1-5eb08aeed9a7401c9195cb933eb7c966
GET /subscribe?host_int=1042356184&ns_map=571794054_374233948806,464381511_13349283399&user_id=245722467&nid=1399334269710011966&ts=1400862514 HTTP/1.1
Host: notify8.dropbox.com
Accept-Encoding: identity
Connection: keep-alive
X-Dropbox-Locale: en_US
User-Agent: DropboxDesktopClient/2.7.54 (Macintosh; 10.8; ('i32',); en_US)
#![cfg(feature = "std")]
#[macro_use]
extern crate criterion;
#[macro_use]
extern crate combine;
use std::fmt;
use {
combine::{
many, many1,
parser::range::{range, take_while1},
stream::easy,
token, ParseError, Parser, RangeStream,
},
criterion::{black_box, Bencher, Criterion},
};
#[allow(dead_code)]
#[derive(Debug)]
struct Request<'a> {
method: &'a [u8],
uri: &'a [u8],
version: &'a [u8],
}
#[allow(dead_code)]
#[derive(Debug)]
struct Header<'a> {
name: &'a [u8],
value: Vec<&'a [u8]>,
}
fn is_token(c: u8) -> bool {
!matches!(
c,
128..=255
| 0..=31
| b'('
| b')'
| b'<'
| b'>'
| b'@'
| b','
| b';'
| b':'
| b'\\'
| b'"'
| b'/'
| b'['
| b']'
| b'?'
| b'='
| b'{'
| b'}'
| b' '
)
}
fn is_horizontal_space(c: u8) -> bool {
c == b' ' || c == b'\t'
}
fn is_space(c: u8) -> bool {
c == b' '
}
fn is_not_space(c: u8) -> bool {
c != b' '
}
fn is_http_version(c: u8) -> bool {
(b'0'..=b'9').contains(&c) || c == b'.'
}
fn end_of_line<'a, Input>() -> impl Parser<Input, Output = u8>
where
Input: RangeStream<Token = u8, Range = &'a [u8]>,
{
(token(b'\r'), token(b'\n')).map(|_| b'\r').or(token(b'\n'))
}
fn message_header<'a, Input>() -> impl Parser<Input, Output = Header<'a>>
where
Input: RangeStream<Token = u8, Range = &'a [u8]>,
{
let message_header_line = (
take_while1(is_horizontal_space),
take_while1(|c| c != b'\r' && c != b'\n'),
end_of_line(),
)
.map(|(_, line, _)| line);
struct_parser!(Header {
name: take_while1(is_token),
_: token(b':'),
value: many1(message_header_line),
})
}
type HttpRequest<'a> = (Request<'a>, Vec<Header<'a>>);
fn parse_http_request<'a, Input>(input: Input) -> Result<(HttpRequest<'a>, Input), Input::Error>
where
Input: RangeStream<Token = u8, Range = &'a [u8]>,
{
let http_version = range(&b"HTTP/"[..]).with(take_while1(is_http_version));
let request_line = struct_parser!(Request {
method: take_while1(is_token),
_: take_while1(is_space),
uri: take_while1(is_not_space),
_: take_while1(is_space),
version: http_version,
});
let mut request = (
request_line,
end_of_line(),
many(message_header()),
end_of_line(),
)
.map(|(request, _, headers, _)| (request, headers));
request.parse(input)
}
static REQUESTS: &[u8] = include_bytes!("http-requests.txt");
fn http_requests_small(b: &mut Bencher<'_>) {
http_requests_bench(b, easy::Stream(REQUESTS))
}
fn http_requests_large(b: &mut Bencher<'_>) {
use std::iter;
let mut buffer = Vec::with_capacity(REQUESTS.len() * 5);
for buf in iter::repeat(REQUESTS).take(5) {
buffer.extend_from_slice(buf);
}
http_requests_bench(b, easy::Stream(&buffer[..]))
}
fn http_requests_large_cheap_error(b: &mut Bencher<'_>) {
use std::iter;
let mut buffer = Vec::with_capacity(REQUESTS.len() * 5);
for buf in iter::repeat(REQUESTS).take(5) {
buffer.extend_from_slice(buf);
}
http_requests_bench(b, &buffer[..])
}
fn http_requests_bench<'a, Input>(b: &mut Bencher<'_>, buffer: Input)
where
Input: RangeStream<Token = u8, Range = &'a [u8]> + Clone,
Input::Error: fmt::Debug,
{
b.iter(|| {
let mut buf = black_box(buffer.clone());
while buf.clone().uncons().is_ok() {
match parse_http_request(buf) {
Ok(((_, _), b)) => {
buf = b;
}
Err(err) => panic!("{:?}", err),
}
}
});
}
fn http_requests(c: &mut Criterion) {
c.bench_function("http_requests_small", http_requests_small);
c.bench_function("http_requests_large", http_requests_large);
c.bench_function(
"http_requests_large_cheap_error",
http_requests_large_cheap_error,
);
}
criterion_group!(http, http_requests,);
criterion_main!(http);
#![cfg(feature = "std")]
#[macro_use]
extern crate criterion;
#[macro_use]
extern crate combine;
use std::{collections::HashMap, fs::File, io::Read, path::Path};
use {
combine::{
error::{Commit, ParseError},
parser::{
char::{char, digit, spaces, string},
choice::{choice, optional},
function::parser,
repeat::{many, many1, sep_by},
sequence::between,
token::{any, satisfy, satisfy_map},
},
stream::{
buffered,
position::{self, SourcePosition},
IteratorStream,
},
EasyParser, Parser, Stream, StreamOnce,
},
criterion::{black_box, Bencher, Criterion},
};
#[derive(PartialEq, Debug)]
enum Value {
Number(f64),
String(String),
Bool(bool),
Null,
Object(HashMap<String, Value>),
Array(Vec<Value>),
}
fn lex<Input, P>(p: P) -> impl Parser<Input, Output = P::Output>
where
P: Parser<Input>,
Input: Stream<Token = char>,
<Input as StreamOnce>::Error: ParseError<
<Input as StreamOnce>::Token,
<Input as StreamOnce>::Range,
<Input as StreamOnce>::Position,
>,
{
p.skip(spaces())
}
fn integer<Input>() -> impl Parser<Input, Output = i64>
where
Input: Stream<Token = char>,
{
lex(many1(digit()))
.map(|s: String| {
let mut n = 0;
for c in s.chars() {
n = n * 10 + (c as i64 - '0' as i64);
}
n
})
.expected("integer")
}
fn number<Input>() -> impl Parser<Input, Output = f64>
where
Input: Stream<Token = char>,
{
let i = char('0').map(|_| 0.0).or(integer().map(|x| x as f64));
let fractional = many(digit()).map(|digits: String| {
let mut magnitude = 1.0;
digits.chars().fold(0.0, |acc, d| {
magnitude /= 10.0;
match d.to_digit(10) {
Some(d) => acc + (d as f64) * magnitude,
None => panic!("Not a digit"),
}
})
});
let exp = satisfy(|c| c == 'e' || c == 'E').with(optional(char('-')).and(integer()));
lex(optional(char('-'))
.and(i)
.map(|(sign, n)| if sign.is_some() { -n } else { n })
.and(optional(char('.')).with(fractional))
.map(|(x, y)| if x >= 0.0 { x + y } else { x - y })
.and(optional(exp))
.map(|(n, exp_option)| match exp_option {
Some((sign, e)) => {
let e = if sign.is_some() { -e } else { e };
n * 10.0f64.powi(e as i32)
}
None => n,
}))
.expected("number")
}
fn json_char<Input>() -> impl Parser<Input, Output = char>
where
Input: Stream<Token = char>,
{
parser(|input: &mut Input| {
let (c, committed) = any().parse_lazy(input).into_result()?;
let mut back_slash_char = satisfy_map(|c| {
Some(match c {
'"' => '"',
'\\' => '\\',
'/' => '/',
'b' => '\u{0008}',
'f' => '\u{000c}',
'n' => '\n',
'r' => '\r',
't' => '\t',
_ => return None,
})
});
match c {
'\\' => committed.combine(|_| back_slash_char.parse_stream(input).into_result()),
'"' => Err(Commit::Peek(Input::Error::empty(input.position()).into())),
_ => Ok((c, committed)),
}
})
}
fn json_string<Input>() -> impl Parser<Input, Output = String>
where
Input: Stream<Token = char>,
{
between(char('"'), lex(char('"')), many(json_char())).expected("string")
}
fn object<Input>() -> impl Parser<Input, Output = Value>
where
Input: Stream<Token = char>,
{
let field = (json_string(), lex(char(':')), json_value()).map(|t| (t.0, t.2));
let fields = sep_by(field, lex(char(',')));
between(lex(char('{')), lex(char('}')), fields)
.map(Value::Object)
.expected("object")
}
#[inline]
fn json_value<Input>() -> impl Parser<Input, Output = Value>
where
Input: Stream<Token = char>,
{
json_value_()
}
// We need to use `parser!` to break the recursive use of `value` to prevent the returned parser
// from containing itself
parser! {
#[inline]
fn json_value_[Input]()(Input) -> Value
where [ Input: Stream<Token = char> ]
{
let array = between(
lex(char('[')),
lex(char(']')),
sep_by(json_value(), lex(char(','))),
).map(Value::Array);
choice((
json_string().map(Value::String),
object(),
array,
number().map(Value::Number),
lex(string("false").map(|_| Value::Bool(false))),
lex(string("true").map(|_| Value::Bool(true))),
lex(string("null").map(|_| Value::Null)),
))
}
}
#[test]
fn json_test() {
use self::Value::*;
let input = r#"{
"array": [1, ""],
"object": {},
"number": 3.14,
"small_number": 0.59,
"int": -100,
"exp": -1e2,
"exp_neg": 23e-2,
"true": true,
"false" : false,
"null" : null
}"#;
let result = json_value().easy_parse(input);
let expected = Object(
vec![
("array", Array(vec![Number(1.0), String("".to_string())])),
("object", Object(HashMap::new())),
("number", Number(3.14)),
("small_number", Number(0.59)),
("int", Number(-100.)),
("exp", Number(-1e2)),
("exp_neg", Number(23E-2)),
("true", Bool(true)),
("false", Bool(false)),
("null", Null),
]
.into_iter()
.map(|(k, v)| (k.to_string(), v))
.collect(),
);
match result {
Ok(result) => assert_eq!(result, (expected, "")),
Err(e) => {
println!("{}", e);
panic!();
}
}
}
fn test_data() -> String {
let mut data = String::new();
File::open(&Path::new(&"benches/data.json"))
.and_then(|mut file| file.read_to_string(&mut data))
.unwrap();
data
}
fn bench_json(bencher: &mut Bencher<'_>) {
let data = test_data();
let mut parser = json_value();
match parser.easy_parse(position::Stream::new(&data[..])) {
Ok((Value::Array(_), _)) => (),
Ok(_) => panic!(),
Err(err) => {
println!("{}", err);
panic!();
}
}
bencher.iter(|| {
let result = parser.easy_parse(position::Stream::new(&data[..]));
black_box(result)
});
}
fn bench_json_core_error(bencher: &mut Bencher<'_>) {
let data = test_data();
let mut parser = json_value();
match parser.parse(position::Stream::new(&data[..])) {
Ok((Value::Array(_), _)) => (),
Ok(_) => panic!(),
Err(err) => {
println!("{}", err);
panic!();
}
}
bencher.iter(|| {
let result = parser.parse(position::Stream::new(&data[..]));
black_box(result)
});
}
fn bench_json_core_error_no_position(bencher: &mut Bencher<'_>) {
let data = test_data();
let mut parser = json_value();
match parser.parse(&data[..]) {
Ok((Value::Array(_), _)) => (),
Ok(_) => panic!(),
Err(err) => {
println!("{}", err);
panic!();
}
}
bencher.iter(|| {
let result = parser.parse(&data[..]);
black_box(result)
});
}
fn bench_buffered_json(bencher: &mut Bencher<'_>) {
let data = test_data();
bencher.iter(|| {
let buffer =
buffered::Stream::new(position::Stream::new(IteratorStream::new(data.chars())), 1);
let mut parser = json_value();
match parser.easy_parse(position::Stream::with_positioner(
buffer,
SourcePosition::default(),
)) {
Ok((Value::Array(v), _)) => {
black_box(v);
}
Ok(_) => panic!(),
Err(err) => {
println!("{}", err);
panic!();
}
}
});
}
fn bench(c: &mut Criterion) {
c.bench_function("json", bench_json);
c.bench_function("json_core_error", bench_json_core_error);
c.bench_function(
"json_core_error_no_position",
bench_json_core_error_no_position,
);
c.bench_function("buffered_json", bench_buffered_json);
}
criterion_group!(json, bench);
criterion_main!(json);
#![cfg(feature = "mp4")]
#[macro_use]
extern crate criterion;
use std::{fs::File, io::Read, str::from_utf8};
use {
combine::{
parser::{
byte::num::be_u32,
range::{range, take},
},
stream::easy::ParseError,
*,
},
criterion::{black_box, Bencher, Criterion},
};
#[derive(Clone, PartialEq, Eq, Debug)]
struct FileType<'a> {
major_brand: &'a str,
major_brand_version: &'a [u8],
compatible_brands: Vec<&'a str>,
}
#[derive(Clone, Debug)]
enum MP4Box<'a> {
Ftyp(FileType<'a>),
Moov,
Mdat,
Free,
Skip,
Wide,
Unknown,
}
fn parse_mp4(data: &[u8]) -> Result<(Vec<MP4Box>, &[u8]), ParseError<&[u8]>> {
let brand_name = || take(4).and_then(from_utf8);
let filetype_box = (
range(&b"ftyp"[..]),
brand_name(),
take(4),
many(brand_name()),
)
.map(|(_, m, v, c)| {
MP4Box::Ftyp(FileType {
major_brand: m,
major_brand_version: v,
compatible_brands: c,
})
});
let mp4_box = be_u32().then(|offset| take(offset as usize - 4));
let mut box_parser = choice((
filetype_box,
range(&b"moov"[..]).map(|_| MP4Box::Moov),
range(&b"mdat"[..]).map(|_| MP4Box::Mdat),
range(&b"free"[..]).map(|_| MP4Box::Free),
range(&b"skip"[..]).map(|_| MP4Box::Skip),
range(&b"wide"[..]).map(|_| MP4Box::Wide),
value(MP4Box::Unknown),
));
let data_interpreter =
mp4_box.flat_map(|box_data| box_parser.easy_parse(box_data).map(|t| t.0));
many(data_interpreter).easy_parse(data)
}
fn run_test(b: &mut Bencher, data: &[u8]) {
b.iter(|| match parse_mp4(data) {
Ok(x) => black_box(x),
Err(err) => panic!("{}", err.map_range(|bytes| format!("{:?}", bytes))),
});
}
fn mp4_small_test(c: &mut Criterion) {
let mut mp4_small = Vec::new();
File::open("benches/small.mp4")
.and_then(|mut f| f.read_to_end(&mut mp4_small))
.expect("Unable to read benches/small.mp4");
c.bench_function("mp4_small", move |b| run_test(b, &mp4_small));
}
criterion_group!(mp4, mp4_small_test);
criterion_main!(mp4);
#!/bin/bash -x
set -ex
cargo "$@" build
cargo "$@" test --all-features
cargo "$@" test --all-features --examples
cargo "$@" test --bench json --bench http -- --test
cargo "$@" check --bench mp4 --features mp4
cargo "$@" build --no-default-features --features alloc
cargo "$@" test --no-default-features --features alloc --examples
cargo "$@" build --no-default-features
cargo "$@" test --no-default-features --examples
cargo "$@" check --no-default-features --features tokio-02
cargo "$@" check --no-default-features --features tokio-03
#![cfg(feature = "std")]
#![cfg(feature = "tokio")]
use std::{cell::Cell, io::Cursor, rc::Rc, str};
use {futures_03_dep as futures, tokio_dep as tokio};
use {
bytes::{Buf, BytesMut},
combine::{
error::{ParseError, StreamError},
parser::{
byte::digit,
combinator::{any_partial_state, AnyPartialState},
range::{range, recognize, take},
},
skip_many, skip_many1,
stream::{easy, PartialStream, RangeStream, StreamErrorFor},
Parser,
},
futures::prelude::*,
partial_io::PartialOp,
tokio_util::codec::{Decoder, FramedRead},
};
// Workaround partial_io not working with tokio-0.2
#[path = "../tests/support/mod.rs"]
mod support;
use support::*;
pub struct LanguageServerDecoder {
state: AnyPartialState,
content_length_parses: Rc<Cell<i32>>,
}
impl Default for LanguageServerDecoder {
fn default() -> Self {
LanguageServerDecoder {
state: Default::default(),
content_length_parses: Rc::new(Cell::new(0)),
}
}
}
/// Parses blocks of data with length headers
///
/// ```
/// Content-Length: 18
///
/// { "some": "data" }
/// ```
// The `content_length_parses` parameter only exists to demonstrate that `content_length` only
// gets parsed once per message
fn decode_parser<'a, Input>(
content_length_parses: Rc<Cell<i32>>,
) -> impl Parser<Input, Output = Vec<u8>, PartialState = AnyPartialState> + 'a
where
Input: RangeStream<Token = u8, Range = &'a [u8]> + 'a,
{
let content_length = range(&b"Content-Length: "[..])
.with(recognize(skip_many1(digit())).and_then(|digits: &[u8]| {
str::from_utf8(digits)
.unwrap()
.parse::<usize>()
// Convert the error from `.parse` into an error combine understands
.map_err(StreamErrorFor::<Input>::other)
}))
.map(move |x| {
content_length_parses.set(content_length_parses.get() + 1);
x
});
// `any_partial_state` boxes the state which hides the type and lets us store it in
// `self`
any_partial_state(
(
skip_many(range(&b"\r\n"[..])),
content_length,
range(&b"\r\n\r\n"[..]).map(|_| ()),
)
.then_partial(|&mut (_, message_length, _)| {
take(message_length).map(|bytes: &[u8]| bytes.to_owned())
}),
)
}
impl Decoder for LanguageServerDecoder {
type Item = String;
type Error = Box<dyn std::error::Error + Send + Sync>;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
println!("Decoding `{:?}`", str::from_utf8(src).unwrap_or("NOT UTF8"));
let (opt, removed_len) = combine::stream::decode(
decode_parser(self.content_length_parses.clone()),
// easy::Stream gives us nice error messages
// (the same error messages that combine has had since its inception)
// PartialStream lets the parser know that more input should be
// expected if end of input is unexpectedly reached
&mut easy::Stream(PartialStream(&src[..])),
&mut self.state,
)
.map_err(|err| {
// Since err contains references into `src` we must replace these before
// we can return an error or call `advance` to remove the input we
// just committed
let err = err
.map_range(|r| {
str::from_utf8(r)
.ok()
.map_or_else(|| format!("{:?}", r), |s| s.to_string())
})
.map_position(|p| p.translate_position(&src[..]));
format!("{}\nIn input: `{}`", err, str::from_utf8(src).unwrap())
})?;
println!(
"Accepted {} bytes: `{:?}`",
removed_len,
str::from_utf8(&src[..removed_len]).unwrap_or("NOT UTF8")
);
// Remove the input we just committed.
// Ideally this would be done automatically by the call to
// `stream::decode` but it does unfortunately not work due
// to lifetime issues (Non lexical lifetimes might fix it!)
src.advance(removed_len);
match opt {
// `None` means we did not have enough input and we require that the
// caller of `decode` supply more before calling us again
None => {
println!("Requesting more input!");
Ok(None)
}
// `Some` means that a message was successfully decoded
// (and that we are ready to start decoding the next message)
Some(output) => {
let value = String::from_utf8(output)?;
println!("Decoded `{}`", value);
Ok(Some(value))
}
}
}
}
#[tokio::main]
async fn main() {
let input = "Content-Length: 6\r\n\
\r\n\
123456\r\n\
Content-Length: 4\r\n\
\r\n\
true";
let seq = vec![
PartialOp::Limited(20),
PartialOp::Limited(1),
PartialOp::Limited(2),
PartialOp::Limited(3),
];
let reader = &mut Cursor::new(input.as_bytes());
// Using the `partial_io` crate we emulate the partial reads that would happen when reading
// asynchronously from an io device.
let partial_reader = PartialAsyncRead::new(reader, seq);
let decoder = LanguageServerDecoder::default();
let content_length_parses = decoder.content_length_parses.clone();
let result = FramedRead::new(partial_reader, decoder).try_collect().await;
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
let values: Vec<_> = result.unwrap();
let expected_values = ["123456", "true"];
assert_eq!(values, expected_values);
assert_eq!(content_length_parses.get(), expected_values.len() as i32);
println!("Successfully parsed: `{}`", input);
println!(
"Found {} items and never repeated a completed parse!",
values.len(),
);
println!("Result: {:?}", values);
}
//! Parser example for ISO8601 dates. This does not handle the entire specification but it should
//! show the gist of it and be easy to extend to parse additional forms.
use std::{
env, fmt,
fs::File,
io::{self, Read},
};
use combine::{
choice,
many, optional,
parser::char::{char, digit},
stream::position,
Parser, Stream,
};
#[cfg(feature = "std")]
use combine::{
stream::{easy, position::SourcePosition},
EasyParser,
};
enum Error<E> {
Io(io::Error),
Parse(E),
}
impl<E> fmt::Display for Error<E>
where
E: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Error::Io(ref err) => write!(f, "{}", err),
Error::Parse(ref err) => write!(f, "{}", err),
}
}
}
#[derive(PartialEq, Debug)]
pub struct Date {
pub year: i32,
pub month: i32,
pub day: i32,
}
#[derive(PartialEq, Debug)]
pub struct Time {
pub hour: i32,
pub minute: i32,
pub second: i32,
pub time_zone: i32,
}
#[derive(PartialEq, Debug)]
pub struct DateTime {
pub date: Date,
pub time: Time,
}
fn two_digits<Input>() -> impl Parser<Input, Output = i32>
where
Input: Stream<Token = char>,
{
(digit(), digit()).map(|(x, y): (char, char)| {
let x = x.to_digit(10).expect("digit");
let y = y.to_digit(10).expect("digit");
(x * 10 + y) as i32
})
}
/// Parses a time zone
/// +0012
/// -06:30
/// -01
/// Z
fn time_zone<Input>() -> impl Parser<Input, Output = i32>
where
Input: Stream<Token = char>,
{
let utc = char('Z').map(|_| 0);
let offset = (
choice([char('-'), char('+')]),
two_digits(),
optional(optional(char(':')).with(two_digits())),
)
.map(|(sign, hour, minute)| {
let offset = hour * 60 + minute.unwrap_or(0);
if sign == '-' {
-offset
} else {
offset
}
});
utc.or(offset)
}
/// Parses a date
/// 2010-01-30
fn date<Input>() -> impl Parser<Input, Output = Date>
where
Input: Stream<Token = char>,
{
(
many::<String, _, _>(digit()),
char('-'),
two_digits(),
char('-'),
two_digits(),
)
.map(|(year, _, month, _, day)| {
// Its ok to just unwrap since we only parsed digits
Date {
year: year.parse().unwrap(),
month,
day,
}
})
}
/// Parses a time
/// 12:30:02
fn time<Input>() -> impl Parser<Input, Output = Time>
where
Input: Stream<Token = char>,
{
(
two_digits(),
char(':'),
two_digits(),
char(':'),
two_digits(),
time_zone(),
)
.map(|(hour, _, minute, _, second, time_zone)| {
// Its ok to just unwrap since we only parsed digits
Time {
hour,
minute,
second,
time_zone,
}
})
}
/// Parses a date time according to ISO8601
/// 2015-08-02T18:54:42+02
fn date_time<Input>() -> impl Parser<Input, Output = DateTime>
where
Input: Stream<Token = char>,
{
(date(), char('T'), time()).map(|(date, _, time)| DateTime { date, time })
}
#[test]
fn test() {
// A parser for
let result = date_time().parse("2015-08-02T18:54:42+02");
let d = DateTime {
date: Date {
year: 2015,
month: 8,
day: 2,
},
time: Time {
hour: 18,
minute: 54,
second: 42,
time_zone: 2 * 60,
},
};
assert_eq!(result, Ok((d, "")));
let result = date_time().parse("50015-12-30T08:54:42Z");
let d = DateTime {
date: Date {
year: 50015,
month: 12,
day: 30,
},
time: Time {
hour: 8,
minute: 54,
second: 42,
time_zone: 0,
},
};
assert_eq!(result, Ok((d, "")));
}
fn main() {
let result = match env::args().nth(1) {
Some(file) => File::open(file).map_err(Error::Io).and_then(main_),
None => main_(io::stdin()),
};
match result {
Ok(_) => println!("OK"),
Err(err) => println!("{}", err),
}
}
#[cfg(feature = "std")]
fn main_<R>(mut read: R) -> Result<(), Error<easy::Errors<char, String, SourcePosition>>>
where
R: Read,
{
let mut text = String::new();
read.read_to_string(&mut text).map_err(Error::Io)?;
date_time()
.easy_parse(position::Stream::new(&*text))
.map_err(|err| Error::Parse(err.map_range(|s| s.to_string())))?;
Ok(())
}
#[cfg(not(feature = "std"))]
fn main_<R>(mut read: R) -> Result<(), Error<::combine::error::StringStreamError>>
where
R: Read,
{
let mut text = String::new();
read.read_to_string(&mut text).map_err(Error::Io)?;
date_time()
.parse(position::Stream::new(&*text))
.map_err(Error::Parse)?;
Ok(())
}
//! Parser example for INI files.
use std::{
collections::HashMap,
env, fmt,
fs::File,
io::{self, Read},
};
use combine::{parser::char::space, stream::position, *};
#[cfg(feature = "std")]
use combine::stream::easy;
#[cfg(feature = "std")]
use combine::stream::position::SourcePosition;
enum Error<E> {
Io(io::Error),
Parse(E),
}
impl<E> fmt::Display for Error<E>
where
E: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Error::Io(ref err) => write!(f, "{}", err),
Error::Parse(ref err) => write!(f, "{}", err),
}
}
}
#[derive(PartialEq, Debug)]
pub struct Ini {
pub global: HashMap<String, String>,
pub sections: HashMap<String, HashMap<String, String>>,
}
fn property<Input>() -> impl Parser<Input, Output = (String, String)>
where
Input: Stream<Token = char>,
{
(
many1(satisfy(|c| c != '=' && c != '[' && c != ';')),
token('='),
many1(satisfy(|c| c != '\n' && c != ';')),
)
.map(|(key, _, value)| (key, value))
.message("while parsing property")
}
fn whitespace<Input>() -> impl Parser<Input>
where
Input: Stream<Token = char>,
{
let comment = (token(';'), skip_many(satisfy(|c| c != '\n'))).map(|_| ());
// Wrap the `spaces().or(comment)` in `skip_many` so that it skips alternating whitespace and
// comments
skip_many(skip_many1(space()).or(comment))
}
fn properties<Input>() -> impl Parser<Input, Output = HashMap<String, String>>
where
Input: Stream<Token = char>,
{
// After each property we skip any whitespace that followed it
many(property().skip(whitespace()))
}
fn section<Input>() -> impl Parser<Input, Output = (String, HashMap<String, String>)>
where
Input: Stream<Token = char>,
{
(
between(token('['), token(']'), many(satisfy(|c| c != ']'))),
whitespace(),
properties(),
)
.map(|(name, _, properties)| (name, properties))
.message("while parsing section")
}
fn ini<Input>() -> impl Parser<Input, Output = Ini>
where
Input: Stream<Token = char>,
{
(whitespace(), properties(), many(section()))
.map(|(_, global, sections)| Ini { global, sections })
}
#[test]
fn ini_ok() {
let text = r#"
language=rust
[section]
name=combine; Comment
type=LL(1)
"#;
let mut expected = Ini {
global: HashMap::new(),
sections: HashMap::new(),
};
expected
.global
.insert(String::from("language"), String::from("rust"));
let mut section = HashMap::new();
section.insert(String::from("name"), String::from("combine"));
section.insert(String::from("type"), String::from("LL(1)"));
expected.sections.insert(String::from("section"), section);
let result = ini().parse(text).map(|t| t.0);
assert_eq!(result, Ok(expected));
}
#[cfg(feature = "std")]
#[test]
fn ini_error() {
let text = "[error";
let result = ini().easy_parse(position::Stream::new(text)).map(|t| t.0);
assert_eq!(
result,
Err(easy::Errors {
position: SourcePosition { line: 1, column: 7 },
errors: vec![
easy::Error::end_of_input(),
easy::Error::Expected(']'.into()),
easy::Error::Message("while parsing section".into()),
],
})
);
}
fn main() {
let result = match env::args().nth(1) {
Some(file) => File::open(file).map_err(Error::Io).and_then(main_),
None => main_(io::stdin()),
};
match result {
Ok(_) => println!("OK"),
Err(err) => println!("{}", err),
}
}
#[cfg(feature = "std")]
fn main_<R>(mut read: R) -> Result<(), Error<easy::Errors<char, String, SourcePosition>>>
where
R: Read,
{
let mut text = String::new();
read.read_to_string(&mut text).map_err(Error::Io)?;
ini()
.easy_parse(position::Stream::new(&*text))
.map_err(|err| Error::Parse(err.map_range(|s| s.to_string())))?;
Ok(())
}
#[cfg(not(feature = "std"))]
fn main_<R>(mut read: R) -> Result<(), Error<::combine::error::StringStreamError>>
where
R: Read,
{
let mut text = String::new();
read.read_to_string(&mut text).map_err(Error::Io)?;
ini()
.parse(position::Stream::new(&*text))
.map_err(Error::Parse)?;
Ok(())
}
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(not(feature = "std"))]
use core::str;
#[cfg(feature = "std")]
use std::str;
use combine::{
error::UnexpectedParse,
parser::{
byte::digit,
choice::optional,
range::recognize,
repeat::{skip_many, skip_many1},
token::token,
},
Parser,
};
fn main() {
let mut parser = recognize((
skip_many1(digit()),
optional((token(b'.'), skip_many(digit()))),
))
.and_then(|bs: &[u8]| {
// `bs` only contains digits which are ascii and thus UTF-8
let s = unsafe { str::from_utf8_unchecked(bs) };
s.parse::<f64>().map_err(|_| UnexpectedParse::Unexpected)
});
let result = parser.parse(&b"123.45"[..]);
assert_eq!(result, Ok((123.45, &b""[..])));
}
use combine::{
many1,
parser::char::{letter, space},
sep_by, Parser,
};
#[test]
fn readme() {
main();
}
fn main() {
let word = many1(letter());
let mut parser = sep_by(word, space()).map(|mut words: Vec<String>| words.pop());
let result = parser.parse("Pick up that word!");
assert_eq!(result, Ok((Some("word".to_string()), "!")));
}
#!/bin/bash
VERSION=$1
if [ -z "$VERSION" ]; then
echo "Expected patch, minor or major"
exit 1
fi
clog --$VERSION && \
git add CHANGELOG.md && \
git commit -m "Updated changelog" && \
cargo release --execute $VERSION
edition = "2018"
#![allow(renamed_and_removed_lints)]
use std::{
cell::Cell,
io::{self, Cursor},
rc::Rc,
str,
};
use {
bytes::{Buf, BytesMut},
combine::{
any, count_min_max,
error::{ParseError, StreamError},
many1, parser,
parser::{
byte::{num, take_until_bytes},
char::{char, digit, letter, string},
choice::optional,
combinator::{
any_partial_state, any_send_partial_state, attempt, from_str, no_partial,
recognize, AnyPartialState, AnySendPartialState,
},
range::{
self, range, recognize_with_value, take, take_fn, take_until_range, take_while,
take_while1,
},
repeat,
},
satisfy, sep_end_by, skip_many, skip_many1,
stream::{easy, RangeStream, StreamErrorFor},
token, Parser,
},
futures::prelude::*,
futures_03_dep as futures,
partial_io::PartialRead,
quick_error::quick_error,
quickcheck::quickcheck,
tokio_dep as tokio,
tokio_util::codec::{Decoder, FramedRead},
};
// Workaround partial_io not working with tokio-0.2
mod support;
use support::*;
quick_error! {
#[derive(Debug)]
enum Error {
Io(err: io::Error) {
display("{}", err)
from()
}
Parse(err: easy::Errors<char, String, usize>) {
display("{}", err)
from()
}
Utf8(err: std::str::Utf8Error) {
display("{}", err)
from()
}
Message(err: String) {
display("{}", err)
from()
}
}
}
macro_rules! mk_parser {
($parser:expr, $self_:expr,()) => {
$parser
};
($parser:expr, $self_:expr,($custom_state:ty)) => {
$parser($self_.1.clone())
};
}
macro_rules! impl_decoder {
($typ: ident, $token: ty, $parser: expr, $custom_state: ty) => {
#[derive(Default)]
struct $typ(AnyPartialState, $custom_state);
impl_decoder!{$typ, $token, $parser; ($custom_state)}
};
($typ: ident, $token: ty, $parser: expr) => {
#[derive(Default)]
struct $typ(AnyPartialState);
impl_decoder!{$typ, $token, $parser; ()}
};
($typ: ident, $token: ty, $parser: expr; ( $($custom_state: tt)* )) => {
impl Decoder for $typ {
type Item = $token;
type Error = Error;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
(&mut &mut *self).decode(src)
}
fn decode_eof(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
(&mut &mut *self).decode_eof(src)
}
}
impl<'a> Decoder for &'a mut $typ {
type Item = $token;
type Error = Error;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
self.decode_stream(src, false)
}
fn decode_eof(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
self.decode_stream(src, true)
}
}
impl<'a> $typ {
fn decode_stream(&mut self, src: &mut BytesMut, eof: bool) -> Result<Option<$token>, Error> {
let (opt, removed_len) = {
let str_src = str::from_utf8(&src[..])?;
println!("Decoding `{}`", str_src);
combine::stream::decode_tokio(
any_partial_state(mk_parser!($parser, self, ($($custom_state)*))),
&mut easy::Stream(combine::stream::MaybePartialStream(str_src, !eof)),
&mut self.0,
).map_err(|err| {
// Since err contains references into `src` we must remove these before
// returning the error and before we call `advance` to remove the input we
// just committed
let err = err.map_range(|r| r.to_string())
.map_position(|p| p.translate_position(&str_src[..]));
format!("{}\nIn input: `{}`", err, str_src)
})?
};
src.advance(removed_len);
match opt {
None => println!("Need more input!"),
Some(_) => (),
}
Ok(opt)
}
}
}
}
macro_rules! impl_byte_decoder {
($typ: ident, $token: ty, $parser: expr, $custom_state: ty) => {
#[derive(Default)]
struct $typ(AnyPartialState, $custom_state);
impl_byte_decoder!{$typ, $token, $parser; ($custom_state)}
};
($typ: ident, $token: ty, $parser: expr) => {
#[derive(Default)]
struct $typ(AnyPartialState);
impl_byte_decoder!{$typ, $token, $parser; ()}
};
($typ: ident, $token: ty, $parser: expr; ( $($custom_state: tt)* )) => {
impl Decoder for $typ {
type Item = $token;
type Error = Error;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
(&mut &mut *self).decode(src)
}
}
impl<'a> Decoder for &'a mut $typ {
type Item = $token;
type Error = Error;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
let (opt, removed_len) = {
let str_src = &src[..];
println!("Decoding `{:?}`", str_src);
combine::stream::decode(
any_partial_state(mk_parser!($parser, self, ($($custom_state)*))),
&mut easy::Stream(combine::stream::PartialStream(str_src)),
&mut self.0,
).map_err(|err| {
// Since err contains references into `src` we must remove these before
// returning the error and before we call `advance` to remove the input we
// just committed
let err = err.map_range(|r| format!("{:?}", r))
.map_position(|p| p.translate_position(&str_src[..]));
format!("{}\nIn input: `{:?}`", err, str_src)
})?
};
src.advance(removed_len);
match opt {
None => println!("Need more input!"),
Some(_) => (),
}
Ok(opt)
}
}
}
}
use partial_io::{GenNoErrors, GenWouldBlock, PartialOp, PartialWithErrors};
fn run_decoder<B, D, S>(input: &B, seq: S, decoder: D) -> Result<Vec<D::Item>, D::Error>
where
D: Decoder<Error = Error>,
D::Item: ::std::fmt::Debug,
S: IntoIterator<Item = PartialOp> + 'static,
S::IntoIter: Send,
B: ?Sized + AsRef<[u8]>,
{
let ref mut reader = Cursor::new(input.as_ref());
let partial_reader = PartialAsyncRead::new(reader, seq);
tokio_02_dep::runtime::Builder::new()
.basic_scheduler()
.build()
.unwrap()
.block_on(
FramedRead::new(partial_reader, decoder)
.map_ok(|x| {
println!("Decoded `{:?}`", x);
x
})
.try_collect(),
)
}
parser! {
type PartialState = AnyPartialState;
fn basic_parser['a, Input]()(Input) -> String
where [ Input: RangeStream<Token = char, Range = &'a str> ]
{
any_partial_state(
many1(digit()).skip(range(&"\r\n"[..])),
)
}
}
impl_decoder! { Basic, String, basic_parser() }
#[test]
fn many1_skip_no_errors() {
let input = "123\r\n\
456\r\n";
let result = run_decoder(input, vec![], Basic::default());
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(result.unwrap(), vec!["123".to_string(), "456".to_string()]);
}
parser! {
type PartialState = AnyPartialState;
fn prefix_many_then_parser['a, Input]()(Input) -> String
where [ Input: RangeStream<Token = char, Range = &'a str> ]
{
let integer = from_str(many1::<String, _, _>(digit()));
any_partial_state((char('#'), skip_many(char(' ')), integer)
.then_partial(|t| {
let c = t.2;
count_min_max(c, c, any())
})
)
}
}
parser! {
type PartialState = AnyPartialState;
fn choice_parser['a, Input]()(Input) -> String
where [ Input: RangeStream<Token = char, Range = &'a str> ]
{
any_partial_state(
many1(digit())
.or(many1(letter()))
.skip(range(&"\r\n"[..]))
)
}
}
fn content_length<'a, Input>(
) -> impl Parser<Input, Output = String, PartialState = AnySendPartialState> + 'a
where
Input: RangeStream<Token = char, Range = &'a str> + 'a,
{
let content_length = range("Content-Length: ").with(
range::recognize(skip_many1(digit())).and_then(|digits: &str| {
// Convert the error from `.parse` into an error combine understands
digits
.parse::<usize>()
.map_err(StreamErrorFor::<Input>::other)
}),
);
any_send_partial_state(
(
skip_many(range("\r\n")),
content_length,
range("\r\n\r\n").map(|_| ()),
)
.then_partial(|&mut (_, message_length, _)| {
take(message_length).map(|bytes: &str| bytes.to_owned())
}),
)
}
quickcheck! {
fn many1_skip_test(seq: PartialWithErrors<GenWouldBlock>) -> () {
let input = "123\r\n\
456\r\n\
1\r\n\
5\r\n\
666666\r\n";
let result = run_decoder(input, seq, Basic::default());
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(
result.unwrap(),
vec!["123".to_string(), "456".to_string(), "1".to_string(), "5".to_string(), "666666".to_string()]
);
}
fn prefix_many_then_test(seq: PartialWithErrors<GenWouldBlock>) -> () {
impl_decoder!{ TestParser, String, prefix_many_then_parser() }
let input = "# 1a\
# 4abcd\
#0\
#3:?a\
#10abcdefghij";
let result = run_decoder(input, seq, TestParser::default());
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(
result.unwrap(),
["a", "abcd", "", ":?a", "abcdefghij"]
);
}
fn choice_test(seq: PartialWithErrors<GenWouldBlock>) -> () {
impl_decoder!{ TestParser, String, choice_parser() }
let input = "1\r\n\
abcd\r\n\
123\r\n\
abc\r\n\
1232751\r\n";
let result = run_decoder(input, seq, TestParser::default());
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(
result.unwrap(),
["1", "abcd", "123", "abc", "1232751"]
);
}
fn recognize_test(seq: PartialWithErrors<GenWouldBlock>) -> () {
impl_decoder!{ TestParser, String,
recognize(
(skip_many1(digit()), optional((char('.'), skip_many(digit()))))
)
.skip(range(&"\r\n"[..]))
}
let input = "1.0\r\n\
123.123\r\n\
17824\r\n\
3.14\r\n\
1.\r\n\
2\r\n";
let result = run_decoder(input, seq, TestParser::default());
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(
result.unwrap(),
["1.0", "123.123", "17824", "3.14", "1.", "2"]
);
}
fn recognize_range_test(seq: PartialWithErrors<GenWouldBlock>) -> () {
impl_decoder!{ TestParser, String,
recognize_with_value(
(skip_many1(digit()), optional((char('.'), skip_many(digit()))))
)
.map(|(r, _)| String::from(r))
.skip(range(&"\r\n"[..]))
}
let input = "1.0\r\n\
123.123\r\n\
17824\r\n\
3.14\r\n\
1.\r\n\
2\r\n";
let result = run_decoder(input, seq, TestParser::default());
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(
result.unwrap(),
["1.0", "123.123", "17824", "3.14", "1.", "2"]
);
}
fn take_while_test(seq: PartialWithErrors<GenWouldBlock>) -> () {
impl_decoder!{ TestParser, String,
|counter: Rc<Cell<i32>>|
take_while(move |c| { counter.set(counter.get() + 1); c != '\r' })
.map(String::from)
.skip(range("\r\n")),
Rc<Cell<i32>>
}
let input = "1.0\r\n\
123.123\r\n\
17824\r\n\
3.14\r\n\
\r\n\
2\r\n";
let counter = Rc::new(Cell::new(0));
let result = run_decoder(input, seq, TestParser(Default::default(), counter.clone()));
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(
result.unwrap(),
["1.0", "123.123", "17824", "3.14", "", "2"]
);
assert_eq!(counter.get(), 26);
}
fn take_while1_test(seq: PartialWithErrors<GenWouldBlock>) -> () {
impl_decoder!{ TestParser, String,
|count: Rc<Cell<i32>>|
take_while1(move |c| { count.set(count.get() + 1); c != '\r' })
.map(String::from)
.skip(range("\r\n")),
Rc<Cell<i32>>
}
let input = "1.0\r\n\
123.123\r\n\
17824\r\n\
3.14\r\n\
1.\r\n\
2\r\n";
let counter = Rc::new(Cell::new(0));
let result = run_decoder(input, seq, TestParser(Default::default(), counter.clone()));
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(
result.unwrap(),
["1.0", "123.123", "17824", "3.14", "1.", "2"]
);
assert_eq!(counter.get(), 28);
}
fn take_until(seq: PartialWithErrors<GenWouldBlock>) -> () {
impl_decoder!{ TestParser, String,
|count: Rc<Cell<i32>>|
repeat::take_until(token(',').map(move |_| count.set(count.get() + 1))).skip(token(',')),
Rc<Cell<i32>>
}
let input = "123,456,789,";
let counter = Rc::new(Cell::new(0));
let result = run_decoder(input, seq, TestParser(Default::default(), counter.clone()));
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(
result.unwrap(),
["123", "456", "789"]
);
assert_eq!(counter.get(), 3);
}
fn take_until_committed(seq: PartialWithErrors<GenWouldBlock>) -> () {
impl_decoder!{ TestParser, String,
|count: Rc<Cell<i32>>| {
let end = attempt((token(':').map(move |_| count.set(count.get() + 1)), token(':')));
repeat::take_until(end).skip((token(':'), token(':')))
},
Rc<Cell<i32>>
}
let input = "123::456::789::";
let counter = Rc::new(Cell::new(0));
let result = run_decoder(input, seq, TestParser(Default::default(), counter.clone()));
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(
result.unwrap(),
["123", "456", "789"]
);
assert_eq!(counter.get(), 3);
}
fn take_until_range_committed(seq: PartialWithErrors<GenWouldBlock>) -> () {
impl_decoder!{ TestParser, String,
take_until_range("::").map(String::from).skip((token(':'), token(':')))
}
let input = "123::456::789::";
let result = run_decoder(input, seq, TestParser(Default::default()));
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(result.unwrap(), ["123", "456", "789"]);
}
fn any_send_partial_state_do_not_forget_state(sizes: Vec<usize>, seq: PartialWithErrors<GenWouldBlock>) -> () {
impl_decoder!{ TestParser, usize,
any_send_partial_state(content_length().map(|bytes| bytes.len()))
}
let input : String = sizes
.iter()
.map(|s| {
format!(
"Content-Length: {}\r\n\r\n{}\r\n",
s,
::std::iter::repeat('a').take(*s).collect::<String>()
)
})
.collect();
let result = run_decoder(input.as_bytes(), seq, TestParser(Default::default()));
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(result.unwrap(), sizes);
}
fn take_fn_test(sizes: Vec<usize>, seq: PartialWithErrors<GenWouldBlock>) -> () {
impl_decoder!{ TestParser, usize,
take_fn(|s: &str| s.find("\r\n")).map(|bytes: &str| bytes.parse::<usize>().unwrap()).skip(take(2))
}
let input : String = sizes
.iter()
.map(|s| {
format!(
"{}\r\n",
s,
)
})
.collect();
let result = run_decoder(input.as_bytes(), seq, TestParser(Default::default()));
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(result.unwrap(), sizes);
}
fn take_until_bytes_test(sizes: Vec<usize>, seq: PartialWithErrors<GenWouldBlock>) -> () {
impl_decoder!{ TestParser, usize,
take_until_bytes("\r\n".as_bytes())
.map(|bytes: &str| bytes.parse::<usize>().unwrap())
.skip(take(2))
}
let input : String = sizes
.iter()
.map(|s| {
format!(
"{}\r\n",
s,
)
})
.collect();
let result = run_decoder(input.as_bytes(), seq, TestParser(Default::default()));
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(result.unwrap(), sizes);
}
fn num_test(ints: Vec<u16>, seq: PartialWithErrors<GenWouldBlock>) -> () {
impl_byte_decoder!{ TestParser, u16,
num::be_u16()
.skip(take(2))
}
let input: Vec<u8> = ints.iter()
.flat_map(|i| {
let mut v = Vec::new();
v.extend_from_slice(&i.to_be_bytes());
v.extend_from_slice(b"\r\n");
v
})
.collect();
let result = run_decoder(&input, seq, TestParser(Default::default()));
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(result.unwrap(), ints);
}
fn sep_end_by_test(seq: PartialWithErrors<GenWouldBlock>) -> () {
impl_decoder!{ TestParser, Vec<String>,
repeat::sep_end_by((digit(), digit(), digit()).map(|(a, b, c)| vec![a, b, c].into_iter().collect()), no_partial(string("::")))
.skip(no_partial(string("\r\n")))
}
let input = "123::456::789::\r\n";
let result = run_decoder(&input, seq, TestParser(Default::default()));
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(result.unwrap(), vec![vec!["123".to_string(), "456".to_string(), "789".to_string()]]);
}
}
#[test]
fn skip_count_min_max_test() {
let seq = vec![PartialOp::Limited(1)];
impl_decoder! { TestParser, String,
repeat::skip_count_min_max(1, 2, char('_')).skip(char('.')).map(|_| "".to_string())
}
let input = "_.";
let result = run_decoder(input, seq, TestParser::default());
assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
assert_eq!(result.unwrap(), [""]);
}
const WORDS_IN_README: usize = 773;
#[test]
fn decode_std() {
quickcheck(
(|ops: PartialWithErrors<GenNoErrors>| {
let buf = include_bytes!("../README.md");
let mut read = PartialRead::new(&buf[..], ops);
let mut decoder =
combine::stream::Decoder::<_, combine::stream::PointerOffset<_>>::new();
let is_whitespace = |b: u8| b == b' ' || b == b'\r' || b == b'\n';
assert_eq!(
combine::decode!(
decoder,
read,
{
let word = many1(satisfy(|b| !is_whitespace(b)));
sep_end_by(word, skip_many1(satisfy(is_whitespace)))
.map(|words: Vec<Vec<u8>>| words.len())
},
|input, _| combine::easy::Stream::from(input)
)
.map_err(From::from)
.map_err(
|err: combine::easy::Errors<u8, &[u8], combine::stream::PointerOffset<_>>| err
.map_position(|p| p.0)
),
Ok(WORDS_IN_README),
);
}) as fn(_) -> _,
)
}
#[test]
fn decode_tokio_02() {
quickcheck(
(|ops: PartialWithErrors<GenWouldBlock>| {
let buf = include_bytes!("../README.md");
let runtime = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
runtime.block_on(async {
let mut read = PartialAsyncRead::new(&buf[..], ops);
let mut decoder =
combine::stream::Decoder::<_, combine::stream::PointerOffset<[u8]>>::new();
let is_whitespace = |b: u8| b == b' ' || b == b'\r' || b == b'\n';
assert_eq!(
combine::decode_tokio_02!(
decoder,
read,
{
let word = many1(satisfy(|b| !is_whitespace(b)));
sep_end_by(word, skip_many1(satisfy(is_whitespace)))
.map(|words: Vec<Vec<u8>>| words.len())
},
|input, _| combine::easy::Stream::from(input)
)
.map_err(From::from)
.map_err(
|err: combine::easy::Errors<u8, &[u8], _>| err.map_range(|r| r.to_owned())
)
.map_err(|err| err.map_position(|p| p.translate_position(&decoder.buffer()))),
Ok(WORDS_IN_README),
);
})
}) as fn(_) -> _,
)
}
#[test]
fn decode_tokio_03() {
quickcheck(
(|ops: PartialWithErrors<GenWouldBlock>| {
let buf = include_bytes!("../README.md");
let runtime = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
runtime.block_on(async {
let mut read = PartialAsyncRead::new(&buf[..], ops);
let mut decoder =
combine::stream::Decoder::<_, combine::stream::PointerOffset<[u8]>>::new();
let is_whitespace = |b: u8| b == b' ' || b == b'\r' || b == b'\n';
assert_eq!(
combine::decode_tokio_03!(
decoder,
read,
{
let word = many1(satisfy(|b| !is_whitespace(b)));
sep_end_by(word, skip_many1(satisfy(is_whitespace)))
.map(|words: Vec<Vec<u8>>| words.len())
},
|input, _| combine::easy::Stream::from(input)
)
.map_err(From::from)
.map_err(
|err: combine::easy::Errors<u8, &[u8], _>| err.map_range(|r| r.to_owned())
)
.map_err(|err| err.map_position(|p| p.translate_position(&decoder.buffer()))),
Ok(WORDS_IN_README),
);
})
}) as fn(_) -> _,
)
}
#[test]
fn decode_tokio() {
quickcheck(
(|ops: PartialWithErrors<GenWouldBlock>| {
let buf = include_bytes!("../README.md");
let runtime = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
runtime.block_on(async {
let mut read = PartialAsyncRead::new(&buf[..], ops);
let mut decoder =
combine::stream::Decoder::<_, combine::stream::PointerOffset<[u8]>>::new();
let is_whitespace = |b: u8| b == b' ' || b == b'\r' || b == b'\n';
assert_eq!(
combine::decode_tokio!(
decoder,
read,
{
let word = many1(satisfy(|b| !is_whitespace(b)));
sep_end_by(word, skip_many1(satisfy(is_whitespace)))
.map(|words: Vec<Vec<u8>>| words.len())
},
|input, _| combine::easy::Stream::from(input)
)
.map_err(From::from)
.map_err(
|err: combine::easy::Errors<u8, &[u8], _>| err.map_range(|r| r.to_owned())
)
.map_err(|err| err.map_position(|p| p.translate_position(&decoder.buffer()))),
Ok(WORDS_IN_README),
);
})
}) as fn(_) -> _,
)
}
#[test]
fn decode_async_std() {
quickcheck(
(|ops: PartialWithErrors<GenWouldBlock>| {
let buf = include_bytes!("../README.md");
async_std::task::block_on(async {
let mut read = FuturesPartialAsyncRead::new(&buf[..], ops);
let mut decoder =
combine::stream::Decoder::<_, combine::stream::PointerOffset<[u8]>>::new();
let is_whitespace = |b: u8| b == b' ' || b == b'\r' || b == b'\n';
assert_eq!(
combine::decode_futures_03!(
decoder,
read,
{
let word = many1(satisfy(|b| !is_whitespace(b)));
sep_end_by(word, skip_many1(satisfy(is_whitespace)))
.map(|words: Vec<Vec<u8>>| words.len())
},
|input, _| combine::easy::Stream::from(input),
)
.map_err(From::from)
.map_err(|err: combine::easy::Errors<u8, &[u8], _>| err),
Ok(WORDS_IN_README),
);
})
}) as fn(_) -> _,
)
}
#[tokio::test]
async fn decode_loop() {
use tokio::fs::File;
use combine::{
decode_tokio, many1, satisfy, skip_many1,
stream::{buf_reader::BufReader, Decoder},
};
let mut read = BufReader::new(File::open("README.md").await.unwrap());
let mut decoder = Decoder::new_bufferless();
let is_whitespace = |b: u8| b == b' ' || b == b'\r' || b == b'\n';
let mut count = 0;
loop {
// async block suppresses a warning about duplicate label
if async {
decode_tokio!(
decoder,
read,
many1(satisfy(|b| !is_whitespace(b))),
|input, _position| combine::easy::Stream::from(input),
)
.is_err()
}
.await
{
break;
}
count += 1;
{
if decode_tokio!(
decoder,
read,
skip_many1(satisfy(is_whitespace)),
|input, _position| combine::easy::Stream::from(input),
)
.is_err()
{
break;
}
}
}
assert_eq!(WORDS_IN_README, count);
}
#![cfg(feature = "std")]
use combine::{
attempt, choice, many, many1,
parser::{
char::{char, digit, spaces, string},
combinator::recognize,
},
sep_by, skip_many1,
stream::{
buffered,
easy::{self, Error, Errors},
position, IteratorStream,
},
Parser, Positioned,
};
#[test]
fn shared_stream_buffer() {
// Iterator that can't be cloned
let text = "10,222,3,44".chars().map(|c| {
if c.is_digit(10) {
(c as u8 + 1) as char
} else {
c
}
});
let buffer = buffered::Stream::new(position::Stream::new(IteratorStream::new(text)), 1);
let int: &mut dyn Parser<_, Output = _, PartialState = _> =
&mut many(digit()).map(|s: String| s.parse::<i64>().unwrap());
let result = sep_by(int, char(',')).parse(buffer).map(|t| t.0);
assert_eq!(result, Ok(vec![21, 333, 4, 55]));
}
#[test]
fn shared_stream_backtrack() {
let text = "apple,apple,ananas,orangeblah";
let mut iter = text.chars();
// Iterator that can't be cloned
let stream = buffered::Stream::new(position::Stream::new(IteratorStream::new(&mut iter)), 2);
let value: &mut dyn Parser<_, Output = _, PartialState = _> = &mut choice([
attempt(string("apple")),
attempt(string("orange")),
attempt(string("ananas")),
]);
let mut parser = sep_by(value, char(','));
let result = parser.parse(stream).map(|t| t.0);
assert_eq!(result, Ok(vec!["apple", "apple", "ananas", "orange"]));
}
#[test]
fn shared_stream_insufficent_backtrack() {
let text = "apple,apple,ananas,orangeblah";
let mut iter = text.chars();
// Iterator that can't be cloned
let stream = buffered::Stream::new(
easy::Stream(position::Stream::new(IteratorStream::new(&mut iter))),
1,
);
let value: &mut dyn Parser<_, Output = _, PartialState = _> = &mut choice([
attempt(string("apple")),
attempt(string("orange")),
attempt(string("ananas")),
]);
let mut parser = sep_by(value, char(','));
let result: Result<Vec<&str>, _> = parser.parse(stream).map(|t| t.0);
assert!(result.is_err());
assert!(
result
.as_ref()
.unwrap_err()
.errors
.iter()
.any(|err| *err == Error::Message("Backtracked to far".into())),
"{}",
result.unwrap_err()
);
}
/// Test which checks that a stream which has ended does not repeat the last token in some cases in
/// which case this test would loop forever
#[test]
fn always_output_end_of_input_after_end_of_input() {
let text = "10".chars();
let buffer = buffered::Stream::new(position::Stream::new(IteratorStream::new(text)), 1);
let int = many1(digit()).map(|s: String| s.parse::<i64>().unwrap());
let result = many(spaces().with(int)).parse(buffer).map(|t| t.0);
assert_eq!(result, Ok(vec![10]));
}
#[test]
fn position() {
let text = "10abc".chars();
let stream = buffered::Stream::new(position::Stream::new(IteratorStream::new(text)), 3);
assert_eq!(stream.position(), 0);
let result = many1::<Vec<_>, _, _>(digit()).parse(stream);
assert!(result.is_ok());
assert_eq!(result.unwrap().1.position(), 2);
}
#[test]
fn buffered_stream_recognize_issue_256() {
let mut parser = recognize::<String, _, _>(skip_many1(digit()));
let input = "12 ";
assert_eq!(
parser
.parse(buffered::Stream::new(easy::Stream(input), 1))
.map_err(|err| err.map_position(|pos| pos.translate_position(input))),
Err(Errors {
position: 2,
errors: vec![easy::Error::Message("Backtracked to far".into())]
})
);
}
#![allow(clippy::single_match)]
#[macro_use]
extern crate combine;
parser! {
pub fn test[Input]()(Input) -> ()
where [Input: ::combine::Stream<Token = char>]
{
use combine::parser::token::value;
let _ = ();
fn _test() { }
match Some(1) {
Some(_) => (),
None => (),
}
value(())
}
}
parser! {
pub fn test_that_parsers_with_unnamed_types_can_be_in_same_scope[Input]()(Input) -> ()
where [Input: ::combine::Stream<Token = char>]
{
use combine::parser::token::value;
value(())
}
}
#[test]
fn test_that_we_dont_need_imports_for_this_macro_to_work() {
test::<&str>();
test_that_parsers_with_unnamed_types_can_be_in_same_scope::<&str>();
}
use combine::{
parser::{
char::{digit, letter},
choice::choice,
combinator::not_followed_by,
range::range,
token::{any, eof, token, Token},
},
Parser,
};
#[test]
fn choice_empty() {
let mut parser = choice::<_, &mut [Token<&str>]>(&mut []);
let result_err = parser.parse("a");
assert!(result_err.is_err());
}
#[test]
fn tuple() {
let mut parser = (digit(), token(','), digit(), token(','), letter());
assert_eq!(parser.parse("1,2,z"), Ok((('1', ',', '2', ',', 'z'), "")));
}
#[test]
fn issue_99() {
let result = any().map(|_| ()).or(eof()).parse("");
assert!(result.is_ok(), "{:?}", result);
}
#[test]
fn not_followed_by_does_not_consume_any_input() {
let mut parser = not_followed_by(range("a")).map(|_| "").or(range("a"));
assert_eq!(parser.parse("a"), Ok(("a", "")));
let mut parser = range("a").skip(not_followed_by(range("aa")));
assert_eq!(parser.parse("aa"), Ok(("a", "a")));
assert!(parser.parse("aaa").is_err());
}
#[cfg(feature = "std")]
mod tests_std {
use super::*;
use combine::easy::{Error, Errors};
use combine::parser::byte::alpha_num;
use combine::parser::byte::bytes;
use combine::parser::byte::bytes_cmp;
use combine::parser::byte::num::be_u32;
use combine::parser::char::char;
use combine::parser::char::{string, string_cmp};
use combine::parser::combinator::no_partial;
use combine::parser::range;
use combine::parser::repeat::{skip_until, take_until};
use combine::stream::position;
use combine::stream::position::SourcePosition;
use combine::{
attempt, count, count_min_max, easy, many, optional, position, sep_by, sep_end_by1,
unexpected, value, EasyParser,
};
#[derive(Clone, PartialEq, Debug)]
struct CloneOnly {
s: String,
}
#[test]
fn token_clone_but_not_copy() {
// Verify we can use token() with a StreamSlice with an token type that is Clone but not
// Copy.
let input = &[
CloneOnly { s: "x".to_string() },
CloneOnly { s: "y".to_string() },
][..];
let result = token(CloneOnly { s: "x".to_string() }).easy_parse(input);
assert_eq!(
result,
Ok((
CloneOnly { s: "x".to_string() },
&[CloneOnly { s: "y".to_string() }][..]
))
);
}
#[test]
fn sep_by_committed_error() {
type TwoLettersList = Vec<(char, char)>;
let mut parser2 = sep_by((letter(), letter()), token(','));
let result_err: Result<(TwoLettersList, &str), easy::ParseError<&str>> =
parser2.easy_parse("a,bc");
assert!(result_err.is_err());
}
/// The expected combinator should retain only errors that are not `Expected`
#[test]
fn expected_retain_errors() {
let mut parser = digit()
.message("message")
.expected("N/A")
.expected("my expected digit");
assert_eq!(
parser.easy_parse(position::Stream::new("a")),
Err(Errors {
position: SourcePosition::default(),
errors: vec![
Error::Unexpected('a'.into()),
Error::Message("message".into()),
Error::Expected("my expected digit".into()),
],
})
);
}
#[test]
fn tuple_parse_error() {
let mut parser = (digit(), digit());
let result = parser.easy_parse(position::Stream::new("a"));
assert_eq!(
result,
Err(Errors {
position: SourcePosition::default(),
errors: vec![
Error::Unexpected('a'.into()),
Error::Expected("digit".into()),
],
})
);
}
#[test]
fn message_tests() {
// Ensure message adds to both committed and empty errors, interacting with parse_lazy and
// parse_stream correctly on either side
let input = "hi";
let mut ok = char('h').message("not expected");
let mut empty0 = char('o').message("expected message");
let mut empty1 = char('o').message("expected message").map(|x| x);
let mut empty2 = char('o').map(|x| x).message("expected message");
let mut committed0 = char('h').with(char('o')).message("expected message");
let mut committed1 = char('h')
.with(char('o'))
.message("expected message")
.map(|x| x);
let mut committed2 = char('h')
.with(char('o'))
.map(|x| x)
.message("expected message");
assert!(ok.easy_parse(position::Stream::new(input)).is_ok());
let empty_expected = Err(Errors {
position: SourcePosition { line: 1, column: 1 },
errors: vec![
Error::Unexpected('h'.into()),
Error::Expected('o'.into()),
Error::Message("expected message".into()),
],
});
let committed_expected = Err(Errors {
position: SourcePosition { line: 1, column: 2 },
errors: vec![
Error::Unexpected('i'.into()),
Error::Expected('o'.into()),
Error::Message("expected message".into()),
],
});
assert_eq!(
empty0.easy_parse(position::Stream::new(input)),
empty_expected
);
assert_eq!(
empty1.easy_parse(position::Stream::new(input)),
empty_expected
);
assert_eq!(
empty2.easy_parse(position::Stream::new(input)),
empty_expected
);
assert_eq!(
committed0.easy_parse(position::Stream::new(input)),
committed_expected
);
assert_eq!(
committed1.easy_parse(position::Stream::new(input)),
committed_expected
);
assert_eq!(
committed2.easy_parse(position::Stream::new(input)),
committed_expected
);
}
#[test]
fn expected_tests() {
// Ensure `expected` replaces only empty errors, interacting with parse_lazy and
// parse_stream correctly on either side
let input = "hi";
let mut ok = char('h').expected("not expected");
let mut empty0 = char('o').expected("expected message");
let mut empty1 = char('o').expected("expected message").map(|x| x);
let mut empty2 = char('o').map(|x| x).expected("expected message");
let mut committed0 = char('h').with(char('o')).expected("expected message");
let mut committed1 = char('h')
.with(char('o'))
.expected("expected message")
.map(|x| x);
let mut committed2 = char('h')
.with(char('o'))
.map(|x| x)
.expected("expected message");
assert!(ok.easy_parse(position::Stream::new(input)).is_ok());
let empty_expected = Err(Errors {
position: SourcePosition { line: 1, column: 1 },
errors: vec![
Error::Unexpected('h'.into()),
Error::Expected("expected message".into()),
],
});
let committed_expected = Err(Errors {
position: SourcePosition { line: 1, column: 2 },
errors: vec![Error::Unexpected('i'.into()), Error::Expected('o'.into())],
});
assert_eq!(
empty0.easy_parse(position::Stream::new(input)),
empty_expected
);
assert_eq!(
empty1.easy_parse(position::Stream::new(input)),
empty_expected
);
assert_eq!(
empty2.easy_parse(position::Stream::new(input)),
empty_expected
);
assert_eq!(
committed0.easy_parse(position::Stream::new(input)),
committed_expected
);
assert_eq!(
committed1.easy_parse(position::Stream::new(input)),
committed_expected
);
assert_eq!(
committed2.easy_parse(position::Stream::new(input)),
committed_expected
);
}
#[test]
fn try_tests() {
// Ensure attempt adds error messages exactly once
assert_eq!(
attempt(unexpected("test")).easy_parse(position::Stream::new("hi")),
Err(Errors {
position: SourcePosition { line: 1, column: 1 },
errors: vec![
Error::Unexpected('h'.into()),
Error::Unexpected("test".into()),
],
})
);
assert_eq!(
attempt(char('h').with(unexpected("test"))).easy_parse(position::Stream::new("hi")),
Err(Errors {
position: SourcePosition { line: 1, column: 2 },
errors: vec![
Error::Unexpected('i'.into()),
Error::Unexpected("test".into()),
],
})
);
}
#[test]
fn sequence_error() {
let mut parser = (char('a'), char('b'), char('c'));
assert_eq!(
parser.easy_parse(position::Stream::new("c")),
Err(Errors {
position: SourcePosition { line: 1, column: 1 },
errors: vec![Error::Unexpected('c'.into()), Error::Expected('a'.into())],
})
);
assert_eq!(
parser.easy_parse(position::Stream::new("ac")),
Err(Errors {
position: SourcePosition { line: 1, column: 2 },
errors: vec![Error::Unexpected('c'.into()), Error::Expected('b'.into())],
})
);
}
#[test]
fn optional_empty_ok_then_error() {
let mut parser = (optional(char('a')), char('b'));
assert_eq!(
parser.easy_parse(position::Stream::new("c")),
Err(Errors {
position: SourcePosition { line: 1, column: 1 },
errors: vec![
Error::Unexpected('c'.into()),
Error::Expected('a'.into()),
Error::Expected('b'.into()),
],
})
);
}
#[test]
fn nested_optional_empty_ok_then_error() {
let mut parser = ((optional(char('a')), char('b')), char('c'));
assert_eq!(
parser.easy_parse(position::Stream::new("c")),
Err(Errors {
position: SourcePosition { line: 1, column: 1 },
errors: vec![
Error::Unexpected('c'.into()),
Error::Expected('a'.into()),
Error::Expected('b'.into()),
],
})
);
}
#[test]
fn committed_then_optional_empty_ok_then_error() {
let mut parser = (char('b'), optional(char('a')), char('b'));
assert_eq!(
parser.easy_parse(position::Stream::new("bc")),
Err(Errors {
position: SourcePosition { line: 1, column: 2 },
errors: vec![
Error::Unexpected('c'.into()),
Error::Expected('a'.into()),
Error::Expected('b'.into()),
],
})
);
}
#[test]
fn sequence_in_choice_parser_empty_err() {
let mut parser = choice((
(optional(char('a')), char('1')),
(optional(char('b')), char('2')).skip(char('d')),
));
assert_eq!(
parser.easy_parse(position::Stream::new("c")),
Err(Errors {
position: SourcePosition { line: 1, column: 1 },
errors: vec![
Error::Expected('a'.into()),
Error::Expected('1'.into()),
Error::Expected('b'.into()),
Error::Expected('2'.into()),
Error::Unexpected('c'.into()),
],
})
);
}
#[test]
fn sequence_in_choice_array_parser_empty_err() {
let mut parser = choice([
(optional(char('a')), char('1')),
(optional(char('b')), char('2')),
]);
assert_eq!(
parser.easy_parse(position::Stream::new("c")),
Err(Errors {
position: SourcePosition { line: 1, column: 1 },
errors: vec![
Error::Expected('a'.into()),
Error::Expected('1'.into()),
Error::Expected('b'.into()),
Error::Expected('2'.into()),
Error::Unexpected('c'.into()),
],
})
);
}
#[test]
fn sequence_in_choice_array_parser_empty_err_where_first_parser_delay_errors() {
let mut p1 = char('1');
let mut p2 = no_partial((optional(char('b')), char('2')).map(|t| t.1));
let mut parser =
choice::<_, [&mut dyn Parser<_, Output = _, PartialState = _>; 2]>([&mut p1, &mut p2]);
assert_eq!(
parser.easy_parse(position::Stream::new("c")),
Err(Errors {
position: SourcePosition { line: 1, column: 1 },
errors: vec![
Error::Expected('1'.into()),
Error::Expected('b'.into()),
Error::Expected('2'.into()),
Error::Unexpected('c'.into()),
],
})
);
}
#[test]
fn sep_end_by1_dont_eat_separator_twice() {
let mut parser = sep_end_by1(digit(), token(';'));
assert_eq!(parser.parse("1;;"), Ok((vec!['1'], ";")));
}
#[test]
fn count_min_max_empty_error() {
assert_eq!(
count_min_max(1, 1, char('a')).or(value(vec![])).parse("b"),
Ok((vec![], "b"))
);
}
#[test]
fn sequence_parser_resets_partial_state_issue_168() {
assert_eq!(
take_until::<String, _, _>(attempt((char('a'), char('b')))).parse("aaab"),
Ok((String::from("aa"), "ab"))
);
}
#[test]
fn parser_macro_must_impl_parse_mode_issue_168() {
assert_eq!(
skip_until(attempt((char('a'), char('b')))).parse("aaab"),
Ok(((), "ab"))
);
}
#[test]
fn recognize_parser_issue_168() {
assert_eq!(
range::recognize(skip_until(attempt((char('a'), char('b'))))).parse("aaab"),
Ok(("aa", "ab"))
);
}
#[test]
fn sequence_in_optional_report_delayed_error() {
assert_eq!(
optional(position().with(char('a')))
.skip(char('}'))
.easy_parse("b")
.map_err(|e| e.errors),
Err(vec![
Error::Unexpected('b'.into()),
Error::Expected('a'.into()),
Error::Expected('}'.into()),
]),
);
}
#[test]
fn sequence_in_optional_nested_report_delayed_error() {
assert_eq!(
optional(position().with(char('a')))
.skip(optional(position().with(char('c'))))
.skip(char('}'))
.easy_parse("b")
.map_err(|e| e.errors),
Err(vec![
Error::Unexpected('b'.into()),
Error::Expected('a'.into()),
Error::Expected('c'.into()),
Error::Expected('}'.into()),
]),
);
}
#[test]
fn sequence_in_optional_nested_2_report_delayed_error() {
assert_eq!(
(
char('{'),
optional(position().with(char('a')))
.skip(optional(position().with(char('c'))))
.skip(char('}'))
)
.easy_parse("{b")
.map_err(|e| e.errors),
Err(vec![
Error::Unexpected('b'.into()),
Error::Expected('a'.into()),
Error::Expected('c'.into()),
Error::Expected('}'.into()),
]),
);
}
macro_rules! sequence_many_test {
($many:expr, $seq:expr) => {
let mut parser = $seq($many(position().with(char('a'))), char('}'));
let expected_error = Err(vec![
Error::Unexpected('b'.into()),
Error::Expected('a'.into()),
Error::Expected('}'.into()),
]);
assert_eq!(
parser.easy_parse("ab").map_err(|e| e.errors),
expected_error,
);
};
}
#[test]
fn sequence_in_many_report_delayed_error() {
use combine::parser::{repeat, sequence};
sequence_many_test!(repeat::many::<Vec<_>, _, _>, sequence::skip);
sequence_many_test!(repeat::many1::<Vec<_>, _, _>, sequence::skip);
sequence_many_test!(repeat::many::<Vec<_>, _, _>, sequence::with);
sequence_many_test!(repeat::many1::<Vec<_>, _, _>, sequence::with);
sequence_many_test!(repeat::many::<Vec<_>, _, _>, |l, x| sequence::between(
l,
char('|'),
x,
));
sequence_many_test!(repeat::many1::<Vec<_>, _, _>, |l, x| sequence::between(
l,
char('|'),
x,
));
}
macro_rules! sequence_sep_by_test {
($many:expr, $seq:expr) => {
let mut parser = $seq($many(position().with(char('a')), char(',')), char('}'));
let expected_error = Err(vec![
Error::Unexpected('b'.into()),
Error::Expected(','.into()),
Error::Expected('}'.into()),
]);
assert_eq!(
parser.easy_parse("a,ab").map_err(|e| e.errors),
expected_error,
);
};
}
#[test]
fn sequence_in_sep_by_report_delayed_error() {
use combine::parser::{repeat, sequence};
sequence_sep_by_test!(repeat::sep_by::<Vec<_>, _, _, _>, sequence::skip);
sequence_sep_by_test!(repeat::sep_by1::<Vec<_>, _, _, _>, sequence::skip);
sequence_sep_by_test!(repeat::sep_by::<Vec<_>, _, _, _>, sequence::with);
sequence_sep_by_test!(repeat::sep_by1::<Vec<_>, _, _, _>, sequence::with);
}
#[test]
fn choice_compose_on_error() {
let ident = |s| attempt(string(s));
let mut parser = choice((ident("aa").skip(string(";")), choice((ident("cc"),))));
assert_eq!(
parser.easy_parse("c").map_err(|err| err.errors),
Err(vec![
Error::Unexpected('c'.into()),
Error::Expected("aa".into()),
Error::Unexpected("end of input".into()),
Error::Expected("cc".into()),
]),
);
}
#[test]
fn choice_compose_issue_175() {
let ident = |s| attempt(string(s));
let mut parser = many::<Vec<_>, _, _>(position().and(choice((
ident("aa").skip(string(";")),
choice((ident("bb"), ident("cc"))),
))))
.skip(string("."));
assert_eq!(
parser.easy_parse("c").map_err(|err| err.errors),
Err(vec![
Error::Unexpected('c'.into()),
Error::Expected("aa".into()),
Error::Expected("bb".into()),
Error::Expected("cc".into()),
]),
);
}
#[test]
fn test() {
let mut parser = (digit(), letter());
assert_eq!(
parser.easy_parse("11").map_err(|err| err.errors),
Err(vec![
Error::Unexpected('1'.into()),
Error::Expected("letter".into()),
]),
);
}
#[test]
fn lifetime_inference() {
fn _string(source: &str) {
range::take(1).or(string("a")).parse(source).ok();
range::take(1)
.or(string_cmp("a", |x, y| x == y))
.parse(source)
.ok();
let _: &'static str = string("a").parse(source).unwrap().0;
let _: &'static str = string_cmp("a", |x, y| x == y).parse(source).unwrap().0;
}
fn _bytes(source: &[u8]) {
range::take(1).or(bytes(&[0u8])).parse(source).ok();
range::take(1)
.or(bytes_cmp(&[0u8], |x, y| x == y))
.parse(source)
.ok();
let _: &'static [u8] = bytes(&[0u8]).parse(source).unwrap().0;
let _: &'static [u8] = bytes_cmp(&[0u8], |x, y| x == y).parse(source).unwrap().0;
}
}
#[test]
fn test_nested_count_overflow() {
let key = || count::<Vec<_>, _, _>(64, alpha_num());
let value_bytes =
|| be_u32().then_partial(|&mut size| count::<Vec<_>, _, _>(size as usize, any()));
let value_messages =
(be_u32(), be_u32()).then_partial(|&mut (_body_size, message_count)| {
count::<Vec<_>, _, _>(message_count as usize, value_bytes())
});
let put = (bytes(b"PUT"), key())
.map(|(_, key)| key)
.and(value_messages);
let parser = || put.map(|(_, messages)| messages);
let command = &b"PUTkey\x00\x00\x00\x12\x00\x00\x00\x02\x00\x00\x00\x04\xDE\xAD\xBE\xEF\x00\x00\x00\x02\xBE\xEF"[..];
let result = parser().parse(command).unwrap();
assert_eq!(2, result.0.len());
}
#[test]
fn not_followed_by_empty_error_issue_220() {
let mut parser = string("let").skip(not_followed_by(eof().map(|_| "EOF")));
assert_eq!(
parser.easy_parse("let").map_err(|err| err.errors),
Err(vec![]),
);
}
}
#![allow(dead_code)]
use std::{
io,
marker::Unpin,
pin::Pin,
task::{self, Poll},
};
use {futures_03_dep::ready, partial_io::PartialOp};
pub struct PartialAsyncRead<R> {
inner: R,
ops: Box<dyn Iterator<Item = PartialOp> + Send>,
}
impl<R> PartialAsyncRead<R>
where
R: Unpin,
{
pub fn new<I>(inner: R, ops: I) -> Self
where
I: IntoIterator<Item = PartialOp>,
I::IntoIter: Send + 'static,
{
PartialAsyncRead {
inner,
ops: Box::new(ops.into_iter()),
}
}
}
impl<R> tokio_02_dep::io::AsyncRead for PartialAsyncRead<R>
where
R: tokio_02_dep::io::AsyncRead + Unpin,
{
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
match self.ops.next() {
Some(PartialOp::Limited(n)) => {
let len = std::cmp::min(n, buf.len());
Pin::new(&mut self.inner).poll_read(cx, &mut buf[..len])
}
Some(PartialOp::Err(err)) => {
if err == io::ErrorKind::WouldBlock {
cx.waker().wake_by_ref();
Poll::Pending
} else {
Err(io::Error::new(
err,
"error during read, generated by partial-io",
))
.into()
}
}
Some(PartialOp::Unlimited) | None => Pin::new(&mut self.inner).poll_read(cx, buf),
}
}
}
impl<R> tokio_03_dep::io::AsyncRead for PartialAsyncRead<R>
where
R: tokio_03_dep::io::AsyncRead + Unpin,
{
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
buf: &mut tokio_03_dep::io::ReadBuf<'_>,
) -> Poll<io::Result<()>> {
match self.ops.next() {
Some(PartialOp::Limited(n)) => {
let len = std::cmp::min(n, buf.remaining());
buf.initialize_unfilled();
let mut sub_buf = buf.take(len);
ready!(Pin::new(&mut self.inner).poll_read(cx, &mut sub_buf))?;
let filled = sub_buf.filled().len();
buf.advance(filled);
Poll::Ready(Ok(()))
}
Some(PartialOp::Err(err)) => {
if err == io::ErrorKind::WouldBlock {
cx.waker().wake_by_ref();
Poll::Pending
} else {
Err(io::Error::new(
err,
"error during read, generated by partial-io",
))
.into()
}
}
Some(PartialOp::Unlimited) | None => Pin::new(&mut self.inner).poll_read(cx, buf),
}
}
}
impl<R> tokio_dep::io::AsyncRead for PartialAsyncRead<R>
where
R: tokio_dep::io::AsyncRead + Unpin,
{
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
buf: &mut tokio_dep::io::ReadBuf<'_>,
) -> Poll<io::Result<()>> {
match self.ops.next() {
Some(PartialOp::Limited(n)) => {
let len = std::cmp::min(n, buf.remaining());
buf.initialize_unfilled();
let mut sub_buf = buf.take(len);
ready!(Pin::new(&mut self.inner).poll_read(cx, &mut sub_buf))?;
let filled = sub_buf.filled().len();
buf.advance(filled);
Poll::Ready(Ok(()))
}
Some(PartialOp::Err(err)) => {
if err == io::ErrorKind::WouldBlock {
cx.waker().wake_by_ref();
Poll::Pending
} else {
Err(io::Error::new(
err,
"error during read, generated by partial-io",
))
.into()
}
}
Some(PartialOp::Unlimited) | None => Pin::new(&mut self.inner).poll_read(cx, buf),
}
}
}
pub struct FuturesPartialAsyncRead<R> {
inner: R,
ops: Box<dyn Iterator<Item = PartialOp> + Send>,
}
impl<R> FuturesPartialAsyncRead<R>
where
R: crate::futures::io::AsyncRead + Unpin,
{
pub fn new<I>(inner: R, ops: I) -> Self
where
I: IntoIterator<Item = PartialOp>,
I::IntoIter: Send + 'static,
{
FuturesPartialAsyncRead {
inner,
ops: Box::new(ops.into_iter()),
}
}
}
impl<R> crate::futures::io::AsyncRead for FuturesPartialAsyncRead<R>
where
R: crate::futures::io::AsyncRead + Unpin,
{
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
match self.ops.next() {
Some(PartialOp::Limited(n)) => {
let len = std::cmp::min(n, buf.len());
Pin::new(&mut self.inner).poll_read(cx, &mut buf[..len])
}
Some(PartialOp::Err(err)) => {
if err == io::ErrorKind::WouldBlock {
cx.waker().wake_by_ref();
Poll::Pending
} else {
Err(io::Error::new(
err,
"error during read, generated by partial-io",
))
.into()
}
}
Some(PartialOp::Unlimited) | None => Pin::new(&mut self.inner).poll_read(cx, buf),
}
}
}

Sorry, the diff of this file is not supported yet