зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound.
This commit is contained in:
Коммит
fd25889a8c
|
@ -140,11 +140,6 @@ dependencies = [
|
|||
"tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.9"
|
||||
|
@ -506,14 +501,6 @@ dependencies = [
|
|||
"vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.29"
|
||||
|
@ -1131,11 +1118,6 @@ dependencies = [
|
|||
"winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
|
@ -1381,7 +1363,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.3.3"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -1402,7 +1384,7 @@ dependencies = [
|
|||
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"h2 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"http 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1585,7 +1567,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.2.1"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -1776,14 +1758,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.16"
|
||||
version = "0.6.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1792,17 +1774,6 @@ dependencies = [
|
|||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-extras"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-named-pipes"
|
||||
version = "0.1.5"
|
||||
|
@ -1810,7 +1781,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -1821,7 +1792,7 @@ version = "0.6.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2345,102 +2316,6 @@ dependencies = [
|
|||
"winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_isaac"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_jitter"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_os"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_pcg"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_xorshift"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.0.0"
|
||||
|
@ -2462,14 +2337,6 @@ dependencies = [
|
|||
"rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdrand"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.32"
|
||||
|
@ -2603,7 +2470,7 @@ dependencies = [
|
|||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"murmurhash3 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2757,15 +2624,9 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.8.1"
|
||||
name = "sha1"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
|
@ -3170,7 +3031,7 @@ version = "0.1.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-fs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3200,7 +3061,7 @@ dependencies = [
|
|||
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3244,7 +3105,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3258,7 +3119,7 @@ dependencies = [
|
|||
"bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -3293,7 +3154,7 @@ dependencies = [
|
|||
"bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3309,7 +3170,7 @@ dependencies = [
|
|||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3533,7 +3394,7 @@ dependencies = [
|
|||
"webrender_api 0.60.0",
|
||||
"webrender_build 0.0.1",
|
||||
"wr_malloc_size_of 0.0.1",
|
||||
"ws 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ws 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3649,18 +3510,17 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ws"
|
||||
version = "0.8.1"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -3759,7 +3619,6 @@ dependencies = [
|
|||
"checksum ascii-canvas 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b385d69402821a1c254533a011a312531cbcc0e3e24f19bbb4747a5a2daf37e2"
|
||||
"checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21"
|
||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||
"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
|
||||
"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
|
||||
"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0"
|
||||
"checksum base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "621fc7ecb8008f86d7fb9b95356cd692ce9514b80a86d85b397f32a22da7b9e2"
|
||||
|
@ -3790,7 +3649,6 @@ dependencies = [
|
|||
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
|
||||
"checksum clang-sys 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4227269cec09f5f83ff160be12a1e9b0262dd1aa305302d5ba296c2ebd291055"
|
||||
"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb"
|
||||
"checksum comedy 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4f03fbb05a4df3523a44cda10340e6ae6bea03ee9d01240a1a2c1ef6c73e95"
|
||||
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
|
||||
|
@ -3855,7 +3713,6 @@ dependencies = [
|
|||
"checksum foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ebc04f19019fff1f2d627b5581574ead502f80c48c88900575a46e0840fe5d0"
|
||||
"checksum freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b659e75b7a7338fe75afd7f909fc2b71937845cffb6ebe54ba2e50f13d8e903d"
|
||||
"checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
|
||||
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "884dbe32a6ae4cd7da5c6db9b78114449df9953b8d490c9d7e1b51720b922c62"
|
||||
|
@ -3871,7 +3728,7 @@ dependencies = [
|
|||
"checksum h2 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "a27e7ed946e8335bdf9a191bc1b9b14a03ba822d013d2f58437f4fabcbd7fc2c"
|
||||
"checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da"
|
||||
"checksum http 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "dca621d0fa606a5ff2850b6e337b57ad6137ee4d67e940449643ff45af6874c6"
|
||||
"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83"
|
||||
"checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07"
|
||||
"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
|
||||
"checksum hyper 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c087746de95e20e4dabe86606c3a019964a8fde2d5f386152939063c116c5971"
|
||||
"checksum ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9826188e666f2ed92071d2dadef6edc430b11b158b5b2b3f4babbcc891eaaa"
|
||||
|
@ -3888,7 +3745,7 @@ dependencies = [
|
|||
"checksum lalrpop-util 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)" = "488da0d45c65af229321623c62660627d02b0e7fbc768a4c3fcd121815404ef1"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"
|
||||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"
|
||||
"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
|
||||
"checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2"
|
||||
"checksum libudev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea626d3bdf40a1c5aee3bcd4f40826970cae8d80a8fec934c82a63840094dcfe"
|
||||
|
@ -3909,8 +3766,7 @@ dependencies = [
|
|||
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
|
||||
"checksum miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aaa2d3ad070f428fffbd7d3ca2ea20bb0d8cffe9024405c44e1840bc1418b398"
|
||||
"checksum miniz_oxide_c_api 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "92d98fdbd6145645828069b37ea92ca3de225e000d80702da25c20d3584b38a5"
|
||||
"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432"
|
||||
"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"
|
||||
"checksum mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "4fcfcb32d63961fb6f367bfd5d21e4600b92cd310f71f9dca25acae196eb1560"
|
||||
"checksum mio-named-pipes 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "82f43a815b57d2d652550f3d20cec88a495bb2d0956aa873dc43040278455677"
|
||||
"checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
|
@ -3960,19 +3816,8 @@ dependencies = [
|
|||
"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
|
||||
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
|
||||
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
||||
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
|
||||
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
|
||||
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
|
||||
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
|
||||
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
|
||||
"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
|
||||
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
|
||||
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
|
||||
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
|
||||
"checksum rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "485541959c8ecc49865526fe6c4de9653dd6e60d829d6edf0be228167b60372d"
|
||||
"checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8"
|
||||
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
"checksum redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ab105df655884ede59d45b7070c8a65002d921461ee813a024558ca16030eea0"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "214a97e49be64fd2c86f568dd0cb2c757d2cc53de95b273b6ad0a1c908482f26"
|
||||
|
@ -4003,7 +3848,7 @@ dependencies = [
|
|||
"checksum serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3"
|
||||
"checksum serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)" = "<none>"
|
||||
"checksum serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "44dd2cfde475037451fa99b7e5df77aa3cfd1536575fa8e7a538ab36dcde49ae"
|
||||
"checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68"
|
||||
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
|
||||
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
|
||||
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
|
||||
"checksum siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ffc669b726f2bc9a3bcff66e5e23b56ba6bf70e22a34c3d7b6d0b3450b65b84"
|
||||
|
@ -4077,7 +3922,7 @@ dependencies = [
|
|||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)" = "<none>"
|
||||
"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767"
|
||||
"checksum winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a"
|
||||
"checksum ws 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ec91ea61b83ce033c43c06c52ddc7532f465c0153281610d44c58b74083aee1a"
|
||||
"checksum ws 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "89c48c53bf9dee34411a08993c10b879c36e105d609b46e25673befe3a5c1320"
|
||||
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
"checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5"
|
||||
"checksum yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95acf0db5515d07da9965ec0e0ba6cc2d825e2caeb7303b66ca441729801254e"
|
||||
|
|
|
@ -147,6 +147,8 @@ var whitelist = [
|
|||
{file: "chrome://pippki/content/resetpassword.xul"},
|
||||
// Bug 1337345
|
||||
{file: "resource://gre/modules/Manifest.jsm"},
|
||||
// Bug 1548381
|
||||
{file: "resource://gre/modules/PasswordGenerator.jsm"},
|
||||
// Bug 1351097
|
||||
{file: "resource://gre/modules/accessibility/AccessFu.jsm"},
|
||||
// Bug 1356043
|
||||
|
|
|
@ -53,11 +53,6 @@ dependencies = [
|
|||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.10.0"
|
||||
|
@ -504,11 +499,6 @@ dependencies = [
|
|||
"servo-freetype-sys 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
|
@ -680,7 +670,7 @@ dependencies = [
|
|||
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -732,7 +722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.2.1"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -846,33 +836,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.16"
|
||||
version = "0.6.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-extras"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.1"
|
||||
|
@ -1140,6 +1119,16 @@ dependencies = [
|
|||
"proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.2"
|
||||
|
@ -1162,107 +1151,11 @@ dependencies = [
|
|||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_isaac"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_jitter"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_os"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_pcg"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_xorshift"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.0.1"
|
||||
|
@ -1284,14 +1177,6 @@ dependencies = [
|
|||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdrand"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.38"
|
||||
|
@ -1442,15 +1327,9 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.8.1"
|
||||
name = "sha1"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
|
@ -1474,7 +1353,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -1794,7 +1673,7 @@ dependencies = [
|
|||
"webrender_api 0.60.0",
|
||||
"webrender_build 0.0.1",
|
||||
"wr_malloc_size_of 0.0.1",
|
||||
"ws 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ws 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1941,18 +1820,17 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ws"
|
||||
version = "0.8.1"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -2009,7 +1887,6 @@ dependencies = [
|
|||
"checksum app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9dadc668390b373e73e4abbfc1f07238b09a25858f2f39c06cebc6d8e141d774"
|
||||
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
|
||||
"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1"
|
||||
"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
|
||||
"checksum base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "621fc7ecb8008f86d7fb9b95356cd692ce9514b80a86d85b397f32a22da7b9e2"
|
||||
"checksum binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff"
|
||||
"checksum bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bda13183df33055cbb84b847becce220d392df502ebe7a4a78d7021771ed94d0"
|
||||
|
@ -2062,7 +1939,6 @@ dependencies = [
|
|||
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
"checksum freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b659e75b7a7338fe75afd7f909fc2b71937845cffb6ebe54ba2e50f13d8e903d"
|
||||
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||
|
@ -2088,7 +1964,7 @@ dependencies = [
|
|||
"checksum khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
||||
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
||||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"
|
||||
"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1"
|
||||
"checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2"
|
||||
"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
|
||||
|
@ -2104,8 +1980,7 @@ dependencies = [
|
|||
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
|
||||
"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
|
||||
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
|
||||
"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432"
|
||||
"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"
|
||||
"checksum mio 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "75f72a93f046f1517e3cfddc0a096eb756a2ba727d36edc8227dee769a50a9b0"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "45a8a18a41cfab0fde25cc2f43ea89064d211a0fbb33225b8ff93ab20406e0e7"
|
||||
"checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0"
|
||||
|
@ -2136,22 +2011,12 @@ dependencies = [
|
|||
"checksum procedural-masquerade 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9a1574a51c3fd37b26d2c0032b649d08a7d51d4cca9c41bbc5bf7118fa4509d0"
|
||||
"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
|
||||
"checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035"
|
||||
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
|
||||
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
|
||||
"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
|
||||
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
|
||||
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
|
||||
"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2"
|
||||
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
|
||||
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
|
||||
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
|
||||
"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
|
||||
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
|
||||
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
|
||||
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
|
||||
"checksum rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e811e76f1dbf68abf87a759083d34600017fc4e10b6bd5ad84a700f9dba4b1"
|
||||
"checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8"
|
||||
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
"checksum redox_syscall 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "0a12d51a5b5fd700e6c757f15877685bfa04fd7eb60c108f01d045cafa0073c2"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53ee8cfdddb2e0291adfb9f13d31d3bbe0a03c9a402c01b1e24188d86c35b24f"
|
||||
|
@ -2171,10 +2036,10 @@ dependencies = [
|
|||
"checksum servo-fontconfig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a088f8d775a5c5314aae09bd77340bc9c67d72b9a45258be34c83548b4814cd9"
|
||||
"checksum servo-fontconfig-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "38b494f03009ee81914b0e7d387ad7c145cafcd69747c2ec89b0e17bb94f303a"
|
||||
"checksum servo-freetype-sys 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4ccb6d0d32d277d3ef7dea86203d8210945eb7a45fba89dd445b3595dd0dfc"
|
||||
"checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68"
|
||||
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
|
||||
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
|
||||
"checksum shared_library 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8254bf098ce4d8d7cc7cc6de438c5488adc5297e5b7ffef88816c0a91bd289c1"
|
||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
|
||||
"checksum smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "26df3bb03ca5eac2e64192b723d51f56c1b1e0860e7c766281f4598f181acdc8"
|
||||
"checksum smithay-client-toolkit 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "428d6c019bb92753be9670367e3f483e4fcef396180a9b59e813b69b20014881"
|
||||
"checksum stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa"
|
||||
|
@ -2215,7 +2080,7 @@ dependencies = [
|
|||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767"
|
||||
"checksum winit 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ec43db5991cc509f5b0c68cb0a0d3614f697c888999990a186a2e895c7f723c0"
|
||||
"checksum ws 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ec91ea61b83ce033c43c06c52ddc7532f465c0153281610d44c58b74083aee1a"
|
||||
"checksum ws 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "89c48c53bf9dee34411a08993c10b879c36e105d609b46e25673befe3a5c1320"
|
||||
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
"checksum x11-dl 2.17.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3235540540fde1ae074c8df49054166c0e070407f1c6e1ee17b8c87c2c7bcc7d"
|
||||
"checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2"
|
||||
|
|
|
@ -51,7 +51,7 @@ time = "0.1"
|
|||
api = { version = "0.60.0", path = "../webrender_api", package = "webrender_api" }
|
||||
webrender_build = { version = "0.0.1", path = "../webrender_build" }
|
||||
malloc_size_of = { version = "0.0.1", path = "../wr_malloc_size_of", package = "wr_malloc_size_of" }
|
||||
ws = { optional = true, version = "0.8" }
|
||||
ws = { optional = true, version = "0.7.3" }
|
||||
svg_fmt = "0.4"
|
||||
|
||||
[dependencies.pathfinder_font_renderer]
|
||||
|
|
|
@ -165,7 +165,6 @@ Please commit or stash these changes before vendoring, or re-run with `--ignore-
|
|||
'bindgen',
|
||||
'fuchsia-zircon',
|
||||
'fuchsia-zircon-sys',
|
||||
'fuchsia-cprng',
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -173,6 +172,7 @@ Please commit or stash these changes before vendoring, or re-run with `--ignore-
|
|||
# license, but that also need to explicitly mentioned in about:license.
|
||||
RUNTIME_LICENSE_PACKAGE_WHITELIST = {
|
||||
'BSD-3-Clause': [
|
||||
'sha1',
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
{"files":{"Cargo.toml":"59b541962c15f51087a11d7296e3b69ec6d9b8a8e9e8db949e7629ea28183564","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"27995d58ad5c1145c1a8cd86244ce844886958a35eb2b78c6b772748669999ac","README.md":"d0e320dccace525a2cbcf3bc5d43ac9b7b61ee86b9c9713bf68993c3ad789d0a","examples/integers.rs":"589ff4271566dfa322becddf3e2c7b592e6e0bc97b02892ce75619b7e452e930","examples/paths.rs":"1b30e466b824ce8df7ad0a55334424131d9d2573d6cf9f7d5d50c09c8901d526","examples/traits.rs":"cbee6a3e1f7db60b02ae25b714926517144a77cb492021f492774cf0e1865a9e","examples/versions.rs":"38535e6d9f5bfae0de474a3db79a40e8f5da8ba9334c5ff4c363de9bc99d4d12","src/error.rs":"12de7dafea4a35d1dc2f0fa79bfa038386bbbea72bf083979f4ddf227999eeda","src/lib.rs":"7392068683dc86107bcf8073c81ff8fb7026f5fb98a355a4d47301c5946eeccb","src/tests.rs":"34bdceeffdbdd7f2535a6ed8272482b17325dba044c91bb96f3f8caeec58a83d","src/version.rs":"165324950f2195aaf068c47a4f2f0992b2bf18d8b7f4f17b6b264767523c0e5d"},"package":"a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"}
|
|
@ -1,24 +0,0 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "autocfg"
|
||||
version = "0.1.2"
|
||||
authors = ["Josh Stone <cuviper@gmail.com>"]
|
||||
description = "Automatic cfg for Rust compiler features"
|
||||
readme = "README.md"
|
||||
keywords = ["rustc", "build", "autoconf"]
|
||||
categories = ["development-tools::build-utils"]
|
||||
license = "Apache-2.0/MIT"
|
||||
repository = "https://github.com/cuviper/autocfg"
|
||||
|
||||
[dependencies]
|
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -1,25 +0,0 @@
|
|||
Copyright (c) 2018 Josh Stone
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -1,68 +0,0 @@
|
|||
autocfg
|
||||
=======
|
||||
|
||||
[![autocfg crate](https://img.shields.io/crates/v/autocfg.svg)](https://crates.io/crates/autocfg)
|
||||
[![autocfg documentation](https://docs.rs/autocfg/badge.svg)](https://docs.rs/autocfg)
|
||||
![minimum rustc 1.0](https://img.shields.io/badge/rustc-1.0+-red.svg)
|
||||
[![Travis Status](https://travis-ci.org/cuviper/autocfg.svg?branch=master)](https://travis-ci.org/cuviper/autocfg)
|
||||
|
||||
A Rust library for build scripts to automatically configure code based on
|
||||
compiler support. Code snippets are dynamically tested to see if the `rustc`
|
||||
will accept them, rather than hard-coding specific version support.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[build-dependencies]
|
||||
autocfg = "0.1"
|
||||
```
|
||||
|
||||
Then use it in your `build.rs` script to detect compiler features. For
|
||||
example, to test for 128-bit integer support, it might look like:
|
||||
|
||||
```rust
|
||||
extern crate autocfg;
|
||||
|
||||
fn main() {
|
||||
let ac = autocfg::new();
|
||||
ac.emit_has_type("i128");
|
||||
|
||||
// (optional) We don't need to rerun for anything external.
|
||||
autocfg::rerun_path(file!());
|
||||
}
|
||||
```
|
||||
|
||||
If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line
|
||||
for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the
|
||||
rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that
|
||||
should only be used when the compiler supports it.
|
||||
|
||||
|
||||
## Release Notes
|
||||
|
||||
- 0.1.2 (2018-01-16)
|
||||
- Add `rerun_env(ENV)` to print `cargo:rerun-if-env-changed=ENV`
|
||||
- Add `rerun_path(PATH)` to print `cargo:rerun-if-changed=PATH`
|
||||
|
||||
|
||||
## Minimum Rust version policy
|
||||
|
||||
This crate's minimum supported `rustc` version is `1.0.0`. Compatibility is
|
||||
its entire reason for existence, so this crate will be extremely conservative
|
||||
about raising this requirement. If this is ever deemed necessary, it will be
|
||||
treated as a major breaking change for semver purposes.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under either of
|
||||
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
|
@ -1,9 +0,0 @@
|
|||
extern crate autocfg;
|
||||
|
||||
fn main() {
|
||||
// Normally, cargo will set `OUT_DIR` for build scripts.
|
||||
let ac = autocfg::AutoCfg::with_dir("target").unwrap();
|
||||
for i in 3..8 {
|
||||
ac.emit_has_type(&format!("i{}", 1 << i));
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
extern crate autocfg;
|
||||
|
||||
fn main() {
|
||||
// Normally, cargo will set `OUT_DIR` for build scripts.
|
||||
let ac = autocfg::AutoCfg::with_dir("target").unwrap();
|
||||
|
||||
// since ancient times...
|
||||
ac.emit_has_path("std::vec::Vec");
|
||||
ac.emit_path_cfg("std::vec::Vec", "has_vec");
|
||||
|
||||
// rustc 1.10.0
|
||||
ac.emit_has_path("std::panic::PanicInfo");
|
||||
ac.emit_path_cfg("std::panic::PanicInfo", "has_panic_info");
|
||||
|
||||
// rustc 1.20.0
|
||||
ac.emit_has_path("std::mem::ManuallyDrop");
|
||||
ac.emit_path_cfg("std::mem::ManuallyDrop", "has_manually_drop");
|
||||
|
||||
// rustc 1.25.0
|
||||
ac.emit_has_path("std::ptr::NonNull");
|
||||
ac.emit_path_cfg("std::ptr::NonNull", "has_non_null");
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
extern crate autocfg;
|
||||
|
||||
fn main() {
|
||||
// Normally, cargo will set `OUT_DIR` for build scripts.
|
||||
let ac = autocfg::AutoCfg::with_dir("target").unwrap();
|
||||
|
||||
// since ancient times...
|
||||
ac.emit_has_trait("std::ops::Add");
|
||||
ac.emit_trait_cfg("std::ops::Add", "has_ops");
|
||||
|
||||
// trait parameters have to be provided
|
||||
ac.emit_has_trait("std::borrow::Borrow<str>");
|
||||
ac.emit_trait_cfg("std::borrow::Borrow<str>", "has_borrow");
|
||||
|
||||
// rustc 1.8.0
|
||||
ac.emit_has_trait("std::ops::AddAssign");
|
||||
ac.emit_trait_cfg("std::ops::AddAssign", "has_assign_ops");
|
||||
|
||||
// rustc 1.12.0
|
||||
ac.emit_has_trait("std::iter::Sum");
|
||||
ac.emit_trait_cfg("std::iter::Sum", "has_sum");
|
||||
|
||||
// rustc 1.28.0
|
||||
ac.emit_has_trait("std::alloc::GlobalAlloc");
|
||||
ac.emit_trait_cfg("std::alloc::GlobalAlloc", "has_global_alloc");
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
extern crate autocfg;
|
||||
|
||||
fn main() {
|
||||
// Normally, cargo will set `OUT_DIR` for build scripts.
|
||||
let ac = autocfg::AutoCfg::with_dir("target").unwrap();
|
||||
for i in 0..100 {
|
||||
ac.emit_rustc_version(1, i);
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
use std::error;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::num;
|
||||
use std::str;
|
||||
|
||||
/// A common error type for the `autocfg` crate.
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
kind: ErrorKind,
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
"AutoCfg error"
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
match self.kind {
|
||||
ErrorKind::Io(ref e) => Some(e),
|
||||
ErrorKind::Num(ref e) => Some(e),
|
||||
ErrorKind::Utf8(ref e) => Some(e),
|
||||
ErrorKind::Other(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match self.kind {
|
||||
ErrorKind::Io(ref e) => e.fmt(f),
|
||||
ErrorKind::Num(ref e) => e.fmt(f),
|
||||
ErrorKind::Utf8(ref e) => e.fmt(f),
|
||||
ErrorKind::Other(s) => s.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ErrorKind {
|
||||
Io(io::Error),
|
||||
Num(num::ParseIntError),
|
||||
Utf8(str::Utf8Error),
|
||||
Other(&'static str),
|
||||
}
|
||||
|
||||
pub fn from_io(e: io::Error) -> Error {
|
||||
Error {
|
||||
kind: ErrorKind::Io(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_num(e: num::ParseIntError) -> Error {
|
||||
Error {
|
||||
kind: ErrorKind::Num(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_utf8(e: str::Utf8Error) -> Error {
|
||||
Error {
|
||||
kind: ErrorKind::Utf8(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(s: &'static str) -> Error {
|
||||
Error {
|
||||
kind: ErrorKind::Other(s),
|
||||
}
|
||||
}
|
|
@ -1,288 +0,0 @@
|
|||
//! A Rust library for build scripts to automatically configure code based on
|
||||
//! compiler support. Code snippets are dynamically tested to see if the `rustc`
|
||||
//! will accept them, rather than hard-coding specific version support.
|
||||
//!
|
||||
//!
|
||||
//! ## Usage
|
||||
//!
|
||||
//! Add this to your `Cargo.toml`:
|
||||
//!
|
||||
//! ```toml
|
||||
//! [build-dependencies]
|
||||
//! autocfg = "0.1"
|
||||
//! ```
|
||||
//!
|
||||
//! Then use it in your `build.rs` script to detect compiler features. For
|
||||
//! example, to test for 128-bit integer support, it might look like:
|
||||
//!
|
||||
//! ```rust
|
||||
//! extern crate autocfg;
|
||||
//!
|
||||
//! fn main() {
|
||||
//! # // Normally, cargo will set `OUT_DIR` for build scripts.
|
||||
//! # std::env::set_var("OUT_DIR", "target");
|
||||
//! let ac = autocfg::new();
|
||||
//! ac.emit_has_type("i128");
|
||||
//!
|
||||
//! // (optional) We don't need to rerun for anything external.
|
||||
//! autocfg::rerun_path(file!());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line
|
||||
//! for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the
|
||||
//! rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that
|
||||
//! should only be used when the compiler supports it.
|
||||
|
||||
#![deny(missing_debug_implementations)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
mod error;
|
||||
pub use error::Error;
|
||||
|
||||
mod version;
|
||||
use version::Version;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
/// Helper to detect compiler features for `cfg` output in build scripts.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AutoCfg {
|
||||
out_dir: PathBuf,
|
||||
rustc: PathBuf,
|
||||
rustc_version: Version,
|
||||
target: Option<OsString>,
|
||||
}
|
||||
|
||||
/// Writes a config flag for rustc on standard out.
|
||||
///
|
||||
/// This looks like: `cargo:rustc-cfg=CFG`
|
||||
///
|
||||
/// Cargo will use this in arguments to rustc, like `--cfg CFG`.
|
||||
pub fn emit(cfg: &str) {
|
||||
println!("cargo:rustc-cfg={}", cfg);
|
||||
}
|
||||
|
||||
/// Writes a line telling Cargo to rerun the build script if `path` changes.
|
||||
///
|
||||
/// This looks like: `cargo:rerun-if-changed=PATH`
|
||||
///
|
||||
/// This requires at least cargo 0.7.0, corresponding to rustc 1.6.0. Earlier
|
||||
/// versions of cargo will simply ignore the directive.
|
||||
pub fn rerun_path(path: &str) {
|
||||
println!("cargo:rerun-if-changed={}", path);
|
||||
}
|
||||
|
||||
/// Writes a line telling Cargo to rerun the build script if the environment
|
||||
/// variable `var` changes.
|
||||
///
|
||||
/// This looks like: `cargo:rerun-if-env-changed=VAR`
|
||||
///
|
||||
/// This requires at least cargo 0.21.0, corresponding to rustc 1.20.0. Earlier
|
||||
/// versions of cargo will simply ignore the directive.
|
||||
pub fn rerun_env(var: &str) {
|
||||
println!("cargo:rerun-if-env-changed={}", var);
|
||||
}
|
||||
|
||||
/// Create a new `AutoCfg` instance.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `AutoCfg::new()` returns an error.
|
||||
pub fn new() -> AutoCfg {
|
||||
AutoCfg::new().unwrap()
|
||||
}
|
||||
|
||||
impl AutoCfg {
|
||||
/// Create a new `AutoCfg` instance.
|
||||
///
|
||||
/// # Common errors
|
||||
///
|
||||
/// - `rustc` can't be executed, from `RUSTC` or in the `PATH`.
|
||||
/// - The version output from `rustc` can't be parsed.
|
||||
/// - `OUT_DIR` is not set in the environment, or is not a writable directory.
|
||||
///
|
||||
pub fn new() -> Result<Self, Error> {
|
||||
match env::var_os("OUT_DIR") {
|
||||
Some(d) => Self::with_dir(d),
|
||||
None => Err(error::from_str("no OUT_DIR specified!")),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `AutoCfg` instance with the specified output directory.
|
||||
///
|
||||
/// # Common errors
|
||||
///
|
||||
/// - `rustc` can't be executed, from `RUSTC` or in the `PATH`.
|
||||
/// - The version output from `rustc` can't be parsed.
|
||||
/// - `dir` is not a writable directory.
|
||||
///
|
||||
pub fn with_dir<T: Into<PathBuf>>(dir: T) -> Result<Self, Error> {
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
|
||||
let rustc: PathBuf = rustc.into();
|
||||
let rustc_version = try!(Version::from_rustc(&rustc));
|
||||
|
||||
// Sanity check the output directory
|
||||
let dir = dir.into();
|
||||
let meta = try!(fs::metadata(&dir).map_err(error::from_io));
|
||||
if !meta.is_dir() || meta.permissions().readonly() {
|
||||
return Err(error::from_str("output path is not a writable directory"));
|
||||
}
|
||||
|
||||
Ok(AutoCfg {
|
||||
out_dir: dir,
|
||||
rustc: rustc,
|
||||
rustc_version: rustc_version,
|
||||
target: env::var_os("TARGET"),
|
||||
})
|
||||
}
|
||||
|
||||
/// Test whether the current `rustc` reports a version greater than
|
||||
/// or equal to "`major`.`minor`".
|
||||
pub fn probe_rustc_version(&self, major: usize, minor: usize) -> bool {
|
||||
self.rustc_version >= Version::new(major, minor, 0)
|
||||
}
|
||||
|
||||
/// Sets a `cfg` value of the form `rustc_major_minor`, like `rustc_1_29`,
|
||||
/// if the current `rustc` is at least that version.
|
||||
pub fn emit_rustc_version(&self, major: usize, minor: usize) {
|
||||
if self.probe_rustc_version(major, minor) {
|
||||
emit(&format!("rustc_{}_{}", major, minor));
|
||||
}
|
||||
}
|
||||
|
||||
fn probe<T: AsRef<[u8]>>(&self, code: T) -> Result<bool, Error> {
|
||||
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
|
||||
|
||||
static ID: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
|
||||
let id = ID.fetch_add(1, Ordering::Relaxed);
|
||||
let mut command = Command::new(&self.rustc);
|
||||
command
|
||||
.arg(format!("--crate-name=probe{}", id))
|
||||
.arg("--crate-type=lib")
|
||||
.arg("--out-dir")
|
||||
.arg(&self.out_dir)
|
||||
.arg("--emit=llvm-ir");
|
||||
|
||||
if let Some(target) = self.target.as_ref() {
|
||||
command.arg("--target").arg(target);
|
||||
}
|
||||
|
||||
command.arg("-").stdin(Stdio::piped());
|
||||
let mut child = try!(command.spawn().map_err(error::from_io));
|
||||
try!(
|
||||
child
|
||||
.stdin
|
||||
.take()
|
||||
.expect("rustc stdin")
|
||||
.write_all(code.as_ref())
|
||||
.map_err(error::from_io)
|
||||
);
|
||||
|
||||
let status = try!(child.wait().map_err(error::from_io));
|
||||
Ok(status.success())
|
||||
}
|
||||
|
||||
/// Tests whether the given path can be used.
|
||||
///
|
||||
/// The test code is subject to change, but currently looks like:
|
||||
///
|
||||
/// ```ignore
|
||||
/// pub use PATH;
|
||||
/// ```
|
||||
pub fn probe_path(&self, path: &str) -> bool {
|
||||
self.probe(format!("pub use {};", path)).unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Emits a config value `has_PATH` if `probe_path` returns true.
|
||||
///
|
||||
/// Any non-identifier characters in the `path` will be replaced with
|
||||
/// `_` in the generated config value.
|
||||
pub fn emit_has_path(&self, path: &str) {
|
||||
if self.probe_path(path) {
|
||||
emit(&format!("has_{}", mangle(path)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Emits the given `cfg` value if `probe_path` returns true.
|
||||
pub fn emit_path_cfg(&self, path: &str, cfg: &str) {
|
||||
if self.probe_path(path) {
|
||||
emit(cfg);
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests whether the given trait can be used.
|
||||
///
|
||||
/// The test code is subject to change, but currently looks like:
|
||||
///
|
||||
/// ```ignore
|
||||
/// pub trait Probe: TRAIT + Sized {}
|
||||
/// ```
|
||||
pub fn probe_trait(&self, name: &str) -> bool {
|
||||
self.probe(format!("pub trait Probe: {} + Sized {{}}", name))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Emits a config value `has_TRAIT` if `probe_trait` returns true.
|
||||
///
|
||||
/// Any non-identifier characters in the trait `name` will be replaced with
|
||||
/// `_` in the generated config value.
|
||||
pub fn emit_has_trait(&self, name: &str) {
|
||||
if self.probe_trait(name) {
|
||||
emit(&format!("has_{}", mangle(name)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Emits the given `cfg` value if `probe_trait` returns true.
|
||||
pub fn emit_trait_cfg(&self, name: &str, cfg: &str) {
|
||||
if self.probe_trait(name) {
|
||||
emit(cfg);
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests whether the given type can be used.
|
||||
///
|
||||
/// The test code is subject to change, but currently looks like:
|
||||
///
|
||||
/// ```ignore
|
||||
/// pub type Probe = TYPE;
|
||||
/// ```
|
||||
pub fn probe_type(&self, name: &str) -> bool {
|
||||
self.probe(format!("pub type Probe = {};", name))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Emits a config value `has_TYPE` if `probe_type` returns true.
|
||||
///
|
||||
/// Any non-identifier characters in the type `name` will be replaced with
|
||||
/// `_` in the generated config value.
|
||||
pub fn emit_has_type(&self, name: &str) {
|
||||
if self.probe_type(name) {
|
||||
emit(&format!("has_{}", mangle(name)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Emits the given `cfg` value if `probe_type` returns true.
|
||||
pub fn emit_type_cfg(&self, name: &str, cfg: &str) {
|
||||
if self.probe_type(name) {
|
||||
emit(cfg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn mangle(s: &str) -> String {
|
||||
s.chars()
|
||||
.map(|c| match c {
|
||||
'A'...'Z' | 'a'...'z' | '0'...'9' => c,
|
||||
_ => '_',
|
||||
}).collect()
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
use super::AutoCfg;
|
||||
|
||||
#[test]
|
||||
fn autocfg_version() {
|
||||
let ac = AutoCfg::with_dir("target").unwrap();
|
||||
println!("version: {:?}", ac.rustc_version);
|
||||
assert!(ac.probe_rustc_version(1, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn version_cmp() {
|
||||
use super::version::Version;
|
||||
let v123 = Version::new(1, 2, 3);
|
||||
|
||||
assert!(Version::new(1, 0, 0) < v123);
|
||||
assert!(Version::new(1, 2, 2) < v123);
|
||||
assert!(Version::new(1, 2, 3) == v123);
|
||||
assert!(Version::new(1, 2, 4) > v123);
|
||||
assert!(Version::new(1, 10, 0) > v123);
|
||||
assert!(Version::new(2, 0, 0) > v123);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_add() {
|
||||
let ac = AutoCfg::with_dir("target").unwrap();
|
||||
assert!(ac.probe_path("std::ops::Add"));
|
||||
assert!(ac.probe_trait("std::ops::Add"));
|
||||
assert!(ac.probe_trait("std::ops::Add<i32>"));
|
||||
assert!(ac.probe_trait("std::ops::Add<i32, Output = i32>"));
|
||||
assert!(ac.probe_type("std::ops::Add<i32, Output = i32>"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_as_ref() {
|
||||
let ac = AutoCfg::with_dir("target").unwrap();
|
||||
assert!(ac.probe_path("std::convert::AsRef"));
|
||||
assert!(ac.probe_trait("std::convert::AsRef<str>"));
|
||||
assert!(ac.probe_type("std::convert::AsRef<str>"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_i128() {
|
||||
let ac = AutoCfg::with_dir("target").unwrap();
|
||||
let missing = !ac.probe_rustc_version(1, 26);
|
||||
assert!(missing ^ ac.probe_path("std::i128"));
|
||||
assert!(missing ^ ac.probe_type("i128"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_sum() {
|
||||
let ac = AutoCfg::with_dir("target").unwrap();
|
||||
let missing = !ac.probe_rustc_version(1, 12);
|
||||
assert!(missing ^ ac.probe_path("std::iter::Sum"));
|
||||
assert!(missing ^ ac.probe_trait("std::iter::Sum"));
|
||||
assert!(missing ^ ac.probe_trait("std::iter::Sum<i32>"));
|
||||
assert!(missing ^ ac.probe_type("std::iter::Sum<i32>"));
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::str;
|
||||
|
||||
use super::{error, Error};
|
||||
|
||||
/// A version structure for making relative comparisons.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Version {
|
||||
major: usize,
|
||||
minor: usize,
|
||||
patch: usize,
|
||||
}
|
||||
|
||||
impl Version {
|
||||
/// Creates a `Version` instance for a specific `major.minor.patch` version.
|
||||
pub fn new(major: usize, minor: usize, patch: usize) -> Self {
|
||||
Version {
|
||||
major: major,
|
||||
minor: minor,
|
||||
patch: patch,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_rustc(rustc: &Path) -> Result<Self, Error> {
|
||||
// Get rustc's verbose version
|
||||
let output = try!(
|
||||
Command::new(rustc)
|
||||
.args(&["--version", "--verbose"])
|
||||
.output()
|
||||
.map_err(error::from_io)
|
||||
);
|
||||
if !output.status.success() {
|
||||
return Err(error::from_str("could not execute rustc"));
|
||||
}
|
||||
let output = try!(str::from_utf8(&output.stdout).map_err(error::from_utf8));
|
||||
|
||||
// Find the release line in the verbose version output.
|
||||
let release = match output.lines().find(|line| line.starts_with("release: ")) {
|
||||
Some(line) => &line["release: ".len()..],
|
||||
None => return Err(error::from_str("could not find rustc release")),
|
||||
};
|
||||
|
||||
// Strip off any extra channel info, e.g. "-beta.N", "-nightly"
|
||||
let version = match release.find('-') {
|
||||
Some(i) => &release[..i],
|
||||
None => release,
|
||||
};
|
||||
|
||||
// Split the version into semver components.
|
||||
let mut iter = version.splitn(3, '.');
|
||||
let major = try!(iter.next().ok_or(error::from_str("missing major version")));
|
||||
let minor = try!(iter.next().ok_or(error::from_str("missing minor version")));
|
||||
let patch = try!(iter.next().ok_or(error::from_str("missing patch version")));
|
||||
|
||||
Ok(Version::new(
|
||||
try!(major.parse().map_err(error::from_num)),
|
||||
try!(minor.parse().map_err(error::from_num)),
|
||||
try!(patch.parse().map_err(error::from_num)),
|
||||
))
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{"files":{"Cargo.toml":"16ef935056e2aaf48b28c1340a63cc75febaabc901c752da9a3a2edbe081b429","bitflags.rs":"4621173dcf1307094cf240d26955b6f25c2f770dfd4e975ec2728771209006b5","cloudabi.rs":"93e139ba72a04db4934b04a6f21b054757a218a687e0bd2f6ba32514ec8c5f38"},"package":"ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"}
|
|
@ -1,31 +0,0 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
authors = ["Nuxi (https://nuxi.nl/) and contributors"]
|
||||
description = "Low level interface to CloudABI. Contains all syscalls and related types."
|
||||
homepage = "https://nuxi.nl/cloudabi/"
|
||||
documentation = "https://docs.rs/cloudabi/"
|
||||
keywords = ["cloudabi"]
|
||||
license = "BSD-2-Clause"
|
||||
repository = "https://github.com/nuxinl/cloudabi"
|
||||
|
||||
[lib]
|
||||
path = "cloudabi.rs"
|
||||
[dependencies.bitflags]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
|
||||
[features]
|
||||
default = ["bitflags"]
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright (c) 2018 Nuxi (https://nuxi.nl/) and contributors.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
|
||||
// Appease Rust's tidy.
|
||||
// ignore-license
|
||||
|
||||
#[cfg(feature = "bitflags")]
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
|
||||
// Minimal implementation of bitflags! in case we can't depend on the bitflags
|
||||
// crate. Only implements `bits()` and a `from_bits_truncate()` that doesn't
|
||||
// actually truncate.
|
||||
#[cfg(not(feature = "bitflags"))]
|
||||
macro_rules! bitflags {
|
||||
(
|
||||
$(#[$attr:meta])*
|
||||
pub struct $name:ident: $type:ty {
|
||||
$($(#[$const_attr:meta])* const $const:ident = $val:expr;)*
|
||||
}
|
||||
) => {
|
||||
$(#[$attr])*
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct $name { bits: $type }
|
||||
impl $name {
|
||||
$($(#[$const_attr])* pub const $const: $name = $name{ bits: $val };)*
|
||||
pub fn bits(&self) -> $type { self.bits }
|
||||
pub fn from_bits_truncate(bits: $type) -> Self { $name{ bits } }
|
||||
}
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1 +0,0 @@
|
|||
{"files":{"AUTHORS":"f82920a5bcfc71b86c1de4be4cdea8af2009ba9e5735824f95ed5043a03e46f0","Cargo.toml":"bb2497b2907c3af499ce7ac3722dae044968e13409a372b7760150f8a01c74c5","LICENSE":"03b114f53e6587a398931762ee11e2395bfdba252a329940e2c8c9e81813845b","PATENTS":"52beb3ac72a0e7f5060384d16e4e6f91573016448fbff363c0b01a66fe99f547","src/lib.rs":"3d76c35c13203093ddf7ce2a3be5e98d768a8091cd9d99bd083fe8db35364096"},"package":"a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"}
|
|
@ -1,10 +0,0 @@
|
|||
# This is the list of Fuchsia Authors.
|
||||
|
||||
# Names should be added to this file as one of
|
||||
# Organization's name
|
||||
# Individual's name <submission email address>
|
||||
# Individual's name <submission email address> <email2> <emailN>
|
||||
|
||||
Google Inc.
|
||||
The Chromium Authors
|
||||
The Go Authors
|
|
@ -1,22 +0,0 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
authors = ["Erick Tryzelaar <etryzelaar@google.com>"]
|
||||
include = ["src/*.rs", "Cargo.toml", "AUTHORS", "LICENSE", "PATENTS"]
|
||||
description = "Rust crate for the Fuchsia cryptographically secure pseudorandom number generator"
|
||||
readme = "README.md"
|
||||
license-file = "LICENSE"
|
||||
repository = "https://fuchsia.googlesource.com/fuchsia/+/master/garnet/public/rust/fuchsia-cprng"
|
|
@ -1,22 +0,0 @@
|
|||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Fuchsia project.
|
||||
|
||||
Google hereby grants to you a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this
|
||||
section) patent license to make, have made, use, offer to sell, sell,
|
||||
import, transfer, and otherwise run, modify and propagate the contents
|
||||
of this implementation of Fuchsia, where such license applies only to
|
||||
those patent claims, both currently owned by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by
|
||||
this implementation. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute
|
||||
or order or agree to the institution of patent litigation or any other
|
||||
patent enforcement activity against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that this
|
||||
implementation of Fuchsia constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of
|
||||
Fuchsia shall terminate as of the date such litigation is filed.
|
|
@ -1,57 +0,0 @@
|
|||
// Copyright 2019 The Fuchsia Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
//! Type-safe bindings for the Zircon kernel's CPRNG.
|
||||
|
||||
#![no_std]
|
||||
#![deny(warnings)]
|
||||
|
||||
/// Draw random bytes from the kernel's CPRNG to fill the given buffer.
|
||||
///
|
||||
/// Wraps the
|
||||
/// [zx_cprng_draw](https://fuchsia.googlesource.com/fuchsia/+/master/zircon/docs/syscalls/cprng_draw.md)
|
||||
/// syscall.
|
||||
pub fn cprng_draw(buffer: &mut [u8]) {
|
||||
unsafe { zx_cprng_draw(buffer.as_mut_ptr(), buffer.len()) };
|
||||
}
|
||||
|
||||
#[link(name = "zircon")]
|
||||
extern "C" {
|
||||
fn zx_cprng_draw(buffer: *mut u8, length: usize);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn cprng() {
|
||||
let mut buffer = [0; 20];
|
||||
cprng_draw(&mut buffer);
|
||||
let mut first_zero = 0;
|
||||
let mut last_zero = 0;
|
||||
for _ in 0..30 {
|
||||
let mut buffer = [0; 20];
|
||||
cprng_draw(&mut buffer);
|
||||
if buffer[0] == 0 {
|
||||
first_zero += 1;
|
||||
}
|
||||
if buffer[19] == 0 {
|
||||
last_zero += 1;
|
||||
}
|
||||
}
|
||||
assert_ne!(first_zero, 30);
|
||||
assert_ne!(last_zero, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cprng_large() {
|
||||
let mut buffer = [0; 1024];
|
||||
cprng_draw(&mut buffer);
|
||||
|
||||
for mut s in buffer.chunks_mut(256) {
|
||||
cprng_draw(&mut s);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"2d893bf5d1e9a5445e74c2a7a75b804492245647004155a798f5456e5c0f4712","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ad5ce29918424008bdd8c6e7851bb064533456cbb32ec0d0955b2bc9444613d3","README.md":"b54e1e379daa12d26aadad7c1bef578a3cbcf243f2f229d8b17868c90a384d7d","benches/parse.rs":"caabd31cbcb00172bb7f31a1398dbed27a3bf36b01d69729c3d6fbd9a4008e05","build.rs":"00bab146ec6a10fac91958a06bdd4b7b4d71932e0480b6e84a4248cb339dbe79","src/iter.rs":"3f165be2f0d3bb7e0cbe37cb67560e36e06cdb5921e145446a5985c3580a6b6e","src/lib.rs":"21436cacd3b33b20ad75877e6260f34391a9215ffa6ad2c10ebf1a0c67ac07dc","src/macros.rs":"25de190f894eefb48a6992f9dc3d039d9065f908f381d683f0395d568d992275","src/simd/avx2.rs":"1b27cad7b5c210f8a1283d423ca18372127ea50f5565b9be0b83d2a51a1eb826","src/simd/fallback.rs":"0234cc11459f3225d6e3d329068a01206e39625a538bdc292e0d1beaa06a37e5","src/simd/mod.rs":"c67e118a45da679d41de0d51c2f632f64902083db4be8f636021dbfe08f0f9b4","src/simd/sse42.rs":"373f5bf0596942b9ba4497a8a89975117ec0da6d8b8c2345fe03e0d28e68627f","tests/uri.rs":"92a0dc4cfa8eee2e6b8e9109e2e0062ccb50b9ec8cb4b7c06794dab1a3e68c9c"},"package":"e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83"}
|
||||
{"files":{"Cargo.toml":"ce89721483a37a5e21e4c7c8bd36b64a03067c23b3c6a9569e552a2a0364522e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ad5ce29918424008bdd8c6e7851bb064533456cbb32ec0d0955b2bc9444613d3","README.md":"8777517c90cff609e5a00a46b548f44803a4943cc7430a0ca6ddc4712af8d4ac","benches/parse.rs":"07f7d63b625090f1ccb086679e24c104de450d8733bb517e38a6eda8511e35e3","src/iter.rs":"9782faa1736e7988feceecdd5169f51b8b7926cbcf6611bbef9e018763e3cec8","src/lib.rs":"d95d4de02b19f2f921e13f0f477092d202fe0e707dc007b9bbd05282d7e69ebc"},"package":"af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07"}
|
|
@ -12,14 +12,9 @@
|
|||
|
||||
[package]
|
||||
name = "httparse"
|
||||
version = "1.3.3"
|
||||
authors = ["Sean McArthur <sean@seanmonstar.com>"]
|
||||
build = "build.rs"
|
||||
version = "1.2.3"
|
||||
authors = ["Sean McArthur <sean.monstar@gmail.com>"]
|
||||
description = "A tiny, safe, speedy, zero-copy HTTP/1.x parser."
|
||||
documentation = "https://docs.rs/httparse"
|
||||
readme = "README.md"
|
||||
keywords = ["http", "parser", "no_std"]
|
||||
categories = ["network-programming", "no-std", "parser-implementations", "web-programming"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/seanmonstar/httparse"
|
||||
[profile.bench]
|
||||
|
|
|
@ -2,14 +2,11 @@
|
|||
|
||||
[![Build Status](https://travis-ci.org/seanmonstar/httparse.svg?branch=master)](https://travis-ci.org/seanmonstar/httparse)
|
||||
[![Coverage Status](https://coveralls.io/repos/seanmonstar/httparse/badge.svg)](https://coveralls.io/r/seanmonstar/httparse)
|
||||
[![crates.io](https://img.shields.io/crates/v/httparse.svg)](https://crates.io/crates/httparse)
|
||||
[![crates.io](http://meritbadge.herokuapp.com/httparse)](https://crates.io/crates/httparse)
|
||||
|
||||
A push parser for the HTTP 1.x protocol. Avoids allocations. No copy. **Fast.**
|
||||
|
||||
Works with `no_std`, simply disable the `std` Cargo feature.
|
||||
A push parser for the HTTP 1.x protocol. Avoids allocations. Fast.
|
||||
|
||||
[Documentation](https://docs.rs/httparse)
|
||||
[Changelog](https://github.com/seanmonstar/httparse/releases)
|
||||
|
||||
## Usage
|
||||
|
||||
|
@ -18,12 +15,12 @@ let mut headers = [httparse::EMPTY_HEADER; 16];
|
|||
let mut req = httparse::Request::new(&mut headers);
|
||||
|
||||
let buf = b"GET /index.html HTTP/1.1\r\nHost";
|
||||
assert!(req.parse(buf)?.is_partial());
|
||||
assert!(try!(req.parse(buf)).is_partial());
|
||||
|
||||
// a partial request, so we try again once we have more data
|
||||
|
||||
let buf = b"GET /index.html HTTP/1.1\r\nHost: example.domain\r\n\r\n";
|
||||
assert!(req.parse(buf)?.is_complete());
|
||||
assert!(try!(req.parse(buf)).is_complete());
|
||||
```
|
||||
|
||||
## License
|
||||
|
|
|
@ -5,11 +5,6 @@ extern crate httparse;
|
|||
|
||||
extern crate test;
|
||||
|
||||
const REQ_SHORT: &'static [u8] = b"\
|
||||
GET / HTTP/1.0\r\n\
|
||||
Host: example.com\r\n\
|
||||
Cookie: session=60; user_id=1\r\n\r\n";
|
||||
|
||||
const REQ: &'static [u8] = b"\
|
||||
GET /wp-content/uploads/2010/03/hello-kitty-darth-vader-pink.jpg HTTP/1.1\r\n\
|
||||
Host: www.kittyhell.com\r\n\
|
||||
|
@ -20,7 +15,9 @@ Accept-Encoding: gzip,deflate\r\n\
|
|||
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7\r\n\
|
||||
Keep-Alive: 115\r\n\
|
||||
Connection: keep-alive\r\n\
|
||||
Cookie: wp_ozh_wsa_visits=2; wp_ozh_wsa_visit_lasttime=xxxxxxxxxx; __utma=xxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.x; __utmz=xxxxxxxxx.xxxxxxxxxx.x.x.utmccn=(referral)|utmcsr=reader.livedoor.com|utmcct=/reader/|utmcmd=referral|padding=under256\r\n\r\n";
|
||||
Cookie: wp_ozh_wsa_visits=2; wp_ozh_wsa_visit_lasttime=xxxxxxxxxx; __utma=xxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.x; __utmz=xxxxxxxxx.xxxxxxxxxx.x.x.utmccn=(referral)|utmcsr=reader.livedoor.com|utmcct=/reader/|utmcmd=referral\r\n\r\n";
|
||||
|
||||
|
||||
|
||||
|
||||
#[bench]
|
||||
|
@ -71,52 +68,3 @@ fn bench_httparse(b: &mut test::Bencher) {
|
|||
});
|
||||
b.bytes = REQ.len() as u64;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_pico_short(b: &mut test::Bencher) {
|
||||
use std::mem;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
struct Header<'a>(&'a [u8], &'a [u8]);
|
||||
|
||||
|
||||
#[repr(C)]
|
||||
struct Headers<'a>(&'a mut [Header<'a>]);
|
||||
let method = [0i8; 16];
|
||||
let path = [0i8; 16];
|
||||
let mut minor_version = 0;
|
||||
let mut h = [Header(&[], &[]); 16];
|
||||
let mut h_len = h.len();
|
||||
let headers = Headers(&mut h);
|
||||
let prev_buf_len = 0;
|
||||
|
||||
b.iter(|| {
|
||||
let ret = unsafe {
|
||||
pico::ffi::phr_parse_request(
|
||||
REQ_SHORT.as_ptr() as *const _,
|
||||
REQ_SHORT.len(),
|
||||
&mut method.as_ptr(),
|
||||
&mut 16,
|
||||
&mut path.as_ptr(),
|
||||
&mut 16,
|
||||
&mut minor_version,
|
||||
mem::transmute::<*mut Header, *mut pico::ffi::phr_header>(headers.0.as_mut_ptr()),
|
||||
&mut h_len as *mut usize as *mut _,
|
||||
prev_buf_len
|
||||
)
|
||||
};
|
||||
assert_eq!(ret, REQ_SHORT.len() as i32);
|
||||
});
|
||||
b.bytes = REQ_SHORT.len() as u64;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_httparse_short(b: &mut test::Bencher) {
|
||||
let mut headers = [httparse::Header{ name: "", value: &[] }; 16];
|
||||
let mut req = httparse::Request::new(&mut headers);
|
||||
b.iter(|| {
|
||||
assert_eq!(req.parse(REQ_SHORT).unwrap(), httparse::Status::Complete(REQ_SHORT.len()));
|
||||
});
|
||||
b.bytes = REQ_SHORT.len() as u64;
|
||||
}
|
||||
|
|
|
@ -1,155 +0,0 @@
|
|||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
let rustc = env::var_os("RUSTC").unwrap_or(OsString::from("rustc"));
|
||||
let output = Command::new(&rustc)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.expect("failed to check 'rustc --version'")
|
||||
.stdout;
|
||||
|
||||
let version = String::from_utf8(output)
|
||||
.expect("rustc version output should be utf-8");
|
||||
|
||||
enable_new_features(&version);
|
||||
}
|
||||
|
||||
fn enable_new_features(raw_version: &str) {
|
||||
let version = match Version::parse(raw_version) {
|
||||
Ok(version) => version,
|
||||
Err(err) => {
|
||||
println!("cargo:warning=failed to parse `rustc --version`: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
enable_simd(version);
|
||||
}
|
||||
|
||||
fn enable_simd(version: Version) {
|
||||
if env::var_os("CARGO_FEATURE_STD").is_none() {
|
||||
println!("cargo:warning=building for no_std disables httparse SIMD");
|
||||
return;
|
||||
}
|
||||
|
||||
let env_disable = "CARGO_CFG_HTTPARSE_DISABLE_SIMD";
|
||||
if env::var_os(env_disable).is_some() {
|
||||
println!("cargo:warning=detected {} environment variable, disabling SIMD", env_disable);
|
||||
return;
|
||||
}
|
||||
|
||||
let min_simd_version = Version {
|
||||
major: 1,
|
||||
minor: 27,
|
||||
patch: 0,
|
||||
};
|
||||
|
||||
if version >= min_simd_version {
|
||||
println!("cargo:rustc-cfg=httparse_simd");
|
||||
}
|
||||
|
||||
// cfg(target_feature) isn't stable yet, but CARGO_CFG_TARGET_FEATURE has
|
||||
// a list... We aren't doing anything unsafe, since the is_x86_feature_detected
|
||||
// macro still checks in the actual lib, BUT!
|
||||
//
|
||||
// By peeking at the list here, we can change up slightly how we do feature
|
||||
// detection in the lib. If our features aren't in the feature list, we
|
||||
// stick with a cached runtime detection strategy.
|
||||
//
|
||||
// But if the features *are* in the list, we benefit from removing our cache,
|
||||
// since the compiler will eliminate several branches with its internal
|
||||
// cfg(target_feature) usage.
|
||||
|
||||
|
||||
let env_runtime_only = "CARGO_CFG_HTTPARSE_DISABLE_SIMD_COMPILETIME";
|
||||
if env::var_os(env_runtime_only).is_some() {
|
||||
println!("cargo:warning=detected {} environment variable, using runtime SIMD detection only", env_runtime_only);
|
||||
return;
|
||||
}
|
||||
let feature_list = match env::var_os("CARGO_CFG_TARGET_FEATURE") {
|
||||
Some(var) => match var.into_string() {
|
||||
Ok(s) => s,
|
||||
Err(_) => {
|
||||
println!("cargo:warning=CARGO_CFG_TARGET_FEATURE was not valid utf-8");
|
||||
return;
|
||||
},
|
||||
},
|
||||
None => {
|
||||
println!("cargo:warning=CARGO_CFG_TARGET_FEATURE was not set");
|
||||
return
|
||||
},
|
||||
};
|
||||
|
||||
let mut saw_sse42 = false;
|
||||
let mut saw_avx2 = false;
|
||||
|
||||
for feature in feature_list.split(',') {
|
||||
let feature = feature.trim();
|
||||
if !saw_sse42 && feature == "sse4.2" {
|
||||
saw_sse42 = true;
|
||||
println!("cargo:rustc-cfg=httparse_simd_target_feature_sse42");
|
||||
}
|
||||
|
||||
if !saw_avx2 && feature == "avx2" {
|
||||
saw_avx2 = true;
|
||||
println!("cargo:rustc-cfg=httparse_simd_target_feature_avx2");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
||||
struct Version {
|
||||
major: u32,
|
||||
minor: u32,
|
||||
patch: u32,
|
||||
}
|
||||
|
||||
impl Version {
|
||||
fn parse(mut s: &str) -> Result<Version, String> {
|
||||
if !s.starts_with("rustc ") {
|
||||
return Err(format!("unrecognized version string: {}", s));
|
||||
}
|
||||
s = &s["rustc ".len()..];
|
||||
|
||||
let parts: Vec<&str> = s.split(".").collect();
|
||||
if parts.len() < 3 {
|
||||
return Err(format!("not enough version parts: {:?}", parts));
|
||||
}
|
||||
|
||||
let mut num = String::new();
|
||||
for c in parts[0].chars() {
|
||||
if !c.is_digit(10) {
|
||||
break;
|
||||
}
|
||||
num.push(c);
|
||||
}
|
||||
let major = try!(num.parse::<u32>().map_err(|e| e.to_string()));
|
||||
|
||||
num.clear();
|
||||
for c in parts[1].chars() {
|
||||
if !c.is_digit(10) {
|
||||
break;
|
||||
}
|
||||
num.push(c);
|
||||
}
|
||||
let minor = try!(num.parse::<u32>().map_err(|e| e.to_string()));
|
||||
|
||||
num.clear();
|
||||
for c in parts[2].chars() {
|
||||
if !c.is_digit(10) {
|
||||
break;
|
||||
}
|
||||
num.push(c);
|
||||
}
|
||||
let patch = try!(num.parse::<u32>().map_err(|e| e.to_string()));
|
||||
|
||||
Ok(Version {
|
||||
major: major,
|
||||
minor: minor,
|
||||
patch: patch,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -25,18 +25,10 @@ impl<'a> Bytes<'a> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn bump(&mut self) {
|
||||
debug_assert!(self.pos + 1 <= self.slice.len(), "overflow");
|
||||
pub fn bump(&mut self) {
|
||||
self.pos += 1;
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[inline]
|
||||
pub unsafe fn advance(&mut self, n: usize) {
|
||||
debug_assert!(self.pos + n <= self.slice.len(), "overflow");
|
||||
self.pos += n;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.slice.len()
|
||||
|
@ -44,22 +36,21 @@ impl<'a> Bytes<'a> {
|
|||
|
||||
#[inline]
|
||||
pub fn slice(&mut self) -> &'a [u8] {
|
||||
// not moving position at all, so it's safe
|
||||
unsafe {
|
||||
self.slice_skip(0)
|
||||
}
|
||||
self.slice_skip(0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn slice_skip(&mut self, skip: usize) -> &'a [u8] {
|
||||
pub fn slice_skip(&mut self, skip: usize) -> &'a [u8] {
|
||||
debug_assert!(self.pos >= skip);
|
||||
let head_pos = self.pos - skip;
|
||||
let ptr = self.slice.as_ptr();
|
||||
let head = slice::from_raw_parts(ptr, head_pos);
|
||||
let tail = slice::from_raw_parts(ptr.offset(self.pos as isize), self.slice.len() - self.pos);
|
||||
self.pos = 0;
|
||||
self.slice = tail;
|
||||
head
|
||||
unsafe {
|
||||
let ptr = self.slice.as_ptr();
|
||||
let head = slice::from_raw_parts(ptr, head_pos);
|
||||
let tail = slice::from_raw_parts(ptr.offset(self.pos as isize), self.slice.len() - self.pos);
|
||||
self.pos = 0;
|
||||
self.slice = tail;
|
||||
head
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -72,13 +63,6 @@ impl<'a> Bytes<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> AsRef<[u8]> for Bytes<'a> {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.slice[self.pos..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Bytes<'a> {
|
||||
type Item = u8;
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#![doc(html_root_url = "https://docs.rs/httparse/1.3.3")]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![cfg_attr(test, deny(warnings))]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
//! # httparse
|
||||
//!
|
||||
//! A push library for parsing HTTP/1.x requests and responses.
|
||||
|
@ -12,25 +10,44 @@
|
|||
//! parsing internals use an `Iterator` instead of direct indexing, while
|
||||
//! skipping bounds checks.
|
||||
//!
|
||||
//! With Rust 1.27.0 or later, support for SIMD is enabled automatically.
|
||||
//! If building an executable to be run on multiple platforms, and thus
|
||||
//! not passing `target_feature` or `target_cpu` flags to the compiler,
|
||||
//! runtime detection can still detect SSE4.2 or AVX2 support to provide
|
||||
//! massive wins.
|
||||
//!
|
||||
//! If compiling for a specific target, remembering to include
|
||||
//! `-C target_cpu=native` allows the detection to become compile time checks,
|
||||
//! making it *even* faster.
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std as core;
|
||||
//! The speed is faster than picohttpparser, when SIMD is not available.
|
||||
#[cfg(feature = "std")] extern crate std as core;
|
||||
|
||||
use core::{fmt, result, str, slice};
|
||||
|
||||
use iter::Bytes;
|
||||
|
||||
mod iter;
|
||||
#[macro_use] mod macros;
|
||||
mod simd;
|
||||
|
||||
macro_rules! next {
|
||||
($bytes:ident) => ({
|
||||
match $bytes.next() {
|
||||
Some(b) => b,
|
||||
None => return Ok(Status::Partial)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! expect {
|
||||
($bytes:ident.next() == $pat:pat => $ret:expr) => {
|
||||
expect!(next!($bytes) => $pat |? $ret)
|
||||
};
|
||||
($e:expr => $pat:pat |? $ret:expr) => {
|
||||
match $e {
|
||||
v@$pat => v,
|
||||
_ => return $ret
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! complete {
|
||||
($e:expr) => {
|
||||
match try!($e) {
|
||||
Status::Complete(v) => v,
|
||||
Status::Partial => return Ok(Status::Partial)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn shrink<T>(slice: &mut &mut [T], len: usize) {
|
||||
|
@ -53,41 +70,10 @@ fn shrink<T>(slice: &mut &mut [T], len: usize) {
|
|||
fn is_token(b: u8) -> bool {
|
||||
b > 0x1F && b < 0x7F
|
||||
}
|
||||
|
||||
// ASCII codes to accept URI string.
|
||||
// i.e. A-Z a-z 0-9 !#$%&'*+-._();:@=,/?[]~^
|
||||
// TODO: Make a stricter checking for URI string?
|
||||
static URI_MAP: [bool; 256] = byte_map![
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
// \0 \n
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
// commands
|
||||
0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
// \w ! " # $ % & ' ( ) * + , - . /
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
|
||||
// 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
// @ A B C D E F G H I J K L M N O
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
|
||||
// P Q R S T U V W X Y Z [ \ ] ^ _
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
// ` a b c d e f g h i j k l m n o
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
|
||||
// p q r s t u v w x y z { | } ~ del
|
||||
// ====== Extended ASCII (aka. obs-text) ======
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
|
||||
#[inline]
|
||||
fn is_uri_token(b: u8) -> bool {
|
||||
URI_MAP[b as usize]
|
||||
macro_rules! byte_map {
|
||||
($($flag:expr,)*) => ([
|
||||
$($flag != 0,)*
|
||||
])
|
||||
}
|
||||
|
||||
static HEADER_NAME_MAP: [bool; 256] = byte_map![
|
||||
|
@ -115,7 +101,7 @@ fn is_header_name_token(b: u8) -> bool {
|
|||
}
|
||||
|
||||
static HEADER_VALUE_MAP: [bool; 256] = byte_map![
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
@ -139,6 +125,29 @@ fn is_header_value_token(b: u8) -> bool {
|
|||
HEADER_VALUE_MAP[b as usize]
|
||||
}
|
||||
|
||||
|
||||
macro_rules! space {
|
||||
($bytes:ident or $err:expr) => ({
|
||||
expect!($bytes.next() == b' ' => Err($err));
|
||||
$bytes.slice();
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! newline {
|
||||
($bytes:ident) => ({
|
||||
match next!($bytes) {
|
||||
b'\r' => {
|
||||
expect!($bytes.next() == b'\n' => Err(Error::NewLine));
|
||||
$bytes.slice();
|
||||
},
|
||||
b'\n' => {
|
||||
$bytes.slice();
|
||||
},
|
||||
_ => return Err(Error::NewLine)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// An error in parsing.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Error {
|
||||
|
@ -302,7 +311,7 @@ impl<'h, 'b> Request<'h, 'b> {
|
|||
let mut bytes = Bytes::new(buf);
|
||||
complete!(skip_empty_lines(&mut bytes));
|
||||
self.method = Some(complete!(parse_token(&mut bytes)));
|
||||
self.path = Some(complete!(parse_uri(&mut bytes)));
|
||||
self.path = Some(complete!(parse_token(&mut bytes)));
|
||||
self.version = Some(complete!(parse_version(&mut bytes)));
|
||||
newline!(bytes);
|
||||
|
||||
|
@ -319,13 +328,11 @@ fn skip_empty_lines(bytes: &mut Bytes) -> Result<()> {
|
|||
let b = bytes.peek();
|
||||
match b {
|
||||
Some(b'\r') => {
|
||||
// there's `\r`, so it's safe to bump 1 pos
|
||||
unsafe { bytes.bump() };
|
||||
bytes.bump();
|
||||
expect!(bytes.next() == b'\n' => Err(Error::NewLine));
|
||||
},
|
||||
Some(b'\n') => {
|
||||
// there's `\n`, so it's safe to bump 1 pos
|
||||
unsafe { bytes.bump(); }
|
||||
bytes.bump();
|
||||
},
|
||||
Some(..) => {
|
||||
bytes.slice();
|
||||
|
@ -389,7 +396,6 @@ impl<'h, 'b> Response<'h, 'b> {
|
|||
},
|
||||
b'\r' => {
|
||||
expect!(bytes.next() == b'\n' => Err(Error::Status));
|
||||
bytes.slice();
|
||||
self.reason = Some("");
|
||||
},
|
||||
b'\n' => self.reason = Some(""),
|
||||
|
@ -442,21 +448,10 @@ fn parse_version(bytes: &mut Bytes) -> Result<u8> {
|
|||
b'1' => 1,
|
||||
_ => return Err(Error::Version)
|
||||
};
|
||||
return Ok(Status::Complete(v))
|
||||
Ok(Status::Complete(v))
|
||||
} else {
|
||||
Ok(Status::Partial)
|
||||
}
|
||||
|
||||
// else (but not in `else` because of borrow checker)
|
||||
|
||||
// If there aren't at least 8 bytes, we still want to detect early
|
||||
// if this is a valid version or not. If it is, we'll return Partial.
|
||||
expect!(bytes.next() == b'H' => Err(Error::Version));
|
||||
expect!(bytes.next() == b'T' => Err(Error::Version));
|
||||
expect!(bytes.next() == b'T' => Err(Error::Version));
|
||||
expect!(bytes.next() == b'P' => Err(Error::Version));
|
||||
expect!(bytes.next() == b'/' => Err(Error::Version));
|
||||
expect!(bytes.next() == b'1' => Err(Error::Version));
|
||||
expect!(bytes.next() == b'.' => Err(Error::Version));
|
||||
Ok(Status::Partial)
|
||||
}
|
||||
|
||||
/// From [RFC 7230](https://tools.ietf.org/html/rfc7230):
|
||||
|
@ -513,24 +508,6 @@ fn parse_token<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn parse_uri<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
|
||||
simd::match_uri_vectored(bytes);
|
||||
|
||||
loop {
|
||||
let b = next!(bytes);
|
||||
if b == b' ' {
|
||||
return Ok(Status::Complete(unsafe {
|
||||
// all bytes up till `i` must have been `is_token`.
|
||||
str::from_utf8_unchecked(bytes.slice_skip(1))
|
||||
}));
|
||||
} else if !is_uri_token(b) {
|
||||
return Err(Error::Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
fn parse_code(bytes: &mut Bytes) -> Result<u16> {
|
||||
let hundreds = expect!(bytes.next() == b'0'...b'9' => Err(Error::Status));
|
||||
|
@ -538,8 +515,8 @@ fn parse_code(bytes: &mut Bytes) -> Result<u16> {
|
|||
let ones = expect!(bytes.next() == b'0'...b'9' => Err(Error::Status));
|
||||
|
||||
Ok(Status::Complete((hundreds - b'0') as u16 * 100 +
|
||||
(tens - b'0') as u16 * 10 +
|
||||
(ones - b'0') as u16))
|
||||
(tens - b'0') as u16 * 10 +
|
||||
(ones - b'0') as u16))
|
||||
}
|
||||
|
||||
/// Parse a buffer of bytes as headers.
|
||||
|
@ -567,7 +544,6 @@ pub fn parse_headers<'b: 'h, 'h>(src: &'b [u8], mut dst: &'h mut [Header<'b>])
|
|||
Ok(Status::Complete((pos, dst)))
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
fn parse_headers_iter<'a, 'b>(headers: &mut &mut [Header<'a>], bytes: &'b mut Bytes<'a>)
|
||||
-> Result<usize> {
|
||||
|
@ -633,7 +609,7 @@ fn parse_headers_iter<'a, 'b>(headers: &mut &mut [Header<'a>], bytes: &'b mut By
|
|||
|
||||
// parse value till EOL
|
||||
|
||||
simd::match_header_value_vectored(bytes);
|
||||
|
||||
|
||||
macro_rules! check {
|
||||
($bytes:ident, $i:ident) => ({
|
||||
|
@ -665,31 +641,17 @@ fn parse_headers_iter<'a, 'b>(headers: &mut &mut [Header<'a>], bytes: &'b mut By
|
|||
}
|
||||
|
||||
//found_ctl
|
||||
let value_slice : &[u8] = if b == b'\r' {
|
||||
if b == b'\r' {
|
||||
expect!(bytes.next() == b'\n' => Err(Error::HeaderValue));
|
||||
count += bytes.pos();
|
||||
// having just check that `\r\n` exists, it's safe to skip those 2 bytes
|
||||
unsafe {
|
||||
bytes.slice_skip(2)
|
||||
}
|
||||
header.value = bytes.slice_skip(2);
|
||||
} else if b == b'\n' {
|
||||
count += bytes.pos();
|
||||
// having just check that `\r\n` exists, it's safe to skip 1 byte
|
||||
unsafe {
|
||||
bytes.slice_skip(1)
|
||||
}
|
||||
header.value = bytes.slice_skip(1);
|
||||
} else {
|
||||
return Err(Error::HeaderValue);
|
||||
};
|
||||
// trim trailing whitespace in the header
|
||||
if let Some(last_visible) = value_slice.iter().rposition(|b| *b != b' ' && *b != b'\t' ) {
|
||||
// There is at least one non-whitespace character.
|
||||
header.value = &value_slice[0..last_visible+1];
|
||||
} else {
|
||||
// There is no non-whitespace character. This can only happen when value_slice is
|
||||
// empty.
|
||||
header.value = value_slice;
|
||||
}
|
||||
|
||||
}
|
||||
} // drop iter
|
||||
|
||||
|
@ -710,7 +672,7 @@ fn parse_headers_iter<'a, 'b>(headers: &mut &mut [Header<'a>], bytes: &'b mut By
|
|||
/// Ok(httparse::Status::Complete((3, 4))));
|
||||
/// ```
|
||||
pub fn parse_chunk_size(buf: &[u8])
|
||||
-> result::Result<Status<(usize, u64)>, InvalidChunkSize> {
|
||||
-> result::Result<Status<(usize, u64)>, InvalidChunkSize> {
|
||||
const RADIX: u64 = 16;
|
||||
let mut bytes = Bytes::new(buf);
|
||||
let mut size = 0;
|
||||
|
@ -720,7 +682,7 @@ pub fn parse_chunk_size(buf: &[u8])
|
|||
loop {
|
||||
let b = next!(bytes);
|
||||
match b {
|
||||
b'0' ... b'9' if in_chunk_size => {
|
||||
b'0'...b'9' if in_chunk_size => {
|
||||
if count > 15 {
|
||||
return Err(InvalidChunkSize);
|
||||
}
|
||||
|
@ -728,7 +690,7 @@ pub fn parse_chunk_size(buf: &[u8])
|
|||
size *= RADIX;
|
||||
size += (b - b'0') as u64;
|
||||
},
|
||||
b'a' ... b'f' if in_chunk_size => {
|
||||
b'a'...b'f' if in_chunk_size => {
|
||||
if count > 15 {
|
||||
return Err(InvalidChunkSize);
|
||||
}
|
||||
|
@ -736,7 +698,7 @@ pub fn parse_chunk_size(buf: &[u8])
|
|||
size *= RADIX;
|
||||
size += (b + 10 - b'a') as u64;
|
||||
}
|
||||
b'A' ... b'F' if in_chunk_size => {
|
||||
b'A'...b'F' if in_chunk_size => {
|
||||
if count > 15 {
|
||||
return Err(InvalidChunkSize);
|
||||
}
|
||||
|
@ -823,28 +785,6 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
req! {
|
||||
test_request_simple_with_query_params,
|
||||
b"GET /thing?data=a HTTP/1.1\r\n\r\n",
|
||||
|req| {
|
||||
assert_eq!(req.method.unwrap(), "GET");
|
||||
assert_eq!(req.path.unwrap(), "/thing?data=a");
|
||||
assert_eq!(req.version.unwrap(), 1);
|
||||
assert_eq!(req.headers.len(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
req! {
|
||||
test_request_simple_with_whatwg_query_params,
|
||||
b"GET /thing?data=a^ HTTP/1.1\r\n\r\n",
|
||||
|req| {
|
||||
assert_eq!(req.method.unwrap(), "GET");
|
||||
assert_eq!(req.path.unwrap(), "/thing?data=a^");
|
||||
assert_eq!(req.version.unwrap(), 1);
|
||||
assert_eq!(req.headers.len(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
req! {
|
||||
test_request_headers,
|
||||
b"GET / HTTP/1.1\r\nHost: foo.com\r\nCookie: \r\n\r\n",
|
||||
|
@ -860,63 +800,6 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
req! {
|
||||
test_request_headers_optional_whitespace,
|
||||
b"GET / HTTP/1.1\r\nHost: \tfoo.com\t \r\nCookie: \t \r\n\r\n",
|
||||
|req| {
|
||||
assert_eq!(req.method.unwrap(), "GET");
|
||||
assert_eq!(req.path.unwrap(), "/");
|
||||
assert_eq!(req.version.unwrap(), 1);
|
||||
assert_eq!(req.headers.len(), 2);
|
||||
assert_eq!(req.headers[0].name, "Host");
|
||||
assert_eq!(req.headers[0].value, b"foo.com");
|
||||
assert_eq!(req.headers[1].name, "Cookie");
|
||||
assert_eq!(req.headers[1].value, b"");
|
||||
}
|
||||
}
|
||||
|
||||
req! {
|
||||
// test the scalar parsing
|
||||
test_request_header_value_htab_short,
|
||||
b"GET / HTTP/1.1\r\nUser-Agent: some\tagent\r\n\r\n",
|
||||
|req| {
|
||||
assert_eq!(req.method.unwrap(), "GET");
|
||||
assert_eq!(req.path.unwrap(), "/");
|
||||
assert_eq!(req.version.unwrap(), 1);
|
||||
assert_eq!(req.headers.len(), 1);
|
||||
assert_eq!(req.headers[0].name, "User-Agent");
|
||||
assert_eq!(req.headers[0].value, b"some\tagent");
|
||||
}
|
||||
}
|
||||
|
||||
req! {
|
||||
// test the sse42 parsing
|
||||
test_request_header_value_htab_med,
|
||||
b"GET / HTTP/1.1\r\nUser-Agent: 1234567890some\tagent\r\n\r\n",
|
||||
|req| {
|
||||
assert_eq!(req.method.unwrap(), "GET");
|
||||
assert_eq!(req.path.unwrap(), "/");
|
||||
assert_eq!(req.version.unwrap(), 1);
|
||||
assert_eq!(req.headers.len(), 1);
|
||||
assert_eq!(req.headers[0].name, "User-Agent");
|
||||
assert_eq!(req.headers[0].value, b"1234567890some\tagent");
|
||||
}
|
||||
}
|
||||
|
||||
req! {
|
||||
// test the avx2 parsing
|
||||
test_request_header_value_htab_long,
|
||||
b"GET / HTTP/1.1\r\nUser-Agent: 1234567890some\t1234567890agent1234567890\r\n\r\n",
|
||||
|req| {
|
||||
assert_eq!(req.method.unwrap(), "GET");
|
||||
assert_eq!(req.path.unwrap(), "/");
|
||||
assert_eq!(req.version.unwrap(), 1);
|
||||
assert_eq!(req.headers.len(), 1);
|
||||
assert_eq!(req.headers[0].name, "User-Agent");
|
||||
assert_eq!(req.headers[0].value, &b"1234567890some\t1234567890agent1234567890"[..]);
|
||||
}
|
||||
}
|
||||
|
||||
req! {
|
||||
test_request_headers_max,
|
||||
b"GET / HTTP/1.1\r\nA: A\r\nB: B\r\nC: C\r\nD: D\r\n\r\n",
|
||||
|
@ -946,12 +829,6 @@ mod tests {
|
|||
|_req| {}
|
||||
}
|
||||
|
||||
req! {
|
||||
test_request_partial_version,
|
||||
b"GET / HTTP/1.", Ok(Status::Partial),
|
||||
|_req| {}
|
||||
}
|
||||
|
||||
req! {
|
||||
test_request_newlines,
|
||||
b"GET / HTTP/1.1\nHost: foo.bar\n\n",
|
||||
|
@ -987,14 +864,6 @@ mod tests {
|
|||
|_r| {}
|
||||
}
|
||||
|
||||
|
||||
req! {
|
||||
test_request_with_invalid_but_short_version,
|
||||
b"GET / HTTP/1!",
|
||||
Err(::Error::Version),
|
||||
|_r| {}
|
||||
}
|
||||
|
||||
macro_rules! res {
|
||||
($name:ident, $buf:expr, |$arg:ident| $body:expr) => (
|
||||
res! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body }
|
||||
|
@ -1051,19 +920,6 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
res! {
|
||||
test_response_reason_missing_no_space_with_headers,
|
||||
b"HTTP/1.1 200\r\nFoo: bar\r\n\r\n",
|
||||
|res| {
|
||||
assert_eq!(res.version.unwrap(), 1);
|
||||
assert_eq!(res.code.unwrap(), 200);
|
||||
assert_eq!(res.reason.unwrap(), "");
|
||||
assert_eq!(res.headers.len(), 1);
|
||||
assert_eq!(res.headers[0].name, "Foo");
|
||||
assert_eq!(res.headers[0].value, b"bar");
|
||||
}
|
||||
}
|
||||
|
||||
res! {
|
||||
test_response_reason_with_space_and_tab,
|
||||
b"HTTP/1.1 101 Switching Protocols\t\r\n\r\n",
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
///! Utility macros
|
||||
|
||||
macro_rules! next {
|
||||
($bytes:ident) => ({
|
||||
match $bytes.next() {
|
||||
Some(b) => b,
|
||||
None => return Ok(Status::Partial)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! expect {
|
||||
($bytes:ident.next() == $pat:pat => $ret:expr) => {
|
||||
expect!(next!($bytes) => $pat |? $ret)
|
||||
};
|
||||
($e:expr => $pat:pat |? $ret:expr) => {
|
||||
match $e {
|
||||
v@$pat => v,
|
||||
_ => return $ret
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! complete {
|
||||
($e:expr) => {
|
||||
match try!($e) {
|
||||
Status::Complete(v) => v,
|
||||
Status::Partial => return Ok(Status::Partial)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! byte_map {
|
||||
($($flag:expr,)*) => ([
|
||||
$($flag != 0,)*
|
||||
])
|
||||
}
|
||||
|
||||
macro_rules! space {
|
||||
($bytes:ident or $err:expr) => ({
|
||||
expect!($bytes.next() == b' ' => Err($err));
|
||||
$bytes.slice();
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! newline {
|
||||
($bytes:ident) => ({
|
||||
match next!($bytes) {
|
||||
b'\r' => {
|
||||
expect!($bytes.next() == b'\n' => Err(Error::NewLine));
|
||||
$bytes.slice();
|
||||
},
|
||||
b'\n' => {
|
||||
$bytes.slice();
|
||||
},
|
||||
_ => return Err(Error::NewLine)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
use ::iter::Bytes;
|
||||
|
||||
pub enum Scan {
|
||||
/// Returned when an implementation finds a noteworthy token.
|
||||
Found,
|
||||
/// Returned when an implementation couldn't keep running because the input was too short.
|
||||
TooShort,
|
||||
}
|
||||
|
||||
|
||||
pub unsafe fn parse_uri_batch_32<'a>(bytes: &mut Bytes<'a>) -> Scan {
|
||||
while bytes.as_ref().len() >= 32 {
|
||||
let advance = match_url_char_32_avx(bytes.as_ref());
|
||||
bytes.advance(advance);
|
||||
|
||||
if advance != 32 {
|
||||
return Scan::Found;
|
||||
}
|
||||
}
|
||||
Scan::TooShort
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[target_feature(enable = "avx2")]
|
||||
#[inline]
|
||||
#[allow(non_snake_case, overflowing_literals)]
|
||||
unsafe fn match_url_char_32_avx(buf: &[u8]) -> usize {
|
||||
debug_assert!(buf.len() >= 32);
|
||||
|
||||
/*
|
||||
#[cfg(target_arch = "x86")]
|
||||
use core::arch::x86::*;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
*/
|
||||
use core::arch::x86_64::*;
|
||||
|
||||
let ptr = buf.as_ptr();
|
||||
|
||||
let LSH: __m256i = _mm256_set1_epi8(0x0f);
|
||||
let URI: __m256i = _mm256_setr_epi8(
|
||||
0xb8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
|
||||
0xfc, 0xfc, 0xfc, 0x7c, 0x54, 0x7c, 0xd4, 0x7c,
|
||||
0xb8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
|
||||
0xfc, 0xfc, 0xfc, 0x7c, 0x54, 0x7c, 0xd4, 0x7c,
|
||||
);
|
||||
let ARF: __m256i = _mm256_setr_epi8(
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
);
|
||||
|
||||
let data = _mm256_lddqu_si256(ptr as *const _);
|
||||
let rbms = _mm256_shuffle_epi8(URI, data);
|
||||
let cols = _mm256_and_si256(LSH, _mm256_srli_epi16(data, 4));
|
||||
let bits = _mm256_and_si256(_mm256_shuffle_epi8(ARF, cols), rbms);
|
||||
|
||||
let v = _mm256_cmpeq_epi8(bits, _mm256_setzero_si256());
|
||||
let r = 0xffffffff_00000000 | _mm256_movemask_epi8(v) as u64;
|
||||
|
||||
_tzcnt_u64(r) as usize
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
unsafe fn match_url_char_32_avx(_: &[u8]) -> usize {
|
||||
unreachable!("AVX2 detection should be disabled for x86");
|
||||
}
|
||||
|
||||
pub unsafe fn match_header_value_batch_32(bytes: &mut Bytes) -> Scan {
|
||||
while bytes.as_ref().len() >= 32 {
|
||||
let advance = match_header_value_char_32_avx(bytes.as_ref());
|
||||
bytes.advance(advance);
|
||||
|
||||
if advance != 32 {
|
||||
return Scan::Found;
|
||||
}
|
||||
}
|
||||
Scan::TooShort
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[target_feature(enable = "avx2")]
|
||||
#[inline]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn match_header_value_char_32_avx(buf: &[u8]) -> usize {
|
||||
debug_assert!(buf.len() >= 32);
|
||||
|
||||
/*
|
||||
#[cfg(target_arch = "x86")]
|
||||
use core::arch::x86::*;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
*/
|
||||
use core::arch::x86_64::*;
|
||||
|
||||
let ptr = buf.as_ptr();
|
||||
|
||||
// %x09 %x20-%x7e %x80-%xff
|
||||
let TAB: __m256i = _mm256_set1_epi8(0x09);
|
||||
let DEL: __m256i = _mm256_set1_epi8(0x7f);
|
||||
let LOW: __m256i = _mm256_set1_epi8(0x1f);
|
||||
|
||||
let dat = _mm256_lddqu_si256(ptr as *const _);
|
||||
let low = _mm256_cmpgt_epi8(dat, LOW);
|
||||
let tab = _mm256_cmpeq_epi8(dat, TAB);
|
||||
let del = _mm256_cmpeq_epi8(dat, DEL);
|
||||
let bit = _mm256_andnot_si256(del, _mm256_or_si256(low, tab));
|
||||
let rev = _mm256_cmpeq_epi8(bit, _mm256_setzero_si256());
|
||||
let res = 0xffffffff_00000000 | _mm256_movemask_epi8(rev) as u64;
|
||||
|
||||
_tzcnt_u64(res) as usize
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
unsafe fn match_header_value_char_32_avx(_: &[u8]) -> usize {
|
||||
unreachable!("AVX2 detection should be disabled for x86");
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
use ::iter::Bytes;
|
||||
|
||||
// Fallbacks that do nothing...
|
||||
|
||||
#[inline(always)]
|
||||
pub fn match_uri_vectored(_: &mut Bytes) {}
|
||||
#[inline(always)]
|
||||
pub fn match_header_value_vectored(_: &mut Bytes) {}
|
|
@ -1,238 +0,0 @@
|
|||
#[cfg(not(all(
|
||||
httparse_simd,
|
||||
any(
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
),
|
||||
)))]
|
||||
mod fallback;
|
||||
|
||||
#[cfg(not(all(
|
||||
httparse_simd,
|
||||
any(
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
),
|
||||
)))]
|
||||
pub use self::fallback::*;
|
||||
|
||||
#[cfg(all(
|
||||
httparse_simd,
|
||||
any(
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
),
|
||||
))]
|
||||
mod sse42;
|
||||
|
||||
#[cfg(all(
|
||||
httparse_simd,
|
||||
any(
|
||||
httparse_simd_target_feature_avx2,
|
||||
not(httparse_simd_target_feature_sse42),
|
||||
),
|
||||
any(
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
),
|
||||
))]
|
||||
mod avx2;
|
||||
|
||||
#[cfg(all(
|
||||
httparse_simd,
|
||||
not(any(
|
||||
httparse_simd_target_feature_sse42,
|
||||
httparse_simd_target_feature_avx2,
|
||||
)),
|
||||
any(
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
),
|
||||
))]
|
||||
mod runtime {
|
||||
//! Runtime detection of simd features. Used when the build script
|
||||
//! doesn't notice any target features at build time.
|
||||
//!
|
||||
//! While `is_x86_feature_detected!` has it's own caching built-in,
|
||||
//! at least in 1.27.0, the functions don't inline, leaving using it
|
||||
//! actually *slower* than just using the scalar fallback.
|
||||
|
||||
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
|
||||
|
||||
static FEATURE: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
|
||||
const INIT: usize = 0;
|
||||
const SSE_42: usize = 1;
|
||||
const AVX_2: usize = 2;
|
||||
const AVX_2_AND_SSE_42: usize = 3;
|
||||
const NONE: usize = ::core::usize::MAX;
|
||||
|
||||
fn detect() -> usize {
|
||||
let feat = FEATURE.load(Ordering::Relaxed);
|
||||
if feat == INIT {
|
||||
if cfg!(target_arch = "x86_64") && is_x86_feature_detected!("avx2") {
|
||||
if is_x86_feature_detected!("sse4.2") {
|
||||
FEATURE.store(AVX_2_AND_SSE_42, Ordering::Relaxed);
|
||||
return AVX_2_AND_SSE_42;
|
||||
} else {
|
||||
FEATURE.store(AVX_2, Ordering::Relaxed);
|
||||
return AVX_2;
|
||||
}
|
||||
} else if is_x86_feature_detected!("sse4.2") {
|
||||
FEATURE.store(SSE_42, Ordering::Relaxed);
|
||||
return SSE_42;
|
||||
} else {
|
||||
FEATURE.store(NONE, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
feat
|
||||
}
|
||||
|
||||
pub fn match_uri_vectored(bytes: &mut ::Bytes) {
|
||||
unsafe {
|
||||
match detect() {
|
||||
SSE_42 => super::sse42::parse_uri_batch_16(bytes),
|
||||
AVX_2 => { super::avx2::parse_uri_batch_32(bytes); },
|
||||
AVX_2_AND_SSE_42 => {
|
||||
if let super::avx2::Scan::Found = super::avx2::parse_uri_batch_32(bytes) {
|
||||
return;
|
||||
}
|
||||
super::sse42::parse_uri_batch_16(bytes)
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
// else do nothing
|
||||
}
|
||||
|
||||
pub fn match_header_value_vectored(bytes: &mut ::Bytes) {
|
||||
unsafe {
|
||||
match detect() {
|
||||
SSE_42 => super::sse42::match_header_value_batch_16(bytes),
|
||||
AVX_2 => { super::avx2::match_header_value_batch_32(bytes); },
|
||||
AVX_2_AND_SSE_42 => {
|
||||
if let super::avx2::Scan::Found = super::avx2::match_header_value_batch_32(bytes) {
|
||||
return;
|
||||
}
|
||||
super::sse42::match_header_value_batch_16(bytes)
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
// else do nothing
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
httparse_simd,
|
||||
not(any(
|
||||
httparse_simd_target_feature_sse42,
|
||||
httparse_simd_target_feature_avx2,
|
||||
)),
|
||||
any(
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
),
|
||||
))]
|
||||
pub use self::runtime::*;
|
||||
|
||||
#[cfg(all(
|
||||
httparse_simd,
|
||||
httparse_simd_target_feature_sse42,
|
||||
not(httparse_simd_target_feature_avx2),
|
||||
any(
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
),
|
||||
))]
|
||||
mod sse42_compile_time {
|
||||
pub fn match_uri_vectored(bytes: &mut ::Bytes) {
|
||||
if is_x86_feature_detected!("sse4.2") {
|
||||
unsafe {
|
||||
super::sse42::parse_uri_batch_16(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// else do nothing
|
||||
}
|
||||
|
||||
pub fn match_header_value_vectored(bytes: &mut ::Bytes) {
|
||||
if is_x86_feature_detected!("sse4.2") {
|
||||
unsafe {
|
||||
super::sse42::match_header_value_batch_16(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// else do nothing
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
httparse_simd,
|
||||
httparse_simd_target_feature_sse42,
|
||||
not(httparse_simd_target_feature_avx2),
|
||||
any(
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
),
|
||||
))]
|
||||
pub use self::sse42_compile_time::*;
|
||||
|
||||
#[cfg(all(
|
||||
httparse_simd,
|
||||
httparse_simd_target_feature_avx2,
|
||||
any(
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
),
|
||||
))]
|
||||
mod avx2_compile_time {
|
||||
pub fn match_uri_vectored(bytes: &mut ::Bytes) {
|
||||
// do both, since avx2 only works when bytes.len() >= 32
|
||||
if cfg!(target_arch = "x86_64") && is_x86_feature_detected!("avx2") {
|
||||
unsafe {
|
||||
super::avx2::parse_uri_batch_32(bytes);
|
||||
}
|
||||
|
||||
}
|
||||
if is_x86_feature_detected!("sse4.2") {
|
||||
unsafe {
|
||||
super::sse42::parse_uri_batch_16(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// else do nothing
|
||||
}
|
||||
|
||||
pub fn match_header_value_vectored(bytes: &mut ::Bytes) {
|
||||
// do both, since avx2 only works when bytes.len() >= 32
|
||||
if cfg!(target_arch = "x86_64") && is_x86_feature_detected!("avx2") {
|
||||
let scanned = unsafe {
|
||||
super::avx2::match_header_value_batch_32(bytes)
|
||||
};
|
||||
|
||||
if let super::avx2::Scan::Found = scanned {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if is_x86_feature_detected!("sse4.2") {
|
||||
unsafe {
|
||||
super::sse42::match_header_value_batch_16(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// else do nothing
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
httparse_simd,
|
||||
httparse_simd_target_feature_avx2,
|
||||
any(
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
),
|
||||
))]
|
||||
pub use self::avx2_compile_time::*;
|
|
@ -1,84 +0,0 @@
|
|||
use ::iter::Bytes;
|
||||
|
||||
pub unsafe fn parse_uri_batch_16<'a>(bytes: &mut Bytes<'a>) {
|
||||
while bytes.as_ref().len() >= 16 {
|
||||
let advance = match_url_char_16_sse(bytes.as_ref());
|
||||
bytes.advance(advance);
|
||||
|
||||
if advance != 16 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[target_feature(enable = "sse4.2")]
|
||||
#[allow(non_snake_case, overflowing_literals)]
|
||||
unsafe fn match_url_char_16_sse(buf: &[u8]) -> usize {
|
||||
debug_assert!(buf.len() >= 16);
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
use core::arch::x86::*;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use core::arch::x86_64::*;
|
||||
|
||||
let ptr = buf.as_ptr();
|
||||
|
||||
let LSH: __m128i = _mm_set1_epi8(0x0f);
|
||||
let URI: __m128i = _mm_setr_epi8(
|
||||
0xb8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
|
||||
0xfc, 0xfc, 0xfc, 0x7c, 0x54, 0x7c, 0xd4, 0x7c,
|
||||
);
|
||||
let ARF: __m128i = _mm_setr_epi8(
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
);
|
||||
|
||||
let data = _mm_lddqu_si128(ptr as *const _);
|
||||
let rbms = _mm_shuffle_epi8(URI, data);
|
||||
let cols = _mm_and_si128(LSH, _mm_srli_epi16(data, 4));
|
||||
let bits = _mm_and_si128(_mm_shuffle_epi8(ARF, cols), rbms);
|
||||
|
||||
let v = _mm_cmpeq_epi8(bits, _mm_setzero_si128());
|
||||
let r = 0xffff_0000 | _mm_movemask_epi8(v) as u32;
|
||||
|
||||
_tzcnt_u32(r) as usize
|
||||
}
|
||||
|
||||
pub unsafe fn match_header_value_batch_16(bytes: &mut Bytes) {
|
||||
while bytes.as_ref().len() >= 16 {
|
||||
let advance = match_header_value_char_16_sse(bytes.as_ref());
|
||||
bytes.advance(advance);
|
||||
|
||||
if advance != 16 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[target_feature(enable = "sse4.2")]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn match_header_value_char_16_sse(buf: &[u8]) -> usize {
|
||||
debug_assert!(buf.len() >= 16);
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
use core::arch::x86::*;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use core::arch::x86_64::*;
|
||||
|
||||
let ptr = buf.as_ptr();
|
||||
|
||||
// %x09 %x20-%x7e %x80-%xff
|
||||
let TAB: __m128i = _mm_set1_epi8(0x09);
|
||||
let DEL: __m128i = _mm_set1_epi8(0x7f);
|
||||
let LOW: __m128i = _mm_set1_epi8(0x1f);
|
||||
|
||||
let dat = _mm_lddqu_si128(ptr as *const _);
|
||||
let low = _mm_cmpgt_epi8(dat, LOW);
|
||||
let tab = _mm_cmpeq_epi8(dat, TAB);
|
||||
let del = _mm_cmpeq_epi8(dat, DEL);
|
||||
let bit = _mm_andnot_si128(del, _mm_or_si128(low, tab));
|
||||
let rev = _mm_cmpeq_epi8(bit, _mm_setzero_si128());
|
||||
let res = 0xffff_0000 | _mm_movemask_epi8(rev) as u32;
|
||||
|
||||
_tzcnt_u32(res) as usize
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1 +1 @@
|
|||
{"files":{"CHANGELOG.md":"0aa4629e399d08ad3a446366d465449a5e92ba95aac708be76961100a9c7df48","Cargo.toml":"15c8e40c3c9ed8635ed338b633d343702b6f4a90dcd5aa759673d31af401dd0a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"03f6ccb4e6040abccf12b31551bbbd1800a5069a17950bbd6db850d85744800f","README.md":"c0798b2c9b0d3b9c0da509fdd9001eb2d80e6ed0850d312e36136ac269dbe49f","src/lib.rs":"7ea882864c246d78be6ea3558b92a8a7dd5732f55556cd641efb7a8caf4e64e3"},"package":"b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"}
|
||||
{"files":{"CHANGELOG.md":"0ac479629dc1cde30432141baf12e6ee347b14bd3cd07a44ea3e645fdb1a0d7c","Cargo.toml":"152d2f4435ce45bd83a0f3842a04c0aed7223f458c843c9ad1cc10ad6f0acca6","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"4d3959aeee87b7924faecca7e7369370a2ac603422e7bb3fea86191b2574899d","README.md":"ea7850a3e9cc388dd40c7e5ea26e08cec788219fc4cd01280ea52cb7382d184f","src/lib.rs":"226ef2985de8085b4edd780578f4cf5e77f58512c566b2fa8462086db8f96e15"},"package":"a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"}
|
|
@ -1,49 +1,3 @@
|
|||
<a name="v1.2.1"></a>
|
||||
## v1.2.1 (2018-12-03)
|
||||
|
||||
|
||||
#### Features
|
||||
|
||||
* Implement Clone for LazyCell and AtomicLazyCell ([30fe4a8f](https://github.com/indiv0/lazycell/commit/30fe4a8f568059b3c78ed149a810962a676cb2b2))
|
||||
|
||||
|
||||
|
||||
<a name="v1.2.0"></a>
|
||||
## v1.2.0 (2018-09-19)
|
||||
|
||||
|
||||
#### Features
|
||||
|
||||
* add `LazyCell::replace` for infallible access ([a63ffb90](https://github.com/indiv0/lazycell/commit/a63ffb9040a5e0683a9bbf9d3d5ef589f2ca8b7c))
|
||||
|
||||
|
||||
|
||||
<a name="v1.1.0"></a>
|
||||
## v1.1.0 (2018-09-10)
|
||||
|
||||
|
||||
#### Documentation
|
||||
|
||||
* add note regarding LazyCell::borrow_mut ([9d634d1f](https://github.com/indiv0/lazycell/commit/9d634d1fd9a21b7aa075d407bedf9fe77ba8b79f))
|
||||
* describe mutability more consistently ([b8078029](https://github.com/indiv0/lazycell/commit/b80780294611e92efddcdd33a701b3049ab5c5eb), closes [#78](https://github.com/indiv0/lazycell/issues/78))
|
||||
|
||||
#### Improvements
|
||||
|
||||
* add NONE constant for an empty AtomicLazyCell ([31aff0da](https://github.com/indiv0/lazycell/commit/31aff0dacf824841c5f38ef4acf0aa71ec4c36eb), closes [#87](https://github.com/indiv0/lazycell/issues/87))
|
||||
* add `LazyCell::borrow_mut_with` and `LazyCell::try_borrow_mut_with` ([fdc6d268](https://github.com/indiv0/lazycell/commit/fdc6d268f0e9a6668768302f45fe2bb4aa9a7c34), closes [#79](https://github.com/indiv0/lazycell/issues/79), [#80](https://github.com/indiv0/lazycell/issues/80))
|
||||
|
||||
|
||||
|
||||
<a name="v1.0.0"></a>
|
||||
## v1.0.0 (2018-06-06)
|
||||
|
||||
|
||||
#### Features
|
||||
|
||||
* Add #![no_std] ([e59f6b55](https://github.com/indiv0/lazycell/commit/e59f6b5531e310d3df26b0eb40b1431937f38096))
|
||||
|
||||
|
||||
|
||||
<a name="0.6.0"></a>
|
||||
## 0.6.0 (2017-11-25)
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
[package]
|
||||
name = "lazycell"
|
||||
version = "1.2.1"
|
||||
version = "0.6.0"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>", "Nikita Pekin <contact@nikitapek.in>"]
|
||||
include = ["CHANGELOG.md", "Cargo.toml", "LICENSE-MIT", "LICENSE-APACHE", "README.md", "src/**/*.rs"]
|
||||
description = "A library providing a lazily filled Cell struct"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Original work Copyright (c) 2014 The Rust Project Developers
|
||||
Modified work Copyright (c) 2016-2018 Nikita Pekin and lazycell contributors
|
||||
Modified work Copyright (c) 2016-2017 Nikita Pekin and lazycell contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
|
|
|
@ -30,7 +30,7 @@ Add the following to your `Cargo.toml`:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
lazycell = "1.2"
|
||||
lazycell = "0.6"
|
||||
```
|
||||
|
||||
And in your `lib.rs` or `main.rs`:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Original work Copyright (c) 2014 The Rust Project Developers
|
||||
// Modified work Copyright (c) 2016-2018 Nikita Pekin and the lazycell contributors
|
||||
// Modified work Copyright (c) 2016-2017 Nikita Pekin and the lazycell contributors
|
||||
// See the README.md file at the top-level directory of this distribution.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
|
@ -8,20 +8,21 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![cfg_attr(feature = "nightly", feature(plugin))]
|
||||
#![cfg_attr(feature = "clippy", plugin(clippy))]
|
||||
|
||||
//! This crate provides a `LazyCell` struct which acts as a lazily filled
|
||||
//! `Cell`.
|
||||
//! `Cell`, but with frozen contents.
|
||||
//!
|
||||
//! With a `RefCell`, the inner contents cannot be borrowed for the lifetime of
|
||||
//! the entire object, but only of the borrows returned. A `LazyCell` is a
|
||||
//! variation on `RefCell` which allows borrows to be tied to the lifetime of
|
||||
//! the outer object.
|
||||
//!
|
||||
//! The limitation of a `LazyCell` is that after it is initialized and shared,
|
||||
//! it can be modified.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! The following example shows a quick example of the basic functionality of
|
||||
|
@ -41,23 +42,12 @@
|
|||
//! ```
|
||||
//!
|
||||
//! `AtomicLazyCell` is a variant that uses an atomic variable to manage
|
||||
//! coordination in a thread-safe fashion. The limitation of an `AtomicLazyCell`
|
||||
//! is that after it is initialized, it can't be modified.
|
||||
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[macro_use]
|
||||
extern crate core as std;
|
||||
//! coordination in a thread-safe fashion.
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
use std::mem;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
/// A lazily filled `Cell`, with mutable contents.
|
||||
///
|
||||
/// A `LazyCell` is completely frozen once filled, **unless** you have `&mut`
|
||||
/// access to it, in which case `LazyCell::borrow_mut` may be used to mutate the
|
||||
/// contents.
|
||||
/// A lazily filled `Cell`, with frozen contents.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct LazyCell<T> {
|
||||
inner: UnsafeCell<Option<T>>,
|
||||
|
@ -73,7 +63,7 @@ impl<T> LazyCell<T> {
|
|||
///
|
||||
/// This function will return `Err(value)` is the cell is already full.
|
||||
pub fn fill(&self, value: T) -> Result<(), T> {
|
||||
let slot = unsafe { &mut *self.inner.get() };
|
||||
let mut slot = unsafe { &mut *self.inner.get() };
|
||||
if slot.is_some() {
|
||||
return Err(value);
|
||||
}
|
||||
|
@ -82,20 +72,6 @@ impl<T> LazyCell<T> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Put a value into this cell.
|
||||
///
|
||||
/// Note that this function is infallible but requires `&mut self`. By
|
||||
/// requiring `&mut self` we're guaranteed that no active borrows to this
|
||||
/// cell can exist so we can always fill in the value. This may not always
|
||||
/// be usable, however, as `&mut self` may not be possible to borrow.
|
||||
///
|
||||
/// # Return value
|
||||
///
|
||||
/// This function returns the previous value, if any.
|
||||
pub fn replace(&mut self, value: T) -> Option<T> {
|
||||
mem::replace(unsafe { &mut *self.inner.get() }, Some(value))
|
||||
}
|
||||
|
||||
/// Test whether this cell has been previously filled.
|
||||
pub fn filled(&self) -> bool {
|
||||
self.borrow().is_some()
|
||||
|
@ -139,26 +115,6 @@ impl<T> LazyCell<T> {
|
|||
self.borrow().unwrap()
|
||||
}
|
||||
|
||||
/// Borrows the contents of this `LazyCell` mutably for the duration of the
|
||||
/// cell itself.
|
||||
///
|
||||
/// If the cell has not yet been filled, the cell is first filled using the
|
||||
/// function provided.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the cell becomes filled as a side effect of `f`.
|
||||
pub fn borrow_mut_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
|
||||
if !self.filled() {
|
||||
let value = f();
|
||||
if self.fill(value).is_err() {
|
||||
panic!("borrow_mut_with: cell was filled by closure")
|
||||
}
|
||||
}
|
||||
|
||||
self.borrow_mut().unwrap()
|
||||
}
|
||||
|
||||
/// Same as `borrow_with`, but allows the initializing function to fail.
|
||||
///
|
||||
/// # Panics
|
||||
|
@ -177,30 +133,8 @@ impl<T> LazyCell<T> {
|
|||
Ok(self.borrow().unwrap())
|
||||
}
|
||||
|
||||
/// Same as `borrow_mut_with`, but allows the initializing function to fail.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the cell becomes filled as a side effect of `f`.
|
||||
pub fn try_borrow_mut_with<E, F>(&mut self, f: F) -> Result<&mut T, E>
|
||||
where F: FnOnce() -> Result<T, E>
|
||||
{
|
||||
if self.filled() {
|
||||
return Ok(self.borrow_mut().unwrap());
|
||||
}
|
||||
let value = f()?;
|
||||
if self.fill(value).is_err() {
|
||||
panic!("try_borrow_mut_with: cell was filled by closure")
|
||||
}
|
||||
Ok(self.borrow_mut().unwrap())
|
||||
}
|
||||
|
||||
/// Consumes this `LazyCell`, returning the underlying value.
|
||||
pub fn into_inner(self) -> Option<T> {
|
||||
// Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe
|
||||
// function. This unsafe can be removed when supporting Rust older than
|
||||
// 1.25 is not needed.
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe { self.inner.into_inner() }
|
||||
}
|
||||
}
|
||||
|
@ -215,23 +149,12 @@ impl<T: Copy> LazyCell<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl <T: Clone> Clone for LazyCell<T> {
|
||||
/// Create a clone of this `LazyCell`
|
||||
///
|
||||
/// If self has not been initialized, returns an uninitialized `LazyCell`
|
||||
/// otherwise returns a `LazyCell` already initialized with a clone of the
|
||||
/// contents of self.
|
||||
fn clone(&self) -> LazyCell<T> {
|
||||
LazyCell { inner: UnsafeCell::new(self.borrow().map(Clone::clone) ) }
|
||||
}
|
||||
}
|
||||
|
||||
// Tracks the AtomicLazyCell inner state
|
||||
const NONE: usize = 0;
|
||||
const LOCK: usize = 1;
|
||||
const SOME: usize = 2;
|
||||
|
||||
/// A lazily filled and thread-safe `Cell`, with frozen contents.
|
||||
/// A lazily filled `Cell`, with frozen contents.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct AtomicLazyCell<T> {
|
||||
inner: UnsafeCell<Option<T>>,
|
||||
|
@ -239,15 +162,12 @@ pub struct AtomicLazyCell<T> {
|
|||
}
|
||||
|
||||
impl<T> AtomicLazyCell<T> {
|
||||
/// An empty `AtomicLazyCell`.
|
||||
pub const NONE: Self = Self {
|
||||
inner: UnsafeCell::new(None),
|
||||
state: AtomicUsize::new(NONE),
|
||||
};
|
||||
|
||||
/// Creates a new, empty, `AtomicLazyCell`.
|
||||
pub fn new() -> AtomicLazyCell<T> {
|
||||
Self::NONE
|
||||
AtomicLazyCell {
|
||||
inner: UnsafeCell::new(None),
|
||||
state: AtomicUsize::new(NONE),
|
||||
}
|
||||
}
|
||||
|
||||
/// Put a value into this cell.
|
||||
|
@ -267,24 +187,6 @@ impl<T> AtomicLazyCell<T> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Put a value into this cell.
|
||||
///
|
||||
/// Note that this function is infallible but requires `&mut self`. By
|
||||
/// requiring `&mut self` we're guaranteed that no active borrows to this
|
||||
/// cell can exist so we can always fill in the value. This may not always
|
||||
/// be usable, however, as `&mut self` may not be possible to borrow.
|
||||
///
|
||||
/// # Return value
|
||||
///
|
||||
/// This function returns the previous value, if any.
|
||||
pub fn replace(&mut self, value: T) -> Option<T> {
|
||||
match mem::replace(self.state.get_mut(), SOME) {
|
||||
NONE | SOME => {}
|
||||
_ => panic!("cell in inconsistent state"),
|
||||
}
|
||||
mem::replace(unsafe { &mut *self.inner.get() }, Some(value))
|
||||
}
|
||||
|
||||
/// Test whether this cell has been previously filled.
|
||||
pub fn filled(&self) -> bool {
|
||||
self.state.load(Ordering::Acquire) == SOME
|
||||
|
@ -304,10 +206,6 @@ impl<T> AtomicLazyCell<T> {
|
|||
|
||||
/// Consumes this `LazyCell`, returning the underlying value.
|
||||
pub fn into_inner(self) -> Option<T> {
|
||||
// Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe
|
||||
// function. This unsafe can be removed when supporting Rust older than
|
||||
// 1.25 is not needed.
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe { self.inner.into_inner() }
|
||||
}
|
||||
}
|
||||
|
@ -325,23 +223,6 @@ impl<T: Copy> AtomicLazyCell<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Clone for AtomicLazyCell<T> {
|
||||
/// Create a clone of this `AtomicLazyCell`
|
||||
///
|
||||
/// If self has not been initialized, returns an uninitialized `AtomicLazyCell`
|
||||
/// otherwise returns an `AtomicLazyCell` already initialized with a clone of the
|
||||
/// contents of self.
|
||||
fn clone(&self) -> AtomicLazyCell<T> {
|
||||
self.borrow().map_or(
|
||||
Self::NONE,
|
||||
|v| AtomicLazyCell {
|
||||
inner: UnsafeCell::new(Some(v.clone())),
|
||||
state: AtomicUsize::new(SOME),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Sync + Send> Sync for AtomicLazyCell<T> {}
|
||||
|
||||
unsafe impl<T: Send> Send for AtomicLazyCell<T> {}
|
||||
|
@ -443,37 +324,6 @@ mod tests {
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_borrow_mut_with() {
|
||||
let mut lazycell = LazyCell::new();
|
||||
|
||||
{
|
||||
let value = lazycell.borrow_mut_with(|| 1);
|
||||
assert_eq!(&mut 1, value);
|
||||
*value = 2;
|
||||
}
|
||||
assert_eq!(&2, lazycell.borrow().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_borrow_mut_with_already_filled() {
|
||||
let mut lazycell = LazyCell::new();
|
||||
lazycell.fill(1).unwrap();
|
||||
|
||||
let value = lazycell.borrow_mut_with(|| 1);
|
||||
assert_eq!(&1, value);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_borrow_mut_with_not_called_when_filled() {
|
||||
let mut lazycell = LazyCell::new();
|
||||
|
||||
lazycell.fill(1).unwrap();
|
||||
|
||||
let value = lazycell.borrow_mut_with(|| 2);
|
||||
assert_eq!(&1, value);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_borrow_with_ok() {
|
||||
let lazycell = LazyCell::new();
|
||||
|
@ -510,32 +360,6 @@ mod tests {
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_borrow_mut_with_ok() {
|
||||
let mut lazycell = LazyCell::new();
|
||||
{
|
||||
let result = lazycell.try_borrow_mut_with::<(), _>(|| Ok(1));
|
||||
assert_eq!(result, Ok(&mut 1));
|
||||
*result.unwrap() = 2;
|
||||
}
|
||||
assert_eq!(&mut 2, lazycell.borrow().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_borrow_mut_with_err() {
|
||||
let mut lazycell = LazyCell::<()>::new();
|
||||
let result = lazycell.try_borrow_mut_with(|| Err(1));
|
||||
assert_eq!(result, Err(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_borrow_mut_with_already_filled() {
|
||||
let mut lazycell = LazyCell::new();
|
||||
lazycell.fill(1).unwrap();
|
||||
let result = lazycell.try_borrow_mut_with::<(), _>(|| unreachable!());
|
||||
assert_eq!(result, Ok(&mut 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_inner() {
|
||||
let lazycell = LazyCell::new();
|
||||
|
@ -587,63 +411,4 @@ mod tests {
|
|||
let value = lazycell.into_inner();
|
||||
assert_eq!(value, Some(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normal_replace() {
|
||||
let mut cell = LazyCell::new();
|
||||
assert_eq!(cell.fill(1), Ok(()));
|
||||
assert_eq!(cell.replace(2), Some(1));
|
||||
assert_eq!(cell.replace(3), Some(2));
|
||||
assert_eq!(cell.borrow(), Some(&3));
|
||||
|
||||
let mut cell = LazyCell::new();
|
||||
assert_eq!(cell.replace(2), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn atomic_replace() {
|
||||
let mut cell = AtomicLazyCell::new();
|
||||
assert_eq!(cell.fill(1), Ok(()));
|
||||
assert_eq!(cell.replace(2), Some(1));
|
||||
assert_eq!(cell.replace(3), Some(2));
|
||||
assert_eq!(cell.borrow(), Some(&3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clone() {
|
||||
let mut cell = LazyCell::new();
|
||||
let clone1 = cell.clone();
|
||||
assert_eq!(clone1.borrow(), None);
|
||||
assert_eq!(cell.fill(1), Ok(()));
|
||||
let mut clone2 = cell.clone();
|
||||
assert_eq!(clone1.borrow(), None);
|
||||
assert_eq!(clone2.borrow(), Some(&1));
|
||||
assert_eq!(cell.replace(2), Some(1));
|
||||
assert_eq!(clone1.borrow(), None);
|
||||
assert_eq!(clone2.borrow(), Some(&1));
|
||||
assert_eq!(clone1.fill(3), Ok(()));
|
||||
assert_eq!(clone2.replace(4), Some(1));
|
||||
assert_eq!(clone1.borrow(), Some(&3));
|
||||
assert_eq!(clone2.borrow(), Some(&4));
|
||||
assert_eq!(cell.borrow(), Some(&2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clone_atomic() {
|
||||
let mut cell = AtomicLazyCell::new();
|
||||
let clone1 = cell.clone();
|
||||
assert_eq!(clone1.borrow(), None);
|
||||
assert_eq!(cell.fill(1), Ok(()));
|
||||
let mut clone2 = cell.clone();
|
||||
assert_eq!(clone1.borrow(), None);
|
||||
assert_eq!(clone2.borrow(), Some(&1));
|
||||
assert_eq!(cell.replace(2), Some(1));
|
||||
assert_eq!(clone1.borrow(), None);
|
||||
assert_eq!(clone2.borrow(), Some(&1));
|
||||
assert_eq!(clone1.fill(3), Ok(()));
|
||||
assert_eq!(clone2.replace(4), Some(1));
|
||||
assert_eq!(clone1.borrow(), Some(&3));
|
||||
assert_eq!(clone2.borrow(), Some(&4));
|
||||
assert_eq!(cell.borrow(), Some(&2));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
{"files":{"CHANGELOG.md":"9f7efb5e07d7bba6e6db9142f35d8379144d3707eaf767ca41759bbfa91e0422","Cargo.toml":"37ea791a7fee2939e800737d62c2cd3189e6c71b57935de9ae02519b04d4dc4c","LICENSE-APACHE":"406e5cbaa2ad1178c300cf28ac5258e8d0db0de4f061e78db559d30e6f38e25c","LICENSE-MIT":"8aa414e6c821efd8be6bade07368a5d9f51f5cc55718bc54e10a59eb826b8d58","README.md":"337973d4db2bd42559bded991de98bf3929d39df00d5f17221e4b493075f8317","src/channel.rs":"bfc4f386595291418a5975250f12431d4fe92714cf422369e6a7960754719b51","src/lib.rs":"2ed1572d3255208681d017265df7f642eb4898b1c2dace91676935f55e03eb04","src/timer.rs":"2aa0070b4d59f74262c926d5378781896260c2264d06e47aa2fc1cafb6cf104b","test/mod.rs":"aa3afc2582f00e5e2a2e5b87d12eb9810b0eed3248b48abef7094fd8d02d9c41","test/test_poll_channel.rs":"a96f5749438853cb8c0727e304eabfd7f23400802da73938337ab29210787bcd","test/test_timer.rs":"082c48a320f603d8a99f6ed13c0efe7f48638d33222782e85364575ce805c20c"},"package":"46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"}
|
|
@ -1,31 +0,0 @@
|
|||
## 2.0.5 (18 Jun 2018)
|
||||
|
||||
* update `lazycell` from 0.6 -> 1.0
|
||||
|
||||
## 2.0.4 (7 Apr 2018)
|
||||
|
||||
* Bump mio dependency (fixes minimal-versions build)
|
||||
|
||||
## 2.0.3 (28 Dec 2017)
|
||||
|
||||
* update `log` from 0.3 -> 0.4
|
||||
|
||||
## 2.0.2
|
||||
|
||||
* More docs tidying.
|
||||
|
||||
## 2.0.1
|
||||
|
||||
* Another try at documenting the timer interface.
|
||||
|
||||
## 2.0.0
|
||||
|
||||
* Remove channel implementation details from the API. Specifically, the following are no longer public:
|
||||
* `ctl_pair()`
|
||||
* `SenderCtl`
|
||||
* `ReceiverCtl`
|
||||
* Document all APIs
|
||||
|
||||
## 1.0.0
|
||||
|
||||
* Initial release. Essentially identical to [mio-more](https://github.com/carllerche/mio-more).
|
|
@ -1,39 +0,0 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "mio-extras"
|
||||
version = "2.0.5"
|
||||
authors = ["Carl Lerche <me@carllerche.com>", "David Hotham"]
|
||||
exclude = [".gitignore"]
|
||||
description = "Extra components for use with Mio"
|
||||
documentation = "https://docs.rs/mio-extras"
|
||||
readme = "README.md"
|
||||
keywords = ["io", "async", "non-blocking"]
|
||||
categories = ["asynchronous"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/dimbleby/mio-extras"
|
||||
|
||||
[[test]]
|
||||
name = "test"
|
||||
path = "test/mod.rs"
|
||||
[dependencies.lazycell]
|
||||
version = "1"
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4"
|
||||
|
||||
[dependencies.mio]
|
||||
version = "0.6.14"
|
||||
|
||||
[dependencies.slab]
|
||||
version = "0.4"
|
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2017 Mio authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -1,25 +0,0 @@
|
|||
Copyright (c) 2017 Mio authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -1,28 +0,0 @@
|
|||
# mio-extras
|
||||
|
||||
Extra components for use with [Mio](https://github.com/carllerche/mio):
|
||||
|
||||
* a channel that implements `Evented`
|
||||
* a timer that implements `Evented`
|
||||
|
||||
[![Build Status](https://travis-ci.org/dimbleby/mio-extras.svg?branch=master)](https://travis-ci.org/dimbleby/mio-extras)
|
||||
[![crates.io](http://meritbadge.herokuapp.com/mio-extras)](https://crates.io/crates/mio-extras)
|
||||
|
||||
[Documentation](https://docs.rs/mio-extras).
|
||||
|
||||
|
||||
## History and maintenance
|
||||
|
||||
This repository is forked from [`mio-more`](https://github.com/carllerche/mio-more), which is unmaintained.
|
||||
|
||||
I don't intend to do very much with this except for routine maintenance - bug fixes, updating dependencies, and suchlike.
|
||||
|
||||
However if you have some code that you think belongs here, then by all means raise an issue or open a pull request.
|
||||
|
||||
# License
|
||||
|
||||
`mio-extras` is primarily distributed under the terms of both the MIT license
|
||||
and the Apache License (Version 2.0), with portions covered by various BSD-like
|
||||
licenses.
|
||||
|
||||
See LICENSE-APACHE, and LICENSE-MIT for details.
|
|
@ -1,431 +0,0 @@
|
|||
//! Thread safe communication channel implementing `Evented`
|
||||
use lazycell::{AtomicLazyCell, LazyCell};
|
||||
use mio::{Evented, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
|
||||
use std::any::Any;
|
||||
use std::error;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::{mpsc, Arc};
|
||||
use std::{fmt, io};
|
||||
|
||||
/// Creates a new asynchronous channel, where the `Receiver` can be registered
|
||||
/// with `Poll`.
|
||||
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
|
||||
let (tx_ctl, rx_ctl) = ctl_pair();
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
let tx = Sender { tx, ctl: tx_ctl };
|
||||
|
||||
let rx = Receiver { rx, ctl: rx_ctl };
|
||||
|
||||
(tx, rx)
|
||||
}
|
||||
|
||||
/// Creates a new synchronous, bounded channel where the `Receiver` can be
|
||||
/// registered with `Poll`.
|
||||
pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
|
||||
let (tx_ctl, rx_ctl) = ctl_pair();
|
||||
let (tx, rx) = mpsc::sync_channel(bound);
|
||||
|
||||
let tx = SyncSender { tx, ctl: tx_ctl };
|
||||
|
||||
let rx = Receiver { rx, ctl: rx_ctl };
|
||||
|
||||
(tx, rx)
|
||||
}
|
||||
|
||||
fn ctl_pair() -> (SenderCtl, ReceiverCtl) {
|
||||
let inner = Arc::new(Inner {
|
||||
pending: AtomicUsize::new(0),
|
||||
senders: AtomicUsize::new(1),
|
||||
set_readiness: AtomicLazyCell::new(),
|
||||
});
|
||||
|
||||
let tx = SenderCtl {
|
||||
inner: Arc::clone(&inner),
|
||||
};
|
||||
|
||||
let rx = ReceiverCtl {
|
||||
registration: LazyCell::new(),
|
||||
inner,
|
||||
};
|
||||
|
||||
(tx, rx)
|
||||
}
|
||||
|
||||
/// Tracks messages sent on a channel in order to update readiness.
|
||||
struct SenderCtl {
|
||||
inner: Arc<Inner>,
|
||||
}
|
||||
|
||||
/// Tracks messages received on a channel in order to track readiness.
|
||||
struct ReceiverCtl {
|
||||
registration: LazyCell<Registration>,
|
||||
inner: Arc<Inner>,
|
||||
}
|
||||
|
||||
/// The sending half of a channel.
|
||||
pub struct Sender<T> {
|
||||
tx: mpsc::Sender<T>,
|
||||
ctl: SenderCtl,
|
||||
}
|
||||
|
||||
/// The sending half of a synchronous channel.
|
||||
pub struct SyncSender<T> {
|
||||
tx: mpsc::SyncSender<T>,
|
||||
ctl: SenderCtl,
|
||||
}
|
||||
|
||||
/// The receiving half of a channel.
|
||||
pub struct Receiver<T> {
|
||||
rx: mpsc::Receiver<T>,
|
||||
ctl: ReceiverCtl,
|
||||
}
|
||||
|
||||
/// An error returned from the `Sender::send` or `SyncSender::send` function.
|
||||
pub enum SendError<T> {
|
||||
/// An IO error.
|
||||
Io(io::Error),
|
||||
|
||||
/// The receiving half of the channel has disconnected.
|
||||
Disconnected(T),
|
||||
}
|
||||
|
||||
/// An error returned from the `SyncSender::try_send` function.
|
||||
pub enum TrySendError<T> {
|
||||
/// An IO error.
|
||||
Io(io::Error),
|
||||
|
||||
/// Data could not be sent because it would require the callee to block.
|
||||
Full(T),
|
||||
|
||||
/// The receiving half of the channel has disconnected.
|
||||
Disconnected(T),
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
// The number of outstanding messages for the receiver to read
|
||||
pending: AtomicUsize,
|
||||
// The number of sender handles
|
||||
senders: AtomicUsize,
|
||||
// The set readiness handle
|
||||
set_readiness: AtomicLazyCell<SetReadiness>,
|
||||
}
|
||||
|
||||
impl<T> Sender<T> {
|
||||
/// Attempts to send a value on this channel, returning it back if it could not be sent.
|
||||
pub fn send(&self, t: T) -> Result<(), SendError<T>> {
|
||||
self.tx.send(t).map_err(SendError::from).and_then(|_| {
|
||||
try!(self.ctl.inc());
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Sender<T> {
|
||||
fn clone(&self) -> Sender<T> {
|
||||
Sender {
|
||||
tx: self.tx.clone(),
|
||||
ctl: self.ctl.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SyncSender<T> {
|
||||
/// Sends a value on this synchronous channel.
|
||||
///
|
||||
/// This function will *block* until space in the internal buffer becomes
|
||||
/// available or a receiver is available to hand off the message to.
|
||||
pub fn send(&self, t: T) -> Result<(), SendError<T>> {
|
||||
self.tx.send(t).map_err(From::from).and_then(|_| {
|
||||
try!(self.ctl.inc());
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/// Attempts to send a value on this channel without blocking.
|
||||
///
|
||||
/// This method differs from `send` by returning immediately if the channel's
|
||||
/// buffer is full or no receiver is waiting to acquire some data.
|
||||
pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
|
||||
self.tx.try_send(t).map_err(From::from).and_then(|_| {
|
||||
try!(self.ctl.inc());
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for SyncSender<T> {
|
||||
fn clone(&self) -> SyncSender<T> {
|
||||
SyncSender {
|
||||
tx: self.tx.clone(),
|
||||
ctl: self.ctl.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Receiver<T> {
|
||||
/// Attempts to return a pending value on this receiver without blocking.
|
||||
pub fn try_recv(&self) -> Result<T, mpsc::TryRecvError> {
|
||||
self.rx.try_recv().and_then(|res| {
|
||||
let _ = self.ctl.dec();
|
||||
Ok(res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Evented for Receiver<T> {
|
||||
fn register(
|
||||
&self,
|
||||
poll: &Poll,
|
||||
token: Token,
|
||||
interest: Ready,
|
||||
opts: PollOpt,
|
||||
) -> io::Result<()> {
|
||||
self.ctl.register(poll, token, interest, opts)
|
||||
}
|
||||
|
||||
fn reregister(
|
||||
&self,
|
||||
poll: &Poll,
|
||||
token: Token,
|
||||
interest: Ready,
|
||||
opts: PollOpt,
|
||||
) -> io::Result<()> {
|
||||
self.ctl.reregister(poll, token, interest, opts)
|
||||
}
|
||||
|
||||
fn deregister(&self, poll: &Poll) -> io::Result<()> {
|
||||
self.ctl.deregister(poll)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== SenderCtl / ReceiverCtl =====
|
||||
*
|
||||
*/
|
||||
|
||||
impl SenderCtl {
|
||||
/// Call to track that a message has been sent
|
||||
fn inc(&self) -> io::Result<()> {
|
||||
let cnt = self.inner.pending.fetch_add(1, Ordering::Acquire);
|
||||
|
||||
if 0 == cnt {
|
||||
// Toggle readiness to readable
|
||||
if let Some(set_readiness) = self.inner.set_readiness.borrow() {
|
||||
try!(set_readiness.set_readiness(Ready::readable()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for SenderCtl {
|
||||
fn clone(&self) -> SenderCtl {
|
||||
self.inner.senders.fetch_add(1, Ordering::Relaxed);
|
||||
SenderCtl {
|
||||
inner: Arc::clone(&self.inner),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SenderCtl {
|
||||
fn drop(&mut self) {
|
||||
if self.inner.senders.fetch_sub(1, Ordering::Release) == 1 {
|
||||
let _ = self.inc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ReceiverCtl {
|
||||
fn dec(&self) -> io::Result<()> {
|
||||
let first = self.inner.pending.load(Ordering::Acquire);
|
||||
|
||||
if first == 1 {
|
||||
// Unset readiness
|
||||
if let Some(set_readiness) = self.inner.set_readiness.borrow() {
|
||||
try!(set_readiness.set_readiness(Ready::empty()));
|
||||
}
|
||||
}
|
||||
|
||||
// Decrement
|
||||
let second = self.inner.pending.fetch_sub(1, Ordering::AcqRel);
|
||||
|
||||
if first == 1 && second > 1 {
|
||||
// There are still pending messages. Since readiness was
|
||||
// previously unset, it must be reset here
|
||||
if let Some(set_readiness) = self.inner.set_readiness.borrow() {
|
||||
try!(set_readiness.set_readiness(Ready::readable()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Evented for ReceiverCtl {
|
||||
fn register(
|
||||
&self,
|
||||
poll: &Poll,
|
||||
token: Token,
|
||||
interest: Ready,
|
||||
opts: PollOpt,
|
||||
) -> io::Result<()> {
|
||||
if self.registration.borrow().is_some() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"receiver already registered",
|
||||
));
|
||||
}
|
||||
|
||||
let (registration, set_readiness) = Registration::new2();
|
||||
poll.register(®istration, token, interest, opts)?;
|
||||
|
||||
if self.inner.pending.load(Ordering::Relaxed) > 0 {
|
||||
// TODO: Don't drop readiness
|
||||
let _ = set_readiness.set_readiness(Ready::readable());
|
||||
}
|
||||
|
||||
self.registration
|
||||
.fill(registration)
|
||||
.expect("unexpected state encountered");
|
||||
self.inner
|
||||
.set_readiness
|
||||
.fill(set_readiness)
|
||||
.expect("unexpected state encountered");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reregister(
|
||||
&self,
|
||||
poll: &Poll,
|
||||
token: Token,
|
||||
interest: Ready,
|
||||
opts: PollOpt,
|
||||
) -> io::Result<()> {
|
||||
match self.registration.borrow() {
|
||||
Some(registration) => poll.reregister(registration, token, interest, opts),
|
||||
None => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"receiver not registered",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn deregister(&self, poll: &Poll) -> io::Result<()> {
|
||||
match self.registration.borrow() {
|
||||
Some(registration) => poll.deregister(registration),
|
||||
None => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"receiver not registered",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Error conversions =====
|
||||
*
|
||||
*/
|
||||
|
||||
impl<T> From<mpsc::SendError<T>> for SendError<T> {
|
||||
fn from(src: mpsc::SendError<T>) -> SendError<T> {
|
||||
SendError::Disconnected(src.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<io::Error> for SendError<T> {
|
||||
fn from(src: io::Error) -> SendError<T> {
|
||||
SendError::Io(src)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<mpsc::TrySendError<T>> for TrySendError<T> {
|
||||
fn from(src: mpsc::TrySendError<T>) -> TrySendError<T> {
|
||||
match src {
|
||||
mpsc::TrySendError::Full(v) => TrySendError::Full(v),
|
||||
mpsc::TrySendError::Disconnected(v) => TrySendError::Disconnected(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<mpsc::SendError<T>> for TrySendError<T> {
|
||||
fn from(src: mpsc::SendError<T>) -> TrySendError<T> {
|
||||
TrySendError::Disconnected(src.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<io::Error> for TrySendError<T> {
|
||||
fn from(src: io::Error) -> TrySendError<T> {
|
||||
TrySendError::Io(src)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== Implement Error, Debug and Display for Errors =====
|
||||
*
|
||||
*/
|
||||
|
||||
impl<T: Any> error::Error for SendError<T> {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
SendError::Io(ref io_err) => io_err.description(),
|
||||
SendError::Disconnected(..) => "Disconnected",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Any> error::Error for TrySendError<T> {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
TrySendError::Io(ref io_err) => io_err.description(),
|
||||
TrySendError::Full(..) => "Full",
|
||||
TrySendError::Disconnected(..) => "Disconnected",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for SendError<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
format_send_error(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Display for SendError<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
format_send_error(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for TrySendError<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
format_try_send_error(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Display for TrySendError<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
format_try_send_error(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn format_send_error<T>(e: &SendError<T>, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *e {
|
||||
SendError::Io(ref io_err) => write!(f, "{}", io_err),
|
||||
SendError::Disconnected(..) => write!(f, "Disconnected"),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn format_try_send_error<T>(e: &TrySendError<T>, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *e {
|
||||
TrySendError::Io(ref io_err) => write!(f, "{}", io_err),
|
||||
TrySendError::Full(..) => write!(f, "Full"),
|
||||
TrySendError::Disconnected(..) => write!(f, "Disconnected"),
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
//! Extra components for use with Mio.
|
||||
#![deny(missing_docs)]
|
||||
extern crate lazycell;
|
||||
extern crate mio;
|
||||
extern crate slab;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
pub mod channel;
|
||||
pub mod timer;
|
||||
|
||||
// Conversion utilities
|
||||
mod convert {
|
||||
use std::time::Duration;
|
||||
|
||||
const NANOS_PER_MILLI: u32 = 1_000_000;
|
||||
const MILLIS_PER_SEC: u64 = 1_000;
|
||||
|
||||
/// Convert a `Duration` to milliseconds, rounding up and saturating at
|
||||
/// `u64::MAX`.
|
||||
///
|
||||
/// The saturating is fine because `u64::MAX` milliseconds are still many
|
||||
/// million years.
|
||||
pub fn millis(duration: Duration) -> u64 {
|
||||
// Round up.
|
||||
let millis = (duration.subsec_nanos() + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI;
|
||||
duration
|
||||
.as_secs()
|
||||
.saturating_mul(MILLIS_PER_SEC)
|
||||
.saturating_add(u64::from(millis))
|
||||
}
|
||||
}
|
|
@ -1,751 +0,0 @@
|
|||
//! Timer optimized for I/O related operations
|
||||
use convert;
|
||||
use lazycell::LazyCell;
|
||||
use mio::{Evented, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
|
||||
use slab::Slab;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{cmp, fmt, io, iter, thread, u64, usize};
|
||||
|
||||
/// A timer.
|
||||
///
|
||||
/// Typical usage goes like this:
|
||||
///
|
||||
/// * register the timer with a `mio::Poll`.
|
||||
/// * set a timeout, by calling `Timer::set_timeout`. Here you provide some
|
||||
/// state to be associated with this timeout.
|
||||
/// * poll the `Poll`, to learn when a timeout has occurred.
|
||||
/// * retrieve state associated with the timeout by calling `Timer::poll`.
|
||||
///
|
||||
/// You can omit use of the `Poll` altogether, if you like, and just poll the
|
||||
/// `Timer` directly.
|
||||
pub struct Timer<T> {
|
||||
// Size of each tick in milliseconds
|
||||
tick_ms: u64,
|
||||
// Slab of timeout entries
|
||||
entries: Slab<Entry<T>>,
|
||||
// Timeout wheel. Each tick, the timer will look at the next slot for
|
||||
// timeouts that match the current tick.
|
||||
wheel: Vec<WheelEntry>,
|
||||
// Tick 0's time instant
|
||||
start: Instant,
|
||||
// The current tick
|
||||
tick: Tick,
|
||||
// The next entry to possibly timeout
|
||||
next: Token,
|
||||
// Masks the target tick to get the slot
|
||||
mask: u64,
|
||||
// Set on registration with Poll
|
||||
inner: LazyCell<Inner>,
|
||||
}
|
||||
|
||||
/// Used to create a `Timer`.
|
||||
pub struct Builder {
|
||||
// Approximate duration of each tick
|
||||
tick: Duration,
|
||||
// Number of slots in the timer wheel
|
||||
num_slots: usize,
|
||||
// Max number of timeouts that can be in flight at a given time.
|
||||
capacity: usize,
|
||||
}
|
||||
|
||||
/// A timeout, as returned by `Timer::set_timeout`.
|
||||
///
|
||||
/// Use this as the argument to `Timer::cancel_timeout`, to cancel this timeout.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Timeout {
|
||||
// Reference into the timer entry slab
|
||||
token: Token,
|
||||
// Tick that it should match up with
|
||||
tick: u64,
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
registration: Registration,
|
||||
set_readiness: SetReadiness,
|
||||
wakeup_state: WakeupState,
|
||||
wakeup_thread: thread::JoinHandle<()>,
|
||||
}
|
||||
|
||||
impl Drop for Inner {
|
||||
fn drop(&mut self) {
|
||||
// 1. Set wakeup state to TERMINATE_THREAD
|
||||
self.wakeup_state.store(TERMINATE_THREAD, Ordering::Release);
|
||||
// 2. Wake him up
|
||||
self.wakeup_thread.thread().unpark();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct WheelEntry {
|
||||
next_tick: Tick,
|
||||
head: Token,
|
||||
}
|
||||
|
||||
// Doubly linked list of timer entries. Allows for efficient insertion /
|
||||
// removal of timeouts.
|
||||
struct Entry<T> {
|
||||
state: T,
|
||||
links: EntryLinks,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct EntryLinks {
|
||||
tick: Tick,
|
||||
prev: Token,
|
||||
next: Token,
|
||||
}
|
||||
|
||||
type Tick = u64;
|
||||
|
||||
const TICK_MAX: Tick = u64::MAX;
|
||||
|
||||
// Manages communication with wakeup thread
|
||||
type WakeupState = Arc<AtomicUsize>;
|
||||
|
||||
const TERMINATE_THREAD: usize = 0;
|
||||
const EMPTY: Token = Token(usize::MAX);
|
||||
|
||||
impl Builder {
|
||||
/// Set the tick duration. Default is 100ms.
|
||||
pub fn tick_duration(mut self, duration: Duration) -> Builder {
|
||||
self.tick = duration;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the number of slots. Default is 256.
|
||||
pub fn num_slots(mut self, num_slots: usize) -> Builder {
|
||||
self.num_slots = num_slots;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the capacity. Default is 65536.
|
||||
pub fn capacity(mut self, capacity: usize) -> Builder {
|
||||
self.capacity = capacity;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build a `Timer` with the parameters set on this `Builder`.
|
||||
pub fn build<T>(self) -> Timer<T> {
|
||||
Timer::new(
|
||||
convert::millis(self.tick),
|
||||
self.num_slots,
|
||||
self.capacity,
|
||||
Instant::now(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Builder {
|
||||
fn default() -> Builder {
|
||||
Builder {
|
||||
tick: Duration::from_millis(100),
|
||||
num_slots: 1 << 8,
|
||||
capacity: 1 << 16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Timer<T> {
|
||||
fn new(tick_ms: u64, num_slots: usize, capacity: usize, start: Instant) -> Timer<T> {
|
||||
let num_slots = num_slots.next_power_of_two();
|
||||
let capacity = capacity.next_power_of_two();
|
||||
let mask = (num_slots as u64) - 1;
|
||||
let wheel = iter::repeat(WheelEntry {
|
||||
next_tick: TICK_MAX,
|
||||
head: EMPTY,
|
||||
}).take(num_slots)
|
||||
.collect();
|
||||
|
||||
Timer {
|
||||
tick_ms,
|
||||
entries: Slab::with_capacity(capacity),
|
||||
wheel,
|
||||
start,
|
||||
tick: 0,
|
||||
next: EMPTY,
|
||||
mask,
|
||||
inner: LazyCell::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a timeout.
|
||||
///
|
||||
/// When the timeout occurs, the given state becomes available via `poll`.
|
||||
pub fn set_timeout(&mut self, delay_from_now: Duration, state: T) -> Timeout {
|
||||
let delay_from_start = self.start.elapsed() + delay_from_now;
|
||||
self.set_timeout_at(delay_from_start, state)
|
||||
}
|
||||
|
||||
fn set_timeout_at(&mut self, delay_from_start: Duration, state: T) -> Timeout {
|
||||
let mut tick = duration_to_tick(delay_from_start, self.tick_ms);
|
||||
trace!(
|
||||
"setting timeout; delay={:?}; tick={:?}; current-tick={:?}",
|
||||
delay_from_start,
|
||||
tick,
|
||||
self.tick
|
||||
);
|
||||
|
||||
// Always target at least 1 tick in the future
|
||||
if tick <= self.tick {
|
||||
tick = self.tick + 1;
|
||||
}
|
||||
|
||||
self.insert(tick, state)
|
||||
}
|
||||
|
||||
fn insert(&mut self, tick: Tick, state: T) -> Timeout {
|
||||
// Get the slot for the requested tick
|
||||
let slot = (tick & self.mask) as usize;
|
||||
let curr = self.wheel[slot];
|
||||
|
||||
// Insert the new entry
|
||||
let entry = Entry::new(state, tick, curr.head);
|
||||
let token = Token(self.entries.insert(entry));
|
||||
|
||||
if curr.head != EMPTY {
|
||||
// If there was a previous entry, set its prev pointer to the new
|
||||
// entry
|
||||
self.entries[curr.head.into()].links.prev = token;
|
||||
}
|
||||
|
||||
// Update the head slot
|
||||
self.wheel[slot] = WheelEntry {
|
||||
next_tick: cmp::min(tick, curr.next_tick),
|
||||
head: token,
|
||||
};
|
||||
|
||||
self.schedule_readiness(tick);
|
||||
|
||||
trace!("inserted timout; slot={}; token={:?}", slot, token);
|
||||
|
||||
// Return the new timeout
|
||||
Timeout { token, tick }
|
||||
}
|
||||
|
||||
/// Cancel a timeout.
|
||||
///
|
||||
/// If the timeout has not yet occurred, the return value holds the
|
||||
/// associated state.
|
||||
pub fn cancel_timeout(&mut self, timeout: &Timeout) -> Option<T> {
|
||||
let links = match self.entries.get(timeout.token.into()) {
|
||||
Some(e) => e.links,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
// Sanity check
|
||||
if links.tick != timeout.tick {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.unlink(&links, timeout.token);
|
||||
Some(self.entries.remove(timeout.token.into()).state)
|
||||
}
|
||||
|
||||
/// Poll for an expired timer.
|
||||
///
|
||||
/// The return value holds the state associated with the first expired
|
||||
/// timer, if any.
|
||||
pub fn poll(&mut self) -> Option<T> {
|
||||
let target_tick = current_tick(self.start, self.tick_ms);
|
||||
self.poll_to(target_tick)
|
||||
}
|
||||
|
||||
fn poll_to(&mut self, mut target_tick: Tick) -> Option<T> {
|
||||
trace!(
|
||||
"tick_to; target_tick={}; current_tick={}",
|
||||
target_tick,
|
||||
self.tick
|
||||
);
|
||||
|
||||
if target_tick < self.tick {
|
||||
target_tick = self.tick;
|
||||
}
|
||||
|
||||
while self.tick <= target_tick {
|
||||
let curr = self.next;
|
||||
|
||||
trace!("ticking; curr={:?}", curr);
|
||||
|
||||
if curr == EMPTY {
|
||||
self.tick += 1;
|
||||
|
||||
let slot = self.slot_for(self.tick);
|
||||
self.next = self.wheel[slot].head;
|
||||
|
||||
// Handle the case when a slot has a single timeout which gets
|
||||
// canceled before the timeout expires. In this case, the
|
||||
// slot's head is EMPTY but there is a value for next_tick. Not
|
||||
// resetting next_tick here causes the timer to get stuck in a
|
||||
// loop.
|
||||
if self.next == EMPTY {
|
||||
self.wheel[slot].next_tick = TICK_MAX;
|
||||
}
|
||||
} else {
|
||||
let slot = self.slot_for(self.tick);
|
||||
|
||||
if curr == self.wheel[slot].head {
|
||||
self.wheel[slot].next_tick = TICK_MAX;
|
||||
}
|
||||
|
||||
let links = self.entries[curr.into()].links;
|
||||
|
||||
if links.tick <= self.tick {
|
||||
trace!("triggering; token={:?}", curr);
|
||||
|
||||
// Unlink will also advance self.next
|
||||
self.unlink(&links, curr);
|
||||
|
||||
// Remove and return the token
|
||||
return Some(self.entries.remove(curr.into()).state);
|
||||
} else {
|
||||
let next_tick = self.wheel[slot].next_tick;
|
||||
self.wheel[slot].next_tick = cmp::min(next_tick, links.tick);
|
||||
self.next = links.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No more timeouts to poll
|
||||
if let Some(inner) = self.inner.borrow() {
|
||||
trace!("unsetting readiness");
|
||||
let _ = inner.set_readiness.set_readiness(Ready::empty());
|
||||
|
||||
if let Some(tick) = self.next_tick() {
|
||||
self.schedule_readiness(tick);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn unlink(&mut self, links: &EntryLinks, token: Token) {
|
||||
trace!(
|
||||
"unlinking timeout; slot={}; token={:?}",
|
||||
self.slot_for(links.tick),
|
||||
token
|
||||
);
|
||||
|
||||
if links.prev == EMPTY {
|
||||
let slot = self.slot_for(links.tick);
|
||||
self.wheel[slot].head = links.next;
|
||||
} else {
|
||||
self.entries[links.prev.into()].links.next = links.next;
|
||||
}
|
||||
|
||||
if links.next != EMPTY {
|
||||
self.entries[links.next.into()].links.prev = links.prev;
|
||||
|
||||
if token == self.next {
|
||||
self.next = links.next;
|
||||
}
|
||||
} else if token == self.next {
|
||||
self.next = EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
fn schedule_readiness(&self, tick: Tick) {
|
||||
if let Some(inner) = self.inner.borrow() {
|
||||
// Coordinate setting readiness w/ the wakeup thread
|
||||
let mut curr = inner.wakeup_state.load(Ordering::Acquire);
|
||||
|
||||
loop {
|
||||
if curr as Tick <= tick {
|
||||
// Nothing to do, wakeup is already scheduled
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt to move the wakeup time forward
|
||||
trace!("advancing the wakeup time; target={}; curr={}", tick, curr);
|
||||
let actual =
|
||||
inner
|
||||
.wakeup_state
|
||||
.compare_and_swap(curr, tick as usize, Ordering::Release);
|
||||
|
||||
if actual == curr {
|
||||
// Signal to the wakeup thread that the wakeup time has
|
||||
// been changed.
|
||||
trace!("unparking wakeup thread");
|
||||
inner.wakeup_thread.thread().unpark();
|
||||
return;
|
||||
}
|
||||
|
||||
curr = actual;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Next tick containing a timeout
|
||||
fn next_tick(&self) -> Option<Tick> {
|
||||
if self.next != EMPTY {
|
||||
let slot = self.slot_for(self.entries[self.next.into()].links.tick);
|
||||
|
||||
if self.wheel[slot].next_tick == self.tick {
|
||||
// There is data ready right now
|
||||
return Some(self.tick);
|
||||
}
|
||||
}
|
||||
|
||||
self.wheel.iter().map(|e| e.next_tick).min()
|
||||
}
|
||||
|
||||
fn slot_for(&self, tick: Tick) -> usize {
|
||||
(self.mask & tick) as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Timer<T> {
|
||||
fn default() -> Timer<T> {
|
||||
Builder::default().build()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Evented for Timer<T> {
|
||||
fn register(
|
||||
&self,
|
||||
poll: &Poll,
|
||||
token: Token,
|
||||
interest: Ready,
|
||||
opts: PollOpt,
|
||||
) -> io::Result<()> {
|
||||
if self.inner.borrow().is_some() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"timer already registered",
|
||||
));
|
||||
}
|
||||
|
||||
let (registration, set_readiness) = Registration::new2();
|
||||
poll.register(®istration, token, interest, opts)?;
|
||||
let wakeup_state = Arc::new(AtomicUsize::new(usize::MAX));
|
||||
let thread_handle = spawn_wakeup_thread(
|
||||
Arc::clone(&wakeup_state),
|
||||
set_readiness.clone(),
|
||||
self.start,
|
||||
self.tick_ms,
|
||||
);
|
||||
|
||||
self.inner
|
||||
.fill(Inner {
|
||||
registration,
|
||||
set_readiness,
|
||||
wakeup_state,
|
||||
wakeup_thread: thread_handle,
|
||||
})
|
||||
.expect("timer already registered");
|
||||
|
||||
if let Some(next_tick) = self.next_tick() {
|
||||
self.schedule_readiness(next_tick);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reregister(
|
||||
&self,
|
||||
poll: &Poll,
|
||||
token: Token,
|
||||
interest: Ready,
|
||||
opts: PollOpt,
|
||||
) -> io::Result<()> {
|
||||
match self.inner.borrow() {
|
||||
Some(inner) => poll.reregister(&inner.registration, token, interest, opts),
|
||||
None => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"receiver not registered",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn deregister(&self, poll: &Poll) -> io::Result<()> {
|
||||
match self.inner.borrow() {
|
||||
Some(inner) => poll.deregister(&inner.registration),
|
||||
None => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"receiver not registered",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Inner {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("Inner")
|
||||
.field("registration", &self.registration)
|
||||
.field("wakeup_state", &self.wakeup_state.load(Ordering::Relaxed))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_wakeup_thread(
|
||||
state: WakeupState,
|
||||
set_readiness: SetReadiness,
|
||||
start: Instant,
|
||||
tick_ms: u64,
|
||||
) -> thread::JoinHandle<()> {
|
||||
thread::spawn(move || {
|
||||
let mut sleep_until_tick = state.load(Ordering::Acquire) as Tick;
|
||||
|
||||
loop {
|
||||
if sleep_until_tick == TERMINATE_THREAD as Tick {
|
||||
return;
|
||||
}
|
||||
|
||||
let now_tick = current_tick(start, tick_ms);
|
||||
|
||||
trace!(
|
||||
"wakeup thread: sleep_until_tick={:?}; now_tick={:?}",
|
||||
sleep_until_tick,
|
||||
now_tick
|
||||
);
|
||||
|
||||
if now_tick < sleep_until_tick {
|
||||
// Calling park_timeout with u64::MAX leads to undefined
|
||||
// behavior in pthread, causing the park to return immediately
|
||||
// and causing the thread to tightly spin. Instead of u64::MAX
|
||||
// on large values, simply use a blocking park.
|
||||
match tick_ms.checked_mul(sleep_until_tick - now_tick) {
|
||||
Some(sleep_duration) => {
|
||||
trace!(
|
||||
"sleeping; tick_ms={}; now_tick={}; sleep_until_tick={}; duration={:?}",
|
||||
tick_ms,
|
||||
now_tick,
|
||||
sleep_until_tick,
|
||||
sleep_duration
|
||||
);
|
||||
thread::park_timeout(Duration::from_millis(sleep_duration));
|
||||
}
|
||||
None => {
|
||||
trace!(
|
||||
"sleeping; tick_ms={}; now_tick={}; blocking sleep",
|
||||
tick_ms,
|
||||
now_tick
|
||||
);
|
||||
thread::park();
|
||||
}
|
||||
}
|
||||
sleep_until_tick = state.load(Ordering::Acquire) as Tick;
|
||||
} else {
|
||||
let actual =
|
||||
state.compare_and_swap(sleep_until_tick as usize, usize::MAX, Ordering::AcqRel)
|
||||
as Tick;
|
||||
|
||||
if actual == sleep_until_tick {
|
||||
trace!("setting readiness from wakeup thread");
|
||||
let _ = set_readiness.set_readiness(Ready::readable());
|
||||
sleep_until_tick = usize::MAX as Tick;
|
||||
} else {
|
||||
sleep_until_tick = actual as Tick;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn duration_to_tick(elapsed: Duration, tick_ms: u64) -> Tick {
|
||||
// Calculate tick rounding up to the closest one
|
||||
let elapsed_ms = convert::millis(elapsed);
|
||||
elapsed_ms.saturating_add(tick_ms / 2) / tick_ms
|
||||
}
|
||||
|
||||
fn current_tick(start: Instant, tick_ms: u64) -> Tick {
|
||||
duration_to_tick(start.elapsed(), tick_ms)
|
||||
}
|
||||
|
||||
impl<T> Entry<T> {
|
||||
fn new(state: T, tick: u64, next: Token) -> Entry<T> {
|
||||
Entry {
|
||||
state,
|
||||
links: EntryLinks {
|
||||
tick,
|
||||
prev: EMPTY,
|
||||
next,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[test]
|
||||
pub fn test_timeout_next_tick() {
|
||||
let mut t = timer();
|
||||
let mut tick;
|
||||
|
||||
t.set_timeout_at(Duration::from_millis(100), "a");
|
||||
|
||||
tick = ms_to_tick(&t, 50);
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
|
||||
tick = ms_to_tick(&t, 100);
|
||||
assert_eq!(Some("a"), t.poll_to(tick));
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
|
||||
tick = ms_to_tick(&t, 150);
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
|
||||
tick = ms_to_tick(&t, 200);
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
|
||||
assert_eq!(count(&t), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_clearing_timeout() {
|
||||
let mut t = timer();
|
||||
let mut tick;
|
||||
|
||||
let to = t.set_timeout_at(Duration::from_millis(100), "a");
|
||||
assert_eq!("a", t.cancel_timeout(&to).unwrap());
|
||||
|
||||
tick = ms_to_tick(&t, 100);
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
|
||||
tick = ms_to_tick(&t, 200);
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
|
||||
assert_eq!(count(&t), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_multiple_timeouts_same_tick() {
|
||||
let mut t = timer();
|
||||
let mut tick;
|
||||
|
||||
t.set_timeout_at(Duration::from_millis(100), "a");
|
||||
t.set_timeout_at(Duration::from_millis(100), "b");
|
||||
|
||||
let mut rcv = vec![];
|
||||
|
||||
tick = ms_to_tick(&t, 100);
|
||||
rcv.push(t.poll_to(tick).unwrap());
|
||||
rcv.push(t.poll_to(tick).unwrap());
|
||||
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
|
||||
rcv.sort();
|
||||
assert!(rcv == ["a", "b"], "actual={:?}", rcv);
|
||||
|
||||
tick = ms_to_tick(&t, 200);
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
|
||||
assert_eq!(count(&t), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_multiple_timeouts_diff_tick() {
|
||||
let mut t = timer();
|
||||
let mut tick;
|
||||
|
||||
t.set_timeout_at(Duration::from_millis(110), "a");
|
||||
t.set_timeout_at(Duration::from_millis(220), "b");
|
||||
t.set_timeout_at(Duration::from_millis(230), "c");
|
||||
t.set_timeout_at(Duration::from_millis(440), "d");
|
||||
t.set_timeout_at(Duration::from_millis(560), "e");
|
||||
|
||||
tick = ms_to_tick(&t, 100);
|
||||
assert_eq!(Some("a"), t.poll_to(tick));
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
|
||||
tick = ms_to_tick(&t, 200);
|
||||
assert_eq!(Some("c"), t.poll_to(tick));
|
||||
assert_eq!(Some("b"), t.poll_to(tick));
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
|
||||
tick = ms_to_tick(&t, 300);
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
|
||||
tick = ms_to_tick(&t, 400);
|
||||
assert_eq!(Some("d"), t.poll_to(tick));
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
|
||||
tick = ms_to_tick(&t, 500);
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
|
||||
tick = ms_to_tick(&t, 600);
|
||||
assert_eq!(Some("e"), t.poll_to(tick));
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_catching_up() {
|
||||
let mut t = timer();
|
||||
|
||||
t.set_timeout_at(Duration::from_millis(110), "a");
|
||||
t.set_timeout_at(Duration::from_millis(220), "b");
|
||||
t.set_timeout_at(Duration::from_millis(230), "c");
|
||||
t.set_timeout_at(Duration::from_millis(440), "d");
|
||||
|
||||
let tick = ms_to_tick(&t, 600);
|
||||
assert_eq!(Some("a"), t.poll_to(tick));
|
||||
assert_eq!(Some("c"), t.poll_to(tick));
|
||||
assert_eq!(Some("b"), t.poll_to(tick));
|
||||
assert_eq!(Some("d"), t.poll_to(tick));
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timeout_hash_collision() {
|
||||
let mut t = timer();
|
||||
let mut tick;
|
||||
|
||||
t.set_timeout_at(Duration::from_millis(100), "a");
|
||||
t.set_timeout_at(Duration::from_millis(100 + TICK * SLOTS as u64), "b");
|
||||
|
||||
tick = ms_to_tick(&t, 100);
|
||||
assert_eq!(Some("a"), t.poll_to(tick));
|
||||
assert_eq!(1, count(&t));
|
||||
|
||||
tick = ms_to_tick(&t, 200);
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
assert_eq!(1, count(&t));
|
||||
|
||||
tick = ms_to_tick(&t, 100 + TICK * SLOTS as u64);
|
||||
assert_eq!(Some("b"), t.poll_to(tick));
|
||||
assert_eq!(0, count(&t));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_clearing_timeout_between_triggers() {
|
||||
let mut t = timer();
|
||||
let mut tick;
|
||||
|
||||
let a = t.set_timeout_at(Duration::from_millis(100), "a");
|
||||
let _ = t.set_timeout_at(Duration::from_millis(100), "b");
|
||||
let _ = t.set_timeout_at(Duration::from_millis(200), "c");
|
||||
|
||||
tick = ms_to_tick(&t, 100);
|
||||
assert_eq!(Some("b"), t.poll_to(tick));
|
||||
assert_eq!(2, count(&t));
|
||||
|
||||
t.cancel_timeout(&a);
|
||||
assert_eq!(1, count(&t));
|
||||
|
||||
assert_eq!(None, t.poll_to(tick));
|
||||
|
||||
tick = ms_to_tick(&t, 200);
|
||||
assert_eq!(Some("c"), t.poll_to(tick));
|
||||
assert_eq!(0, count(&t));
|
||||
}
|
||||
|
||||
const TICK: u64 = 100;
|
||||
const SLOTS: usize = 16;
|
||||
const CAPACITY: usize = 32;
|
||||
|
||||
fn count<T>(timer: &Timer<T>) -> usize {
|
||||
timer.entries.len()
|
||||
}
|
||||
|
||||
fn timer() -> Timer<&'static str> {
|
||||
Timer::new(TICK, SLOTS, CAPACITY, Instant::now())
|
||||
}
|
||||
|
||||
fn ms_to_tick<T>(timer: &Timer<T>, ms: u64) -> u64 {
|
||||
ms / timer.tick_ms
|
||||
}
|
||||
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
extern crate mio;
|
||||
extern crate mio_extras;
|
||||
|
||||
use mio::event::Event;
|
||||
use mio::{Events, Poll};
|
||||
use std::time::Duration;
|
||||
|
||||
mod test_poll_channel;
|
||||
mod test_timer;
|
||||
|
||||
pub fn expect_events(
|
||||
poll: &Poll,
|
||||
event_buffer: &mut Events,
|
||||
poll_try_count: usize,
|
||||
mut expected: Vec<Event>,
|
||||
) {
|
||||
const MS: u64 = 1_000;
|
||||
|
||||
for _ in 0..poll_try_count {
|
||||
poll.poll(event_buffer, Some(Duration::from_millis(MS)))
|
||||
.unwrap();
|
||||
for event in event_buffer.iter() {
|
||||
let pos_opt = match expected.iter().position(|exp_event| {
|
||||
(event.token() == exp_event.token())
|
||||
&& event.readiness().contains(exp_event.readiness())
|
||||
}) {
|
||||
Some(x) => Some(x),
|
||||
None => None,
|
||||
};
|
||||
if let Some(pos) = pos_opt {
|
||||
expected.remove(pos);
|
||||
}
|
||||
}
|
||||
|
||||
if expected.is_empty() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert!(
|
||||
expected.is_empty(),
|
||||
"The following expected events were not found: {:?}",
|
||||
expected
|
||||
);
|
||||
}
|
|
@ -1,338 +0,0 @@
|
|||
use expect_events;
|
||||
use mio::event::Event;
|
||||
use mio::{Events, Poll, PollOpt, Ready, Token};
|
||||
use mio_extras::channel;
|
||||
use std::sync::mpsc::TryRecvError;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
pub fn test_poll_channel_edge() {
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let (tx, rx) = channel::channel();
|
||||
|
||||
poll.register(&rx, Token(123), Ready::readable(), PollOpt::edge())
|
||||
.unwrap();
|
||||
|
||||
// Wait, but nothing should happen
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(0, num);
|
||||
|
||||
// Push the value
|
||||
tx.send("hello").unwrap();
|
||||
|
||||
// Polling will contain the event
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(1, num);
|
||||
|
||||
let event = events.iter().next().unwrap();
|
||||
assert_eq!(event.token(), Token(123));
|
||||
assert_eq!(event.readiness(), Ready::readable());
|
||||
|
||||
// Poll again and there should be no events
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(0, num);
|
||||
|
||||
// Read the value
|
||||
assert_eq!("hello", rx.try_recv().unwrap());
|
||||
|
||||
// Poll again, nothing
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(0, num);
|
||||
|
||||
// Push a value
|
||||
tx.send("goodbye").unwrap();
|
||||
|
||||
// Have an event
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(1, num);
|
||||
|
||||
let event = events.iter().next().unwrap();
|
||||
assert_eq!(event.token(), Token(123));
|
||||
assert_eq!(event.readiness(), Ready::readable());
|
||||
|
||||
// Read the value
|
||||
rx.try_recv().unwrap();
|
||||
|
||||
// Drop the sender half
|
||||
drop(tx);
|
||||
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(1, num);
|
||||
|
||||
let event = events.iter().next().unwrap();
|
||||
assert_eq!(event.token(), Token(123));
|
||||
assert_eq!(event.readiness(), Ready::readable());
|
||||
|
||||
match rx.try_recv() {
|
||||
Err(TryRecvError::Disconnected) => {}
|
||||
no => panic!("unexpected value {:?}", no),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_poll_channel_oneshot() {
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let (tx, rx) = channel::channel();
|
||||
|
||||
poll.register(
|
||||
&rx,
|
||||
Token(123),
|
||||
Ready::readable(),
|
||||
PollOpt::edge() | PollOpt::oneshot(),
|
||||
).unwrap();
|
||||
|
||||
// Wait, but nothing should happen
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(0, num);
|
||||
|
||||
// Push the value
|
||||
tx.send("hello").unwrap();
|
||||
|
||||
// Polling will contain the event
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(1, num);
|
||||
|
||||
let event = events.iter().next().unwrap();
|
||||
assert_eq!(event.token(), Token(123));
|
||||
assert_eq!(event.readiness(), Ready::readable());
|
||||
|
||||
// Poll again and there should be no events
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(0, num);
|
||||
|
||||
// Read the value
|
||||
assert_eq!("hello", rx.try_recv().unwrap());
|
||||
|
||||
// Poll again, nothing
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(0, num);
|
||||
|
||||
// Push a value
|
||||
tx.send("goodbye").unwrap();
|
||||
|
||||
// Poll again, nothing
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(0, num);
|
||||
|
||||
// Reregistering will re-trigger the notification
|
||||
for _ in 0..3 {
|
||||
poll.reregister(
|
||||
&rx,
|
||||
Token(123),
|
||||
Ready::readable(),
|
||||
PollOpt::edge() | PollOpt::oneshot(),
|
||||
).unwrap();
|
||||
|
||||
// Have an event
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(1, num);
|
||||
|
||||
let event = events.iter().next().unwrap();
|
||||
assert_eq!(event.token(), Token(123));
|
||||
assert_eq!(event.readiness(), Ready::readable());
|
||||
}
|
||||
|
||||
// Get the value
|
||||
assert_eq!("goodbye", rx.try_recv().unwrap());
|
||||
|
||||
poll.reregister(
|
||||
&rx,
|
||||
Token(123),
|
||||
Ready::readable(),
|
||||
PollOpt::edge() | PollOpt::oneshot(),
|
||||
).unwrap();
|
||||
|
||||
// Have an event
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(0, num);
|
||||
|
||||
poll.reregister(
|
||||
&rx,
|
||||
Token(123),
|
||||
Ready::readable(),
|
||||
PollOpt::edge() | PollOpt::oneshot(),
|
||||
).unwrap();
|
||||
|
||||
// Have an event
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(0, num);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_poll_channel_level() {
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let (tx, rx) = channel::channel();
|
||||
|
||||
poll.register(&rx, Token(123), Ready::readable(), PollOpt::level())
|
||||
.unwrap();
|
||||
|
||||
// Wait, but nothing should happen
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(0, num);
|
||||
|
||||
// Push the value
|
||||
tx.send("hello").unwrap();
|
||||
|
||||
// Polling will contain the event
|
||||
for i in 0..5 {
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert!(1 == num, "actually got {} on iteration {}", num, i);
|
||||
|
||||
let event = events.iter().next().unwrap();
|
||||
assert_eq!(event.token(), Token(123));
|
||||
assert_eq!(event.readiness(), Ready::readable());
|
||||
}
|
||||
|
||||
// Read the value
|
||||
assert_eq!("hello", rx.try_recv().unwrap());
|
||||
|
||||
// Wait, but nothing should happen
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(0, num);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_poll_channel_writable() {
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let (tx, rx) = channel::channel();
|
||||
|
||||
poll.register(&rx, Token(123), Ready::writable(), PollOpt::edge())
|
||||
.unwrap();
|
||||
|
||||
// Wait, but nothing should happen
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(0, num);
|
||||
|
||||
// Push the value
|
||||
tx.send("hello").unwrap();
|
||||
|
||||
// Wait, but nothing should happen
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(0, num);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_dropping_receive_before_poll() {
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let (tx, rx) = channel::channel();
|
||||
|
||||
poll.register(&rx, Token(123), Ready::readable(), PollOpt::edge())
|
||||
.unwrap();
|
||||
|
||||
// Push the value
|
||||
tx.send("hello").unwrap();
|
||||
|
||||
// Drop the receive end
|
||||
drop(rx);
|
||||
|
||||
// Wait, but nothing should happen
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(0, num);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_mixing_channel_with_socket() {
|
||||
use mio::net::{TcpListener, TcpStream};
|
||||
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let (tx, rx) = channel::channel();
|
||||
|
||||
// Create the listener
|
||||
let l = TcpListener::bind(&"127.0.0.1:0".parse().unwrap()).unwrap();
|
||||
|
||||
// Register the listener with `Poll`
|
||||
poll.register(&l, Token(0), Ready::readable(), PollOpt::edge())
|
||||
.unwrap();
|
||||
poll.register(&rx, Token(1), Ready::readable(), PollOpt::edge())
|
||||
.unwrap();
|
||||
|
||||
// Push a value onto the channel
|
||||
tx.send("hello").unwrap();
|
||||
|
||||
// Connect a TCP socket
|
||||
let s1 = TcpStream::connect(&l.local_addr().unwrap()).unwrap();
|
||||
|
||||
// Register the socket
|
||||
poll.register(&s1, Token(2), Ready::readable(), PollOpt::edge())
|
||||
.unwrap();
|
||||
|
||||
// Sleep a bit to ensure it arrives at dest
|
||||
thread::sleep(Duration::from_millis(250));
|
||||
|
||||
expect_events(
|
||||
&poll,
|
||||
&mut events,
|
||||
2,
|
||||
vec![
|
||||
Event::new(Ready::empty(), Token(0)),
|
||||
Event::new(Ready::empty(), Token(1)),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_sending_from_other_thread_while_polling() {
|
||||
const ITERATIONS: usize = 20;
|
||||
const THREADS: usize = 5;
|
||||
|
||||
// Make sure to run multiple times
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
|
||||
for _ in 0..ITERATIONS {
|
||||
let (tx, rx) = channel::channel();
|
||||
poll.register(&rx, Token(0), Ready::readable(), PollOpt::edge())
|
||||
.unwrap();
|
||||
|
||||
for _ in 0..THREADS {
|
||||
let tx = tx.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(50));
|
||||
tx.send("ping").unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
let mut recv = 0;
|
||||
|
||||
while recv < THREADS {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
|
||||
if num != 0 {
|
||||
assert_eq!(1, num);
|
||||
assert_eq!(events.iter().next().unwrap().token(), Token(0));
|
||||
|
||||
while let Ok(_) = rx.try_recv() {
|
||||
recv += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,304 +0,0 @@
|
|||
use mio::{Events, Poll, PollOpt, Ready, Token};
|
||||
use mio_extras::timer::{self, Timer};
|
||||
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn test_basic_timer_without_poll() {
|
||||
let mut timer = Timer::default();
|
||||
|
||||
// Set the timeout
|
||||
timer.set_timeout(Duration::from_millis(200), "hello");
|
||||
|
||||
// Nothing when polled immediately
|
||||
assert!(timer.poll().is_none());
|
||||
|
||||
// Wait for the timeout
|
||||
thread::sleep(Duration::from_millis(250));
|
||||
|
||||
assert_eq!(Some("hello"), timer.poll());
|
||||
assert!(timer.poll().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic_timer_with_poll_edge_set_timeout_after_register() {
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut timer = Timer::default();
|
||||
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge())
|
||||
.unwrap();
|
||||
timer.set_timeout(Duration::from_millis(200), "hello");
|
||||
|
||||
let elapsed = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
|
||||
assert_eq!(num, 1);
|
||||
let event = events.iter().next().unwrap();
|
||||
assert_eq!(Token(0), event.token());
|
||||
assert_eq!(Ready::readable(), event.readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(200, elapsed), "actual={:?}", elapsed);
|
||||
assert_eq!("hello", timer.poll().unwrap());
|
||||
assert_eq!(None, timer.poll());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic_timer_with_poll_edge_set_timeout_before_register() {
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut timer = Timer::default();
|
||||
|
||||
timer.set_timeout(Duration::from_millis(200), "hello");
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge())
|
||||
.unwrap();
|
||||
|
||||
let elapsed = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
|
||||
assert_eq!(num, 1);
|
||||
let event = events.iter().next().unwrap();
|
||||
assert_eq!(Token(0), event.token());
|
||||
assert_eq!(Ready::readable(), event.readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(200, elapsed), "actual={:?}", elapsed);
|
||||
assert_eq!("hello", timer.poll().unwrap());
|
||||
assert_eq!(None, timer.poll());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_setting_later_timeout_then_earlier_one() {
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut timer = Timer::default();
|
||||
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge())
|
||||
.unwrap();
|
||||
|
||||
timer.set_timeout(Duration::from_millis(600), "hello");
|
||||
timer.set_timeout(Duration::from_millis(200), "world");
|
||||
|
||||
let elapsed = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
|
||||
assert_eq!(num, 1);
|
||||
let event = events.iter().next().unwrap();
|
||||
assert_eq!(Token(0), event.token());
|
||||
assert_eq!(Ready::readable(), event.readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(200, elapsed), "actual={:?}", elapsed);
|
||||
assert_eq!("world", timer.poll().unwrap());
|
||||
assert_eq!(None, timer.poll());
|
||||
|
||||
let elapsed = self::elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
|
||||
assert_eq!(num, 1);
|
||||
let event = events.iter().next().unwrap();
|
||||
assert_eq!(Token(0), event.token());
|
||||
assert_eq!(Ready::readable(), event.readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(400, elapsed), "actual={:?}", elapsed);
|
||||
assert_eq!("hello", timer.poll().unwrap());
|
||||
assert_eq!(None, timer.poll());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_with_looping_wheel() {
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut timer = timer::Builder::default().num_slots(2).build();
|
||||
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge())
|
||||
.unwrap();
|
||||
|
||||
const TOKENS: &[&str] = &["hello", "world", "some", "thing"];
|
||||
|
||||
for (i, msg) in TOKENS.iter().enumerate() {
|
||||
timer.set_timeout(Duration::from_millis(500 * (i as u64 + 1)), msg);
|
||||
}
|
||||
|
||||
for msg in TOKENS {
|
||||
let elapsed = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
|
||||
assert_eq!(num, 1);
|
||||
let event = events.iter().next().unwrap();
|
||||
assert_eq!(Token(0), event.token());
|
||||
assert_eq!(Ready::readable(), event.readiness());
|
||||
});
|
||||
|
||||
assert!(
|
||||
is_about(500, elapsed),
|
||||
"actual={:?}; msg={:?}",
|
||||
elapsed,
|
||||
msg
|
||||
);
|
||||
assert_eq!(Some(msg), timer.poll());
|
||||
assert_eq!(None, timer.poll());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edge_without_polling() {
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut timer = Timer::default();
|
||||
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge())
|
||||
.unwrap();
|
||||
|
||||
timer.set_timeout(Duration::from_millis(400), "hello");
|
||||
|
||||
let ms = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
assert_eq!(num, 1);
|
||||
let event = events.iter().next().unwrap();
|
||||
assert_eq!(Token(0), event.token());
|
||||
assert_eq!(Ready::readable(), event.readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(400, ms), "actual={:?}", ms);
|
||||
|
||||
let ms = elapsed(|| {
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(num, 0);
|
||||
});
|
||||
|
||||
assert!(is_about(300, ms), "actual={:?}", ms);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_level_triggered() {
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut timer = Timer::default();
|
||||
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::level())
|
||||
.unwrap();
|
||||
|
||||
timer.set_timeout(Duration::from_millis(400), "hello");
|
||||
|
||||
let ms = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
assert_eq!(num, 1);
|
||||
let event = events.iter().next().unwrap();
|
||||
assert_eq!(Token(0), event.token());
|
||||
assert_eq!(Ready::readable(), event.readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(400, ms), "actual={:?}", ms);
|
||||
|
||||
let ms = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
assert_eq!(num, 1);
|
||||
let event = events.iter().next().unwrap();
|
||||
assert_eq!(Token(0), event.token());
|
||||
assert_eq!(Ready::readable(), event.readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(0, ms), "actual={:?}", ms);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edge_oneshot_triggered() {
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut timer = Timer::default();
|
||||
|
||||
poll.register(
|
||||
&timer,
|
||||
Token(0),
|
||||
Ready::readable(),
|
||||
PollOpt::edge() | PollOpt::oneshot(),
|
||||
).unwrap();
|
||||
|
||||
timer.set_timeout(Duration::from_millis(200), "hello");
|
||||
|
||||
let ms = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
assert_eq!(num, 1);
|
||||
});
|
||||
|
||||
assert!(is_about(200, ms), "actual={:?}", ms);
|
||||
|
||||
let ms = elapsed(|| {
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300)))
|
||||
.unwrap();
|
||||
assert_eq!(num, 0);
|
||||
});
|
||||
|
||||
assert!(is_about(300, ms), "actual={:?}", ms);
|
||||
|
||||
poll.reregister(
|
||||
&timer,
|
||||
Token(0),
|
||||
Ready::readable(),
|
||||
PollOpt::edge() | PollOpt::oneshot(),
|
||||
).unwrap();
|
||||
|
||||
let ms = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
assert_eq!(num, 1);
|
||||
});
|
||||
|
||||
assert!(is_about(0, ms));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cancel_timeout() {
|
||||
use std::time::Instant;
|
||||
|
||||
let mut timer: Timer<u32> = Default::default();
|
||||
let timeout = timer.set_timeout(Duration::from_millis(200), 1);
|
||||
timer.cancel_timeout(&timeout);
|
||||
|
||||
let poll = Poll::new().unwrap();
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge())
|
||||
.unwrap();
|
||||
|
||||
let mut events = Events::with_capacity(16);
|
||||
|
||||
let now = Instant::now();
|
||||
let dur = Duration::from_millis(500);
|
||||
let mut i = 0;
|
||||
|
||||
while Instant::now() - now < dur {
|
||||
if i > 10 {
|
||||
panic!("iterated too many times");
|
||||
}
|
||||
|
||||
i += 1;
|
||||
|
||||
let elapsed = Instant::now() - now;
|
||||
|
||||
poll.poll(&mut events, Some(dur - elapsed)).unwrap();
|
||||
|
||||
while let Some(_) = timer.poll() {
|
||||
panic!("did not expect to receive timeout");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn elapsed<F: FnMut()>(mut f: F) -> u64 {
|
||||
use std::time::Instant;
|
||||
|
||||
let now = Instant::now();
|
||||
|
||||
f();
|
||||
|
||||
let elapsed = now.elapsed();
|
||||
elapsed.as_secs() * 1000 + u64::from(elapsed.subsec_nanos() / 1_000_000)
|
||||
}
|
||||
|
||||
fn is_about(expect: u64, val: u64) -> bool {
|
||||
const WINDOW: i64 = 200;
|
||||
|
||||
((expect as i64) - (val as i64)).abs() <= WINDOW
|
||||
}
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,8 +1,3 @@
|
|||
# 0.6.16 (September 5, 2018)
|
||||
|
||||
* Add EPOLLPRI readiness to UnixReady on supported platforms (#867)
|
||||
* Reduce spurious awaken calls (#875)
|
||||
|
||||
# 0.6.15 (July 3, 2018)
|
||||
|
||||
* Implement `Evented` for containers (#840).
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
|
||||
[package]
|
||||
name = "mio"
|
||||
version = "0.6.16"
|
||||
version = "0.6.15"
|
||||
authors = ["Carl Lerche <me@carllerche.com>"]
|
||||
exclude = [".gitignore", ".travis.yml", "deploy.sh"]
|
||||
description = "Lightweight non-blocking IO"
|
||||
homepage = "https://github.com/carllerche/mio"
|
||||
documentation = "https://docs.rs/mio/0.6.16/mio/"
|
||||
documentation = "https://docs.rs/mio"
|
||||
readme = "README.md"
|
||||
keywords = ["io", "async", "non-blocking"]
|
||||
categories = ["asynchronous"]
|
||||
|
@ -31,7 +31,7 @@ path = "test/mod.rs"
|
|||
version = "0.1.1"
|
||||
|
||||
[dependencies.lazycell]
|
||||
version = "1"
|
||||
version = "0.6.0"
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4"
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// This is a script to deploy and execute a binary on an iOS simulator.
|
||||
// The primary use of this is to be able to run unit tests on the simulator and
|
||||
// retrieve the results.
|
||||
//
|
||||
// To do this through Cargo instead, use Dinghy
|
||||
// (https://github.com/snipsco/dinghy): cargo dinghy install, then cargo dinghy
|
||||
// test.
|
||||
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::thread;
|
||||
use std::process::{self, Command, Stdio};
|
||||
|
||||
macro_rules! t {
|
||||
($e:expr) => (match $e {
|
||||
Ok(e) => e,
|
||||
Err(e) => panic!("{} failed with: {}", stringify!($e), e),
|
||||
})
|
||||
}
|
||||
|
||||
// Step one: Wrap as an app
|
||||
fn package_as_simulator_app(crate_name: &str, test_binary_path: &Path) {
|
||||
println!("Packaging simulator app");
|
||||
drop(fs::remove_dir_all("ios_simulator_app"));
|
||||
t!(fs::create_dir("ios_simulator_app"));
|
||||
t!(fs::copy(test_binary_path,
|
||||
Path::new("ios_simulator_app").join(crate_name)));
|
||||
|
||||
let mut f = t!(File::create("ios_simulator_app/Info.plist"));
|
||||
t!(f.write_all(format!(r#"
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC
|
||||
"-//Apple//DTD PLIST 1.0//EN"
|
||||
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>{}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.rust.unittests</string>
|
||||
</dict>
|
||||
</plist>
|
||||
"#, crate_name).as_bytes()));
|
||||
}
|
||||
|
||||
// Step two: Start the iOS simulator
|
||||
fn start_simulator() {
|
||||
println!("Looking for iOS simulator");
|
||||
let output = t!(Command::new("xcrun").arg("simctl").arg("list").output());
|
||||
assert!(output.status.success());
|
||||
let mut simulator_exists = false;
|
||||
let mut simulator_booted = false;
|
||||
let mut found_rust_sim = false;
|
||||
let stdout = t!(String::from_utf8(output.stdout));
|
||||
for line in stdout.lines() {
|
||||
if line.contains("rust_ios") {
|
||||
if found_rust_sim {
|
||||
panic!("Duplicate rust_ios simulators found. Please \
|
||||
double-check xcrun simctl list.");
|
||||
}
|
||||
simulator_exists = true;
|
||||
simulator_booted = line.contains("(Booted)");
|
||||
found_rust_sim = true;
|
||||
}
|
||||
}
|
||||
|
||||
if simulator_exists == false {
|
||||
println!("Creating iOS simulator");
|
||||
Command::new("xcrun")
|
||||
.arg("simctl")
|
||||
.arg("create")
|
||||
.arg("rust_ios")
|
||||
.arg("com.apple.CoreSimulator.SimDeviceType.iPhone-SE")
|
||||
.arg("com.apple.CoreSimulator.SimRuntime.iOS-10-2")
|
||||
.check_status();
|
||||
} else if simulator_booted == true {
|
||||
println!("Shutting down already-booted simulator");
|
||||
Command::new("xcrun")
|
||||
.arg("simctl")
|
||||
.arg("shutdown")
|
||||
.arg("rust_ios")
|
||||
.check_status();
|
||||
}
|
||||
|
||||
println!("Starting iOS simulator");
|
||||
// We can't uninstall the app (if present) as that will hang if the
|
||||
// simulator isn't completely booted; just erase the simulator instead.
|
||||
Command::new("xcrun").arg("simctl").arg("erase").arg("rust_ios").check_status();
|
||||
Command::new("xcrun").arg("simctl").arg("boot").arg("rust_ios").check_status();
|
||||
}
|
||||
|
||||
// Step three: Install the app
|
||||
fn install_app_to_simulator() {
|
||||
println!("Installing app to simulator");
|
||||
Command::new("xcrun")
|
||||
.arg("simctl")
|
||||
.arg("install")
|
||||
.arg("booted")
|
||||
.arg("ios_simulator_app/")
|
||||
.check_status();
|
||||
}
|
||||
|
||||
// Step four: Run the app
|
||||
fn run_app_on_simulator() {
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
println!("Running app");
|
||||
let mut child = t!(Command::new("xcrun")
|
||||
.arg("simctl")
|
||||
.arg("launch")
|
||||
.arg("--console")
|
||||
.arg("booted")
|
||||
.arg("com.rust.unittests")
|
||||
.arg("--color")
|
||||
.arg("never")
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn());
|
||||
|
||||
let stdout = child.stdout.take().unwrap();
|
||||
let stderr = child.stderr.take().unwrap();
|
||||
|
||||
let th = thread::spawn(move || {
|
||||
let mut out = vec![];
|
||||
|
||||
for b in stdout.bytes() {
|
||||
let b = b.unwrap();
|
||||
out.push(b);
|
||||
let out = [b];
|
||||
io::stdout().write(&out[..]).unwrap();
|
||||
}
|
||||
|
||||
out
|
||||
});
|
||||
|
||||
thread::spawn(move || {
|
||||
for b in stderr.bytes() {
|
||||
let out = [b.unwrap()];
|
||||
io::stderr().write(&out[..]).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
println!("Waiting for cmd to finish");
|
||||
child.wait().unwrap();
|
||||
|
||||
println!("Waiting for stdout");
|
||||
let stdout = th.join().unwrap();
|
||||
let stdout = String::from_utf8_lossy(&stdout);
|
||||
let passed = stdout.lines()
|
||||
.find(|l| l.contains("test result"))
|
||||
.map(|l| l.contains(" 0 failed"))
|
||||
.unwrap_or(false);
|
||||
|
||||
println!("Shutting down simulator");
|
||||
Command::new("xcrun")
|
||||
.arg("simctl")
|
||||
.arg("shutdown")
|
||||
.arg("rust_ios")
|
||||
.check_status();
|
||||
if !passed {
|
||||
panic!("tests didn't pass");
|
||||
}
|
||||
}
|
||||
|
||||
trait CheckStatus {
|
||||
fn check_status(&mut self);
|
||||
}
|
||||
|
||||
impl CheckStatus for Command {
|
||||
fn check_status(&mut self) {
|
||||
println!("\trunning: {:?}", self);
|
||||
assert!(t!(self.status()).success());
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() != 2 {
|
||||
println!("Usage: {} <executable>", args[0]);
|
||||
process::exit(-1);
|
||||
}
|
||||
|
||||
let test_binary_path = Path::new(&args[1]);
|
||||
let crate_name = test_binary_path.file_name().unwrap();
|
||||
|
||||
package_as_simulator_app(crate_name.to_str().unwrap(), test_binary_path);
|
||||
start_simulator();
|
||||
install_app_to_simulator();
|
||||
run_app_on_simulator();
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Builds and runs tests for a particular target passed as an argument to this
|
||||
# script.
|
||||
|
||||
set -ex
|
||||
|
||||
TARGET=$1
|
||||
|
||||
|
||||
case "$TARGET" in
|
||||
*-apple-ios)
|
||||
# Download the iOS test harness
|
||||
curl -vv -L https://github.com/carllerche/ios-test-harness/releases/download/v0.1.0/libiosharness-$TARGET.a > libiosharness.a;
|
||||
|
||||
# Build the test
|
||||
cargo rustc --test test --target $TARGET -- \
|
||||
-L . \
|
||||
-C link-args="-mios-simulator-version-min=7.0 -e _ios_main -liosharness";
|
||||
|
||||
|
||||
# Find the file to run
|
||||
TEST_FILE="$(find $TARGET/debug -maxdepth 1 -type f -name test-* | head -1)";
|
||||
|
||||
rustc -O ./ci/ios/deploy_and_run_on_ios_simulator.rs;
|
||||
./deploy_and_run_on_ios_simulator $TEST_FILE;
|
||||
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "unsupported target $TARGET";
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
|
@ -718,8 +718,6 @@ impl Ready {
|
|||
/// let ready = Ready::empty();
|
||||
/// assert!(ready.is_empty());
|
||||
/// ```
|
||||
///
|
||||
/// [`Poll`]: struct.Poll.html
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
*self == Ready::empty()
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
#![doc(html_root_url = "https://docs.rs/mio/0.6.16")]
|
||||
#![deny(missing_docs, missing_debug_implementations)]
|
||||
#![cfg_attr(test, deny(warnings))]
|
||||
|
||||
//! A fast, low-level IO library for Rust focusing on non-blocking APIs, event
|
||||
//! notification, and other useful utilities for building high performance IO
|
||||
//! apps.
|
||||
|
@ -94,6 +90,11 @@
|
|||
//!
|
||||
//! ```
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/mio/0.6.15")]
|
||||
#![crate_name = "mio"]
|
||||
|
||||
#![deny(warnings, missing_docs, missing_debug_implementations)]
|
||||
|
||||
extern crate lazycell;
|
||||
extern crate net2;
|
||||
extern crate iovec;
|
||||
|
|
|
@ -695,8 +695,8 @@ impl Poll {
|
|||
/// readiness. `Poll` will only return readiness events for operations
|
||||
/// specified by this argument.
|
||||
///
|
||||
/// If a socket is registered with readable interest and the socket becomes
|
||||
/// writable, no event will be returned from [`poll`].
|
||||
/// If a socket is registered with [`readable`] interest and the socket
|
||||
/// becomes writable, no event will be returned from [`poll`].
|
||||
///
|
||||
/// The readiness interest for an `Evented` handle can be changed at any
|
||||
/// time by calling [`reregister`].
|
||||
|
@ -860,7 +860,7 @@ impl Poll {
|
|||
///
|
||||
/// When an `Evented` handle is deregistered, the `Poll` instance will
|
||||
/// no longer monitor it for readiness state changes. Unlike disabling
|
||||
/// handles with oneshot, deregistering clears up any internal resources
|
||||
/// handles with [`oneshot`], deregistering clears up any internal resources
|
||||
/// needed to track the handle.
|
||||
///
|
||||
/// A handle can be passed back to `register` after it has been
|
||||
|
@ -1157,8 +1157,6 @@ impl Poll {
|
|||
if timeout == Some(Duration::from_millis(0)) {
|
||||
// If blocking is not requested, then there is no need to prepare
|
||||
// the queue for sleep
|
||||
//
|
||||
// The sleep_marker should be removed by readiness_queue.poll().
|
||||
} else if self.readiness_queue.prepare_for_sleep() {
|
||||
// The readiness queue is empty. The call to `prepare_for_sleep`
|
||||
// inserts `sleep_marker` into the queue. This signals to any
|
||||
|
@ -2118,13 +2116,6 @@ impl ReadinessQueue {
|
|||
// loop where `Poll::poll` will keep dequeuing nodes it enqueues.
|
||||
let mut until = ptr::null_mut();
|
||||
|
||||
if dst.len() == dst.capacity() {
|
||||
// If `dst` is already full, the readiness queue won't be drained.
|
||||
// This might result in `sleep_marker` staying in the queue and
|
||||
// unecessary pipe writes occuring.
|
||||
self.inner.clear_sleep_marker();
|
||||
}
|
||||
|
||||
'outer:
|
||||
while dst.len() < dst.capacity() {
|
||||
// Dequeue a node. If the queue is in an inconsistent state, then
|
||||
|
@ -2362,37 +2353,6 @@ impl ReadinessQueueInner {
|
|||
}
|
||||
}
|
||||
|
||||
fn clear_sleep_marker(&self) {
|
||||
let end_marker = self.end_marker();
|
||||
let sleep_marker = self.sleep_marker();
|
||||
|
||||
unsafe {
|
||||
let tail = *self.tail_readiness.get();
|
||||
|
||||
if tail != self.sleep_marker() {
|
||||
return;
|
||||
}
|
||||
|
||||
// The empty markeer is *not* currently in the readiness queue
|
||||
// (since the sleep markeris).
|
||||
self.end_marker.next_readiness.store(ptr::null_mut(), Relaxed);
|
||||
|
||||
let actual = self.head_readiness.compare_and_swap(
|
||||
sleep_marker, end_marker, AcqRel);
|
||||
|
||||
debug_assert!(actual != end_marker);
|
||||
|
||||
if actual != sleep_marker {
|
||||
// The readiness queue is not empty, we cannot remove the sleep
|
||||
// markeer
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the tail pointer.
|
||||
*self.tail_readiness.get() = end_marker;
|
||||
}
|
||||
}
|
||||
|
||||
/// Must only be called in `poll` or `drop`
|
||||
unsafe fn dequeue_node(&self, until: *mut ReadinessNode) -> Dequeue {
|
||||
// This is the 1024cores.net intrusive MPSC queue [1] "pop" function
|
||||
|
@ -2402,10 +2362,6 @@ impl ReadinessQueueInner {
|
|||
|
||||
if tail == self.end_marker() || tail == self.sleep_marker() || tail == self.closed_marker() {
|
||||
if next.is_null() {
|
||||
// Make sure the sleep marker is removed (as we are no longer
|
||||
// sleeping
|
||||
self.clear_sleep_marker();
|
||||
|
||||
return Dequeue::Empty;
|
||||
}
|
||||
|
||||
|
|
|
@ -145,11 +145,6 @@ fn ioevent_to_epoll(interest: Ready, opts: PollOpt) -> u32 {
|
|||
kind |= EPOLLRDHUP;
|
||||
}
|
||||
|
||||
|
||||
if UnixReady::from(interest).is_priority() {
|
||||
kind |= EPOLLPRI;
|
||||
}
|
||||
|
||||
if opts.is_edge() {
|
||||
kind |= EPOLLET;
|
||||
}
|
||||
|
@ -211,14 +206,10 @@ impl Events {
|
|||
let epoll = event.events as c_int;
|
||||
let mut kind = Ready::empty();
|
||||
|
||||
if (epoll & EPOLLIN) != 0 {
|
||||
if (epoll & EPOLLIN) != 0 || (epoll & EPOLLPRI) != 0 {
|
||||
kind = kind | Ready::readable();
|
||||
}
|
||||
|
||||
if (epoll & EPOLLPRI) != 0 {
|
||||
kind = kind | Ready::readable() | UnixReady::priority();
|
||||
}
|
||||
|
||||
if (epoll & EPOLLOUT) != 0 {
|
||||
kind = kind | Ready::writable();
|
||||
}
|
||||
|
|
|
@ -109,11 +109,6 @@ const LIO: usize = 0b100000;
|
|||
#[cfg(not(any(target_os = "freebsd")))]
|
||||
const LIO: usize = 0b000000;
|
||||
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android", target_os = "solaris"))]
|
||||
const PRI: usize = ::libc::EPOLLPRI as usize;
|
||||
|
||||
|
||||
// Export to support `Ready::all`
|
||||
pub const READY_ALL: usize = ERROR | HUP | AIO | LIO;
|
||||
|
||||
|
@ -224,28 +219,6 @@ impl UnixReady {
|
|||
UnixReady(ready_from_usize(LIO))
|
||||
}
|
||||
|
||||
/// Returns a `Ready` representing priority (`EPOLLPRI`) readiness
|
||||
///
|
||||
/// See [`Poll`] for more documentation on polling.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use mio::unix::UnixReady;
|
||||
///
|
||||
/// let ready = UnixReady::priority();
|
||||
///
|
||||
/// assert!(ready.is_priority());
|
||||
/// ```
|
||||
///
|
||||
/// [`Poll`]: struct.Poll.html
|
||||
#[inline]
|
||||
#[cfg(any(target_os = "linux",
|
||||
target_os = "android", target_os = "solaris"))]
|
||||
pub fn priority() -> UnixReady {
|
||||
UnixReady(ready_from_usize(PRI))
|
||||
}
|
||||
|
||||
/// Returns true if `Ready` contains AIO readiness
|
||||
///
|
||||
/// See [`Poll`] for more documentation on polling.
|
||||
|
@ -350,28 +323,6 @@ impl UnixReady {
|
|||
pub fn is_lio(&self) -> bool {
|
||||
self.contains(ready_from_usize(LIO))
|
||||
}
|
||||
|
||||
/// Returns true if `Ready` contains priority (`EPOLLPRI`) readiness
|
||||
///
|
||||
/// See [`Poll`] for more documentation on polling.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use mio::unix::UnixReady;
|
||||
///
|
||||
/// let ready = UnixReady::priority();
|
||||
///
|
||||
/// assert!(ready.is_priority());
|
||||
/// ```
|
||||
///
|
||||
/// [`Poll`]: struct.Poll.html
|
||||
#[inline]
|
||||
#[cfg(any(target_os = "linux",
|
||||
target_os = "android", target_os = "solaris"))]
|
||||
pub fn is_priority(&self) -> bool {
|
||||
self.contains(ready_from_usize(PRI))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Ready> for UnixReady {
|
||||
|
@ -457,11 +408,7 @@ impl fmt::Debug for UnixReady {
|
|||
(UnixReady::error(), "Error"),
|
||||
(UnixReady::hup(), "Hup"),
|
||||
#[allow(deprecated)]
|
||||
(UnixReady::aio(), "Aio"),
|
||||
#[cfg(any(target_os = "linux",
|
||||
target_os = "android", target_os = "solaris"))]
|
||||
(UnixReady::priority(), "Priority"),
|
||||
];
|
||||
(UnixReady::aio(), "Aio")];
|
||||
|
||||
for &(flag, msg) in &flags {
|
||||
if self.contains(flag) {
|
||||
|
|
|
@ -45,6 +45,9 @@ mod test_tick;
|
|||
// platforms that were supported from before the features were deprecated
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
#[cfg(feature = "with-deprecated")]
|
||||
mod test_timer;
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
#[cfg(feature = "with-deprecated")]
|
||||
mod test_battery;
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||
|
|
|
@ -0,0 +1,433 @@
|
|||
use {sleep_ms, TryRead, TryWrite};
|
||||
use mio::*;
|
||||
use mio::deprecated::{EventLoop, Handler};
|
||||
use mio::timer::{Timer};
|
||||
|
||||
use mio::net::{TcpListener, TcpStream};
|
||||
use bytes::{Buf, ByteBuf, SliceBuf};
|
||||
use localhost;
|
||||
use std::time::Duration;
|
||||
|
||||
use self::TestState::{Initial, AfterRead};
|
||||
|
||||
#[test]
|
||||
fn test_basic_timer_without_poll() {
|
||||
let mut timer = Timer::default();
|
||||
|
||||
// Set the timeout
|
||||
timer.set_timeout(Duration::from_millis(200), "hello").unwrap();
|
||||
|
||||
// Nothing when polled immediately
|
||||
assert!(timer.poll().is_none());
|
||||
|
||||
// Wait for the timeout
|
||||
sleep_ms(200);
|
||||
|
||||
assert_eq!(Some("hello"), timer.poll());
|
||||
assert!(timer.poll().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic_timer_with_poll_edge_set_timeout_after_register() {
|
||||
let _ = ::env_logger::init();
|
||||
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut timer = Timer::default();
|
||||
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
|
||||
timer.set_timeout(Duration::from_millis(200), "hello").unwrap();
|
||||
|
||||
let elapsed = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
|
||||
assert_eq!(num, 1);
|
||||
assert_eq!(Token(0), events.get(0).unwrap().token());
|
||||
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(200, elapsed), "actual={:?}", elapsed);
|
||||
assert_eq!("hello", timer.poll().unwrap());
|
||||
assert_eq!(None, timer.poll());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic_timer_with_poll_edge_set_timeout_before_register() {
|
||||
let _ = ::env_logger::init();
|
||||
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut timer = Timer::default();
|
||||
|
||||
timer.set_timeout(Duration::from_millis(200), "hello").unwrap();
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
|
||||
|
||||
let elapsed = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
|
||||
assert_eq!(num, 1);
|
||||
assert_eq!(Token(0), events.get(0).unwrap().token());
|
||||
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(200, elapsed), "actual={:?}", elapsed);
|
||||
assert_eq!("hello", timer.poll().unwrap());
|
||||
assert_eq!(None, timer.poll());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_setting_later_timeout_then_earlier_one() {
|
||||
let _ = ::env_logger::init();
|
||||
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut timer = Timer::default();
|
||||
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
|
||||
|
||||
timer.set_timeout(Duration::from_millis(600), "hello").unwrap();
|
||||
timer.set_timeout(Duration::from_millis(200), "world").unwrap();
|
||||
|
||||
let elapsed = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
|
||||
assert_eq!(num, 1);
|
||||
assert_eq!(Token(0), events.get(0).unwrap().token());
|
||||
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(200, elapsed), "actual={:?}", elapsed);
|
||||
assert_eq!("world", timer.poll().unwrap());
|
||||
assert_eq!(None, timer.poll());
|
||||
|
||||
let elapsed = self::elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
|
||||
assert_eq!(num, 1);
|
||||
assert_eq!(Token(0), events.get(0).unwrap().token());
|
||||
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(400, elapsed), "actual={:?}", elapsed);
|
||||
assert_eq!("hello", timer.poll().unwrap());
|
||||
assert_eq!(None, timer.poll());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_with_looping_wheel() {
|
||||
let _ = ::env_logger::init();
|
||||
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut timer = timer::Builder::default()
|
||||
.num_slots(2)
|
||||
.build();
|
||||
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
|
||||
|
||||
const TOKENS: &'static [ &'static str ] = &[ "hello", "world", "some", "thing" ];
|
||||
|
||||
for (i, msg) in TOKENS.iter().enumerate() {
|
||||
timer.set_timeout(Duration::from_millis(500 * (i as u64 + 1)), msg).unwrap();
|
||||
}
|
||||
|
||||
for msg in TOKENS {
|
||||
let elapsed = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
|
||||
assert_eq!(num, 1);
|
||||
assert_eq!(Token(0), events.get(0).unwrap().token());
|
||||
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(500, elapsed), "actual={:?}; msg={:?}", elapsed, msg);
|
||||
assert_eq!(Some(msg), timer.poll());
|
||||
assert_eq!(None, timer.poll());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edge_without_polling() {
|
||||
let _ = ::env_logger::init();
|
||||
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut timer = Timer::default();
|
||||
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
|
||||
|
||||
timer.set_timeout(Duration::from_millis(400), "hello").unwrap();
|
||||
|
||||
let ms = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
assert_eq!(num, 1);
|
||||
assert_eq!(Token(0), events.get(0).unwrap().token());
|
||||
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(400, ms), "actual={:?}", ms);
|
||||
|
||||
let ms = elapsed(|| {
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300))).unwrap();
|
||||
assert_eq!(num, 0);
|
||||
});
|
||||
|
||||
assert!(is_about(300, ms), "actual={:?}", ms);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_level_triggered() {
|
||||
let _ = ::env_logger::init();
|
||||
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut timer = Timer::default();
|
||||
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::level()).unwrap();
|
||||
|
||||
timer.set_timeout(Duration::from_millis(400), "hello").unwrap();
|
||||
|
||||
let ms = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
assert_eq!(num, 1);
|
||||
assert_eq!(Token(0), events.get(0).unwrap().token());
|
||||
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(400, ms), "actual={:?}", ms);
|
||||
|
||||
let ms = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
assert_eq!(num, 1);
|
||||
assert_eq!(Token(0), events.get(0).unwrap().token());
|
||||
assert_eq!(Ready::readable(), events.get(0).unwrap().readiness());
|
||||
});
|
||||
|
||||
assert!(is_about(0, ms), "actual={:?}", ms);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edge_oneshot_triggered() {
|
||||
let _ = ::env_logger::init();
|
||||
|
||||
let poll = Poll::new().unwrap();
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut timer = Timer::default();
|
||||
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();
|
||||
|
||||
timer.set_timeout(Duration::from_millis(200), "hello").unwrap();
|
||||
|
||||
let ms = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
assert_eq!(num, 1);
|
||||
});
|
||||
|
||||
assert!(is_about(200, ms), "actual={:?}", ms);
|
||||
|
||||
let ms = elapsed(|| {
|
||||
let num = poll.poll(&mut events, Some(Duration::from_millis(300))).unwrap();
|
||||
assert_eq!(num, 0);
|
||||
});
|
||||
|
||||
assert!(is_about(300, ms), "actual={:?}", ms);
|
||||
|
||||
poll.reregister(&timer, Token(0), Ready::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();
|
||||
|
||||
let ms = elapsed(|| {
|
||||
let num = poll.poll(&mut events, None).unwrap();
|
||||
assert_eq!(num, 1);
|
||||
});
|
||||
|
||||
assert!(is_about(0, ms));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cancel_timeout() {
|
||||
use std::time::Instant;
|
||||
|
||||
let _ = ::env_logger::init();
|
||||
|
||||
let mut timer: Timer<u32> = Default::default();
|
||||
let timeout = timer.set_timeout(Duration::from_millis(200), 1).unwrap();
|
||||
timer.cancel_timeout(&timeout);
|
||||
|
||||
let poll = Poll::new().unwrap();
|
||||
poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
|
||||
|
||||
let mut events = Events::with_capacity(16);
|
||||
|
||||
let now = Instant::now();
|
||||
let dur = Duration::from_millis(500);
|
||||
let mut i = 0;
|
||||
|
||||
while Instant::now() - now < dur {
|
||||
if i > 10 {
|
||||
panic!("iterated too many times");
|
||||
}
|
||||
|
||||
i += 1;
|
||||
|
||||
let elapsed = Instant::now() - now;
|
||||
|
||||
poll.poll(&mut events, Some(dur - elapsed)).unwrap();
|
||||
|
||||
while let Some(_) = timer.poll() {
|
||||
panic!("did not expect to receive timeout");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn elapsed<F: FnMut()>(mut f: F) -> u64 {
|
||||
use std::time::Instant;
|
||||
|
||||
let now = Instant::now();
|
||||
|
||||
f();
|
||||
|
||||
let elapsed = now.elapsed();
|
||||
elapsed.as_secs() * 1000 + (elapsed.subsec_nanos() / 1_000_000) as u64
|
||||
}
|
||||
|
||||
fn is_about(expect: u64, val: u64) -> bool {
|
||||
const WINDOW: i64 = 200;
|
||||
|
||||
((expect as i64) - (val as i64)).abs() <= WINDOW
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ===== OLD TIMER =====
|
||||
*
|
||||
*/
|
||||
|
||||
const SERVER: Token = Token(0);
|
||||
const CLIENT: Token = Token(1);
|
||||
const CONN: Token = Token(2);
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum TestState {
|
||||
Initial,
|
||||
AfterRead,
|
||||
}
|
||||
|
||||
struct TestHandler {
|
||||
srv: TcpListener,
|
||||
cli: TcpStream,
|
||||
state: TestState
|
||||
}
|
||||
|
||||
impl TestHandler {
|
||||
fn new(srv: TcpListener, cli: TcpStream) -> TestHandler {
|
||||
TestHandler {
|
||||
srv: srv,
|
||||
cli: cli,
|
||||
state: Initial
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_read(&mut self, event_loop: &mut EventLoop<TestHandler>,
|
||||
tok: Token, _events: Ready) {
|
||||
match tok {
|
||||
SERVER => {
|
||||
debug!("server connection ready for accept");
|
||||
let conn = self.srv.accept().unwrap().0;
|
||||
event_loop.register(&conn, CONN, Ready::readable() | Ready::writable(),
|
||||
PollOpt::edge()).unwrap();
|
||||
event_loop.timeout(conn, Duration::from_millis(200)).unwrap();
|
||||
|
||||
event_loop.reregister(&self.srv, SERVER, Ready::readable(),
|
||||
PollOpt::edge()).unwrap();
|
||||
}
|
||||
CLIENT => {
|
||||
debug!("client readable");
|
||||
|
||||
match self.state {
|
||||
Initial => self.state = AfterRead,
|
||||
AfterRead => {}
|
||||
}
|
||||
|
||||
let mut buf = ByteBuf::mut_with_capacity(2048);
|
||||
|
||||
match self.cli.try_read_buf(&mut buf) {
|
||||
Ok(Some(0)) => return event_loop.shutdown(),
|
||||
Ok(n) => {
|
||||
debug!("read {:?} bytes", n);
|
||||
assert!(b"zomg" == buf.flip().bytes());
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("client sock failed to read; err={:?}", e.kind());
|
||||
}
|
||||
}
|
||||
|
||||
event_loop.reregister(&self.cli, CLIENT,
|
||||
Ready::readable() | Ready::hup(),
|
||||
PollOpt::edge()).unwrap();
|
||||
}
|
||||
CONN => {}
|
||||
_ => panic!("received unknown token {:?}", tok),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_write(&mut self, event_loop: &mut EventLoop<TestHandler>,
|
||||
tok: Token, _: Ready) {
|
||||
match tok {
|
||||
SERVER => panic!("received writable for token 0"),
|
||||
CLIENT => debug!("client connected"),
|
||||
CONN => {}
|
||||
_ => panic!("received unknown token {:?}", tok),
|
||||
}
|
||||
|
||||
event_loop.reregister(&self.cli, CLIENT, Ready::readable(),
|
||||
PollOpt::edge()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler for TestHandler {
|
||||
type Timeout = TcpStream;
|
||||
type Message = ();
|
||||
|
||||
fn ready(&mut self, event_loop: &mut EventLoop<TestHandler>, tok: Token, events: Ready) {
|
||||
if events.is_readable() {
|
||||
self.handle_read(event_loop, tok, events);
|
||||
}
|
||||
|
||||
if events.is_writable() {
|
||||
self.handle_write(event_loop, tok, events);
|
||||
}
|
||||
}
|
||||
|
||||
fn timeout(&mut self, _event_loop: &mut EventLoop<TestHandler>, mut sock: TcpStream) {
|
||||
debug!("timeout handler : writing to socket");
|
||||
sock.try_write_buf(&mut SliceBuf::wrap(b"zomg")).unwrap().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_old_timer() {
|
||||
let _ = ::env_logger::init();
|
||||
|
||||
debug!("Starting TEST_TIMER");
|
||||
let mut event_loop = EventLoop::new().unwrap();
|
||||
|
||||
let addr = localhost();
|
||||
|
||||
let srv = TcpListener::bind(&addr).unwrap();
|
||||
|
||||
info!("listening for connections");
|
||||
|
||||
event_loop.register(&srv, SERVER, Ready::readable() | Ready::writable(), PollOpt::edge()).unwrap();
|
||||
|
||||
let sock = TcpStream::connect(&addr).unwrap();
|
||||
|
||||
// Connect to the server
|
||||
event_loop.register(&sock, CLIENT, Ready::readable() | Ready::writable(), PollOpt::edge()).unwrap();
|
||||
|
||||
// Init the handler
|
||||
let mut handler = TestHandler::new(srv, sock);
|
||||
// Start the event loop
|
||||
event_loop.run(&mut handler).unwrap();
|
||||
|
||||
assert!(handler.state == AfterRead, "actual={:?}", handler.state);
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{"files":{"CHANGELOG.md":"460c7dbfdf227b4c725f7da8131fd51a54d0355b3c5804c0d388c70d3c1c49ec","Cargo.toml":"7d29da51fe4bf73964b3b3dea0af88040514569e2d184c9e8eb2f1746d540fb7","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"fb8071c3bc1013107b16ebcb303f31ef614e81440f2d58a46bfb9ff1e311b792","appveyor.yml":"8796156caf7041ef2a43f7a313df21ea639de3f2563b6181bba1096b1c489f1b","benches/bench.rs":"35c4ab609f2a5f5aab6c52c257415258dc0780621b492b5a82bb12d048cab6db","benches/distributions/exponential.rs":"99cb59c013a0b6bb390d34c5649b341fc3b88ea7df0caf2470bdda8798f9fe3d","benches/distributions/gamma.rs":"3533f311e4b55d743c5b01a7eb6529c94fd97726ef6702a6372f914f5f33666b","benches/distributions/mod.rs":"0028f1cb96f61152ed5b49a4fe91227d809ef6d19035592c36032a538af7f95e","benches/distributions/normal.rs":"4e10c18cb583ccb96301ea953c8e0aa9ee3b6662060271d1b8d19ca23364dc6b","benches/generators.rs":"aaa2f1dbfb399df8323d8a5796b92add6210cd5f0f1d916895ffdd81d60f812b","benches/misc.rs":"bd2f7c5a16f0fcb59022d5aeef66ed3c94e89ebf6c06667851dd23d0b1595504","src/distributions/exponential.rs":"103c8412c8a581b71835f1c00e40f6370e7702adf9d499243933a793d132d4e7","src/distributions/gamma.rs":"7a3f85c8daad4e56e334586ddb9fc9d83df3b0699738ed681a6c41e4ed455be9","src/distributions/mod.rs":"7943c4f83721bac816f831cca3b1574b6136932f7b4927aa6101130080ba62c5","src/distributions/normal.rs":"1562b43f80e4d5f83a8deb5af18de5a18dfeeeeda11fefc577da26672b14c949","src/distributions/range.rs":"a72a538d3ec4ed23f8d632aa55fd4793c464f24a5872d04ce8095ddd5db92115","src/distributions/ziggurat_tables.rs":"4eacf94fc352c91c455a6623de6a721e53842e1690f13a5662b6a79c7fbb73de","src/jitter.rs":"befd4b84bf753c107370b5b9498ad49611c220bdae2e4be9ee4398e9fa497042","src/lib.rs":"fbdc5f56ce1a52b15c85b0aa70a555c64be8f65d9f6f90fa0a3555d7862666b4","src/os.rs":"4860f165f68b7c978b0488c75d264cd9aaf54e7e4484036736ee5c4f5b6bd78d","src/prng/chacha.rs":"558007276f9c22933d39e5b8e853f4dd9533e823ed66df8dc1f23ad6925b1d51","src/prng/isaac.rs":"a8a2ee8b38d312663308e3bdf03376e342fd91330655f39144e5bba7392b2a8e","src/prng/isaac64.rs":"f28f7596ccab910db265b42671116abb9d2039fa8a421cbc75312bd0e7715d3a","src/prng/mod.rs":"c1a73450f49e819a20942a5b591f84a08ebb5ac33aa0f65b18ac1dc9a19a3084","src/prng/xorshift.rs":"606c308747293652c868b46dc3cad847d0c3717629c04ba75681c887c7634114","src/rand_impls.rs":"e1f27077fc13d5855bb66235f8ccfb216e116337eb38424d9c30c090e112215c","src/read.rs":"bd0eb508a6b659dc578d546fc2f231484aed80c73cfe8c475e0d65c8d699a769","src/reseeding.rs":"a97b86387b87ea1adc5262ddea480fe735c9c2a86762abaace29119022ac9f6e","src/seq.rs":"76dd58af0f580aed2721c393a5c036322186dc7cb3b4abed33436620c7c49288","utils/ziggurat_tables.py":"a9fc0a2fdae9b5c798c238788f94b720c156e13fd96f2356c409aa533191eb94"},"package":"8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"}
|
|
@ -1,269 +0,0 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.4.3] - 2018-08-16
|
||||
### Fixed
|
||||
- Use correct syscall number for PowerPC (#589)
|
||||
|
||||
## [0.4.2] - 2018-01-05
|
||||
### Changed
|
||||
- Use winapi on Windows
|
||||
- Update for Fuchsia OS
|
||||
- Remove dev-dependency on `log`
|
||||
|
||||
## [0.4.1] - 2017-12-17
|
||||
### Added
|
||||
- `no_std` support
|
||||
|
||||
## [0.4.0-pre.0] - 2017-12-11
|
||||
### Added
|
||||
- `JitterRng` added as a high-quality alternative entropy source using the
|
||||
system timer
|
||||
- new `seq` module with `sample_iter`, `sample_slice`, etc.
|
||||
- WASM support via dummy implementations (fail at run-time)
|
||||
- Additional benchmarks, covering generators and new seq code
|
||||
|
||||
### Changed
|
||||
- `thread_rng` uses `JitterRng` if seeding from system time fails
|
||||
(slower but more secure than previous method)
|
||||
|
||||
### Deprecated
|
||||
- `sample` function deprecated (replaced by `sample_iter`)
|
||||
|
||||
## [0.3.18] - 2017-11-06
|
||||
### Changed
|
||||
- `thread_rng` is seeded from the system time if `OsRng` fails
|
||||
- `weak_rng` now uses `thread_rng` internally
|
||||
|
||||
|
||||
## [0.3.17] - 2017-10-07
|
||||
### Changed
|
||||
- Fuchsia: Magenta was renamed Zircon
|
||||
|
||||
## [0.3.16] - 2017-07-27
|
||||
### Added
|
||||
- Implement Debug for mote non-public types
|
||||
- implement `Rand` for (i|u)i128
|
||||
- Support for Fuchsia
|
||||
|
||||
### Changed
|
||||
- Add inline attribute to SampleRange::construct_range.
|
||||
This improves the benchmark for sample in 11% and for shuffle in 16%.
|
||||
- Use `RtlGenRandom` instead of `CryptGenRandom`
|
||||
|
||||
|
||||
## [0.3.15] - 2016-11-26
|
||||
### Added
|
||||
- Add `Rng` trait method `choose_mut`
|
||||
- Redox support
|
||||
|
||||
### Changed
|
||||
- Use `arc4rand` for `OsRng` on FreeBSD.
|
||||
- Use `arc4random(3)` for `OsRng` on OpenBSD.
|
||||
|
||||
### Fixed
|
||||
- Fix filling buffers 4 GiB or larger with `OsRng::fill_bytes` on Windows
|
||||
|
||||
|
||||
## [0.3.14] - 2016-02-13
|
||||
### Fixed
|
||||
- Inline definitions from winapi/advapi32, wich decreases build times
|
||||
|
||||
|
||||
## [0.3.13] - 2016-01-09
|
||||
### Fixed
|
||||
- Compatible with Rust 1.7.0-nightly (needed some extra type annotations)
|
||||
|
||||
|
||||
## [0.3.12] - 2015-11-09
|
||||
### Changed
|
||||
- Replaced the methods in `next_f32` and `next_f64` with the technique described
|
||||
Saito & Matsumoto at MCQMC'08. The new method should exhibit a slightly more
|
||||
uniform distribution.
|
||||
- Depend on libc 0.2
|
||||
|
||||
### Fixed
|
||||
- Fix iterator protocol issue in `rand::sample`
|
||||
|
||||
|
||||
## [0.3.11] - 2015-08-31
|
||||
### Added
|
||||
- Implement `Rand` for arrays with n <= 32
|
||||
|
||||
|
||||
## [0.3.10] - 2015-08-17
|
||||
### Added
|
||||
- Support for NaCl platforms
|
||||
|
||||
### Changed
|
||||
- Allow `Rng` to be `?Sized`, impl for `&mut R` and `Box<R>` where `R: ?Sized + Rng`
|
||||
|
||||
|
||||
## [0.3.9] - 2015-06-18
|
||||
### Changed
|
||||
- Use `winapi` for Windows API things
|
||||
|
||||
### Fixed
|
||||
- Fixed test on stable/nightly
|
||||
- Fix `getrandom` syscall number for aarch64-unknown-linux-gnu
|
||||
|
||||
|
||||
## [0.3.8] - 2015-04-23
|
||||
### Changed
|
||||
- `log` is a dev dependency
|
||||
|
||||
### Fixed
|
||||
- Fix race condition of atomics in `is_getrandom_available`
|
||||
|
||||
|
||||
## [0.3.7] - 2015-04-03
|
||||
### Fixed
|
||||
- Derive Copy/Clone changes
|
||||
|
||||
|
||||
## [0.3.6] - 2015-04-02
|
||||
### Changed
|
||||
- Move to stable Rust!
|
||||
|
||||
|
||||
## [0.3.5] - 2015-04-01
|
||||
### Fixed
|
||||
- Compatible with Rust master
|
||||
|
||||
|
||||
## [0.3.4] - 2015-03-31
|
||||
### Added
|
||||
- Implement Clone for `Weighted`
|
||||
|
||||
### Fixed
|
||||
- Compatible with Rust master
|
||||
|
||||
|
||||
## [0.3.3] - 2015-03-26
|
||||
### Fixed
|
||||
- Fix compile on Windows
|
||||
|
||||
|
||||
## [0.3.2] - 2015-03-26
|
||||
|
||||
|
||||
## [0.3.1] - 2015-03-26
|
||||
### Fixed
|
||||
- Fix compile on Windows
|
||||
|
||||
|
||||
## [0.3.0] - 2015-03-25
|
||||
### Changed
|
||||
- Update to use log version 0.3.x
|
||||
|
||||
|
||||
## [0.2.1] - 2015-03-22
|
||||
### Fixed
|
||||
- Compatible with Rust master
|
||||
- Fixed iOS compilation
|
||||
|
||||
|
||||
## [0.2.0] - 2015-03-06
|
||||
### Fixed
|
||||
- Compatible with Rust master (move from `old_io` to `std::io`)
|
||||
|
||||
|
||||
## [0.1.4] - 2015-03-04
|
||||
### Fixed
|
||||
- Compatible with Rust master (use wrapping ops)
|
||||
|
||||
|
||||
## [0.1.3] - 2015-02-20
|
||||
### Fixed
|
||||
- Compatible with Rust master
|
||||
|
||||
### Removed
|
||||
- Removed Copy inplementaions from RNGs
|
||||
|
||||
|
||||
## [0.1.2] - 2015-02-03
|
||||
### Added
|
||||
- Imported functionality from `std::rand`, including:
|
||||
- `StdRng`, `SeedableRng`, `TreadRng`, `weak_rng()`
|
||||
- `ReaderRng`: A wrapper around any Reader to treat it as an RNG.
|
||||
- Imported documentation from `std::rand`
|
||||
- Imported tests from `std::rand`
|
||||
|
||||
|
||||
## [0.1.1] - 2015-02-03
|
||||
### Added
|
||||
- Migrate to a cargo-compatible directory structure.
|
||||
|
||||
### Fixed
|
||||
- Do not use entropy during `gen_weighted_bool(1)`
|
||||
|
||||
|
||||
## [Rust 0.12.0] - 2014-10-09
|
||||
### Added
|
||||
- Impl Rand for tuples of arity 11 and 12
|
||||
- Include ChaCha pseudorandom generator
|
||||
- Add `next_f64` and `next_f32` to Rng
|
||||
- Implement Clone for PRNGs
|
||||
|
||||
### Changed
|
||||
- Rename `TaskRng` to `ThreadRng` and `task_rng` to `thread_rng` (since a
|
||||
runtime is removed from Rust).
|
||||
|
||||
### Fixed
|
||||
- Improved performance of ISAAC and ISAAC64 by 30% and 12 % respectively, by
|
||||
informing the optimiser that indexing is never out-of-bounds.
|
||||
|
||||
### Removed
|
||||
- Removed the Deprecated `choose_option`
|
||||
|
||||
|
||||
## [Rust 0.11.0] - 2014-07-02
|
||||
### Added
|
||||
- document when to use `OSRng` in cryptographic context, and explain why we use `/dev/urandom` instead of `/dev/random`
|
||||
- `Rng::gen_iter()` which will return an infinite stream of random values
|
||||
- `Rng::gen_ascii_chars()` which will return an infinite stream of random ascii characters
|
||||
|
||||
### Changed
|
||||
- Now only depends on libcore! 2adf5363f88ffe06f6d2ea5c338d1b186d47f4a1
|
||||
- Remove `Rng.choose()`, rename `Rng.choose_option()` to `.choose()`
|
||||
- Rename OSRng to OsRng
|
||||
- The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
|
||||
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
|
||||
structure now has a lifetime associated with it.
|
||||
- The `sample` method on `Rng` has been moved to a top-level function in the
|
||||
`rand` module due to its dependence on `Vec`.
|
||||
|
||||
### Removed
|
||||
- `Rng::gen_vec()` was removed. Previous behavior can be regained with
|
||||
`rng.gen_iter().take(n).collect()`
|
||||
- `Rng::gen_ascii_str()` was removed. Previous behavior can be regained with
|
||||
`rng.gen_ascii_chars().take(n).collect()`
|
||||
- {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
|
||||
relied on being able to use an OSRng for seeding, but this is no longer
|
||||
available in librand (where these types are defined). To retain the same
|
||||
functionality, these types now implement the `Rand` trait so they can be
|
||||
generated with a random seed from another random number generator. This allows
|
||||
the stdlib to use an OSRng to create seeded instances of these RNGs.
|
||||
- Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
|
||||
pretty rare in the codebase, and it allows for librand to not depend on
|
||||
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
|
||||
supported.
|
||||
- Remove a slew of old deprecated functions
|
||||
|
||||
|
||||
## [Rust 0.10] - 2014-04-03
|
||||
### Changed
|
||||
- replace `Rng.shuffle's` functionality with `.shuffle_mut`
|
||||
- bubble up IO errors when creating an OSRng
|
||||
|
||||
### Fixed
|
||||
- Use `fill()` instead of `read()`
|
||||
- Rewrite OsRng in Rust for windows
|
||||
|
||||
## [0.10-pre] - 2014-03-02
|
||||
### Added
|
||||
- Seperate `rand` out of the standard library
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "rand"
|
||||
version = "0.4.3"
|
||||
authors = ["The Rust Project Developers"]
|
||||
description = "Random number generators and other randomness functionality.\n"
|
||||
homepage = "https://github.com/rust-lang-nursery/rand"
|
||||
documentation = "https://docs.rs/rand"
|
||||
readme = "README.md"
|
||||
keywords = ["random", "rng"]
|
||||
categories = ["algorithms"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/rust-lang-nursery/rand"
|
||||
|
||||
[features]
|
||||
alloc = []
|
||||
default = ["std"]
|
||||
i128_support = []
|
||||
nightly = ["i128_support"]
|
||||
std = ["libc"]
|
||||
[target."cfg(target_os = \"fuchsia\")".dependencies.fuchsia-zircon]
|
||||
version = "0.3.2"
|
||||
[target."cfg(unix)".dependencies.libc]
|
||||
version = "0.2"
|
||||
optional = true
|
||||
[target."cfg(windows)".dependencies.winapi]
|
||||
version = "0.3"
|
||||
features = ["minwindef", "ntsecapi", "profileapi", "winnt"]
|
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -1,25 +0,0 @@
|
|||
Copyright (c) 2014 The Rust Project Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -1,139 +0,0 @@
|
|||
rand
|
||||
====
|
||||
|
||||
A Rust library for random number generators and other randomness functionality.
|
||||
|
||||
[![Build Status](https://travis-ci.org/rust-lang-nursery/rand.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rand)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/rm5c9o33k3jhchbw?svg=true)](https://ci.appveyor.com/project/alexcrichton/rand)
|
||||
|
||||
[Documentation](https://docs.rs/rand)
|
||||
|
||||
## Usage
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
rand = "0.4"
|
||||
```
|
||||
|
||||
and this to your crate root:
|
||||
|
||||
```rust
|
||||
extern crate rand;
|
||||
```
|
||||
|
||||
### Versions
|
||||
|
||||
Version `0.4`was released in December 2017. It contains almost no breaking
|
||||
changes since the `0.3` series, but nevertheless contains some significant
|
||||
new code, including a new "external" entropy source (`JitterRng`) and `no_std`
|
||||
support.
|
||||
|
||||
Version `0.5` is in development and contains significant performance
|
||||
improvements for the ISAAC random number generators.
|
||||
|
||||
## Examples
|
||||
|
||||
There is built-in support for a random number generator (RNG) associated with each thread stored in thread-local storage. This RNG can be accessed via thread_rng, or used implicitly via random. This RNG is normally randomly seeded from an operating-system source of randomness, e.g. /dev/urandom on Unix systems, and will automatically reseed itself from this source after generating 32 KiB of random data.
|
||||
|
||||
```rust
|
||||
let tuple = rand::random::<(f64, char)>();
|
||||
println!("{:?}", tuple)
|
||||
```
|
||||
|
||||
```rust
|
||||
use rand::Rng;
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
if rng.gen() { // random bool
|
||||
println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
|
||||
}
|
||||
```
|
||||
|
||||
It is also possible to use other RNG types, which have a similar interface. The following uses the "ChaCha" algorithm instead of the default.
|
||||
|
||||
```rust
|
||||
use rand::{Rng, ChaChaRng};
|
||||
|
||||
let mut rng = rand::ChaChaRng::new_unseeded();
|
||||
println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
By default, `rand` is built with all stable features available. The following
|
||||
optional features are available:
|
||||
|
||||
- `i128_support` enables support for generating `u128` and `i128` values
|
||||
- `nightly` enables all unstable features (`i128_support`)
|
||||
- `std` enabled by default; by setting "default-features = false" `no_std`
|
||||
mode is activated; this removes features depending on `std` functionality:
|
||||
|
||||
- `OsRng` is entirely unavailable
|
||||
- `JitterRng` code is still present, but a nanosecond timer must be
|
||||
provided via `JitterRng::new_with_timer`
|
||||
- Since no external entropy is available, it is not possible to create
|
||||
generators with fresh seeds (user must provide entropy)
|
||||
- `thread_rng`, `weak_rng` and `random` are all disabled
|
||||
- exponential, normal and gamma type distributions are unavailable
|
||||
since `exp` and `log` functions are not provided in `core`
|
||||
- any code requiring `Vec` or `Box`
|
||||
- `alloc` can be used instead of `std` to provide `Vec` and `Box`
|
||||
|
||||
## Testing
|
||||
|
||||
Unfortunately, `cargo test` does not test everything. The following tests are
|
||||
recommended:
|
||||
|
||||
```
|
||||
# Basic tests for rand and sub-crates
|
||||
cargo test --all
|
||||
|
||||
# Test no_std support (build only since nearly all tests require std)
|
||||
cargo build --all --no-default-features
|
||||
|
||||
# Test 128-bit support (requires nightly)
|
||||
cargo test --all --features nightly
|
||||
|
||||
# Benchmarks (requires nightly)
|
||||
cargo bench
|
||||
# or just to test the benchmark code:
|
||||
cargo test --benches
|
||||
```
|
||||
|
||||
# `derive(Rand)`
|
||||
|
||||
You can derive the `Rand` trait for your custom type via the `#[derive(Rand)]`
|
||||
directive. To use this first add this to your Cargo.toml:
|
||||
|
||||
```toml
|
||||
rand = "0.4"
|
||||
rand_derive = "0.3"
|
||||
```
|
||||
|
||||
Next in your crate:
|
||||
|
||||
```rust
|
||||
extern crate rand;
|
||||
#[macro_use]
|
||||
extern crate rand_derive;
|
||||
|
||||
#[derive(Rand, Debug)]
|
||||
struct MyStruct {
|
||||
a: i32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", rand::random::<MyStruct>());
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# License
|
||||
|
||||
`rand` is primarily distributed under the terms of both the MIT
|
||||
license and the Apache License (Version 2.0).
|
||||
|
||||
See LICENSE-APACHE, and LICENSE-MIT for details.
|
|
@ -1,133 +0,0 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate rand;
|
||||
|
||||
const RAND_BENCH_N: u64 = 1000;
|
||||
const BYTES_LEN: usize = 1024;
|
||||
|
||||
use std::mem::size_of;
|
||||
use test::{black_box, Bencher};
|
||||
|
||||
use rand::{Rng, StdRng, OsRng, JitterRng};
|
||||
use rand::{XorShiftRng, IsaacRng, Isaac64Rng, ChaChaRng};
|
||||
|
||||
macro_rules! gen_bytes {
|
||||
($fnn:ident, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng: $gen = OsRng::new().unwrap().gen();
|
||||
let mut buf = [0u8; BYTES_LEN];
|
||||
b.iter(|| {
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
rng.fill_bytes(&mut buf);
|
||||
black_box(buf);
|
||||
}
|
||||
});
|
||||
b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! gen_bytes_new {
|
||||
($fnn:ident, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = $gen::new().unwrap();
|
||||
let mut buf = [0u8; BYTES_LEN];
|
||||
b.iter(|| {
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
rng.fill_bytes(&mut buf);
|
||||
black_box(buf);
|
||||
}
|
||||
});
|
||||
b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gen_bytes!(gen_bytes_xorshift, XorShiftRng);
|
||||
gen_bytes!(gen_bytes_isaac, IsaacRng);
|
||||
gen_bytes!(gen_bytes_isaac64, Isaac64Rng);
|
||||
gen_bytes!(gen_bytes_chacha, ChaChaRng);
|
||||
gen_bytes_new!(gen_bytes_std, StdRng);
|
||||
gen_bytes_new!(gen_bytes_os, OsRng);
|
||||
|
||||
|
||||
macro_rules! gen_uint {
|
||||
($fnn:ident, $ty:ty, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng: $gen = OsRng::new().unwrap().gen();
|
||||
b.iter(|| {
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
black_box(rng.gen::<$ty>());
|
||||
}
|
||||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! gen_uint_new {
|
||||
($fnn:ident, $ty:ty, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = $gen::new().unwrap();
|
||||
b.iter(|| {
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
black_box(rng.gen::<$ty>());
|
||||
}
|
||||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gen_uint!(gen_u32_xorshift, u32, XorShiftRng);
|
||||
gen_uint!(gen_u32_isaac, u32, IsaacRng);
|
||||
gen_uint!(gen_u32_isaac64, u32, Isaac64Rng);
|
||||
gen_uint!(gen_u32_chacha, u32, ChaChaRng);
|
||||
gen_uint_new!(gen_u32_std, u32, StdRng);
|
||||
gen_uint_new!(gen_u32_os, u32, OsRng);
|
||||
|
||||
gen_uint!(gen_u64_xorshift, u64, XorShiftRng);
|
||||
gen_uint!(gen_u64_isaac, u64, IsaacRng);
|
||||
gen_uint!(gen_u64_isaac64, u64, Isaac64Rng);
|
||||
gen_uint!(gen_u64_chacha, u64, ChaChaRng);
|
||||
gen_uint_new!(gen_u64_std, u64, StdRng);
|
||||
gen_uint_new!(gen_u64_os, u64, OsRng);
|
||||
|
||||
#[bench]
|
||||
fn gen_u64_jitter(b: &mut Bencher) {
|
||||
let mut rng = JitterRng::new().unwrap();
|
||||
b.iter(|| {
|
||||
black_box(rng.gen::<u64>());
|
||||
});
|
||||
b.bytes = size_of::<u64>() as u64;
|
||||
}
|
||||
|
||||
macro_rules! init_gen {
|
||||
($fnn:ident, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng: XorShiftRng = OsRng::new().unwrap().gen();
|
||||
b.iter(|| {
|
||||
let r2: $gen = rng.gen();
|
||||
black_box(r2);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init_gen!(init_xorshift, XorShiftRng);
|
||||
init_gen!(init_isaac, IsaacRng);
|
||||
init_gen!(init_isaac64, Isaac64Rng);
|
||||
init_gen!(init_chacha, ChaChaRng);
|
||||
|
||||
#[bench]
|
||||
fn init_jitter(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
black_box(JitterRng::new().unwrap());
|
||||
});
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate rand;
|
||||
|
||||
use test::{black_box, Bencher};
|
||||
|
||||
use rand::{Rng, weak_rng};
|
||||
use rand::seq::*;
|
||||
|
||||
#[bench]
|
||||
fn misc_shuffle_100(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
let x : &mut [usize] = &mut [1; 100];
|
||||
b.iter(|| {
|
||||
rng.shuffle(x);
|
||||
black_box(&x);
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn misc_sample_iter_10_of_100(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
let x : &[usize] = &[1; 100];
|
||||
b.iter(|| {
|
||||
black_box(sample_iter(&mut rng, x, 10).unwrap_or_else(|e| e));
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn misc_sample_slice_10_of_100(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
let x : &[usize] = &[1; 100];
|
||||
b.iter(|| {
|
||||
black_box(sample_slice(&mut rng, x, 10));
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn misc_sample_slice_ref_10_of_100(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
let x : &[usize] = &[1; 100];
|
||||
b.iter(|| {
|
||||
black_box(sample_slice_ref(&mut rng, x, 10));
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! sample_indices {
|
||||
($name:ident, $amount:expr, $length:expr) => {
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
b.iter(|| {
|
||||
black_box(sample_indices(&mut rng, $length, $amount));
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sample_indices!(misc_sample_indices_10_of_1k, 10, 1000);
|
||||
sample_indices!(misc_sample_indices_50_of_1k, 50, 1000);
|
||||
sample_indices!(misc_sample_indices_100_of_1k, 100, 1000);
|
|
@ -1,124 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The exponential distribution.
|
||||
|
||||
use {Rng, Rand};
|
||||
use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
|
||||
|
||||
/// A wrapper around an `f64` to generate Exp(1) random numbers.
|
||||
///
|
||||
/// See `Exp` for the general exponential distribution.
|
||||
///
|
||||
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The
|
||||
/// exact description in the paper was adjusted to use tables for the
|
||||
/// exponential distribution rather than normal.
|
||||
///
|
||||
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
|
||||
/// Generate Normal Random
|
||||
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
|
||||
/// College, Oxford
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::exponential::Exp1;
|
||||
///
|
||||
/// let Exp1(x) = rand::random();
|
||||
/// println!("{}", x);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Exp1(pub f64);
|
||||
|
||||
// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
|
||||
impl Rand for Exp1 {
|
||||
#[inline]
|
||||
fn rand<R:Rng>(rng: &mut R) -> Exp1 {
|
||||
#[inline]
|
||||
fn pdf(x: f64) -> f64 {
|
||||
(-x).exp()
|
||||
}
|
||||
#[inline]
|
||||
fn zero_case<R:Rng>(rng: &mut R, _u: f64) -> f64 {
|
||||
ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln()
|
||||
}
|
||||
|
||||
Exp1(ziggurat(rng, false,
|
||||
&ziggurat_tables::ZIG_EXP_X,
|
||||
&ziggurat_tables::ZIG_EXP_F,
|
||||
pdf, zero_case))
|
||||
}
|
||||
}
|
||||
|
||||
/// The exponential distribution `Exp(lambda)`.
|
||||
///
|
||||
/// This distribution has density function: `f(x) = lambda *
|
||||
/// exp(-lambda * x)` for `x > 0`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{Exp, IndependentSample};
|
||||
///
|
||||
/// let exp = Exp::new(2.0);
|
||||
/// let v = exp.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a Exp(2) distribution", v);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Exp {
|
||||
/// `lambda` stored as `1/lambda`, since this is what we scale by.
|
||||
lambda_inverse: f64
|
||||
}
|
||||
|
||||
impl Exp {
|
||||
/// Construct a new `Exp` with the given shape parameter
|
||||
/// `lambda`. Panics if `lambda <= 0`.
|
||||
#[inline]
|
||||
pub fn new(lambda: f64) -> Exp {
|
||||
assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0");
|
||||
Exp { lambda_inverse: 1.0 / lambda }
|
||||
}
|
||||
}
|
||||
|
||||
impl Sample<f64> for Exp {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl IndependentSample<f64> for Exp {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
let Exp1(n) = rng.gen::<Exp1>();
|
||||
n * self.lambda_inverse
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use distributions::{Sample, IndependentSample};
|
||||
use super::Exp;
|
||||
|
||||
#[test]
|
||||
fn test_exp() {
|
||||
let mut exp = Exp::new(10.0);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
assert!(exp.sample(&mut rng) >= 0.0);
|
||||
assert!(exp.ind_sample(&mut rng) >= 0.0);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_exp_invalid_lambda_zero() {
|
||||
Exp::new(0.0);
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_exp_invalid_lambda_neg() {
|
||||
Exp::new(-10.0);
|
||||
}
|
||||
}
|
|
@ -1,386 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
//
|
||||
// ignore-lexer-test FIXME #15679
|
||||
|
||||
//! The Gamma and derived distributions.
|
||||
|
||||
use self::GammaRepr::*;
|
||||
use self::ChiSquaredRepr::*;
|
||||
|
||||
use {Rng, Open01};
|
||||
use super::normal::StandardNormal;
|
||||
use super::{IndependentSample, Sample, Exp};
|
||||
|
||||
/// The Gamma distribution `Gamma(shape, scale)` distribution.
|
||||
///
|
||||
/// The density function of this distribution is
|
||||
///
|
||||
/// ```text
|
||||
/// f(x) = x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k)
|
||||
/// ```
|
||||
///
|
||||
/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the
|
||||
/// scale and both `k` and `θ` are strictly positive.
|
||||
///
|
||||
/// The algorithm used is that described by Marsaglia & Tsang 2000[1],
|
||||
/// falling back to directly sampling from an Exponential for `shape
|
||||
/// == 1`, and using the boosting technique described in [1] for
|
||||
/// `shape < 1`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{IndependentSample, Gamma};
|
||||
///
|
||||
/// let gamma = Gamma::new(2.0, 5.0);
|
||||
/// let v = gamma.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a Gamma(2, 5) distribution", v);
|
||||
/// ```
|
||||
///
|
||||
/// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method
|
||||
/// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
|
||||
/// (September 2000),
|
||||
/// 363-372. DOI:[10.1145/358407.358414](http://doi.acm.org/10.1145/358407.358414)
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Gamma {
|
||||
repr: GammaRepr,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum GammaRepr {
|
||||
Large(GammaLargeShape),
|
||||
One(Exp),
|
||||
Small(GammaSmallShape)
|
||||
}
|
||||
|
||||
// These two helpers could be made public, but saving the
|
||||
// match-on-Gamma-enum branch from using them directly (e.g. if one
|
||||
// knows that the shape is always > 1) doesn't appear to be much
|
||||
// faster.
|
||||
|
||||
/// Gamma distribution where the shape parameter is less than 1.
|
||||
///
|
||||
/// Note, samples from this require a compulsory floating-point `pow`
|
||||
/// call, which makes it significantly slower than sampling from a
|
||||
/// gamma distribution where the shape parameter is greater than or
|
||||
/// equal to 1.
|
||||
///
|
||||
/// See `Gamma` for sampling from a Gamma distribution with general
|
||||
/// shape parameters.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct GammaSmallShape {
|
||||
inv_shape: f64,
|
||||
large_shape: GammaLargeShape
|
||||
}
|
||||
|
||||
/// Gamma distribution where the shape parameter is larger than 1.
|
||||
///
|
||||
/// See `Gamma` for sampling from a Gamma distribution with general
|
||||
/// shape parameters.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct GammaLargeShape {
|
||||
scale: f64,
|
||||
c: f64,
|
||||
d: f64
|
||||
}
|
||||
|
||||
impl Gamma {
|
||||
/// Construct an object representing the `Gamma(shape, scale)`
|
||||
/// distribution.
|
||||
///
|
||||
/// Panics if `shape <= 0` or `scale <= 0`.
|
||||
#[inline]
|
||||
pub fn new(shape: f64, scale: f64) -> Gamma {
|
||||
assert!(shape > 0.0, "Gamma::new called with shape <= 0");
|
||||
assert!(scale > 0.0, "Gamma::new called with scale <= 0");
|
||||
|
||||
let repr = if shape == 1.0 {
|
||||
One(Exp::new(1.0 / scale))
|
||||
} else if shape < 1.0 {
|
||||
Small(GammaSmallShape::new_raw(shape, scale))
|
||||
} else {
|
||||
Large(GammaLargeShape::new_raw(shape, scale))
|
||||
};
|
||||
Gamma { repr: repr }
|
||||
}
|
||||
}
|
||||
|
||||
impl GammaSmallShape {
|
||||
fn new_raw(shape: f64, scale: f64) -> GammaSmallShape {
|
||||
GammaSmallShape {
|
||||
inv_shape: 1. / shape,
|
||||
large_shape: GammaLargeShape::new_raw(shape + 1.0, scale)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GammaLargeShape {
|
||||
fn new_raw(shape: f64, scale: f64) -> GammaLargeShape {
|
||||
let d = shape - 1. / 3.;
|
||||
GammaLargeShape {
|
||||
scale: scale,
|
||||
c: 1. / (9. * d).sqrt(),
|
||||
d: d
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sample<f64> for Gamma {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl Sample<f64> for GammaSmallShape {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl Sample<f64> for GammaLargeShape {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
|
||||
impl IndependentSample<f64> for Gamma {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
match self.repr {
|
||||
Small(ref g) => g.ind_sample(rng),
|
||||
One(ref g) => g.ind_sample(rng),
|
||||
Large(ref g) => g.ind_sample(rng),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl IndependentSample<f64> for GammaSmallShape {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
let Open01(u) = rng.gen::<Open01<f64>>();
|
||||
|
||||
self.large_shape.ind_sample(rng) * u.powf(self.inv_shape)
|
||||
}
|
||||
}
|
||||
impl IndependentSample<f64> for GammaLargeShape {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
loop {
|
||||
let StandardNormal(x) = rng.gen::<StandardNormal>();
|
||||
let v_cbrt = 1.0 + self.c * x;
|
||||
if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0
|
||||
continue
|
||||
}
|
||||
|
||||
let v = v_cbrt * v_cbrt * v_cbrt;
|
||||
let Open01(u) = rng.gen::<Open01<f64>>();
|
||||
|
||||
let x_sqr = x * x;
|
||||
if u < 1.0 - 0.0331 * x_sqr * x_sqr ||
|
||||
u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln()) {
|
||||
return self.d * v * self.scale
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of
|
||||
/// freedom.
|
||||
///
|
||||
/// For `k > 0` integral, this distribution is the sum of the squares
|
||||
/// of `k` independent standard normal random variables. For other
|
||||
/// `k`, this uses the equivalent characterisation
|
||||
/// `χ²(k) = Gamma(k/2, 2)`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{ChiSquared, IndependentSample};
|
||||
///
|
||||
/// let chi = ChiSquared::new(11.0);
|
||||
/// let v = chi.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a χ²(11) distribution", v)
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ChiSquared {
|
||||
repr: ChiSquaredRepr,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum ChiSquaredRepr {
|
||||
// k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1,
|
||||
// e.g. when alpha = 1/2 as it would be for this case, so special-
|
||||
// casing and using the definition of N(0,1)^2 is faster.
|
||||
DoFExactlyOne,
|
||||
DoFAnythingElse(Gamma),
|
||||
}
|
||||
|
||||
impl ChiSquared {
|
||||
/// Create a new chi-squared distribution with degrees-of-freedom
|
||||
/// `k`. Panics if `k < 0`.
|
||||
pub fn new(k: f64) -> ChiSquared {
|
||||
let repr = if k == 1.0 {
|
||||
DoFExactlyOne
|
||||
} else {
|
||||
assert!(k > 0.0, "ChiSquared::new called with `k` < 0");
|
||||
DoFAnythingElse(Gamma::new(0.5 * k, 2.0))
|
||||
};
|
||||
ChiSquared { repr: repr }
|
||||
}
|
||||
}
|
||||
impl Sample<f64> for ChiSquared {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl IndependentSample<f64> for ChiSquared {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
match self.repr {
|
||||
DoFExactlyOne => {
|
||||
// k == 1 => N(0,1)^2
|
||||
let StandardNormal(norm) = rng.gen::<StandardNormal>();
|
||||
norm * norm
|
||||
}
|
||||
DoFAnythingElse(ref g) => g.ind_sample(rng)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The Fisher F distribution `F(m, n)`.
|
||||
///
|
||||
/// This distribution is equivalent to the ratio of two normalised
|
||||
/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) /
|
||||
/// (χ²(n)/n)`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{FisherF, IndependentSample};
|
||||
///
|
||||
/// let f = FisherF::new(2.0, 32.0);
|
||||
/// let v = f.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from an F(2, 32) distribution", v)
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct FisherF {
|
||||
numer: ChiSquared,
|
||||
denom: ChiSquared,
|
||||
// denom_dof / numer_dof so that this can just be a straight
|
||||
// multiplication, rather than a division.
|
||||
dof_ratio: f64,
|
||||
}
|
||||
|
||||
impl FisherF {
|
||||
/// Create a new `FisherF` distribution, with the given
|
||||
/// parameter. Panics if either `m` or `n` are not positive.
|
||||
pub fn new(m: f64, n: f64) -> FisherF {
|
||||
assert!(m > 0.0, "FisherF::new called with `m < 0`");
|
||||
assert!(n > 0.0, "FisherF::new called with `n < 0`");
|
||||
|
||||
FisherF {
|
||||
numer: ChiSquared::new(m),
|
||||
denom: ChiSquared::new(n),
|
||||
dof_ratio: n / m
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Sample<f64> for FisherF {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl IndependentSample<f64> for FisherF {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
self.numer.ind_sample(rng) / self.denom.ind_sample(rng) * self.dof_ratio
|
||||
}
|
||||
}
|
||||
|
||||
/// The Student t distribution, `t(nu)`, where `nu` is the degrees of
|
||||
/// freedom.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{StudentT, IndependentSample};
|
||||
///
|
||||
/// let t = StudentT::new(11.0);
|
||||
/// let v = t.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a t(11) distribution", v)
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct StudentT {
|
||||
chi: ChiSquared,
|
||||
dof: f64
|
||||
}
|
||||
|
||||
impl StudentT {
|
||||
/// Create a new Student t distribution with `n` degrees of
|
||||
/// freedom. Panics if `n <= 0`.
|
||||
pub fn new(n: f64) -> StudentT {
|
||||
assert!(n > 0.0, "StudentT::new called with `n <= 0`");
|
||||
StudentT {
|
||||
chi: ChiSquared::new(n),
|
||||
dof: n
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Sample<f64> for StudentT {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl IndependentSample<f64> for StudentT {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
let StandardNormal(norm) = rng.gen::<StandardNormal>();
|
||||
norm * (self.dof / self.chi.ind_sample(rng)).sqrt()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use distributions::{Sample, IndependentSample};
|
||||
use super::{ChiSquared, StudentT, FisherF};
|
||||
|
||||
#[test]
|
||||
fn test_chi_squared_one() {
|
||||
let mut chi = ChiSquared::new(1.0);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
chi.sample(&mut rng);
|
||||
chi.ind_sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_chi_squared_small() {
|
||||
let mut chi = ChiSquared::new(0.5);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
chi.sample(&mut rng);
|
||||
chi.ind_sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_chi_squared_large() {
|
||||
let mut chi = ChiSquared::new(30.0);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
chi.sample(&mut rng);
|
||||
chi.ind_sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_chi_squared_invalid_dof() {
|
||||
ChiSquared::new(-1.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f() {
|
||||
let mut f = FisherF::new(2.0, 32.0);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
f.sample(&mut rng);
|
||||
f.ind_sample(&mut rng);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_t() {
|
||||
let mut t = StudentT::new(11.0);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
t.sample(&mut rng);
|
||||
t.ind_sample(&mut rng);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,409 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Sampling from random distributions.
|
||||
//!
|
||||
//! This is a generalization of `Rand` to allow parameters to control the
|
||||
//! exact properties of the generated values, e.g. the mean and standard
|
||||
//! deviation of a normal distribution. The `Sample` trait is the most
|
||||
//! general, and allows for generating values that change some state
|
||||
//! internally. The `IndependentSample` trait is for generating values
|
||||
//! that do not need to record state.
|
||||
|
||||
use core::marker;
|
||||
|
||||
use {Rng, Rand};
|
||||
|
||||
pub use self::range::Range;
|
||||
#[cfg(feature="std")]
|
||||
pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT};
|
||||
#[cfg(feature="std")]
|
||||
pub use self::normal::{Normal, LogNormal};
|
||||
#[cfg(feature="std")]
|
||||
pub use self::exponential::Exp;
|
||||
|
||||
pub mod range;
|
||||
#[cfg(feature="std")]
|
||||
pub mod gamma;
|
||||
#[cfg(feature="std")]
|
||||
pub mod normal;
|
||||
#[cfg(feature="std")]
|
||||
pub mod exponential;
|
||||
|
||||
#[cfg(feature="std")]
|
||||
mod ziggurat_tables;
|
||||
|
||||
/// Types that can be used to create a random instance of `Support`.
|
||||
pub trait Sample<Support> {
|
||||
/// Generate a random value of `Support`, using `rng` as the
|
||||
/// source of randomness.
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> Support;
|
||||
}
|
||||
|
||||
/// `Sample`s that do not require keeping track of state.
|
||||
///
|
||||
/// Since no state is recorded, each sample is (statistically)
|
||||
/// independent of all others, assuming the `Rng` used has this
|
||||
/// property.
|
||||
// FIXME maybe having this separate is overkill (the only reason is to
|
||||
// take &self rather than &mut self)? or maybe this should be the
|
||||
// trait called `Sample` and the other should be `DependentSample`.
|
||||
pub trait IndependentSample<Support>: Sample<Support> {
|
||||
/// Generate a random value.
|
||||
fn ind_sample<R: Rng>(&self, &mut R) -> Support;
|
||||
}
|
||||
|
||||
/// A wrapper for generating types that implement `Rand` via the
|
||||
/// `Sample` & `IndependentSample` traits.
|
||||
#[derive(Debug)]
|
||||
pub struct RandSample<Sup> {
|
||||
_marker: marker::PhantomData<fn() -> Sup>,
|
||||
}
|
||||
|
||||
impl<Sup> Copy for RandSample<Sup> {}
|
||||
impl<Sup> Clone for RandSample<Sup> {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
|
||||
impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
|
||||
}
|
||||
|
||||
impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
|
||||
rng.gen()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Sup> RandSample<Sup> {
|
||||
pub fn new() -> RandSample<Sup> {
|
||||
RandSample { _marker: marker::PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
/// A value with a particular weight for use with `WeightedChoice`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Weighted<T> {
|
||||
/// The numerical weight of this item
|
||||
pub weight: u32,
|
||||
/// The actual item which is being weighted
|
||||
pub item: T,
|
||||
}
|
||||
|
||||
/// A distribution that selects from a finite collection of weighted items.
|
||||
///
|
||||
/// Each item has an associated weight that influences how likely it
|
||||
/// is to be chosen: higher weight is more likely.
|
||||
///
|
||||
/// The `Clone` restriction is a limitation of the `Sample` and
|
||||
/// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for
|
||||
/// all `T`, as is `u32`, so one can store references or indices into
|
||||
/// another vector.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{Weighted, WeightedChoice, IndependentSample};
|
||||
///
|
||||
/// let mut items = vec!(Weighted { weight: 2, item: 'a' },
|
||||
/// Weighted { weight: 4, item: 'b' },
|
||||
/// Weighted { weight: 1, item: 'c' });
|
||||
/// let wc = WeightedChoice::new(&mut items);
|
||||
/// let mut rng = rand::thread_rng();
|
||||
/// for _ in 0..16 {
|
||||
/// // on average prints 'a' 4 times, 'b' 8 and 'c' twice.
|
||||
/// println!("{}", wc.ind_sample(&mut rng));
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct WeightedChoice<'a, T:'a> {
|
||||
items: &'a mut [Weighted<T>],
|
||||
weight_range: Range<u32>
|
||||
}
|
||||
|
||||
impl<'a, T: Clone> WeightedChoice<'a, T> {
|
||||
/// Create a new `WeightedChoice`.
|
||||
///
|
||||
/// Panics if:
|
||||
///
|
||||
/// - `items` is empty
|
||||
/// - the total weight is 0
|
||||
/// - the total weight is larger than a `u32` can contain.
|
||||
pub fn new(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> {
|
||||
// strictly speaking, this is subsumed by the total weight == 0 case
|
||||
assert!(!items.is_empty(), "WeightedChoice::new called with no items");
|
||||
|
||||
let mut running_total: u32 = 0;
|
||||
|
||||
// we convert the list from individual weights to cumulative
|
||||
// weights so we can binary search. This *could* drop elements
|
||||
// with weight == 0 as an optimisation.
|
||||
for item in items.iter_mut() {
|
||||
running_total = match running_total.checked_add(item.weight) {
|
||||
Some(n) => n,
|
||||
None => panic!("WeightedChoice::new called with a total weight \
|
||||
larger than a u32 can contain")
|
||||
};
|
||||
|
||||
item.weight = running_total;
|
||||
}
|
||||
assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0");
|
||||
|
||||
WeightedChoice {
|
||||
items: items,
|
||||
// we're likely to be generating numbers in this range
|
||||
// relatively often, so might as well cache it
|
||||
weight_range: Range::new(0, running_total)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Clone> Sample<T> for WeightedChoice<'a, T> {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> T { self.ind_sample(rng) }
|
||||
}
|
||||
|
||||
impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> T {
|
||||
// we want to find the first element that has cumulative
|
||||
// weight > sample_weight, which we do by binary since the
|
||||
// cumulative weights of self.items are sorted.
|
||||
|
||||
// choose a weight in [0, total_weight)
|
||||
let sample_weight = self.weight_range.ind_sample(rng);
|
||||
|
||||
// short circuit when it's the first item
|
||||
if sample_weight < self.items[0].weight {
|
||||
return self.items[0].item.clone();
|
||||
}
|
||||
|
||||
let mut idx = 0;
|
||||
let mut modifier = self.items.len();
|
||||
|
||||
// now we know that every possibility has an element to the
|
||||
// left, so we can just search for the last element that has
|
||||
// cumulative weight <= sample_weight, then the next one will
|
||||
// be "it". (Note that this greatest element will never be the
|
||||
// last element of the vector, since sample_weight is chosen
|
||||
// in [0, total_weight) and the cumulative weight of the last
|
||||
// one is exactly the total weight.)
|
||||
while modifier > 1 {
|
||||
let i = idx + modifier / 2;
|
||||
if self.items[i].weight <= sample_weight {
|
||||
// we're small, so look to the right, but allow this
|
||||
// exact element still.
|
||||
idx = i;
|
||||
// we need the `/ 2` to round up otherwise we'll drop
|
||||
// the trailing elements when `modifier` is odd.
|
||||
modifier += 1;
|
||||
} else {
|
||||
// otherwise we're too big, so go left. (i.e. do
|
||||
// nothing)
|
||||
}
|
||||
modifier /= 2;
|
||||
}
|
||||
return self.items[idx + 1].item.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/// Sample a random number using the Ziggurat method (specifically the
|
||||
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
|
||||
/// directly from the paper:
|
||||
///
|
||||
/// * `rng`: source of randomness
|
||||
/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
|
||||
/// * `X`: the $x_i$ abscissae.
|
||||
/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
|
||||
/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
|
||||
/// * `pdf`: the probability density function
|
||||
/// * `zero_case`: manual sampling from the tail when we chose the
|
||||
/// bottom box (i.e. i == 0)
|
||||
|
||||
// the perf improvement (25-50%) is definitely worth the extra code
|
||||
// size from force-inlining.
|
||||
#[cfg(feature="std")]
|
||||
#[inline(always)]
|
||||
fn ziggurat<R: Rng, P, Z>(
|
||||
rng: &mut R,
|
||||
symmetric: bool,
|
||||
x_tab: ziggurat_tables::ZigTable,
|
||||
f_tab: ziggurat_tables::ZigTable,
|
||||
mut pdf: P,
|
||||
mut zero_case: Z)
|
||||
-> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 {
|
||||
const SCALE: f64 = (1u64 << 53) as f64;
|
||||
loop {
|
||||
// reimplement the f64 generation as an optimisation suggested
|
||||
// by the Doornik paper: we have a lot of precision-space
|
||||
// (i.e. there are 11 bits of the 64 of a u64 to use after
|
||||
// creating a f64), so we might as well reuse some to save
|
||||
// generating a whole extra random number. (Seems to be 15%
|
||||
// faster.)
|
||||
//
|
||||
// This unfortunately misses out on the benefits of direct
|
||||
// floating point generation if an RNG like dSMFT is
|
||||
// used. (That is, such RNGs create floats directly, highly
|
||||
// efficiently and overload next_f32/f64, so by not calling it
|
||||
// this may be slower than it would be otherwise.)
|
||||
// FIXME: investigate/optimise for the above.
|
||||
let bits: u64 = rng.gen();
|
||||
let i = (bits & 0xff) as usize;
|
||||
let f = (bits >> 11) as f64 / SCALE;
|
||||
|
||||
// u is either U(-1, 1) or U(0, 1) depending on if this is a
|
||||
// symmetric distribution or not.
|
||||
let u = if symmetric {2.0 * f - 1.0} else {f};
|
||||
let x = u * x_tab[i];
|
||||
|
||||
let test_x = if symmetric { x.abs() } else {x};
|
||||
|
||||
// algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i])
|
||||
if test_x < x_tab[i + 1] {
|
||||
return x;
|
||||
}
|
||||
if i == 0 {
|
||||
return zero_case(rng, u);
|
||||
}
|
||||
// algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
|
||||
if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::<f64>() < pdf(x) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use {Rng, Rand};
|
||||
use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample};
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct ConstRand(usize);
|
||||
impl Rand for ConstRand {
|
||||
fn rand<R: Rng>(_: &mut R) -> ConstRand {
|
||||
ConstRand(0)
|
||||
}
|
||||
}
|
||||
|
||||
// 0, 1, 2, 3, ...
|
||||
struct CountingRng { i: u32 }
|
||||
impl Rng for CountingRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.i += 1;
|
||||
self.i - 1
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
self.next_u32() as u64
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rand_sample() {
|
||||
let mut rand_sample = RandSample::<ConstRand>::new();
|
||||
|
||||
assert_eq!(rand_sample.sample(&mut ::test::rng()), ConstRand(0));
|
||||
assert_eq!(rand_sample.ind_sample(&mut ::test::rng()), ConstRand(0));
|
||||
}
|
||||
#[test]
|
||||
fn test_weighted_choice() {
|
||||
// this makes assumptions about the internal implementation of
|
||||
// WeightedChoice, specifically: it doesn't reorder the items,
|
||||
// it doesn't do weird things to the RNG (so 0 maps to 0, 1 to
|
||||
// 1, internally; modulo a modulo operation).
|
||||
|
||||
macro_rules! t {
|
||||
($items:expr, $expected:expr) => {{
|
||||
let mut items = $items;
|
||||
let wc = WeightedChoice::new(&mut items);
|
||||
let expected = $expected;
|
||||
|
||||
let mut rng = CountingRng { i: 0 };
|
||||
|
||||
for &val in expected.iter() {
|
||||
assert_eq!(wc.ind_sample(&mut rng), val)
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
t!(vec!(Weighted { weight: 1, item: 10}), [10]);
|
||||
|
||||
// skip some
|
||||
t!(vec!(Weighted { weight: 0, item: 20},
|
||||
Weighted { weight: 2, item: 21},
|
||||
Weighted { weight: 0, item: 22},
|
||||
Weighted { weight: 1, item: 23}),
|
||||
[21,21, 23]);
|
||||
|
||||
// different weights
|
||||
t!(vec!(Weighted { weight: 4, item: 30},
|
||||
Weighted { weight: 3, item: 31}),
|
||||
[30,30,30,30, 31,31,31]);
|
||||
|
||||
// check that we're binary searching
|
||||
// correctly with some vectors of odd
|
||||
// length.
|
||||
t!(vec!(Weighted { weight: 1, item: 40},
|
||||
Weighted { weight: 1, item: 41},
|
||||
Weighted { weight: 1, item: 42},
|
||||
Weighted { weight: 1, item: 43},
|
||||
Weighted { weight: 1, item: 44}),
|
||||
[40, 41, 42, 43, 44]);
|
||||
t!(vec!(Weighted { weight: 1, item: 50},
|
||||
Weighted { weight: 1, item: 51},
|
||||
Weighted { weight: 1, item: 52},
|
||||
Weighted { weight: 1, item: 53},
|
||||
Weighted { weight: 1, item: 54},
|
||||
Weighted { weight: 1, item: 55},
|
||||
Weighted { weight: 1, item: 56}),
|
||||
[50, 51, 52, 53, 54, 55, 56]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weighted_clone_initialization() {
|
||||
let initial : Weighted<u32> = Weighted {weight: 1, item: 1};
|
||||
let clone = initial.clone();
|
||||
assert_eq!(initial.weight, clone.weight);
|
||||
assert_eq!(initial.item, clone.item);
|
||||
}
|
||||
|
||||
#[test] #[should_panic]
|
||||
fn test_weighted_clone_change_weight() {
|
||||
let initial : Weighted<u32> = Weighted {weight: 1, item: 1};
|
||||
let mut clone = initial.clone();
|
||||
clone.weight = 5;
|
||||
assert_eq!(initial.weight, clone.weight);
|
||||
}
|
||||
|
||||
#[test] #[should_panic]
|
||||
fn test_weighted_clone_change_item() {
|
||||
let initial : Weighted<u32> = Weighted {weight: 1, item: 1};
|
||||
let mut clone = initial.clone();
|
||||
clone.item = 5;
|
||||
assert_eq!(initial.item, clone.item);
|
||||
|
||||
}
|
||||
|
||||
#[test] #[should_panic]
|
||||
fn test_weighted_choice_no_items() {
|
||||
WeightedChoice::<isize>::new(&mut []);
|
||||
}
|
||||
#[test] #[should_panic]
|
||||
fn test_weighted_choice_zero_weight() {
|
||||
WeightedChoice::new(&mut [Weighted { weight: 0, item: 0},
|
||||
Weighted { weight: 0, item: 1}]);
|
||||
}
|
||||
#[test] #[should_panic]
|
||||
fn test_weighted_choice_weight_overflows() {
|
||||
let x = ::std::u32::MAX / 2; // x + x + 2 is the overflow
|
||||
WeightedChoice::new(&mut [Weighted { weight: x, item: 0 },
|
||||
Weighted { weight: 1, item: 1 },
|
||||
Weighted { weight: x, item: 2 },
|
||||
Weighted { weight: 1, item: 3 }]);
|
||||
}
|
||||
}
|
|
@ -1,201 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The normal and derived distributions.
|
||||
|
||||
use {Rng, Rand, Open01};
|
||||
use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
|
||||
|
||||
/// A wrapper around an `f64` to generate N(0, 1) random numbers
|
||||
/// (a.k.a. a standard normal, or Gaussian).
|
||||
///
|
||||
/// See `Normal` for the general normal distribution.
|
||||
///
|
||||
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method.
|
||||
///
|
||||
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
|
||||
/// Generate Normal Random
|
||||
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
|
||||
/// College, Oxford
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::normal::StandardNormal;
|
||||
///
|
||||
/// let StandardNormal(x) = rand::random();
|
||||
/// println!("{}", x);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct StandardNormal(pub f64);
|
||||
|
||||
impl Rand for StandardNormal {
|
||||
fn rand<R:Rng>(rng: &mut R) -> StandardNormal {
|
||||
#[inline]
|
||||
fn pdf(x: f64) -> f64 {
|
||||
(-x*x/2.0).exp()
|
||||
}
|
||||
#[inline]
|
||||
fn zero_case<R:Rng>(rng: &mut R, u: f64) -> f64 {
|
||||
// compute a random number in the tail by hand
|
||||
|
||||
// strange initial conditions, because the loop is not
|
||||
// do-while, so the condition should be true on the first
|
||||
// run, they get overwritten anyway (0 < 1, so these are
|
||||
// good).
|
||||
let mut x = 1.0f64;
|
||||
let mut y = 0.0f64;
|
||||
|
||||
while -2.0 * y < x * x {
|
||||
let Open01(x_) = rng.gen::<Open01<f64>>();
|
||||
let Open01(y_) = rng.gen::<Open01<f64>>();
|
||||
|
||||
x = x_.ln() / ziggurat_tables::ZIG_NORM_R;
|
||||
y = y_.ln();
|
||||
}
|
||||
|
||||
if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x }
|
||||
}
|
||||
|
||||
StandardNormal(ziggurat(
|
||||
rng,
|
||||
true, // this is symmetric
|
||||
&ziggurat_tables::ZIG_NORM_X,
|
||||
&ziggurat_tables::ZIG_NORM_F,
|
||||
pdf, zero_case))
|
||||
}
|
||||
}
|
||||
|
||||
/// The normal distribution `N(mean, std_dev**2)`.
|
||||
///
|
||||
/// This uses the ZIGNOR variant of the Ziggurat method, see
|
||||
/// `StandardNormal` for more details.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{Normal, IndependentSample};
|
||||
///
|
||||
/// // mean 2, standard deviation 3
|
||||
/// let normal = Normal::new(2.0, 3.0);
|
||||
/// let v = normal.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a N(2, 9) distribution", v)
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Normal {
|
||||
mean: f64,
|
||||
std_dev: f64,
|
||||
}
|
||||
|
||||
impl Normal {
|
||||
/// Construct a new `Normal` distribution with the given mean and
|
||||
/// standard deviation.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `std_dev < 0`.
|
||||
#[inline]
|
||||
pub fn new(mean: f64, std_dev: f64) -> Normal {
|
||||
assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0");
|
||||
Normal {
|
||||
mean: mean,
|
||||
std_dev: std_dev
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Sample<f64> for Normal {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl IndependentSample<f64> for Normal {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
let StandardNormal(n) = rng.gen::<StandardNormal>();
|
||||
self.mean + self.std_dev * n
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// The log-normal distribution `ln N(mean, std_dev**2)`.
|
||||
///
|
||||
/// If `X` is log-normal distributed, then `ln(X)` is `N(mean,
|
||||
/// std_dev**2)` distributed.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{LogNormal, IndependentSample};
|
||||
///
|
||||
/// // mean 2, standard deviation 3
|
||||
/// let log_normal = LogNormal::new(2.0, 3.0);
|
||||
/// let v = log_normal.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from an ln N(2, 9) distribution", v)
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct LogNormal {
|
||||
norm: Normal
|
||||
}
|
||||
|
||||
impl LogNormal {
|
||||
/// Construct a new `LogNormal` distribution with the given mean
|
||||
/// and standard deviation.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `std_dev < 0`.
|
||||
#[inline]
|
||||
pub fn new(mean: f64, std_dev: f64) -> LogNormal {
|
||||
assert!(std_dev >= 0.0, "LogNormal::new called with `std_dev` < 0");
|
||||
LogNormal { norm: Normal::new(mean, std_dev) }
|
||||
}
|
||||
}
|
||||
impl Sample<f64> for LogNormal {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl IndependentSample<f64> for LogNormal {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
self.norm.ind_sample(rng).exp()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use distributions::{Sample, IndependentSample};
|
||||
use super::{Normal, LogNormal};
|
||||
|
||||
#[test]
|
||||
fn test_normal() {
|
||||
let mut norm = Normal::new(10.0, 10.0);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
norm.sample(&mut rng);
|
||||
norm.ind_sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_normal_invalid_sd() {
|
||||
Normal::new(10.0, -1.0);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_log_normal() {
|
||||
let mut lnorm = LogNormal::new(10.0, 10.0);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
lnorm.sample(&mut rng);
|
||||
lnorm.ind_sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_log_normal_invalid_sd() {
|
||||
LogNormal::new(10.0, -1.0);
|
||||
}
|
||||
}
|
|
@ -1,280 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Tables for distributions which are sampled using the ziggurat
|
||||
// algorithm. Autogenerated by `ziggurat_tables.py`.
|
||||
|
||||
pub type ZigTable = &'static [f64; 257];
|
||||
pub const ZIG_NORM_R: f64 = 3.654152885361008796;
|
||||
pub static ZIG_NORM_X: [f64; 257] =
|
||||
[3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074,
|
||||
3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434,
|
||||
2.978603279880844834, 2.934366867207854224, 2.894121053612348060, 2.857138730872132548,
|
||||
2.822877396825325125, 2.790921174000785765, 2.760944005278822555, 2.732685359042827056,
|
||||
2.705933656121858100, 2.680514643284522158, 2.656283037575502437, 2.633116393630324570,
|
||||
2.610910518487548515, 2.589575986706995181, 2.569035452680536569, 2.549221550323460761,
|
||||
2.530075232158516929, 2.511544441625342294, 2.493583041269680667, 2.476149939669143318,
|
||||
2.459208374333311298, 2.442725318198956774, 2.426670984935725972, 2.411018413899685520,
|
||||
2.395743119780480601, 2.380822795170626005, 2.366237056715818632, 2.351967227377659952,
|
||||
2.337996148795031370, 2.324308018869623016, 2.310888250599850036, 2.297723348901329565,
|
||||
2.284800802722946056, 2.272108990226823888, 2.259637095172217780, 2.247375032945807760,
|
||||
2.235313384928327984, 2.223443340090905718, 2.211756642882544366, 2.200245546609647995,
|
||||
2.188902771624720689, 2.177721467738641614, 2.166695180352645966, 2.155817819875063268,
|
||||
2.145083634046203613, 2.134487182844320152, 2.124023315687815661, 2.113687150684933957,
|
||||
2.103474055713146829, 2.093379631137050279, 2.083399693996551783, 2.073530263516978778,
|
||||
2.063767547809956415, 2.054107931648864849, 2.044547965215732788, 2.035084353727808715,
|
||||
2.025713947862032960, 2.016433734904371722, 2.007240830558684852, 1.998132471356564244,
|
||||
1.989106007615571325, 1.980158896898598364, 1.971288697931769640, 1.962493064942461896,
|
||||
1.953769742382734043, 1.945116560006753925, 1.936531428273758904, 1.928012334050718257,
|
||||
1.919557336591228847, 1.911164563769282232, 1.902832208548446369, 1.894558525668710081,
|
||||
1.886341828534776388, 1.878180486290977669, 1.870072921069236838, 1.862017605397632281,
|
||||
1.854013059758148119, 1.846057850283119750, 1.838150586580728607, 1.830289919680666566,
|
||||
1.822474540091783224, 1.814703175964167636, 1.806974591348693426, 1.799287584547580199,
|
||||
1.791640986550010028, 1.784033659547276329, 1.776464495522344977, 1.768932414909077933,
|
||||
1.761436365316706665, 1.753975320315455111, 1.746548278279492994, 1.739154261283669012,
|
||||
1.731792314050707216, 1.724461502945775715, 1.717160915015540690, 1.709889657069006086,
|
||||
1.702646854797613907, 1.695431651932238548, 1.688243209434858727, 1.681080704722823338,
|
||||
1.673943330923760353, 1.666830296159286684, 1.659740822855789499, 1.652674147080648526,
|
||||
1.645629517902360339, 1.638606196773111146, 1.631603456932422036, 1.624620582830568427,
|
||||
1.617656869570534228, 1.610711622367333673, 1.603784156023583041, 1.596873794420261339,
|
||||
1.589979870021648534, 1.583101723393471438, 1.576238702733332886, 1.569390163412534456,
|
||||
1.562555467528439657, 1.555733983466554893, 1.548925085471535512, 1.542128153226347553,
|
||||
1.535342571438843118, 1.528567729435024614, 1.521803020758293101, 1.515047842773992404,
|
||||
1.508301596278571965, 1.501563685112706548, 1.494833515777718391, 1.488110497054654369,
|
||||
1.481394039625375747, 1.474683555695025516, 1.467978458615230908, 1.461278162507407830,
|
||||
1.454582081885523293, 1.447889631277669675, 1.441200224845798017, 1.434513276002946425,
|
||||
1.427828197027290358, 1.421144398672323117, 1.414461289772464658, 1.407778276843371534,
|
||||
1.401094763676202559, 1.394410150925071257, 1.387723835686884621, 1.381035211072741964,
|
||||
1.374343665770030531, 1.367648583594317957, 1.360949343030101844, 1.354245316759430606,
|
||||
1.347535871177359290, 1.340820365893152122, 1.334098153216083604, 1.327368577624624679,
|
||||
1.320630975217730096, 1.313884673146868964, 1.307128989027353860, 1.300363230327433728,
|
||||
1.293586693733517645, 1.286798664489786415, 1.279998415710333237, 1.273185207661843732,
|
||||
1.266358287014688333, 1.259516886060144225, 1.252660221891297887, 1.245787495544997903,
|
||||
1.238897891102027415, 1.231990574742445110, 1.225064693752808020, 1.218119375481726552,
|
||||
1.211153726239911244, 1.204166830140560140, 1.197157747875585931, 1.190125515422801650,
|
||||
1.183069142678760732, 1.175987612011489825, 1.168879876726833800, 1.161744859441574240,
|
||||
1.154581450355851802, 1.147388505416733873, 1.140164844363995789, 1.132909248648336975,
|
||||
1.125620459211294389, 1.118297174115062909, 1.110938046009249502, 1.103541679420268151,
|
||||
1.096106627847603487, 1.088631390649514197, 1.081114409698889389, 1.073554065787871714,
|
||||
1.065948674757506653, 1.058296483326006454, 1.050595664586207123, 1.042844313139370538,
|
||||
1.035040439828605274, 1.027181966030751292, 1.019266717460529215, 1.011292417434978441,
|
||||
1.003256679539591412, 0.995156999629943084, 0.986990747093846266, 0.978755155288937750,
|
||||
0.970447311058864615, 0.962064143217605250, 0.953602409875572654, 0.945058684462571130,
|
||||
0.936429340280896860, 0.927710533396234771, 0.918898183643734989, 0.909987953490768997,
|
||||
0.900975224455174528, 0.891855070726792376, 0.882622229578910122, 0.873271068082494550,
|
||||
0.863795545546826915, 0.854189171001560554, 0.844444954902423661, 0.834555354079518752,
|
||||
0.824512208745288633, 0.814306670128064347, 0.803929116982664893, 0.793369058833152785,
|
||||
0.782615023299588763, 0.771654424216739354, 0.760473406422083165, 0.749056662009581653,
|
||||
0.737387211425838629, 0.725446140901303549, 0.713212285182022732, 0.700661841097584448,
|
||||
0.687767892786257717, 0.674499822827436479, 0.660822574234205984, 0.646695714884388928,
|
||||
0.632072236375024632, 0.616896989996235545, 0.601104617743940417, 0.584616766093722262,
|
||||
0.567338257040473026, 0.549151702313026790, 0.529909720646495108, 0.509423329585933393,
|
||||
0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746,
|
||||
0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806,
|
||||
0.000000000000000000];
|
||||
pub static ZIG_NORM_F: [f64; 257] =
|
||||
[0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872,
|
||||
0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100,
|
||||
0.011842757857943104, 0.013497450601780807, 0.015177088307982072, 0.016880083152595839,
|
||||
0.018605121275783350, 0.020351096230109354, 0.022117062707379922, 0.023902203305873237,
|
||||
0.025705804008632656, 0.027527235669693315, 0.029365939758230111, 0.031221417192023690,
|
||||
0.033093219458688698, 0.034980941461833073, 0.036884215688691151, 0.038802707404656918,
|
||||
0.040736110656078753, 0.042684144916619378, 0.044646552251446536, 0.046623094902089664,
|
||||
0.048613553216035145, 0.050617723861121788, 0.052635418276973649, 0.054666461325077916,
|
||||
0.056710690106399467, 0.058767952921137984, 0.060838108349751806, 0.062921024437977854,
|
||||
0.065016577971470438, 0.067124653828023989, 0.069245144397250269, 0.071377949059141965,
|
||||
0.073522973714240991, 0.075680130359194964, 0.077849336702372207, 0.080030515814947509,
|
||||
0.082223595813495684, 0.084428509570654661, 0.086645194450867782, 0.088873592068594229,
|
||||
0.091113648066700734, 0.093365311913026619, 0.095628536713353335, 0.097903279039215627,
|
||||
0.100189498769172020, 0.102487158942306270, 0.104796225622867056, 0.107116667775072880,
|
||||
0.109448457147210021, 0.111791568164245583, 0.114145977828255210, 0.116511665626037014,
|
||||
0.118888613443345698, 0.121276805485235437, 0.123676228202051403, 0.126086870220650349,
|
||||
0.128508722280473636, 0.130941777174128166, 0.133386029692162844, 0.135841476571757352,
|
||||
0.138308116449064322, 0.140785949814968309, 0.143274978974047118, 0.145775208006537926,
|
||||
0.148286642733128721, 0.150809290682410169, 0.153343161060837674, 0.155888264725064563,
|
||||
0.158444614156520225, 0.161012223438117663, 0.163591108232982951, 0.166181285765110071,
|
||||
0.168782774801850333, 0.171395595638155623, 0.174019770082499359, 0.176655321444406654,
|
||||
0.179302274523530397, 0.181960655600216487, 0.184630492427504539, 0.187311814224516926,
|
||||
0.190004651671193070, 0.192709036904328807, 0.195425003514885592, 0.198152586546538112,
|
||||
0.200891822495431333, 0.203642749311121501, 0.206405406398679298, 0.209179834621935651,
|
||||
0.211966076307852941, 0.214764175252008499, 0.217574176725178370, 0.220396127481011589,
|
||||
0.223230075764789593, 0.226076071323264877, 0.228934165415577484, 0.231804410825248525,
|
||||
0.234686861873252689, 0.237581574432173676, 0.240488605941449107, 0.243408015423711988,
|
||||
0.246339863502238771, 0.249284212419516704, 0.252241126056943765, 0.255210669955677150,
|
||||
0.258192911338648023, 0.261187919133763713, 0.264195763998317568, 0.267216518344631837,
|
||||
0.270250256366959984, 0.273297054069675804, 0.276356989296781264, 0.279430141762765316,
|
||||
0.282516593084849388, 0.285616426816658109, 0.288729728483353931, 0.291856585618280984,
|
||||
0.294997087801162572, 0.298151326697901342, 0.301319396102034120, 0.304501391977896274,
|
||||
0.307697412505553769, 0.310907558127563710, 0.314131931597630143, 0.317370638031222396,
|
||||
0.320623784958230129, 0.323891482377732021, 0.327173842814958593, 0.330470981380537099,
|
||||
0.333783015832108509, 0.337110066638412809, 0.340452257045945450, 0.343809713148291340,
|
||||
0.347182563958251478, 0.350570941482881204, 0.353974980801569250, 0.357394820147290515,
|
||||
0.360830600991175754, 0.364282468130549597, 0.367750569780596226, 0.371235057669821344,
|
||||
0.374736087139491414, 0.378253817247238111, 0.381788410875031348, 0.385340034841733958,
|
||||
0.388908860020464597, 0.392495061461010764, 0.396098818517547080, 0.399720314981931668,
|
||||
0.403359739222868885, 0.407017284331247953, 0.410693148271983222, 0.414387534042706784,
|
||||
0.418100649839684591, 0.421832709231353298, 0.425583931339900579, 0.429354541031341519,
|
||||
0.433144769114574058, 0.436954852549929273, 0.440785034667769915, 0.444635565397727750,
|
||||
0.448506701509214067, 0.452398706863882505, 0.456311852680773566, 0.460246417814923481,
|
||||
0.464202689050278838, 0.468180961407822172, 0.472181538469883255, 0.476204732721683788,
|
||||
0.480250865911249714, 0.484320269428911598, 0.488413284707712059, 0.492530263646148658,
|
||||
0.496671569054796314, 0.500837575128482149, 0.505028667945828791, 0.509245245998136142,
|
||||
0.513487720749743026, 0.517756517232200619, 0.522052074674794864, 0.526374847174186700,
|
||||
0.530725304406193921, 0.535103932383019565, 0.539511234259544614, 0.543947731192649941,
|
||||
0.548413963257921133, 0.552910490428519918, 0.557437893621486324, 0.561996775817277916,
|
||||
0.566587763258951771, 0.571211506738074970, 0.575868682975210544, 0.580559996103683473,
|
||||
0.585286179266300333, 0.590047996335791969, 0.594846243770991268, 0.599681752622167719,
|
||||
0.604555390700549533, 0.609468064928895381, 0.614420723892076803, 0.619414360609039205,
|
||||
0.624450015550274240, 0.629528779928128279, 0.634651799290960050, 0.639820277456438991,
|
||||
0.645035480824251883, 0.650298743114294586, 0.655611470583224665, 0.660975147780241357,
|
||||
0.666391343912380640, 0.671861719900766374, 0.677388036222513090, 0.682972161648791376,
|
||||
0.688616083008527058, 0.694321916130032579, 0.700091918140490099, 0.705928501336797409,
|
||||
0.711834248882358467, 0.717811932634901395, 0.723864533472881599, 0.729995264565802437,
|
||||
0.736207598131266683, 0.742505296344636245, 0.748892447223726720, 0.755373506511754500,
|
||||
0.761953346841546475, 0.768637315803334831, 0.775431304986138326, 0.782341832659861902,
|
||||
0.789376143571198563, 0.796542330428254619, 0.803849483176389490, 0.811307874318219935,
|
||||
0.818929191609414797, 0.826726833952094231, 0.834716292992930375, 0.842915653118441077,
|
||||
0.851346258465123684, 0.860033621203008636, 0.869008688043793165, 0.878309655816146839,
|
||||
0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247,
|
||||
0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328,
|
||||
1.000000000000000000];
|
||||
pub const ZIG_EXP_R: f64 = 7.697117470131050077;
|
||||
pub static ZIG_EXP_X: [f64; 257] =
|
||||
[8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696,
|
||||
6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488,
|
||||
5.323090505754398016, 5.181487281301500047, 5.054288489981304089, 4.938777085901250530,
|
||||
4.832939741025112035, 4.735242996601741083, 4.644491885420085175, 4.559737061707351380,
|
||||
4.480211746528421912, 4.405287693473573185, 4.334443680317273007, 4.267242480277365857,
|
||||
4.203313713735184365, 4.142340865664051464, 4.084051310408297830, 4.028208544647936762,
|
||||
3.974606066673788796, 3.923062500135489739, 3.873417670399509127, 3.825529418522336744,
|
||||
3.779270992411667862, 3.734528894039797375, 3.691201090237418825, 3.649195515760853770,
|
||||
3.608428813128909507, 3.568825265648337020, 3.530315889129343354, 3.492837654774059608,
|
||||
3.456332821132760191, 3.420748357251119920, 3.386035442460300970, 3.352149030900109405,
|
||||
3.319047470970748037, 3.286692171599068679, 3.255047308570449882, 3.224079565286264160,
|
||||
3.193757903212240290, 3.164053358025972873, 3.134938858084440394, 3.106389062339824481,
|
||||
3.078380215254090224, 3.050890016615455114, 3.023897504455676621, 2.997382949516130601,
|
||||
2.971327759921089662, 2.945714394895045718, 2.920526286512740821, 2.895747768600141825,
|
||||
2.871364012015536371, 2.847360965635188812, 2.823725302450035279, 2.800444370250737780,
|
||||
2.777506146439756574, 2.754899196562344610, 2.732612636194700073, 2.710636095867928752,
|
||||
2.688959688741803689, 2.667573980773266573, 2.646469963151809157, 2.625639026797788489,
|
||||
2.605072938740835564, 2.584763820214140750, 2.564704126316905253, 2.544886627111869970,
|
||||
2.525304390037828028, 2.505950763528594027, 2.486819361740209455, 2.467904050297364815,
|
||||
2.449198932978249754, 2.430698339264419694, 2.412396812688870629, 2.394289099921457886,
|
||||
2.376370140536140596, 2.358635057409337321, 2.341079147703034380, 2.323697874390196372,
|
||||
2.306486858283579799, 2.289441870532269441, 2.272558825553154804, 2.255833774367219213,
|
||||
2.239262898312909034, 2.222842503111036816, 2.206569013257663858, 2.190438966723220027,
|
||||
2.174449009937774679, 2.158595893043885994, 2.142876465399842001, 2.127287671317368289,
|
||||
2.111826546019042183, 2.096490211801715020, 2.081275874393225145, 2.066180819490575526,
|
||||
2.051202409468584786, 2.036338080248769611, 2.021585338318926173, 2.006941757894518563,
|
||||
1.992404978213576650, 1.977972700957360441, 1.963642687789548313, 1.949412758007184943,
|
||||
1.935280786297051359, 1.921244700591528076, 1.907302480018387536, 1.893452152939308242,
|
||||
1.879691795072211180, 1.866019527692827973, 1.852433515911175554, 1.838931967018879954,
|
||||
1.825513128903519799, 1.812175288526390649, 1.798916770460290859, 1.785735935484126014,
|
||||
1.772631179231305643, 1.759600930889074766, 1.746643651946074405, 1.733757834985571566,
|
||||
1.720942002521935299, 1.708194705878057773, 1.695514524101537912, 1.682900062917553896,
|
||||
1.670349953716452118, 1.657862852574172763, 1.645437439303723659, 1.633072416535991334,
|
||||
1.620766508828257901, 1.608518461798858379, 1.596327041286483395, 1.584191032532688892,
|
||||
1.572109239386229707, 1.560080483527888084, 1.548103603714513499, 1.536177455041032092,
|
||||
1.524300908219226258, 1.512472848872117082, 1.500692176842816750, 1.488957805516746058,
|
||||
1.477268661156133867, 1.465623682245745352, 1.454021818848793446, 1.442462031972012504,
|
||||
1.430943292938879674, 1.419464582769983219, 1.408024891569535697, 1.396623217917042137,
|
||||
1.385258568263121992, 1.373929956328490576, 1.362636402505086775, 1.351376933258335189,
|
||||
1.340150580529504643, 1.328956381137116560, 1.317793376176324749, 1.306660610415174117,
|
||||
1.295557131686601027, 1.284481990275012642, 1.273434238296241139, 1.262412929069615330,
|
||||
1.251417116480852521, 1.240445854334406572, 1.229498195693849105, 1.218573192208790124,
|
||||
1.207669893426761121, 1.196787346088403092, 1.185924593404202199, 1.175080674310911677,
|
||||
1.164254622705678921, 1.153445466655774743, 1.142652227581672841, 1.131873919411078511,
|
||||
1.121109547701330200, 1.110358108727411031, 1.099618588532597308, 1.088889961938546813,
|
||||
1.078171191511372307, 1.067461226479967662, 1.056759001602551429, 1.046063435977044209,
|
||||
1.035373431790528542, 1.024687873002617211, 1.014005623957096480, 1.003325527915696735,
|
||||
0.992646405507275897, 0.981967053085062602, 0.971286240983903260, 0.960602711668666509,
|
||||
0.949915177764075969, 0.939222319955262286, 0.928522784747210395, 0.917815182070044311,
|
||||
0.907098082715690257, 0.896370015589889935, 0.885629464761751528, 0.874874866291025066,
|
||||
0.864104604811004484, 0.853317009842373353, 0.842510351810368485, 0.831682837734273206,
|
||||
0.820832606554411814, 0.809957724057418282, 0.799056177355487174, 0.788125868869492430,
|
||||
0.777164609759129710, 0.766170112735434672, 0.755139984181982249, 0.744071715500508102,
|
||||
0.732962673584365398, 0.721810090308756203, 0.710611050909655040, 0.699362481103231959,
|
||||
0.688061132773747808, 0.676703568029522584, 0.665286141392677943, 0.653804979847664947,
|
||||
0.642255960424536365, 0.630634684933490286, 0.618936451394876075, 0.607156221620300030,
|
||||
0.595288584291502887, 0.583327712748769489, 0.571267316532588332, 0.559100585511540626,
|
||||
0.546820125163310577, 0.534417881237165604, 0.521885051592135052, 0.509211982443654398,
|
||||
0.496388045518671162, 0.483401491653461857, 0.470239275082169006, 0.456886840931420235,
|
||||
0.443327866073552401, 0.429543940225410703, 0.415514169600356364, 0.401214678896277765,
|
||||
0.386617977941119573, 0.371692145329917234, 0.356399760258393816, 0.340696481064849122,
|
||||
0.324529117016909452, 0.307832954674932158, 0.290527955491230394, 0.272513185478464703,
|
||||
0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842,
|
||||
0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570,
|
||||
0.000000000000000000];
|
||||
pub static ZIG_EXP_F: [f64; 257] =
|
||||
[0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573,
|
||||
0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797,
|
||||
0.004877655983542396, 0.005619642207205489, 0.006381905937319183, 0.007163353183634991,
|
||||
0.007963077438017043, 0.008780314985808977, 0.009614413642502212, 0.010464810181029981,
|
||||
0.011331013597834600, 0.012212592426255378, 0.013109164931254991, 0.014020391403181943,
|
||||
0.014945968011691148, 0.015885621839973156, 0.016839106826039941, 0.017806200410911355,
|
||||
0.018786700744696024, 0.019780424338009740, 0.020787204072578114, 0.021806887504283581,
|
||||
0.022839335406385240, 0.023884420511558174, 0.024942026419731787, 0.026012046645134221,
|
||||
0.027094383780955803, 0.028188948763978646, 0.029295660224637411, 0.030414443910466622,
|
||||
0.031545232172893622, 0.032687963508959555, 0.033842582150874358, 0.035009037697397431,
|
||||
0.036187284781931443, 0.037377282772959382, 0.038578995503074871, 0.039792391023374139,
|
||||
0.041017441380414840, 0.042254122413316254, 0.043502413568888197, 0.044762297732943289,
|
||||
0.046033761076175184, 0.047316792913181561, 0.048611385573379504, 0.049917534282706379,
|
||||
0.051235237055126281, 0.052564494593071685, 0.053905310196046080, 0.055257689676697030,
|
||||
0.056621641283742870, 0.057997175631200659, 0.059384305633420280, 0.060783046445479660,
|
||||
0.062193415408541036, 0.063615431999807376, 0.065049117786753805, 0.066494496385339816,
|
||||
0.067951593421936643, 0.069420436498728783, 0.070901055162371843, 0.072393480875708752,
|
||||
0.073897746992364746, 0.075413888734058410, 0.076941943170480517, 0.078481949201606435,
|
||||
0.080033947542319905, 0.081597980709237419, 0.083174093009632397, 0.084762330532368146,
|
||||
0.086362741140756927, 0.087975374467270231, 0.089600281910032886, 0.091237516631040197,
|
||||
0.092887133556043569, 0.094549189376055873, 0.096223742550432825, 0.097910853311492213,
|
||||
0.099610583670637132, 0.101322997425953631, 0.103048160171257702, 0.104786139306570145,
|
||||
0.106537004050001632, 0.108300825451033755, 0.110077676405185357, 0.111867631670056283,
|
||||
0.113670767882744286, 0.115487163578633506, 0.117316899211555525, 0.119160057175327641,
|
||||
0.121016721826674792, 0.122886979509545108, 0.124770918580830933, 0.126668629437510671,
|
||||
0.128580204545228199, 0.130505738468330773, 0.132445327901387494, 0.134399071702213602,
|
||||
0.136367070926428829, 0.138349428863580176, 0.140346251074862399, 0.142357645432472146,
|
||||
0.144383722160634720, 0.146424593878344889, 0.148480375643866735, 0.150551185001039839,
|
||||
0.152637142027442801, 0.154738369384468027, 0.156854992369365148, 0.158987138969314129,
|
||||
0.161134939917591952, 0.163298528751901734, 0.165478041874935922, 0.167673618617250081,
|
||||
0.169885401302527550, 0.172113535315319977, 0.174358169171353411, 0.176619454590494829,
|
||||
0.178897546572478278, 0.181192603475496261, 0.183504787097767436, 0.185834262762197083,
|
||||
0.188181199404254262, 0.190545769663195363, 0.192928149976771296, 0.195328520679563189,
|
||||
0.197747066105098818, 0.200183974691911210, 0.202639439093708962, 0.205113656293837654,
|
||||
0.207606827724221982, 0.210119159388988230, 0.212650861992978224, 0.215202151075378628,
|
||||
0.217773247148700472, 0.220364375843359439, 0.222975768058120111, 0.225607660116683956,
|
||||
0.228260293930716618, 0.230933917169627356, 0.233628783437433291, 0.236345152457059560,
|
||||
0.239083290262449094, 0.241843469398877131, 0.244625969131892024, 0.247431075665327543,
|
||||
0.250259082368862240, 0.253110290015629402, 0.255985007030415324, 0.258883549749016173,
|
||||
0.261806242689362922, 0.264753418835062149, 0.267725419932044739, 0.270722596799059967,
|
||||
0.273745309652802915, 0.276793928448517301, 0.279868833236972869, 0.282970414538780746,
|
||||
0.286099073737076826, 0.289255223489677693, 0.292439288161892630, 0.295651704281261252,
|
||||
0.298892921015581847, 0.302163400675693528, 0.305463619244590256, 0.308794066934560185,
|
||||
0.312155248774179606, 0.315547685227128949, 0.318971912844957239, 0.322428484956089223,
|
||||
0.325917972393556354, 0.329440964264136438, 0.332998068761809096, 0.336589914028677717,
|
||||
0.340217149066780189, 0.343880444704502575, 0.347580494621637148, 0.351318016437483449,
|
||||
0.355093752866787626, 0.358908472948750001, 0.362762973354817997, 0.366658079781514379,
|
||||
0.370594648435146223, 0.374573567615902381, 0.378595759409581067, 0.382662181496010056,
|
||||
0.386773829084137932, 0.390931736984797384, 0.395136981833290435, 0.399390684475231350,
|
||||
0.403694012530530555, 0.408048183152032673, 0.412454465997161457, 0.416914186433003209,
|
||||
0.421428728997616908, 0.425999541143034677, 0.430628137288459167, 0.435316103215636907,
|
||||
0.440065100842354173, 0.444876873414548846, 0.449753251162755330, 0.454696157474615836,
|
||||
0.459707615642138023, 0.464789756250426511, 0.469944825283960310, 0.475175193037377708,
|
||||
0.480483363930454543, 0.485871987341885248, 0.491343869594032867, 0.496901987241549881,
|
||||
0.502549501841348056, 0.508289776410643213, 0.514126393814748894, 0.520063177368233931,
|
||||
0.526104213983620062, 0.532253880263043655, 0.538516872002862246, 0.544898237672440056,
|
||||
0.551403416540641733, 0.558038282262587892, 0.564809192912400615, 0.571723048664826150,
|
||||
0.578787358602845359, 0.586010318477268366, 0.593400901691733762, 0.600968966365232560,
|
||||
0.608725382079622346, 0.616682180915207878, 0.624852738703666200, 0.633251994214366398,
|
||||
0.641896716427266423, 0.650805833414571433, 0.660000841079000145, 0.669506316731925177,
|
||||
0.679350572264765806, 0.689566496117078431, 0.700192655082788606, 0.711274760805076456,
|
||||
0.722867659593572465, 0.735038092431424039, 0.747868621985195658, 0.761463388849896838,
|
||||
0.775956852040116218, 0.791527636972496285, 0.808421651523009044, 0.826993296643051101,
|
||||
0.847785500623990496, 0.871704332381204705, 0.900469929925747703, 0.938143680862176477,
|
||||
1.000000000000000000];
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,51 +0,0 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Pseudo random number generators are algorithms to produce *apparently
|
||||
//! random* numbers deterministically, and usually fairly quickly.
|
||||
//!
|
||||
//! So long as the algorithm is computationally secure, is initialised with
|
||||
//! sufficient entropy (i.e. unknown by an attacker), and its internal state is
|
||||
//! also protected (unknown to an attacker), the output will also be
|
||||
//! *computationally secure*. Computationally Secure Pseudo Random Number
|
||||
//! Generators (CSPRNGs) are thus suitable sources of random numbers for
|
||||
//! cryptography. There are a couple of gotchas here, however. First, the seed
|
||||
//! used for initialisation must be unknown. Usually this should be provided by
|
||||
//! the operating system and should usually be secure, however this may not
|
||||
//! always be the case (especially soon after startup). Second, user-space
|
||||
//! memory may be vulnerable, for example when written to swap space, and after
|
||||
//! forking a child process should reinitialise any user-space PRNGs. For this
|
||||
//! reason it may be preferable to source random numbers directly from the OS
|
||||
//! for cryptographic applications.
|
||||
//!
|
||||
//! PRNGs are also widely used for non-cryptographic uses: randomised
|
||||
//! algorithms, simulations, games. In these applications it is usually not
|
||||
//! important for numbers to be cryptographically *unguessable*, but even
|
||||
//! distribution and independence from other samples (from the point of view
|
||||
//! of someone unaware of the algorithm used, at least) may still be important.
|
||||
//! Good PRNGs should satisfy these properties, but do not take them for
|
||||
//! granted; Wikipedia's article on
|
||||
//! [Pseudorandom number generators](https://en.wikipedia.org/wiki/Pseudorandom_number_generator)
|
||||
//! provides some background on this topic.
|
||||
//!
|
||||
//! Care should be taken when seeding (initialising) PRNGs. Some PRNGs have
|
||||
//! short periods for some seeds. If one PRNG is seeded from another using the
|
||||
//! same algorithm, it is possible that both will yield the same sequence of
|
||||
//! values (with some lag).
|
||||
|
||||
mod chacha;
|
||||
mod isaac;
|
||||
mod isaac64;
|
||||
mod xorshift;
|
||||
|
||||
pub use self::chacha::ChaChaRng;
|
||||
pub use self::isaac::IsaacRng;
|
||||
pub use self::isaac64::Isaac64Rng;
|
||||
pub use self::xorshift::XorShiftRng;
|
|
@ -1 +1 @@
|
|||
{"files":{"CHANGELOG.md":"ddc101ef9368ef83c21ea9e43064307b1c59b0698b78f59ea01cba32c0ef55bf","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"54c97aa3fc80f7482358b32df3fb96dbd63a4b52fb7f2eb06f1707cda7d15f09","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"d442009fc242a0670f6e7a418862c67514e2c544a43c88b24cb7f37695b8ae38","benches/distributions.rs":"fea4337cd3eb6eaa7bb3250bb04b084290a2b081d3f4679510f3e1dab9c9506b","benches/generators.rs":"19286f1022041bca7e9f83ff615534397565246d5cd26c53abcaeaebebad6773","benches/misc.rs":"c0302e0d9ab973ba4463506d90f89f903104b2a42fc11247be2056a2e1cb561f","benches/seq.rs":"188043fe02640c3936da7634517d0bc0bbdbf685739c52d2ec51a95f238aa347","build.rs":"00d4e7d3521f631913001cfaeb5c97f9dab8b550346046deb2683b962a99e9b3","examples/monte-carlo.rs":"2161c9c1ed90af6b72a5b05b6650d5fce6a983873c29c99798957099cd7a5153","examples/monty-hall.rs":"6a1921868c41d4c130a6b098632f2c127d2446ac6a73aeea10b79b845df1cbbc","src/deprecated.rs":"da2a39dfc440a09bdcdf5af93842dce0fbbc179e5e7146dc94ea861c244bf4c5","src/distributions/bernoulli.rs":"02526bdc24fe17f390505779fb38a441c6a1792c1f7e6093d8b86e143bf9e07e","src/distributions/binomial.rs":"5e2cd6ebc0a5411a4af26ff07d05dd30ae91fc47852cd29757b370ce496074b6","src/distributions/cauchy.rs":"b49d4abd1d861e9f9e9a27444680ea0e24779a6a263dce07c400cf43bab9363c","src/distributions/dirichlet.rs":"b6c0273216a05d32ab21320c11f46f80bc6a6173c93f7aa63fd397927fa365fb","src/distributions/exponential.rs":"7e8a98b63a271714c1f982dd15bc21626593691eaa92c7a76bd59af7b37a56a2","src/distributions/float.rs":"6e1e15b47f9efd282a0e7d140c141d35ece4ebbb748ce7ead620782dc492e88f","src/distributions/gamma.rs":"c922a1b7b2f20ee5a7f5241a252b8b947ab998a88a747df488380211b865f9a6","src/distributions/integer.rs":"b615123a814b118f8bc0563cd7615eec7ee171223bf8100416fb7d22e350c8d7","src/distributions/mod.rs":"6824a6a461d84aef22646d6c3ac8af5d2b5dfc90f09d537be2112fde98a9a8ea","src/distributions/normal.rs":"fe5df9d00ff4038ef6e1f6ca22971547aaec57887c700a511806da01bb4a2f17","src/distributions/other.rs":"44abe480bdc2000ca91a9d41c04e3d5fff2b08e81dfc9168d82c90ddc5cbf616","src/distributions/pareto.rs":"8a9d0f6a7b7221c5716f92b4b65dc19954c146eaeeddcc0b9533d01e2b7414ff","src/distributions/poisson.rs":"918f36d9f7b6c9c4a249b49138cf4df5e1498dd894e3856c21d2f82b83d33e53","src/distributions/triangular.rs":"5a3927b4f1306686591c6d6f3df01d774a5dbf9ec2450ee2f3ce6a71b54f744d","src/distributions/uniform.rs":"9536012592e978cda4e72cd936f21b9986704468de531fbe873f25f763afa4da","src/distributions/unit_circle.rs":"007815186a3696a3d835e9004f51e52402557a7cda09219a0ade13122578e1bd","src/distributions/unit_sphere.rs":"24b8dea60bee580378713477235ddac5e8da07e4f9ceb610fe655ec82390abaf","src/distributions/utils.rs":"68a8257290fdbbd1e72c77e55f21aab4420c6ff168ffb82f7cabc3ad815f4803","src/distributions/weibull.rs":"7678c47145bbb8455fb34326e59d05c2564d427b9c13d5d32435119fd37b5eeb","src/distributions/weighted.rs":"2c98d09ed15d204687efce857129742f905e50e96ba0518122a742f3b47753df","src/distributions/ziggurat_tables.rs":"6368acec20801c703ae76dd1e08983793732c5ac221c491f85d719ef75448b6d","src/lib.rs":"5a7c48d633e75c6d9f2598651ac7b754b3b34fec4212bdc50358a0abbc4ffc62","src/prelude.rs":"36f87f720c1ce0c9d0041872b0498e016b5578b96ba4f6152765ac5084d3b5da","src/prng/mod.rs":"e38182ca652acd0f9348e70e6896e2143b11e9cdcdb34fc78ad13b150dbd7da9","src/rngs/adapter/mod.rs":"e8f37aed72eaebc7dff20787f194e3a74da3e824e2b92a6839b7e6f01fcd911c","src/rngs/adapter/read.rs":"f9502c774607b5c3e62b87ea58698db258486b7c0dbb9b01559e3c18b468bb34","src/rngs/adapter/reseeding.rs":"0ce93bd0f00da429459bca7081346bddea85735bf2d617bcde92708907016a0d","src/rngs/entropy.rs":"cd89359f7891e955245279e4848c37733c508a8cf126eee34f2361a228014f4e","src/rngs/mock.rs":"ef812949b98e4f2eea3e62f8b3ee56edaeffc99d17625337efc882b7b2b19f4b","src/rngs/mod.rs":"440870d8066f1fbeb5d3b178bbf62d899f565d3cbc99c9b179ae4bca81b45a4f","src/rngs/small.rs":"eb942851fe2c2ce11eb0fe179efdfe2889dfc9bc72398bddbdfa327882935dd9","src/rngs/std.rs":"8420c2c32f312b2400ed23afdd9019632c2dd61bb5bd935d6d73bacbcbb9a5b2","src/rngs/thread.rs":"82ef4cf043d16d1d3e6f0037b269f817b133833240f866cd8a7b6e82d3c279ff","src/seq/index.rs":"384500a66361d21531db1380474066fa0bafb672ff7c9db00208b30a94664511","src/seq/mod.rs":"5a9938dc2ac75f393b54267abced2c5f7fbba4ffbdeb6ecdc80afe618c28fea6","tests/uniformity.rs":"0b774361f7db445bd910ad2cbac71207d01ace6881b8d501f4ff01bffd16cd68"},"package":"6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"}
|
||||
{"files":{"CHANGELOG.md":"460c7dbfdf227b4c725f7da8131fd51a54d0355b3c5804c0d388c70d3c1c49ec","Cargo.toml":"7d29da51fe4bf73964b3b3dea0af88040514569e2d184c9e8eb2f1746d540fb7","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"fb8071c3bc1013107b16ebcb303f31ef614e81440f2d58a46bfb9ff1e311b792","appveyor.yml":"8796156caf7041ef2a43f7a313df21ea639de3f2563b6181bba1096b1c489f1b","benches/bench.rs":"35c4ab609f2a5f5aab6c52c257415258dc0780621b492b5a82bb12d048cab6db","benches/distributions/exponential.rs":"99cb59c013a0b6bb390d34c5649b341fc3b88ea7df0caf2470bdda8798f9fe3d","benches/distributions/gamma.rs":"3533f311e4b55d743c5b01a7eb6529c94fd97726ef6702a6372f914f5f33666b","benches/distributions/mod.rs":"0028f1cb96f61152ed5b49a4fe91227d809ef6d19035592c36032a538af7f95e","benches/distributions/normal.rs":"4e10c18cb583ccb96301ea953c8e0aa9ee3b6662060271d1b8d19ca23364dc6b","benches/generators.rs":"aaa2f1dbfb399df8323d8a5796b92add6210cd5f0f1d916895ffdd81d60f812b","benches/misc.rs":"bd2f7c5a16f0fcb59022d5aeef66ed3c94e89ebf6c06667851dd23d0b1595504","src/distributions/exponential.rs":"103c8412c8a581b71835f1c00e40f6370e7702adf9d499243933a793d132d4e7","src/distributions/gamma.rs":"7a3f85c8daad4e56e334586ddb9fc9d83df3b0699738ed681a6c41e4ed455be9","src/distributions/mod.rs":"7943c4f83721bac816f831cca3b1574b6136932f7b4927aa6101130080ba62c5","src/distributions/normal.rs":"1562b43f80e4d5f83a8deb5af18de5a18dfeeeeda11fefc577da26672b14c949","src/distributions/range.rs":"a72a538d3ec4ed23f8d632aa55fd4793c464f24a5872d04ce8095ddd5db92115","src/distributions/ziggurat_tables.rs":"4eacf94fc352c91c455a6623de6a721e53842e1690f13a5662b6a79c7fbb73de","src/jitter.rs":"befd4b84bf753c107370b5b9498ad49611c220bdae2e4be9ee4398e9fa497042","src/lib.rs":"fbdc5f56ce1a52b15c85b0aa70a555c64be8f65d9f6f90fa0a3555d7862666b4","src/os.rs":"4860f165f68b7c978b0488c75d264cd9aaf54e7e4484036736ee5c4f5b6bd78d","src/prng/chacha.rs":"558007276f9c22933d39e5b8e853f4dd9533e823ed66df8dc1f23ad6925b1d51","src/prng/isaac.rs":"a8a2ee8b38d312663308e3bdf03376e342fd91330655f39144e5bba7392b2a8e","src/prng/isaac64.rs":"f28f7596ccab910db265b42671116abb9d2039fa8a421cbc75312bd0e7715d3a","src/prng/mod.rs":"c1a73450f49e819a20942a5b591f84a08ebb5ac33aa0f65b18ac1dc9a19a3084","src/prng/xorshift.rs":"606c308747293652c868b46dc3cad847d0c3717629c04ba75681c887c7634114","src/rand_impls.rs":"e1f27077fc13d5855bb66235f8ccfb216e116337eb38424d9c30c090e112215c","src/read.rs":"bd0eb508a6b659dc578d546fc2f231484aed80c73cfe8c475e0d65c8d699a769","src/reseeding.rs":"a97b86387b87ea1adc5262ddea480fe735c9c2a86762abaace29119022ac9f6e","src/seq.rs":"76dd58af0f580aed2721c393a5c036322186dc7cb3b4abed33436620c7c49288","utils/ziggurat_tables.py":"a9fc0a2fdae9b5c798c238788f94b720c156e13fd96f2356c409aa533191eb94"},"package":"8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"}
|
|
@ -2,262 +2,22 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md).
|
||||
|
||||
You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful.
|
||||
|
||||
|
||||
## [0.6.5] - 2019-01-28
|
||||
### Crates
|
||||
- Update `rand_core` to 0.4 (#703)
|
||||
- Move `JitterRng` to its own crate (#685)
|
||||
- Add a warm-bindgen test crate (#696)
|
||||
|
||||
### Platforms
|
||||
- Fuchsia: Replaced fuchsia-zircon with fuchsia-cprng
|
||||
|
||||
### Doc
|
||||
- Use RFC 1946 for doc links (#691)
|
||||
- Fix some doc links and notes (#711)
|
||||
|
||||
## [0.6.4] - 2019-01-08
|
||||
### Fixes
|
||||
- Move wasm-bindgen shims to correct crate (#686)
|
||||
- Make `wasm32-unknown-unknown` compile but fail at run-time if missing bindingsg (#686)
|
||||
|
||||
## [0.6.3] - 2019-01-04
|
||||
### Fixes
|
||||
- Make the `std` feature require the optional `rand_os` dependency (#675)
|
||||
- Re-export the optional WASM dependencies of `rand_os` from `rand` to avoid breakage (#674)
|
||||
|
||||
## [0.6.2] - 2019-01-04
|
||||
### Additions
|
||||
- Add `Default` for `ThreadRng` (#657)
|
||||
- Move `rngs::OsRng` to `rand_os` sub-crate; clean up code; use as dependency (#643) ##BLOCKER##
|
||||
- Add `rand_xoshiro` sub-crate, plus benchmarks (#642, #668)
|
||||
|
||||
### Fixes
|
||||
- Fix bias in `UniformInt::sample_single` (#662)
|
||||
- Use `autocfg` instead of `rustc_version` for rustc version detection (#664)
|
||||
- Disable `i128` and `u128` if the `target_os` is `emscripten` (#671: work-around Emscripten limitation)
|
||||
- CI fixes (#660, #671)
|
||||
|
||||
### Optimisations
|
||||
- Optimise memory usage of `UnitCircle` and `UnitSphereSurface` distributions (no PR)
|
||||
|
||||
## [0.6.1] - 2018-11-22
|
||||
- Support sampling `Duration` also for `no_std` (only since Rust 1.25) (#649)
|
||||
- Disable default features of `libc` (#647)
|
||||
|
||||
## [0.6.0] - 2018-11-14
|
||||
|
||||
### Project organisation
|
||||
- Rand has moved from [rust-lang-nursery](https://github.com/rust-lang-nursery/rand)
|
||||
to [rust-random](https://github.com/rust-random/rand)! (#578)
|
||||
- Created [The Rust Random Book](https://rust-random.github.io/book/)
|
||||
([source](https://github.com/rust-random/book))
|
||||
- Update copyright and licence notices (#591, #611)
|
||||
- Migrate policy documentation from the wiki (#544)
|
||||
|
||||
### Platforms
|
||||
- Add fork protection on Unix (#466)
|
||||
- Added support for wasm-bindgen. (#541, #559, #562, #600)
|
||||
- Enable `OsRng` for powerpc64, sparc and sparc64 (#609)
|
||||
- Use `syscall` from `libc` on Linux instead of redefining it (#629)
|
||||
|
||||
### RNGs
|
||||
- Switch `SmallRng` to use PCG (#623)
|
||||
- Implement `Pcg32` and `Pcg64Mcg` generators (#632)
|
||||
- Move ISAAC RNGs to a dedicated crate (#551)
|
||||
- Move Xorshift RNG to its own crate (#557)
|
||||
- Move ChaCha and HC128 RNGs to dedicated crates (#607, #636)
|
||||
- Remove usage of `Rc` from `ThreadRng` (#615)
|
||||
|
||||
### Sampling and distributions
|
||||
- Implement `Rng.gen_ratio()` and `Bernoulli::new_ratio()` (#491)
|
||||
- Make `Uniform` strictly respect `f32` / `f64` high/low bounds (#477)
|
||||
- Allow `gen_range` and `Uniform` to work on non-`Copy` types (#506)
|
||||
- `Uniform` supports inclusive ranges: `Uniform::from(a..=b)`. This is
|
||||
automatically enabled for Rust >= 1.27. (#566)
|
||||
- Implement `TrustedLen` and `FusedIterator` for `DistIter` (#620)
|
||||
|
||||
#### New distributions
|
||||
- Add the `Dirichlet` distribution (#485)
|
||||
- Added sampling from the unit sphere and circle. (#567)
|
||||
- Implement the triangular distribution (#575)
|
||||
- Implement the Weibull distribution (#576)
|
||||
- Implement the Beta distribution (#574)
|
||||
|
||||
#### Optimisations
|
||||
|
||||
- Optimise `Bernoulli::new` (#500)
|
||||
- Optimise `char` sampling (#519)
|
||||
- Optimise sampling of `std::time::Duration` (#583)
|
||||
|
||||
### Sequences
|
||||
- Redesign the `seq` module (#483, #515)
|
||||
- Add `WeightedIndex` and `choose_weighted` (#518, #547)
|
||||
- Optimised and changed return type of the `sample_indices` function. (#479)
|
||||
- Use `Iterator::size_hint()` to speed up `IteratorRandom::choose` (#593)
|
||||
|
||||
### SIMD
|
||||
- Support for generating SIMD types (#523, #542, #561, #630)
|
||||
|
||||
### Other
|
||||
- Revise CI scripts (#632, #635)
|
||||
- Remove functionality already deprecated in 0.5 (#499)
|
||||
- Support for `i128` and `u128` is automatically enabled for Rust >= 1.26. This
|
||||
renders the `i128_support` feature obsolete. It still exists for backwards
|
||||
compatibility but does not have any effect. This breaks programs using Rand
|
||||
with `i128_support` on nightlies older than Rust 1.26. (#571)
|
||||
|
||||
|
||||
## [0.5.5] - 2018-08-07
|
||||
### Documentation
|
||||
- Fix links in documentation (#582)
|
||||
|
||||
|
||||
## [0.5.4] - 2018-07-11
|
||||
### Platform support
|
||||
- Make `OsRng` work via WASM/stdweb for WebWorkers
|
||||
|
||||
|
||||
## [0.5.3] - 2018-06-26
|
||||
### Platform support
|
||||
- OpenBSD, Bitrig: fix compilation (broken in 0.5.1) (#530)
|
||||
|
||||
|
||||
## [0.5.2] - 2018-06-18
|
||||
### Platform support
|
||||
- Hide `OsRng` and `JitterRng` on unsupported platforms (#512; fixes #503).
|
||||
|
||||
|
||||
## [0.5.1] - 2018-06-08
|
||||
|
||||
### New distributions
|
||||
- Added Cauchy distribution. (#474, #486)
|
||||
- Added Pareto distribution. (#495)
|
||||
|
||||
### Platform support and `OsRng`
|
||||
- Remove blanket Unix implementation. (#484)
|
||||
- Remove Wasm unimplemented stub. (#484)
|
||||
- Dragonfly BSD: read from `/dev/random`. (#484)
|
||||
- Bitrig: use `getentropy` like OpenBSD. (#484)
|
||||
- Solaris: (untested) use `getrandom` if available, otherwise `/dev/random`. (#484)
|
||||
- Emscripten, `stdweb`: split the read up in chunks. (#484)
|
||||
- Emscripten, Haiku: don't do an extra blocking read from `/dev/random`. (#484)
|
||||
- Linux, NetBSD, Solaris: read in blocking mode on first use in `fill_bytes`. (#484)
|
||||
- Fuchsia, CloudABI: fix compilation (broken in Rand 0.5). (#484)
|
||||
|
||||
|
||||
## [0.5.0] - 2018-05-21
|
||||
|
||||
### Crate features and organisation
|
||||
- Minimum Rust version update: 1.22.0. (#239)
|
||||
- Create a separate `rand_core` crate. (#288)
|
||||
- Deprecate `rand_derive`. (#256)
|
||||
- Add `prelude` (and module reorganisation). (#435)
|
||||
- Add `log` feature. Logging is now available in `JitterRng`, `OsRng`, `EntropyRng` and `ReseedingRng`. (#246)
|
||||
- Add `serde1` feature for some PRNGs. (#189)
|
||||
- `stdweb` feature for `OsRng` support on WASM via stdweb. (#272, #336)
|
||||
|
||||
### `Rng` trait
|
||||
- Split `Rng` in `RngCore` and `Rng` extension trait.
|
||||
`next_u32`, `next_u64` and `fill_bytes` are now part of `RngCore`. (#265)
|
||||
- Add `Rng::sample`. (#256)
|
||||
- Deprecate `Rng::gen_weighted_bool`. (#308)
|
||||
- Add `Rng::gen_bool`. (#308)
|
||||
- Remove `Rng::next_f32` and `Rng::next_f64`. (#273)
|
||||
- Add optimized `Rng::fill` and `Rng::try_fill` methods. (#247)
|
||||
- Deprecate `Rng::gen_iter`. (#286)
|
||||
- Deprecate `Rng::gen_ascii_chars`. (#279)
|
||||
|
||||
### `rand_core` crate
|
||||
- `rand` now depends on new `rand_core` crate (#288)
|
||||
- `RngCore` and `SeedableRng` are now part of `rand_core`. (#288)
|
||||
- Add modules to help implementing RNGs `impl` and `le`. (#209, #228)
|
||||
- Add `Error` and `ErrorKind`. (#225)
|
||||
- Add `CryptoRng` marker trait. (#273)
|
||||
- Add `BlockRngCore` trait. (#281)
|
||||
- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325)
|
||||
- Revise the `SeedableRng` trait. (#233)
|
||||
- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288)
|
||||
- Add `RngCore::try_fill_bytes`. (#225)
|
||||
|
||||
### Other traits and types
|
||||
- Add `FromEntropy` trait. (#233, #375)
|
||||
- Add `SmallRng` wrapper. (#296)
|
||||
- Rewrite `ReseedingRng` to only work with `BlockRngCore` (substantial performance improvement). (#281)
|
||||
- Deprecate `weak_rng`. Use `SmallRng` instead. (#296)
|
||||
- Deprecate `AsciiGenerator`. (#279)
|
||||
|
||||
### Random number generators
|
||||
- Switch `StdRng` and `thread_rng` to HC-128. (#277)
|
||||
- `StdRng` must now be created with `from_entropy` instead of `new`
|
||||
- Change `thread_rng` reseeding threshold to 32 MiB. (#277)
|
||||
- PRNGs no longer implement `Copy`. (#209)
|
||||
- `Debug` implementations no longer show internals. (#209)
|
||||
- Implement `Clone` for `ReseedingRng`, `JitterRng`, OsRng`. (#383, #384)
|
||||
- Implement serialization for `XorShiftRng`, `IsaacRng` and `Isaac64Rng` under the `serde1` feature. (#189)
|
||||
- Implement `BlockRngCore` for `ChaChaCore` and `Hc128Core`. (#281)
|
||||
- All PRNGs are now portable across big- and little-endian architectures. (#209)
|
||||
- `Isaac64Rng::next_u32` no longer throws away half the results. (#209)
|
||||
- Add `IsaacRng::new_from_u64` and `Isaac64Rng::new_from_u64`. (#209)
|
||||
- Add the HC-128 CSPRNG `Hc128Rng`. (#210)
|
||||
- Change ChaCha20 to have 64-bit counter and 64-bit stream. (#349)
|
||||
- Changes to `JitterRng` to get its size down from 2112 to 24 bytes. (#251)
|
||||
- Various performance improvements to all PRNGs.
|
||||
|
||||
### Platform support and `OsRng`
|
||||
- Add support for CloudABI. (#224)
|
||||
- Remove support for NaCl. (#225)
|
||||
- WASM support for `OsRng` via stdweb, behind the `stdweb` feature. (#272, #336)
|
||||
- Use `getrandom` on more platforms for Linux, and on Android. (#338)
|
||||
- Use the `SecRandomCopyBytes` interface on macOS. (#322)
|
||||
- On systems that do not have a syscall interface, only keep a single file descriptor open for `OsRng`. (#239)
|
||||
- On Unix, first try a single read from `/dev/random`, then `/dev/urandom`. (#338)
|
||||
- Better error handling and reporting in `OsRng` (using new error type). (#225)
|
||||
- `OsRng` now uses non-blocking when available. (#225)
|
||||
- Add `EntropyRng`, which provides `OsRng`, but has `JitterRng` as a fallback. (#235)
|
||||
|
||||
### Distributions
|
||||
- New `Distribution` trait. (#256)
|
||||
- Add `Distribution::sample_iter` and `Rng::::sample_iter`. (#361)
|
||||
- Deprecate `Rand`, `Sample` and `IndependentSample` traits. (#256)
|
||||
- Add a `Standard` distribution (replaces most `Rand` implementations). (#256)
|
||||
- Add `Binomial` and `Poisson` distributions. (#96)
|
||||
- Add `Bernoulli` dsitribution. (#411)
|
||||
- Add `Alphanumeric` distribution. (#279)
|
||||
- Remove `Closed01` distribution, add `OpenClosed01`. (#274, #420)
|
||||
- Rework `Range` type, making it possible to implement it for user types. (#274)
|
||||
- Rename `Range` to `Uniform`. (#395)
|
||||
- Add `Uniform::new_inclusive` for inclusive ranges. (#274)
|
||||
- Use widening multiply method for much faster integer range reduction. (#274)
|
||||
- `Standard` distribution for `char` uses `Uniform` internally. (#274)
|
||||
- `Standard` distribution for `bool` uses sign test. (#274)
|
||||
- Implement `Standard` distribution for `Wrapping<T>`. (#436)
|
||||
- Implement `Uniform` distribution for `Duration`. (#427)
|
||||
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.4.3] - 2018-08-16
|
||||
### Fixed
|
||||
- Use correct syscall number for PowerPC (#589)
|
||||
|
||||
|
||||
## [0.4.2] - 2018-01-06
|
||||
## [0.4.2] - 2018-01-05
|
||||
### Changed
|
||||
- Use `winapi` on Windows
|
||||
- Use winapi on Windows
|
||||
- Update for Fuchsia OS
|
||||
- Remove dev-dependency on `log`
|
||||
|
||||
|
||||
## [0.4.1] - 2017-12-17
|
||||
### Added
|
||||
- `no_std` support
|
||||
|
||||
|
||||
## [0.4.0-pre.0] - 2017-12-11
|
||||
### Added
|
||||
- `JitterRng` added as a high-quality alternative entropy source using the
|
||||
|
@ -273,20 +33,6 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.
|
|||
### Deprecated
|
||||
- `sample` function deprecated (replaced by `sample_iter`)
|
||||
|
||||
|
||||
## [0.3.20] - 2018-01-06
|
||||
### Changed
|
||||
- Remove dev-dependency on `log`
|
||||
- Update `fuchsia-zircon` dependency to 0.3.2
|
||||
|
||||
|
||||
## [0.3.19] - 2017-12-27
|
||||
### Changed
|
||||
- Require `log <= 0.3.8` for dev builds
|
||||
- Update `fuchsia-zircon` dependency to 0.3
|
||||
- Fix broken links in docs (to unblock compiler docs testing CI)
|
||||
|
||||
|
||||
## [0.3.18] - 2017-11-06
|
||||
### Changed
|
||||
- `thread_rng` is seeded from the system time if `OsRng` fails
|
||||
|
@ -435,7 +181,7 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.
|
|||
- Compatible with Rust master
|
||||
|
||||
### Removed
|
||||
- Removed Copy implementations from RNGs
|
||||
- Removed Copy inplementaions from RNGs
|
||||
|
||||
|
||||
## [0.1.2] - 2015-02-03
|
||||
|
@ -481,7 +227,7 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.
|
|||
- `Rng::gen_ascii_chars()` which will return an infinite stream of random ascii characters
|
||||
|
||||
### Changed
|
||||
- Now only depends on libcore!
|
||||
- Now only depends on libcore! 2adf5363f88ffe06f6d2ea5c338d1b186d47f4a1
|
||||
- Remove `Rng.choose()`, rename `Rng.choose_option()` to `.choose()`
|
||||
- Rename OSRng to OsRng
|
||||
- The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
|
||||
|
@ -520,3 +266,4 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.
|
|||
## [0.10-pre] - 2014-03-02
|
||||
### Added
|
||||
- Seperate `rand` out of the standard library
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
Copyrights in the Rand project are retained by their contributors. No
|
||||
copyright assignment is required to contribute to the Rand project.
|
||||
|
||||
For full authorship information, see the version control history.
|
||||
|
||||
Except as otherwise noted (below and/or in individual files), Rand is
|
||||
licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
|
||||
<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
|
||||
|
||||
The Rand project includes code from the Rust project
|
||||
published under these same licenses.
|
|
@ -12,79 +12,28 @@
|
|||
|
||||
[package]
|
||||
name = "rand"
|
||||
version = "0.6.5"
|
||||
authors = ["The Rand Project Developers", "The Rust Project Developers"]
|
||||
build = "build.rs"
|
||||
exclude = ["/utils/*", "/.travis.yml", "/appveyor.yml", ".gitignore"]
|
||||
version = "0.4.3"
|
||||
authors = ["The Rust Project Developers"]
|
||||
description = "Random number generators and other randomness functionality.\n"
|
||||
homepage = "https://crates.io/crates/rand"
|
||||
documentation = "https://rust-random.github.io/rand"
|
||||
homepage = "https://github.com/rust-lang-nursery/rand"
|
||||
documentation = "https://docs.rs/rand"
|
||||
readme = "README.md"
|
||||
keywords = ["random", "rng"]
|
||||
categories = ["algorithms", "no-std"]
|
||||
categories = ["algorithms"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/rust-random/rand"
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
[dependencies.log]
|
||||
version = "0.4"
|
||||
optional = true
|
||||
|
||||
[dependencies.packed_simd]
|
||||
version = "0.3"
|
||||
features = ["into_bits"]
|
||||
optional = true
|
||||
|
||||
[dependencies.rand_chacha]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.rand_core]
|
||||
version = "0.4"
|
||||
|
||||
[dependencies.rand_hc]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.rand_isaac]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.rand_jitter]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.rand_os]
|
||||
version = "0.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.rand_pcg]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.rand_xorshift]
|
||||
version = "0.1"
|
||||
[dev-dependencies.average]
|
||||
version = "0.9.2"
|
||||
|
||||
[dev-dependencies.rand_xoshiro]
|
||||
version = "0.1"
|
||||
[build-dependencies.autocfg]
|
||||
version = "0.1"
|
||||
repository = "https://github.com/rust-lang-nursery/rand"
|
||||
|
||||
[features]
|
||||
alloc = ["rand_core/alloc"]
|
||||
alloc = []
|
||||
default = ["std"]
|
||||
i128_support = []
|
||||
nightly = ["simd_support"]
|
||||
serde1 = ["rand_core/serde1", "rand_isaac/serde1", "rand_xorshift/serde1"]
|
||||
simd_support = ["packed_simd"]
|
||||
std = ["rand_core/std", "alloc", "rand_os", "rand_jitter/std"]
|
||||
stdweb = ["rand_os/stdweb"]
|
||||
wasm-bindgen = ["rand_os/wasm-bindgen"]
|
||||
nightly = ["i128_support"]
|
||||
std = ["libc"]
|
||||
[target."cfg(target_os = \"fuchsia\")".dependencies.fuchsia-zircon]
|
||||
version = "0.3.2"
|
||||
[target."cfg(unix)".dependencies.libc]
|
||||
version = "0.2"
|
||||
default-features = false
|
||||
optional = true
|
||||
[target."cfg(windows)".dependencies.winapi]
|
||||
version = "0.3"
|
||||
features = ["minwindef", "ntsecapi", "profileapi", "winnt"]
|
||||
[badges.appveyor]
|
||||
repository = "rust-random/rand"
|
||||
|
||||
[badges.travis-ci]
|
||||
repository = "rust-random/rand"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
|
@ -192,7 +192,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
|
|||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
Copyright 2018 Developers of the Rand project
|
||||
Copyright (c) 2014 The Rust Project Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
|
|
|
@ -1,28 +1,12 @@
|
|||
# Rand
|
||||
rand
|
||||
====
|
||||
|
||||
[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand)
|
||||
[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand)
|
||||
[![Crate](https://img.shields.io/crates/v/rand.svg)](https://crates.io/crates/rand)
|
||||
[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/)
|
||||
[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand)
|
||||
[![API](https://docs.rs/rand/badge.svg)](https://docs.rs/rand)
|
||||
[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
|
||||
A Rust library for random number generators and other randomness functionality.
|
||||
|
||||
A Rust library for random number generation.
|
||||
|
||||
Rand provides utilities to generate random numbers, to convert them to useful
|
||||
types and distributions, and some randomness-related algorithms.
|
||||
|
||||
The core random number generation traits of Rand live in the [rand_core](
|
||||
https://crates.io/crates/rand_core) crate but are also exposed here; RNG
|
||||
implementations should prefer to use `rand_core` while most other users should
|
||||
depend on `rand`.
|
||||
|
||||
Documentation:
|
||||
- [The Rust Rand Book](https://rust-random.github.io/book)
|
||||
- [API reference (master)](https://rust-random.github.io/rand)
|
||||
- [API reference (docs.rs)](https://docs.rs/rand)
|
||||
[![Build Status](https://travis-ci.org/rust-lang-nursery/rand.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rand)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/rm5c9o33k3jhchbw?svg=true)](https://ci.appveyor.com/project/alexcrichton/rand)
|
||||
|
||||
[Documentation](https://docs.rs/rand)
|
||||
|
||||
## Usage
|
||||
|
||||
|
@ -30,93 +14,126 @@ Add this to your `Cargo.toml`:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
rand = "0.6"
|
||||
rand = "0.4"
|
||||
```
|
||||
|
||||
To get started using Rand, see [The Book](https://rust-random.github.io/book).
|
||||
and this to your crate root:
|
||||
|
||||
```rust
|
||||
extern crate rand;
|
||||
```
|
||||
|
||||
## Versions
|
||||
### Versions
|
||||
|
||||
The Rand lib is not yet stable, however we are careful to limit breaking changes
|
||||
and warn via deprecation wherever possible. Patch versions never introduce
|
||||
breaking changes. The following minor versions are supported:
|
||||
Version `0.4`was released in December 2017. It contains almost no breaking
|
||||
changes since the `0.3` series, but nevertheless contains some significant
|
||||
new code, including a new "external" entropy source (`JitterRng`) and `no_std`
|
||||
support.
|
||||
|
||||
- Version 0.6 was released in November 2018, redesigning the `seq` module,
|
||||
moving most PRNGs to external crates, and many small changes.
|
||||
- Version 0.5 was released in May 2018, as a major reorganisation
|
||||
(introducing `RngCore` and `rand_core`, and deprecating `Rand` and the
|
||||
previous distribution traits).
|
||||
- Version 0.4 was released in December 2017, but contained almost no breaking
|
||||
changes from the 0.3 series.
|
||||
Version `0.5` is in development and contains significant performance
|
||||
improvements for the ISAAC random number generators.
|
||||
|
||||
A detailed [changelog](CHANGELOG.md) is available.
|
||||
## Examples
|
||||
|
||||
When upgrading to the next minor series (especially 0.4 → 0.5), we recommend
|
||||
reading the [Upgrade Guide](https://rust-random.github.io/book/update.html).
|
||||
There is built-in support for a random number generator (RNG) associated with each thread stored in thread-local storage. This RNG can be accessed via thread_rng, or used implicitly via random. This RNG is normally randomly seeded from an operating-system source of randomness, e.g. /dev/urandom on Unix systems, and will automatically reseed itself from this source after generating 32 KiB of random data.
|
||||
|
||||
### Rust version requirements
|
||||
```rust
|
||||
let tuple = rand::random::<(f64, char)>();
|
||||
println!("{:?}", tuple)
|
||||
```
|
||||
|
||||
Since version 0.5, Rand requires **Rustc version 1.22 or greater**.
|
||||
Rand 0.4 and 0.3 (since approx. June 2017) require Rustc version 1.15 or
|
||||
greater. Subsets of the Rand code may work with older Rust versions, but this
|
||||
is not supported.
|
||||
```rust
|
||||
use rand::Rng;
|
||||
|
||||
Travis CI always has a build with a pinned version of Rustc matching the oldest
|
||||
supported Rust release. The current policy is that this can be updated in any
|
||||
Rand release if required, but the change must be noted in the changelog.
|
||||
let mut rng = rand::thread_rng();
|
||||
if rng.gen() { // random bool
|
||||
println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
|
||||
}
|
||||
```
|
||||
|
||||
To avoid bumping the required version unnecessarily, we use a `build.rs` script
|
||||
to auto-detect the compiler version and enable certain features or change code
|
||||
paths automatically. Since this makes it easy to unintentionally make use of
|
||||
features requiring a more recent Rust version, we recommend testing with a
|
||||
pinned version of Rustc if you require compatibility with a specific version.
|
||||
It is also possible to use other RNG types, which have a similar interface. The following uses the "ChaCha" algorithm instead of the default.
|
||||
|
||||
## Crate Features
|
||||
```rust
|
||||
use rand::{Rng, ChaChaRng};
|
||||
|
||||
Rand is built with the `std` and `rand_os` features enabled by default:
|
||||
let mut rng = rand::ChaChaRng::new_unseeded();
|
||||
println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
|
||||
```
|
||||
|
||||
- `std` enables functionality dependent on the `std` lib and implies `alloc`
|
||||
and `rand_os`
|
||||
- `rand_os` enables the `rand_os` crate, `rngs::OsRng` and enables its usage;
|
||||
the continued existance of this feature is not guaranteed so users are
|
||||
encouraged to specify `std` instead
|
||||
## Features
|
||||
|
||||
The following optional features are available:
|
||||
By default, `rand` is built with all stable features available. The following
|
||||
optional features are available:
|
||||
|
||||
- `alloc` can be used instead of `std` to provide `Vec` and `Box`.
|
||||
- `log` enables some logging via the `log` crate.
|
||||
- `nightly` enables all unstable features (`simd_support`).
|
||||
- `serde1` enables serialization for some types, via Serde version 1.
|
||||
- `simd_support` enables uniform sampling of SIMD types (integers and floats).
|
||||
- `stdweb` enables support for `OsRng` on `wasm32-unknown-unknown` via `stdweb`
|
||||
combined with `cargo-web`.
|
||||
- `wasm-bindgen` enables support for `OsRng` on `wasm32-unknown-unknown` via
|
||||
[`wasm-bindgen`]
|
||||
- `i128_support` enables support for generating `u128` and `i128` values
|
||||
- `nightly` enables all unstable features (`i128_support`)
|
||||
- `std` enabled by default; by setting "default-features = false" `no_std`
|
||||
mode is activated; this removes features depending on `std` functionality:
|
||||
|
||||
- `OsRng` is entirely unavailable
|
||||
- `JitterRng` code is still present, but a nanosecond timer must be
|
||||
provided via `JitterRng::new_with_timer`
|
||||
- Since no external entropy is available, it is not possible to create
|
||||
generators with fresh seeds (user must provide entropy)
|
||||
- `thread_rng`, `weak_rng` and `random` are all disabled
|
||||
- exponential, normal and gamma type distributions are unavailable
|
||||
since `exp` and `log` functions are not provided in `core`
|
||||
- any code requiring `Vec` or `Box`
|
||||
- `alloc` can be used instead of `std` to provide `Vec` and `Box`
|
||||
|
||||
[`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen
|
||||
## Testing
|
||||
|
||||
`no_std` mode is activated by setting `default-features = false`; this removes
|
||||
functionality depending on `std`:
|
||||
Unfortunately, `cargo test` does not test everything. The following tests are
|
||||
recommended:
|
||||
|
||||
- `thread_rng()`, and `random()` are not available, as they require thread-local
|
||||
storage and an entropy source.
|
||||
- `OsRng` and `EntropyRng` are unavailable.
|
||||
- `JitterRng` code is still present, but a nanosecond timer must be provided via
|
||||
`JitterRng::new_with_timer`
|
||||
- Since no external entropy is available, it is not possible to create
|
||||
generators with fresh seeds using the `FromEntropy` trait (user must provide
|
||||
a seed).
|
||||
- Several non-linear distributions distributions are unavailable since `exp`
|
||||
and `log` functions are not provided in `core`.
|
||||
- Large parts of the `seq`-uence module are unavailable, unless the `alloc`
|
||||
feature is used (several APIs and many implementations require `Vec`).
|
||||
```
|
||||
# Basic tests for rand and sub-crates
|
||||
cargo test --all
|
||||
|
||||
# Test no_std support (build only since nearly all tests require std)
|
||||
cargo build --all --no-default-features
|
||||
|
||||
# Test 128-bit support (requires nightly)
|
||||
cargo test --all --features nightly
|
||||
|
||||
# Benchmarks (requires nightly)
|
||||
cargo bench
|
||||
# or just to test the benchmark code:
|
||||
cargo test --benches
|
||||
```
|
||||
|
||||
# `derive(Rand)`
|
||||
|
||||
You can derive the `Rand` trait for your custom type via the `#[derive(Rand)]`
|
||||
directive. To use this first add this to your Cargo.toml:
|
||||
|
||||
```toml
|
||||
rand = "0.4"
|
||||
rand_derive = "0.3"
|
||||
```
|
||||
|
||||
Next in your crate:
|
||||
|
||||
```rust
|
||||
extern crate rand;
|
||||
#[macro_use]
|
||||
extern crate rand_derive;
|
||||
|
||||
#[derive(Rand, Debug)]
|
||||
struct MyStruct {
|
||||
a: i32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", rand::random::<MyStruct>());
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# License
|
||||
|
||||
Rand is distributed under the terms of both the MIT license and the
|
||||
Apache License (Version 2.0).
|
||||
`rand` is primarily distributed under the terms of both the MIT
|
||||
license and the Apache License (Version 2.0).
|
||||
|
||||
See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
|
||||
[COPYRIGHT](COPYRIGHT) for details.
|
||||
See LICENSE-APACHE, and LICENSE-MIT for details.
|
||||
|
|
|
@ -1,259 +0,0 @@
|
|||
// Copyright 2018 Developers of the Rand project.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate rand;
|
||||
|
||||
const RAND_BENCH_N: u64 = 1000;
|
||||
|
||||
use std::mem::size_of;
|
||||
use test::Bencher;
|
||||
use std::time::Duration;
|
||||
|
||||
use rand::{Rng, FromEntropy};
|
||||
use rand::rngs::SmallRng;
|
||||
use rand::distributions::*;
|
||||
|
||||
macro_rules! distr_int {
|
||||
($fnn:ident, $ty:ty, $distr:expr) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
let distr = $distr;
|
||||
|
||||
b.iter(|| {
|
||||
let mut accum = 0 as $ty;
|
||||
for _ in 0..::RAND_BENCH_N {
|
||||
let x: $ty = distr.sample(&mut rng);
|
||||
accum = accum.wrapping_add(x);
|
||||
}
|
||||
accum
|
||||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! distr_float {
|
||||
($fnn:ident, $ty:ty, $distr:expr) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
let distr = $distr;
|
||||
|
||||
b.iter(|| {
|
||||
let mut accum = 0.0;
|
||||
for _ in 0..::RAND_BENCH_N {
|
||||
let x: $ty = distr.sample(&mut rng);
|
||||
accum += x;
|
||||
}
|
||||
accum
|
||||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! distr_duration {
|
||||
($fnn:ident, $distr:expr) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
let distr = $distr;
|
||||
|
||||
b.iter(|| {
|
||||
let mut accum = Duration::new(0, 0);
|
||||
for _ in 0..::RAND_BENCH_N {
|
||||
let x: Duration = distr.sample(&mut rng);
|
||||
accum = accum.checked_add(x).unwrap_or(Duration::new(u64::max_value(), 999_999_999));
|
||||
}
|
||||
accum
|
||||
});
|
||||
b.bytes = size_of::<Duration>() as u64 * ::RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! distr {
|
||||
($fnn:ident, $ty:ty, $distr:expr) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
let distr = $distr;
|
||||
|
||||
b.iter(|| {
|
||||
let mut accum = 0u32;
|
||||
for _ in 0..::RAND_BENCH_N {
|
||||
let x: $ty = distr.sample(&mut rng);
|
||||
accum = accum.wrapping_add(x as u32);
|
||||
}
|
||||
accum
|
||||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! distr_arr {
|
||||
($fnn:ident, $ty:ty, $distr:expr) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
let distr = $distr;
|
||||
|
||||
b.iter(|| {
|
||||
let mut accum = 0u32;
|
||||
for _ in 0..::RAND_BENCH_N {
|
||||
let x: $ty = distr.sample(&mut rng);
|
||||
accum = accum.wrapping_add(x[0] as u32);
|
||||
}
|
||||
accum
|
||||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// uniform
|
||||
distr_int!(distr_uniform_i8, i8, Uniform::new(20i8, 100));
|
||||
distr_int!(distr_uniform_i16, i16, Uniform::new(-500i16, 2000));
|
||||
distr_int!(distr_uniform_i32, i32, Uniform::new(-200_000_000i32, 800_000_000));
|
||||
distr_int!(distr_uniform_i64, i64, Uniform::new(3i64, 123_456_789_123));
|
||||
distr_int!(distr_uniform_i128, i128, Uniform::new(-123_456_789_123i128, 123_456_789_123_456_789));
|
||||
|
||||
distr_float!(distr_uniform_f32, f32, Uniform::new(2.26f32, 2.319));
|
||||
distr_float!(distr_uniform_f64, f64, Uniform::new(2.26f64, 2.319));
|
||||
|
||||
const LARGE_SEC: u64 = u64::max_value() / 1000;
|
||||
|
||||
distr_duration!(distr_uniform_duration_largest,
|
||||
Uniform::new_inclusive(Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999))
|
||||
);
|
||||
distr_duration!(distr_uniform_duration_large,
|
||||
Uniform::new(Duration::new(0, 0), Duration::new(LARGE_SEC, 1_000_000_000 / 2))
|
||||
);
|
||||
distr_duration!(distr_uniform_duration_one,
|
||||
Uniform::new(Duration::new(0, 0), Duration::new(1, 0))
|
||||
);
|
||||
distr_duration!(distr_uniform_duration_variety,
|
||||
Uniform::new(Duration::new(10000, 423423), Duration::new(200000, 6969954))
|
||||
);
|
||||
distr_duration!(distr_uniform_duration_edge,
|
||||
Uniform::new_inclusive(Duration::new(LARGE_SEC, 999_999_999), Duration::new(LARGE_SEC + 1, 1))
|
||||
);
|
||||
|
||||
|
||||
// standard
|
||||
distr_int!(distr_standard_i8, i8, Standard);
|
||||
distr_int!(distr_standard_i16, i16, Standard);
|
||||
distr_int!(distr_standard_i32, i32, Standard);
|
||||
distr_int!(distr_standard_i64, i64, Standard);
|
||||
distr_int!(distr_standard_i128, i128, Standard);
|
||||
|
||||
distr!(distr_standard_bool, bool, Standard);
|
||||
distr!(distr_standard_alphanumeric, char, Alphanumeric);
|
||||
distr!(distr_standard_codepoint, char, Standard);
|
||||
|
||||
distr_float!(distr_standard_f32, f32, Standard);
|
||||
distr_float!(distr_standard_f64, f64, Standard);
|
||||
distr_float!(distr_open01_f32, f32, Open01);
|
||||
distr_float!(distr_open01_f64, f64, Open01);
|
||||
distr_float!(distr_openclosed01_f32, f32, OpenClosed01);
|
||||
distr_float!(distr_openclosed01_f64, f64, OpenClosed01);
|
||||
|
||||
// distributions
|
||||
distr_float!(distr_exp, f64, Exp::new(1.23 * 4.56));
|
||||
distr_float!(distr_normal, f64, Normal::new(-1.23, 4.56));
|
||||
distr_float!(distr_log_normal, f64, LogNormal::new(-1.23, 4.56));
|
||||
distr_float!(distr_gamma_large_shape, f64, Gamma::new(10., 1.0));
|
||||
distr_float!(distr_gamma_small_shape, f64, Gamma::new(0.1, 1.0));
|
||||
distr_float!(distr_cauchy, f64, Cauchy::new(4.2, 6.9));
|
||||
distr_int!(distr_binomial, u64, Binomial::new(20, 0.7));
|
||||
distr_int!(distr_poisson, u64, Poisson::new(4.0));
|
||||
distr!(distr_bernoulli, bool, Bernoulli::new(0.18));
|
||||
distr_arr!(distr_circle, [f64; 2], UnitCircle::new());
|
||||
distr_arr!(distr_sphere_surface, [f64; 3], UnitSphereSurface::new());
|
||||
|
||||
// Weighted
|
||||
distr_int!(distr_weighted_i8, usize, WeightedIndex::new(&[1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap());
|
||||
distr_int!(distr_weighted_u32, usize, WeightedIndex::new(&[1u32, 2, 3, 4, 12, 0, 2, 1]).unwrap());
|
||||
distr_int!(distr_weighted_f64, usize, WeightedIndex::new(&[1.0f64, 0.001, 1.0/3.0, 4.01, 0.0, 3.3, 22.0, 0.001]).unwrap());
|
||||
distr_int!(distr_weighted_large_set, usize, WeightedIndex::new((0..10000).rev().chain(1..10001)).unwrap());
|
||||
|
||||
// construct and sample from a range
|
||||
macro_rules! gen_range_int {
|
||||
($fnn:ident, $ty:ident, $low:expr, $high:expr) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
|
||||
b.iter(|| {
|
||||
let mut high = $high;
|
||||
let mut accum: $ty = 0;
|
||||
for _ in 0..::RAND_BENCH_N {
|
||||
accum = accum.wrapping_add(rng.gen_range($low, high));
|
||||
// force recalculation of range each time
|
||||
high = high.wrapping_add(1) & std::$ty::MAX;
|
||||
}
|
||||
accum
|
||||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gen_range_int!(gen_range_i8, i8, -20i8, 100);
|
||||
gen_range_int!(gen_range_i16, i16, -500i16, 2000);
|
||||
gen_range_int!(gen_range_i32, i32, -200_000_000i32, 800_000_000);
|
||||
gen_range_int!(gen_range_i64, i64, 3i64, 123_456_789_123);
|
||||
gen_range_int!(gen_range_i128, i128, -12345678901234i128, 123_456_789_123_456_789);
|
||||
|
||||
// construct and sample from a floating-point range
|
||||
macro_rules! gen_range_float {
|
||||
($fnn:ident, $ty:ident, $low:expr, $high:expr) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
|
||||
b.iter(|| {
|
||||
let mut high = $high;
|
||||
let mut low = $low;
|
||||
let mut accum: $ty = 0.0;
|
||||
for _ in 0..::RAND_BENCH_N {
|
||||
accum += rng.gen_range(low, high);
|
||||
// force recalculation of range each time
|
||||
low += 0.9;
|
||||
high += 1.1;
|
||||
}
|
||||
accum
|
||||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gen_range_float!(gen_range_f32, f32, -20000.0f32, 100000.0);
|
||||
gen_range_float!(gen_range_f64, f64, 123.456f64, 7890.12);
|
||||
|
||||
#[bench]
|
||||
fn dist_iter(b: &mut Bencher) {
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
let distr = Normal::new(-2.71828, 3.14159);
|
||||
let mut iter = distr.sample_iter(&mut rng);
|
||||
|
||||
b.iter(|| {
|
||||
let mut accum = 0.0;
|
||||
for _ in 0..::RAND_BENCH_N {
|
||||
accum += iter.next().unwrap();
|
||||
}
|
||||
accum
|
||||
});
|
||||
b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N;
|
||||
}
|
|
@ -1,21 +1,7 @@
|
|||
// Copyright 2018 Developers of the Rand project.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate rand;
|
||||
extern crate rand_isaac;
|
||||
extern crate rand_chacha;
|
||||
extern crate rand_hc;
|
||||
extern crate rand_pcg;
|
||||
extern crate rand_xorshift;
|
||||
extern crate rand_xoshiro;
|
||||
|
||||
const RAND_BENCH_N: u64 = 1000;
|
||||
const BYTES_LEN: usize = 1024;
|
||||
|
@ -23,23 +9,14 @@ const BYTES_LEN: usize = 1024;
|
|||
use std::mem::size_of;
|
||||
use test::{black_box, Bencher};
|
||||
|
||||
use rand::prelude::*;
|
||||
use rand::rngs::adapter::ReseedingRng;
|
||||
use rand::rngs::{OsRng, JitterRng, EntropyRng};
|
||||
use rand_isaac::{IsaacRng, Isaac64Rng};
|
||||
use rand_chacha::ChaChaRng;
|
||||
use rand_hc::{Hc128Rng, Hc128Core};
|
||||
use rand_pcg::{Lcg64Xsh32, Mcg128Xsl64};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use rand_xoshiro::{Xoshiro256StarStar, Xoshiro256Plus, Xoshiro128StarStar,
|
||||
Xoshiro128Plus, Xoroshiro128StarStar, Xoroshiro128Plus, SplitMix64,
|
||||
Xoroshiro64StarStar, Xoroshiro64Star};
|
||||
use rand::{Rng, StdRng, OsRng, JitterRng};
|
||||
use rand::{XorShiftRng, IsaacRng, Isaac64Rng, ChaChaRng};
|
||||
|
||||
macro_rules! gen_bytes {
|
||||
($fnn:ident, $gen:expr) => {
|
||||
($fnn:ident, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = $gen;
|
||||
let mut rng: $gen = OsRng::new().unwrap().gen();
|
||||
let mut buf = [0u8; BYTES_LEN];
|
||||
b.iter(|| {
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
|
@ -52,90 +29,80 @@ macro_rules! gen_bytes {
|
|||
}
|
||||
}
|
||||
|
||||
gen_bytes!(gen_bytes_xorshift, XorShiftRng::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoshiro256starstar, Xoshiro256StarStar::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoshiro256plus, Xoshiro256Plus::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoshiro128starstar, Xoshiro128StarStar::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoshiro128plus, Xoshiro128Plus::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoroshiro128starstar, Xoroshiro128StarStar::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoroshiro128plus, Xoroshiro128Plus::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoroshiro64starstar, Xoroshiro64StarStar::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoroshiro64star, Xoroshiro64Star::from_entropy());
|
||||
gen_bytes!(gen_bytes_splitmix64, SplitMix64::from_entropy());
|
||||
gen_bytes!(gen_bytes_lcg64_xsh32, Lcg64Xsh32::from_entropy());
|
||||
gen_bytes!(gen_bytes_mcg128_xsh64, Mcg128Xsl64::from_entropy());
|
||||
gen_bytes!(gen_bytes_chacha20, ChaChaRng::from_entropy());
|
||||
gen_bytes!(gen_bytes_hc128, Hc128Rng::from_entropy());
|
||||
gen_bytes!(gen_bytes_isaac, IsaacRng::from_entropy());
|
||||
gen_bytes!(gen_bytes_isaac64, Isaac64Rng::from_entropy());
|
||||
gen_bytes!(gen_bytes_std, StdRng::from_entropy());
|
||||
gen_bytes!(gen_bytes_small, SmallRng::from_entropy());
|
||||
gen_bytes!(gen_bytes_os, OsRng::new().unwrap());
|
||||
|
||||
macro_rules! gen_uint {
|
||||
($fnn:ident, $ty:ty, $gen:expr) => {
|
||||
macro_rules! gen_bytes_new {
|
||||
($fnn:ident, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = $gen;
|
||||
let mut rng = $gen::new().unwrap();
|
||||
let mut buf = [0u8; BYTES_LEN];
|
||||
b.iter(|| {
|
||||
let mut accum: $ty = 0;
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
accum = accum.wrapping_add(rng.gen::<$ty>());
|
||||
rng.fill_bytes(&mut buf);
|
||||
black_box(buf);
|
||||
}
|
||||
});
|
||||
b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gen_bytes!(gen_bytes_xorshift, XorShiftRng);
|
||||
gen_bytes!(gen_bytes_isaac, IsaacRng);
|
||||
gen_bytes!(gen_bytes_isaac64, Isaac64Rng);
|
||||
gen_bytes!(gen_bytes_chacha, ChaChaRng);
|
||||
gen_bytes_new!(gen_bytes_std, StdRng);
|
||||
gen_bytes_new!(gen_bytes_os, OsRng);
|
||||
|
||||
|
||||
macro_rules! gen_uint {
|
||||
($fnn:ident, $ty:ty, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng: $gen = OsRng::new().unwrap().gen();
|
||||
b.iter(|| {
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
black_box(rng.gen::<$ty>());
|
||||
}
|
||||
accum
|
||||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gen_uint!(gen_u32_xorshift, u32, XorShiftRng::from_entropy());
|
||||
gen_uint!(gen_u32_xoshiro256starstar, u32, Xoshiro256StarStar::from_entropy());
|
||||
gen_uint!(gen_u32_xoshiro256plus, u32, Xoshiro256Plus::from_entropy());
|
||||
gen_uint!(gen_u32_xoshiro128starstar, u32, Xoshiro128StarStar::from_entropy());
|
||||
gen_uint!(gen_u32_xoshiro128plus, u32, Xoshiro128Plus::from_entropy());
|
||||
gen_uint!(gen_u32_xoroshiro128starstar, u32, Xoroshiro128StarStar::from_entropy());
|
||||
gen_uint!(gen_u32_xoroshiro128plus, u32, Xoroshiro128Plus::from_entropy());
|
||||
gen_uint!(gen_u32_xoroshiro64starstar, u32, Xoroshiro64StarStar::from_entropy());
|
||||
gen_uint!(gen_u32_xoroshiro64star, u32, Xoroshiro64Star::from_entropy());
|
||||
gen_uint!(gen_u32_splitmix64, u32, SplitMix64::from_entropy());
|
||||
gen_uint!(gen_u32_lcg64_xsh32, u32, Lcg64Xsh32::from_entropy());
|
||||
gen_uint!(gen_u32_mcg128_xsh64, u32, Mcg128Xsl64::from_entropy());
|
||||
gen_uint!(gen_u32_chacha20, u32, ChaChaRng::from_entropy());
|
||||
gen_uint!(gen_u32_hc128, u32, Hc128Rng::from_entropy());
|
||||
gen_uint!(gen_u32_isaac, u32, IsaacRng::from_entropy());
|
||||
gen_uint!(gen_u32_isaac64, u32, Isaac64Rng::from_entropy());
|
||||
gen_uint!(gen_u32_std, u32, StdRng::from_entropy());
|
||||
gen_uint!(gen_u32_small, u32, SmallRng::from_entropy());
|
||||
gen_uint!(gen_u32_os, u32, OsRng::new().unwrap());
|
||||
macro_rules! gen_uint_new {
|
||||
($fnn:ident, $ty:ty, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = $gen::new().unwrap();
|
||||
b.iter(|| {
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
black_box(rng.gen::<$ty>());
|
||||
}
|
||||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gen_uint!(gen_u64_xorshift, u64, XorShiftRng::from_entropy());
|
||||
gen_uint!(gen_u64_xoshiro256starstar, u64, Xoshiro256StarStar::from_entropy());
|
||||
gen_uint!(gen_u64_xoshiro256plus, u64, Xoshiro256Plus::from_entropy());
|
||||
gen_uint!(gen_u64_xoshiro128starstar, u64, Xoshiro128StarStar::from_entropy());
|
||||
gen_uint!(gen_u64_xoshiro128plus, u64, Xoshiro128Plus::from_entropy());
|
||||
gen_uint!(gen_u64_xoroshiro128starstar, u64, Xoroshiro128StarStar::from_entropy());
|
||||
gen_uint!(gen_u64_xoroshiro128plus, u64, Xoroshiro128Plus::from_entropy());
|
||||
gen_uint!(gen_u64_xoroshiro64starstar, u64, Xoroshiro64StarStar::from_entropy());
|
||||
gen_uint!(gen_u64_xoroshiro64star, u64, Xoroshiro64Star::from_entropy());
|
||||
gen_uint!(gen_u64_splitmix64, u64, SplitMix64::from_entropy());
|
||||
gen_uint!(gen_u64_lcg64_xsh32, u64, Lcg64Xsh32::from_entropy());
|
||||
gen_uint!(gen_u64_mcg128_xsh64, u64, Mcg128Xsl64::from_entropy());
|
||||
gen_uint!(gen_u64_chacha20, u64, ChaChaRng::from_entropy());
|
||||
gen_uint!(gen_u64_hc128, u64, Hc128Rng::from_entropy());
|
||||
gen_uint!(gen_u64_isaac, u64, IsaacRng::from_entropy());
|
||||
gen_uint!(gen_u64_isaac64, u64, Isaac64Rng::from_entropy());
|
||||
gen_uint!(gen_u64_std, u64, StdRng::from_entropy());
|
||||
gen_uint!(gen_u64_small, u64, SmallRng::from_entropy());
|
||||
gen_uint!(gen_u64_os, u64, OsRng::new().unwrap());
|
||||
gen_uint!(gen_u32_xorshift, u32, XorShiftRng);
|
||||
gen_uint!(gen_u32_isaac, u32, IsaacRng);
|
||||
gen_uint!(gen_u32_isaac64, u32, Isaac64Rng);
|
||||
gen_uint!(gen_u32_chacha, u32, ChaChaRng);
|
||||
gen_uint_new!(gen_u32_std, u32, StdRng);
|
||||
gen_uint_new!(gen_u32_os, u32, OsRng);
|
||||
|
||||
gen_uint!(gen_u64_xorshift, u64, XorShiftRng);
|
||||
gen_uint!(gen_u64_isaac, u64, IsaacRng);
|
||||
gen_uint!(gen_u64_isaac64, u64, Isaac64Rng);
|
||||
gen_uint!(gen_u64_chacha, u64, ChaChaRng);
|
||||
gen_uint_new!(gen_u64_std, u64, StdRng);
|
||||
gen_uint_new!(gen_u64_os, u64, OsRng);
|
||||
|
||||
// Do not test JitterRng like the others by running it RAND_BENCH_N times per,
|
||||
// measurement, because it is way too slow. Only run it once.
|
||||
#[bench]
|
||||
fn gen_u64_jitter(b: &mut Bencher) {
|
||||
let mut rng = JitterRng::new().unwrap();
|
||||
b.iter(|| {
|
||||
rng.gen::<u64>()
|
||||
black_box(rng.gen::<u64>());
|
||||
});
|
||||
b.bytes = size_of::<u64>() as u64;
|
||||
}
|
||||
|
@ -144,28 +111,16 @@ macro_rules! init_gen {
|
|||
($fnn:ident, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = XorShiftRng::from_entropy();
|
||||
let mut rng: XorShiftRng = OsRng::new().unwrap().gen();
|
||||
b.iter(|| {
|
||||
let r2 = $gen::from_rng(&mut rng).unwrap();
|
||||
r2
|
||||
let r2: $gen = rng.gen();
|
||||
black_box(r2);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init_gen!(init_xorshift, XorShiftRng);
|
||||
init_gen!(init_xoshiro256starstar, Xoshiro256StarStar);
|
||||
init_gen!(init_xoshiro256plus, Xoshiro256Plus);
|
||||
init_gen!(init_xoshiro128starstar, Xoshiro128StarStar);
|
||||
init_gen!(init_xoshiro128plus, Xoshiro128Plus);
|
||||
init_gen!(init_xoroshiro128starstar, Xoroshiro128StarStar);
|
||||
init_gen!(init_xoroshiro128plus, Xoroshiro128Plus);
|
||||
init_gen!(init_xoroshiro64starstar, Xoroshiro64StarStar);
|
||||
init_gen!(init_xoroshiro64star, Xoroshiro64Star);
|
||||
init_gen!(init_splitmix64, SplitMix64);
|
||||
init_gen!(init_lcg64_xsh32, Lcg64Xsh32);
|
||||
init_gen!(init_mcg128_xsh64, Mcg128Xsl64);
|
||||
init_gen!(init_hc128, Hc128Rng);
|
||||
init_gen!(init_isaac, IsaacRng);
|
||||
init_gen!(init_isaac64, Isaac64Rng);
|
||||
init_gen!(init_chacha, ChaChaRng);
|
||||
|
@ -173,68 +128,6 @@ init_gen!(init_chacha, ChaChaRng);
|
|||
#[bench]
|
||||
fn init_jitter(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
JitterRng::new().unwrap()
|
||||
black_box(JitterRng::new().unwrap());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const RESEEDING_THRESHOLD: u64 = 1024*1024*1024; // something high enough to get
|
||||
// deterministic measurements
|
||||
|
||||
#[bench]
|
||||
fn reseeding_hc128_bytes(b: &mut Bencher) {
|
||||
let mut rng = ReseedingRng::new(Hc128Core::from_entropy(),
|
||||
RESEEDING_THRESHOLD,
|
||||
EntropyRng::new());
|
||||
let mut buf = [0u8; BYTES_LEN];
|
||||
b.iter(|| {
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
rng.fill_bytes(&mut buf);
|
||||
black_box(buf);
|
||||
}
|
||||
});
|
||||
b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
|
||||
}
|
||||
|
||||
macro_rules! reseeding_uint {
|
||||
($fnn:ident, $ty:ty) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = ReseedingRng::new(Hc128Core::from_entropy(),
|
||||
RESEEDING_THRESHOLD,
|
||||
EntropyRng::new());
|
||||
b.iter(|| {
|
||||
let mut accum: $ty = 0;
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
accum = accum.wrapping_add(rng.gen::<$ty>());
|
||||
}
|
||||
accum
|
||||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reseeding_uint!(reseeding_hc128_u32, u32);
|
||||
reseeding_uint!(reseeding_hc128_u64, u64);
|
||||
|
||||
|
||||
macro_rules! threadrng_uint {
|
||||
($fnn:ident, $ty:ty) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = thread_rng();
|
||||
b.iter(|| {
|
||||
let mut accum: $ty = 0;
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
accum = accum.wrapping_add(rng.gen::<$ty>());
|
||||
}
|
||||
accum
|
||||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
threadrng_uint!(thread_rng_u32, u32);
|
||||
threadrng_uint!(thread_rng_u64, u64);
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче