Compare commits
33 Commits
Author | SHA1 | Date |
---|---|---|
Avril | 3267151615 | 2 years ago |
Avril | bfaff6067a | 4 years ago |
Avril | 5c784482f6 | 4 years ago |
Avril | bdf61340db | 4 years ago |
Avril | 7635ff9d52 | 4 years ago |
Avril | acf2ac605e | 4 years ago |
Avril | d1251a592c | 4 years ago |
Avril | 75730cbe0f | 4 years ago |
Avril | 5dc10547d5 | 4 years ago |
Avril | 6453392758 | 4 years ago |
Avril | a6fc26a053 | 4 years ago |
Avril | 3b4dc663fa | 4 years ago |
Avril | d8404f65ed | 4 years ago |
Avril | 5280c622c9 | 4 years ago |
Avril | 1c509031d6 | 4 years ago |
Avril | 107b34bcbd | 4 years ago |
Avril | 684a6f6aa0 | 4 years ago |
Avril | 8996b0bb7b | 4 years ago |
Avril | 633b4351c2 | 4 years ago |
Avril | bcaac2b2e3 | 4 years ago |
Avril | 59dcecded3 | 4 years ago |
Avril | 4e1e38a0fd | 4 years ago |
Avril | 5ba673e64f | 4 years ago |
Avril | cb163a14e9 | 4 years ago |
Avril | 34a62da8ba | 4 years ago |
Avril | 460d2b0081 | 4 years ago |
Avril | 5f2e3a5b5b | 4 years ago |
Avril | 7c67a4decc | 4 years ago |
Avril | 4227a12521 | 4 years ago |
Avril | 9e25c7cfa3 | 4 years ago |
Avril | b488194fd3 | 4 years ago |
Avril | a6b6ee9a42 | 4 years ago |
Avril | 13dbe37d2b | 4 years ago |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1 @@
|
|||||||
|
Disallow exact same map input buffers by keeping hashes of input buffers.
|
@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
extern crate rustc_version;
|
||||||
|
use rustc_version::{version, version_meta, Channel};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Assert we haven't travelled back in time
|
||||||
|
assert!(version().unwrap().major >= 1);
|
||||||
|
|
||||||
|
// Set cfg flags depending on release channel
|
||||||
|
match version_meta().unwrap().channel {
|
||||||
|
Channel::Stable => {
|
||||||
|
println!("cargo:rustc-cfg=stable");
|
||||||
|
}
|
||||||
|
Channel::Beta => {
|
||||||
|
println!("cargo:rustc-cfg=beta");
|
||||||
|
}
|
||||||
|
Channel::Nightly => {
|
||||||
|
println!("cargo:rustc-cfg=nightly");
|
||||||
|
}
|
||||||
|
Channel::Dev => {
|
||||||
|
println!("cargo:rustc-cfg=dev");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//println!("cargo:rustc-link-lib=static=bz2"); // TODO: Make this conditional for `compress-chain`
|
||||||
|
}
|
@ -0,0 +1,217 @@
|
|||||||
|
# Copyright 2017-2020 Gentoo Authors
|
||||||
|
# Distributed under the terms of the GNU General Public License v2
|
||||||
|
|
||||||
|
# Auto-Generated by cargo-ebuild 0.3.1
|
||||||
|
|
||||||
|
EAPI=7
|
||||||
|
|
||||||
|
CRATES="
|
||||||
|
aho-corasick-0.7.13
|
||||||
|
arc-swap-0.4.7
|
||||||
|
async-compression-0.3.5
|
||||||
|
atty-0.2.14
|
||||||
|
autocfg-0.1.7
|
||||||
|
autocfg-1.0.1
|
||||||
|
base64-0.12.3
|
||||||
|
bitflags-1.2.1
|
||||||
|
block-buffer-0.7.3
|
||||||
|
block-buffer-0.9.0
|
||||||
|
block-padding-0.1.5
|
||||||
|
buf_redux-0.8.4
|
||||||
|
byte-tools-0.3.1
|
||||||
|
byteorder-1.3.4
|
||||||
|
bytes-0.5.6
|
||||||
|
bzip2-0.3.3
|
||||||
|
bzip2-sys-0.1.9+1.0.8
|
||||||
|
cc-1.0.60
|
||||||
|
cfg-if-0.1.10
|
||||||
|
cfg-if-1.0.0
|
||||||
|
cloudabi-0.0.3
|
||||||
|
cpuid-bool-0.1.2
|
||||||
|
digest-0.8.1
|
||||||
|
digest-0.9.0
|
||||||
|
dtoa-0.4.6
|
||||||
|
either-1.6.1
|
||||||
|
env_logger-0.7.1
|
||||||
|
fake-simd-0.1.2
|
||||||
|
fixedbitset-0.2.0
|
||||||
|
fnv-1.0.7
|
||||||
|
fuchsia-cprng-0.1.1
|
||||||
|
fuchsia-zircon-0.3.3
|
||||||
|
fuchsia-zircon-sys-0.3.3
|
||||||
|
futures-0.3.6
|
||||||
|
futures-channel-0.3.6
|
||||||
|
futures-core-0.3.6
|
||||||
|
futures-executor-0.3.6
|
||||||
|
futures-io-0.3.6
|
||||||
|
futures-macro-0.3.6
|
||||||
|
futures-sink-0.3.6
|
||||||
|
futures-task-0.3.6
|
||||||
|
futures-util-0.3.6
|
||||||
|
generic-array-0.12.3
|
||||||
|
generic-array-0.14.4
|
||||||
|
getopts-0.2.21
|
||||||
|
getrandom-0.1.15
|
||||||
|
h2-0.2.6
|
||||||
|
half-1.6.0
|
||||||
|
hashbrown-0.9.1
|
||||||
|
headers-0.3.2
|
||||||
|
headers-core-0.2.0
|
||||||
|
hermit-abi-0.1.17
|
||||||
|
http-0.2.1
|
||||||
|
http-body-0.3.1
|
||||||
|
httparse-1.3.4
|
||||||
|
httpdate-0.3.2
|
||||||
|
humantime-1.3.0
|
||||||
|
hyper-0.13.8
|
||||||
|
idna-0.2.0
|
||||||
|
indexmap-1.6.0
|
||||||
|
input_buffer-0.3.1
|
||||||
|
iovec-0.1.4
|
||||||
|
itertools-0.9.0
|
||||||
|
itoa-0.4.6
|
||||||
|
kernel32-sys-0.2.2
|
||||||
|
lazy_static-1.4.0
|
||||||
|
libc-0.2.79
|
||||||
|
linked-hash-map-0.5.3
|
||||||
|
log-0.4.11
|
||||||
|
markov-1.1.0
|
||||||
|
matches-0.1.8
|
||||||
|
memchr-2.3.3
|
||||||
|
mime-0.3.16
|
||||||
|
mime_guess-2.0.3
|
||||||
|
mio-0.6.22
|
||||||
|
mio-named-pipes-0.1.7
|
||||||
|
mio-uds-0.6.8
|
||||||
|
miow-0.2.1
|
||||||
|
miow-0.3.5
|
||||||
|
multipart-0.17.0
|
||||||
|
net2-0.2.35
|
||||||
|
num_cpus-1.13.0
|
||||||
|
once_cell-1.4.1
|
||||||
|
opaque-debug-0.2.3
|
||||||
|
opaque-debug-0.3.0
|
||||||
|
percent-encoding-2.1.0
|
||||||
|
petgraph-0.5.1
|
||||||
|
pin-project-0.4.26
|
||||||
|
pin-project-internal-0.4.26
|
||||||
|
pin-project-lite-0.1.10
|
||||||
|
pin-utils-0.1.0
|
||||||
|
pkg-config-0.3.18
|
||||||
|
ppv-lite86-0.2.9
|
||||||
|
pretty_env_logger-0.4.0
|
||||||
|
proc-macro-hack-0.5.18
|
||||||
|
proc-macro-nested-0.1.6
|
||||||
|
proc-macro2-1.0.24
|
||||||
|
quick-error-1.2.3
|
||||||
|
quote-1.0.7
|
||||||
|
rand-0.6.5
|
||||||
|
rand-0.7.3
|
||||||
|
rand_chacha-0.1.1
|
||||||
|
rand_chacha-0.2.2
|
||||||
|
rand_core-0.3.1
|
||||||
|
rand_core-0.4.2
|
||||||
|
rand_core-0.5.1
|
||||||
|
rand_hc-0.1.0
|
||||||
|
rand_hc-0.2.0
|
||||||
|
rand_isaac-0.1.1
|
||||||
|
rand_jitter-0.1.4
|
||||||
|
rand_os-0.1.3
|
||||||
|
rand_pcg-0.1.2
|
||||||
|
rand_xorshift-0.1.1
|
||||||
|
rdrand-0.4.0
|
||||||
|
redox_syscall-0.1.57
|
||||||
|
regex-1.3.9
|
||||||
|
regex-syntax-0.6.18
|
||||||
|
remove_dir_all-0.5.3
|
||||||
|
rustc_version-0.2.3
|
||||||
|
ryu-1.0.5
|
||||||
|
safemem-0.3.3
|
||||||
|
scoped-tls-1.0.0
|
||||||
|
semver-0.9.0
|
||||||
|
semver-parser-0.7.0
|
||||||
|
serde-1.0.116
|
||||||
|
serde_cbor-0.11.1
|
||||||
|
serde_derive-1.0.116
|
||||||
|
serde_json-1.0.58
|
||||||
|
serde_urlencoded-0.6.1
|
||||||
|
serde_yaml-0.8.13
|
||||||
|
sha-1-0.8.2
|
||||||
|
sha-1-0.9.1
|
||||||
|
signal-hook-registry-1.2.1
|
||||||
|
slab-0.4.2
|
||||||
|
smallmap-1.1.5
|
||||||
|
socket2-0.3.15
|
||||||
|
syn-1.0.42
|
||||||
|
tempfile-3.1.0
|
||||||
|
termcolor-1.1.0
|
||||||
|
thread_local-1.0.1
|
||||||
|
time-0.1.44
|
||||||
|
tinyvec-0.3.4
|
||||||
|
tokio-0.2.22
|
||||||
|
tokio-macros-0.2.5
|
||||||
|
tokio-tungstenite-0.11.0
|
||||||
|
tokio-util-0.3.1
|
||||||
|
toml-0.5.6
|
||||||
|
tower-service-0.3.0
|
||||||
|
tracing-0.1.21
|
||||||
|
tracing-core-0.1.17
|
||||||
|
tracing-futures-0.2.4
|
||||||
|
try-lock-0.2.3
|
||||||
|
tungstenite-0.11.1
|
||||||
|
twoway-0.1.8
|
||||||
|
typenum-1.12.0
|
||||||
|
unicase-2.6.0
|
||||||
|
unicode-bidi-0.3.4
|
||||||
|
unicode-normalization-0.1.13
|
||||||
|
unicode-width-0.1.8
|
||||||
|
unicode-xid-0.2.1
|
||||||
|
url-2.1.1
|
||||||
|
urlencoding-1.1.1
|
||||||
|
utf-8-0.7.5
|
||||||
|
version_check-0.9.2
|
||||||
|
want-0.3.0
|
||||||
|
warp-0.2.5
|
||||||
|
wasi-0.10.0+wasi-snapshot-preview1
|
||||||
|
wasi-0.9.0+wasi-snapshot-preview1
|
||||||
|
winapi-0.2.8
|
||||||
|
winapi-0.3.9
|
||||||
|
winapi-build-0.1.1
|
||||||
|
winapi-i686-pc-windows-gnu-0.4.0
|
||||||
|
winapi-util-0.1.5
|
||||||
|
winapi-x86_64-pc-windows-gnu-0.4.0
|
||||||
|
ws2_32-sys-0.2.1
|
||||||
|
yaml-rust-0.4.4
|
||||||
|
"
|
||||||
|
|
||||||
|
inherit cargo
|
||||||
|
|
||||||
|
DESCRIPTION="Generate string of text from Markov chain fed by stdin"
|
||||||
|
# Double check the homepage as the cargo_metadata crate
|
||||||
|
# does not provide this value so instead repository is used
|
||||||
|
HOMEPAGE="https://flanchan.moe/markov/"
|
||||||
|
SRC_URI="$(cargo_crate_uris ${CRATES}) https://git.flanchan.moe/attachments/cf0b9095-2403-465b-b3aa-61b121134c84 -> markov-0.7.1.crate"
|
||||||
|
RESTRICT="mirror"
|
||||||
|
# License set may be more restrictive as OR is not respected
|
||||||
|
# use cargo-license for a more accurate license picture
|
||||||
|
LICENSE="GPL-3+"
|
||||||
|
SLOT="0"
|
||||||
|
KEYWORDS="~amd64"
|
||||||
|
IUSE="+compress-chain +split-newlines +api split-sentance always-aggregate hog-buffer"
|
||||||
|
|
||||||
|
DEPEND="compress-chain? ( app-arch/bzip2 )"
|
||||||
|
RDEPEND=""
|
||||||
|
|
||||||
|
src_configure() {
|
||||||
|
local myfeatures=(
|
||||||
|
$(usev compress-chain)
|
||||||
|
$(usev split-newlines)
|
||||||
|
$(usev api)
|
||||||
|
$(usev split-sentance)
|
||||||
|
$(usev always-aggregate)
|
||||||
|
$(usev hog-buffer)
|
||||||
|
)
|
||||||
|
#TODO: This hack slows compilation down I think, but without it ld fails so... We should add cargo buildscript to do this instead
|
||||||
|
use compress-chain && export RUSTFLAGS="${RUSTFLAGS} -ldylib=bz2"
|
||||||
|
cargo_src_configure --no-default-features
|
||||||
|
}
|
@ -0,0 +1,217 @@
|
|||||||
|
# Copyright 2017-2020 Gentoo Authors
|
||||||
|
# Distributed under the terms of the GNU General Public License v2
|
||||||
|
|
||||||
|
# Auto-Generated by cargo-ebuild 0.3.1
|
||||||
|
|
||||||
|
EAPI=7
|
||||||
|
CRATES="
|
||||||
|
aho-corasick-0.7.13
|
||||||
|
arc-swap-0.4.7
|
||||||
|
async-compression-0.3.5
|
||||||
|
atty-0.2.14
|
||||||
|
autocfg-0.1.7
|
||||||
|
autocfg-1.0.1
|
||||||
|
base64-0.12.3
|
||||||
|
bitflags-1.2.1
|
||||||
|
block-buffer-0.7.3
|
||||||
|
block-buffer-0.9.0
|
||||||
|
block-padding-0.1.5
|
||||||
|
buf_redux-0.8.4
|
||||||
|
byte-tools-0.3.1
|
||||||
|
byteorder-1.3.4
|
||||||
|
bytes-0.5.6
|
||||||
|
bzip2-0.3.3
|
||||||
|
bzip2-sys-0.1.9+1.0.8
|
||||||
|
cc-1.0.60
|
||||||
|
cfg-if-0.1.10
|
||||||
|
cfg-if-1.0.0
|
||||||
|
cloudabi-0.0.3
|
||||||
|
cpuid-bool-0.1.2
|
||||||
|
digest-0.8.1
|
||||||
|
digest-0.9.0
|
||||||
|
dtoa-0.4.6
|
||||||
|
either-1.6.1
|
||||||
|
env_logger-0.7.1
|
||||||
|
fake-simd-0.1.2
|
||||||
|
fixedbitset-0.2.0
|
||||||
|
fnv-1.0.7
|
||||||
|
fuchsia-cprng-0.1.1
|
||||||
|
fuchsia-zircon-0.3.3
|
||||||
|
fuchsia-zircon-sys-0.3.3
|
||||||
|
futures-0.3.6
|
||||||
|
futures-channel-0.3.6
|
||||||
|
futures-core-0.3.6
|
||||||
|
futures-executor-0.3.6
|
||||||
|
futures-io-0.3.6
|
||||||
|
futures-macro-0.3.6
|
||||||
|
futures-sink-0.3.6
|
||||||
|
futures-task-0.3.6
|
||||||
|
futures-util-0.3.6
|
||||||
|
generic-array-0.12.3
|
||||||
|
generic-array-0.14.4
|
||||||
|
getopts-0.2.21
|
||||||
|
getrandom-0.1.15
|
||||||
|
h2-0.2.6
|
||||||
|
half-1.6.0
|
||||||
|
hashbrown-0.9.1
|
||||||
|
headers-0.3.2
|
||||||
|
headers-core-0.2.0
|
||||||
|
hermit-abi-0.1.17
|
||||||
|
http-0.2.1
|
||||||
|
http-body-0.3.1
|
||||||
|
httparse-1.3.4
|
||||||
|
httpdate-0.3.2
|
||||||
|
humantime-1.3.0
|
||||||
|
hyper-0.13.8
|
||||||
|
idna-0.2.0
|
||||||
|
indexmap-1.6.0
|
||||||
|
input_buffer-0.3.1
|
||||||
|
iovec-0.1.4
|
||||||
|
itertools-0.9.0
|
||||||
|
itoa-0.4.6
|
||||||
|
kernel32-sys-0.2.2
|
||||||
|
lazy_static-1.4.0
|
||||||
|
libc-0.2.79
|
||||||
|
linked-hash-map-0.5.3
|
||||||
|
log-0.4.11
|
||||||
|
markov-1.1.0
|
||||||
|
matches-0.1.8
|
||||||
|
memchr-2.3.3
|
||||||
|
mime-0.3.16
|
||||||
|
mime_guess-2.0.3
|
||||||
|
mio-0.6.22
|
||||||
|
mio-named-pipes-0.1.7
|
||||||
|
mio-uds-0.6.8
|
||||||
|
miow-0.2.1
|
||||||
|
miow-0.3.5
|
||||||
|
multipart-0.17.0
|
||||||
|
net2-0.2.35
|
||||||
|
num_cpus-1.13.0
|
||||||
|
once_cell-1.4.1
|
||||||
|
opaque-debug-0.2.3
|
||||||
|
opaque-debug-0.3.0
|
||||||
|
percent-encoding-2.1.0
|
||||||
|
petgraph-0.5.1
|
||||||
|
pin-project-0.4.26
|
||||||
|
pin-project-internal-0.4.26
|
||||||
|
pin-project-lite-0.1.10
|
||||||
|
pin-utils-0.1.0
|
||||||
|
pkg-config-0.3.18
|
||||||
|
ppv-lite86-0.2.9
|
||||||
|
pretty_env_logger-0.4.0
|
||||||
|
proc-macro-hack-0.5.18
|
||||||
|
proc-macro-nested-0.1.6
|
||||||
|
proc-macro2-1.0.24
|
||||||
|
quick-error-1.2.3
|
||||||
|
quote-1.0.7
|
||||||
|
rand-0.6.5
|
||||||
|
rand-0.7.3
|
||||||
|
rand_chacha-0.1.1
|
||||||
|
rand_chacha-0.2.2
|
||||||
|
rand_core-0.3.1
|
||||||
|
rand_core-0.4.2
|
||||||
|
rand_core-0.5.1
|
||||||
|
rand_hc-0.1.0
|
||||||
|
rand_hc-0.2.0
|
||||||
|
rand_isaac-0.1.1
|
||||||
|
rand_jitter-0.1.4
|
||||||
|
rand_os-0.1.3
|
||||||
|
rand_pcg-0.1.2
|
||||||
|
rand_xorshift-0.1.1
|
||||||
|
rdrand-0.4.0
|
||||||
|
redox_syscall-0.1.57
|
||||||
|
regex-1.3.9
|
||||||
|
regex-syntax-0.6.18
|
||||||
|
remove_dir_all-0.5.3
|
||||||
|
rustc_version-0.2.3
|
||||||
|
ryu-1.0.5
|
||||||
|
safemem-0.3.3
|
||||||
|
scoped-tls-1.0.0
|
||||||
|
semver-0.9.0
|
||||||
|
semver-parser-0.7.0
|
||||||
|
serde-1.0.116
|
||||||
|
serde_cbor-0.11.1
|
||||||
|
serde_derive-1.0.116
|
||||||
|
serde_json-1.0.58
|
||||||
|
serde_urlencoded-0.6.1
|
||||||
|
serde_yaml-0.8.13
|
||||||
|
sha-1-0.8.2
|
||||||
|
sha-1-0.9.1
|
||||||
|
signal-hook-registry-1.2.1
|
||||||
|
slab-0.4.2
|
||||||
|
smallmap-1.1.5
|
||||||
|
socket2-0.3.15
|
||||||
|
syn-1.0.42
|
||||||
|
tempfile-3.1.0
|
||||||
|
termcolor-1.1.0
|
||||||
|
thread_local-1.0.1
|
||||||
|
time-0.1.44
|
||||||
|
tinyvec-0.3.4
|
||||||
|
tokio-0.2.22
|
||||||
|
tokio-macros-0.2.5
|
||||||
|
tokio-tungstenite-0.11.0
|
||||||
|
tokio-util-0.3.1
|
||||||
|
toml-0.5.6
|
||||||
|
tower-service-0.3.0
|
||||||
|
tracing-0.1.21
|
||||||
|
tracing-core-0.1.17
|
||||||
|
tracing-futures-0.2.4
|
||||||
|
try-lock-0.2.3
|
||||||
|
tungstenite-0.11.1
|
||||||
|
twoway-0.1.8
|
||||||
|
typenum-1.12.0
|
||||||
|
unicase-2.6.0
|
||||||
|
unicode-bidi-0.3.4
|
||||||
|
unicode-normalization-0.1.13
|
||||||
|
unicode-width-0.1.8
|
||||||
|
unicode-xid-0.2.1
|
||||||
|
url-2.1.1
|
||||||
|
urlencoding-1.1.1
|
||||||
|
utf-8-0.7.5
|
||||||
|
version_check-0.9.2
|
||||||
|
want-0.3.0
|
||||||
|
warp-0.2.5
|
||||||
|
wasi-0.10.0+wasi-snapshot-preview1
|
||||||
|
wasi-0.9.0+wasi-snapshot-preview1
|
||||||
|
winapi-0.2.8
|
||||||
|
winapi-0.3.9
|
||||||
|
winapi-build-0.1.1
|
||||||
|
winapi-i686-pc-windows-gnu-0.4.0
|
||||||
|
winapi-util-0.1.5
|
||||||
|
winapi-x86_64-pc-windows-gnu-0.4.0
|
||||||
|
ws2_32-sys-0.2.1
|
||||||
|
yaml-rust-0.4.4
|
||||||
|
"
|
||||||
|
|
||||||
|
inherit cargo
|
||||||
|
|
||||||
|
DESCRIPTION="Generate string of text from Markov chain fed by stdin"
|
||||||
|
# Double check the homepage as the cargo_metadata crate
|
||||||
|
# does not provide this value so instead repository is used
|
||||||
|
HOMEPAGE="https://flanchan.moe/markov/"
|
||||||
|
SRC_URI="$(cargo_crate_uris ${CRATES}) https://git.flanchan.moe/attachments/c6f37bfc-afd8-462f-807f-ab9f95197680 -> markov-0.8.1.crate"
|
||||||
|
RESTRICT="mirror"
|
||||||
|
# License set may be more restrictive as OR is not respected
|
||||||
|
# use cargo-license for a more accurate license picture
|
||||||
|
LICENSE="GPL-3+"
|
||||||
|
SLOT="0"
|
||||||
|
KEYWORDS="~amd64"
|
||||||
|
IUSE="+compress-chain +split-newlines +api split-sentance feed-sentance always-aggregate hog-buffer"
|
||||||
|
|
||||||
|
DEPEND="compress-chain? ( app-arch/bzip2 )"
|
||||||
|
RDEPEND=""
|
||||||
|
|
||||||
|
src_configure() {
|
||||||
|
local myfeatures=(
|
||||||
|
$(usev compress-chain)
|
||||||
|
$(usev split-newlines)
|
||||||
|
$(usev api)
|
||||||
|
$(usev split-sentance)
|
||||||
|
$(usev feed-sentance)
|
||||||
|
$(usev always-aggregate)
|
||||||
|
$(usev hog-buffer)
|
||||||
|
)
|
||||||
|
#TODO: This hack slows compilation down I think, but without it ld fails so... We should add cargo buildscript to do this instead
|
||||||
|
use compress-chain && export RUSTFLAGS="${RUSTFLAGS} -ldylib=bz2"
|
||||||
|
cargo_src_configure --no-default-features
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
|
||||||
|
<pkgmetadata>
|
||||||
|
<maintainer type="person">
|
||||||
|
<email>flanchan@cumallover.me</email>
|
||||||
|
</maintainer>
|
||||||
|
<use>
|
||||||
|
<flag name="compress-chain">Compress chain when saving/loading</flag>
|
||||||
|
<flag name="split-newlines">Treat each new line as a new set to feed</flag>
|
||||||
|
<flag name="api">Enable /api route</flag>
|
||||||
|
<flag name="feed-sentance">Further split buffers by sentance, feeding a new one for each.</flag>
|
||||||
|
<flag name="split-sentance">Split by sentance as well as word boundaries</flag>
|
||||||
|
<flag name="always-aggregate">Always operate on aggregated request body (can speed up writes at the cost of memory)</flag>
|
||||||
|
<flag name="hog-buffer">Acquire chain mutex write lock while streaming body (can speed up writes, but can also allow for DoS)</flag></use>
|
||||||
|
</pkgmetadata>
|
@ -0,0 +1,203 @@
|
|||||||
|
# Copyright 2017-2020 Gentoo Authors
|
||||||
|
# Distributed under the terms of the GNU General Public License v2
|
||||||
|
|
||||||
|
# Auto-Generated by cargo-ebuild 0.3.1
|
||||||
|
|
||||||
|
EAPI=7
|
||||||
|
|
||||||
|
CRATES="
|
||||||
|
aho-corasick-0.7.13
|
||||||
|
arc-swap-0.4.7
|
||||||
|
async-compression-0.3.5
|
||||||
|
atty-0.2.14
|
||||||
|
autocfg-0.1.7
|
||||||
|
autocfg-1.0.1
|
||||||
|
base64-0.12.3
|
||||||
|
bitflags-1.2.1
|
||||||
|
block-buffer-0.7.3
|
||||||
|
block-buffer-0.9.0
|
||||||
|
block-padding-0.1.5
|
||||||
|
buf_redux-0.8.4
|
||||||
|
byte-tools-0.3.1
|
||||||
|
byteorder-1.3.4
|
||||||
|
bytes-0.5.6
|
||||||
|
bzip2-0.3.3
|
||||||
|
bzip2-sys-0.1.9+1.0.8
|
||||||
|
cc-1.0.60
|
||||||
|
cfg-if-0.1.10
|
||||||
|
cfg-if-1.0.0
|
||||||
|
cloudabi-0.0.3
|
||||||
|
cpuid-bool-0.1.2
|
||||||
|
digest-0.8.1
|
||||||
|
digest-0.9.0
|
||||||
|
dtoa-0.4.6
|
||||||
|
either-1.6.1
|
||||||
|
env_logger-0.7.1
|
||||||
|
fake-simd-0.1.2
|
||||||
|
fixedbitset-0.2.0
|
||||||
|
fnv-1.0.7
|
||||||
|
fuchsia-cprng-0.1.1
|
||||||
|
fuchsia-zircon-0.3.3
|
||||||
|
fuchsia-zircon-sys-0.3.3
|
||||||
|
futures-0.3.6
|
||||||
|
futures-channel-0.3.6
|
||||||
|
futures-core-0.3.6
|
||||||
|
futures-executor-0.3.6
|
||||||
|
futures-io-0.3.6
|
||||||
|
futures-macro-0.3.6
|
||||||
|
futures-sink-0.3.6
|
||||||
|
futures-task-0.3.6
|
||||||
|
futures-util-0.3.6
|
||||||
|
generic-array-0.12.3
|
||||||
|
generic-array-0.14.4
|
||||||
|
getopts-0.2.21
|
||||||
|
getrandom-0.1.15
|
||||||
|
h2-0.2.6
|
||||||
|
half-1.6.0
|
||||||
|
hashbrown-0.9.1
|
||||||
|
headers-0.3.2
|
||||||
|
headers-core-0.2.0
|
||||||
|
hermit-abi-0.1.17
|
||||||
|
http-0.2.1
|
||||||
|
http-body-0.3.1
|
||||||
|
httparse-1.3.4
|
||||||
|
httpdate-0.3.2
|
||||||
|
humantime-1.3.0
|
||||||
|
hyper-0.13.8
|
||||||
|
idna-0.2.0
|
||||||
|
indexmap-1.6.0
|
||||||
|
input_buffer-0.3.1
|
||||||
|
iovec-0.1.4
|
||||||
|
itertools-0.9.0
|
||||||
|
itoa-0.4.6
|
||||||
|
kernel32-sys-0.2.2
|
||||||
|
lazy_static-1.4.0
|
||||||
|
libc-0.2.79
|
||||||
|
linked-hash-map-0.5.3
|
||||||
|
log-0.4.11
|
||||||
|
markov-1.1.0
|
||||||
|
matches-0.1.8
|
||||||
|
memchr-2.3.3
|
||||||
|
mime-0.3.16
|
||||||
|
mime_guess-2.0.3
|
||||||
|
mio-0.6.22
|
||||||
|
mio-named-pipes-0.1.7
|
||||||
|
mio-uds-0.6.8
|
||||||
|
miow-0.2.1
|
||||||
|
miow-0.3.5
|
||||||
|
multipart-0.17.0
|
||||||
|
net2-0.2.35
|
||||||
|
num_cpus-1.13.0
|
||||||
|
once_cell-1.4.1
|
||||||
|
opaque-debug-0.2.3
|
||||||
|
opaque-debug-0.3.0
|
||||||
|
percent-encoding-2.1.0
|
||||||
|
petgraph-0.5.1
|
||||||
|
pin-project-0.4.26
|
||||||
|
pin-project-internal-0.4.26
|
||||||
|
pin-project-lite-0.1.10
|
||||||
|
pin-utils-0.1.0
|
||||||
|
pkg-config-0.3.18
|
||||||
|
ppv-lite86-0.2.9
|
||||||
|
pretty_env_logger-0.4.0
|
||||||
|
proc-macro-hack-0.5.18
|
||||||
|
proc-macro-nested-0.1.6
|
||||||
|
proc-macro2-1.0.24
|
||||||
|
quick-error-1.2.3
|
||||||
|
quote-1.0.7
|
||||||
|
rand-0.6.5
|
||||||
|
rand-0.7.3
|
||||||
|
rand_chacha-0.1.1
|
||||||
|
rand_chacha-0.2.2
|
||||||
|
rand_core-0.3.1
|
||||||
|
rand_core-0.4.2
|
||||||
|
rand_core-0.5.1
|
||||||
|
rand_hc-0.1.0
|
||||||
|
rand_hc-0.2.0
|
||||||
|
rand_isaac-0.1.1
|
||||||
|
rand_jitter-0.1.4
|
||||||
|
rand_os-0.1.3
|
||||||
|
rand_pcg-0.1.2
|
||||||
|
rand_xorshift-0.1.1
|
||||||
|
rdrand-0.4.0
|
||||||
|
redox_syscall-0.1.57
|
||||||
|
regex-1.3.9
|
||||||
|
regex-syntax-0.6.18
|
||||||
|
remove_dir_all-0.5.3
|
||||||
|
rustc_version-0.2.3
|
||||||
|
ryu-1.0.5
|
||||||
|
safemem-0.3.3
|
||||||
|
scoped-tls-1.0.0
|
||||||
|
semver-0.9.0
|
||||||
|
semver-parser-0.7.0
|
||||||
|
serde-1.0.116
|
||||||
|
serde_cbor-0.11.1
|
||||||
|
serde_derive-1.0.116
|
||||||
|
serde_json-1.0.58
|
||||||
|
serde_urlencoded-0.6.1
|
||||||
|
serde_yaml-0.8.13
|
||||||
|
sha-1-0.8.2
|
||||||
|
sha-1-0.9.1
|
||||||
|
signal-hook-registry-1.2.1
|
||||||
|
slab-0.4.2
|
||||||
|
smallmap-1.1.5
|
||||||
|
socket2-0.3.15
|
||||||
|
syn-1.0.42
|
||||||
|
tempfile-3.1.0
|
||||||
|
termcolor-1.1.0
|
||||||
|
thread_local-1.0.1
|
||||||
|
time-0.1.44
|
||||||
|
tinyvec-0.3.4
|
||||||
|
tokio-0.2.22
|
||||||
|
tokio-macros-0.2.5
|
||||||
|
tokio-tungstenite-0.11.0
|
||||||
|
tokio-util-0.3.1
|
||||||
|
toml-0.5.6
|
||||||
|
tower-service-0.3.0
|
||||||
|
tracing-0.1.21
|
||||||
|
tracing-core-0.1.17
|
||||||
|
tracing-futures-0.2.4
|
||||||
|
try-lock-0.2.3
|
||||||
|
tungstenite-0.11.1
|
||||||
|
twoway-0.1.8
|
||||||
|
typenum-1.12.0
|
||||||
|
unicase-2.6.0
|
||||||
|
unicode-bidi-0.3.4
|
||||||
|
unicode-normalization-0.1.13
|
||||||
|
unicode-width-0.1.8
|
||||||
|
unicode-xid-0.2.1
|
||||||
|
url-2.1.1
|
||||||
|
urlencoding-1.1.1
|
||||||
|
utf-8-0.7.5
|
||||||
|
version_check-0.9.2
|
||||||
|
want-0.3.0
|
||||||
|
warp-0.2.5
|
||||||
|
wasi-0.10.0+wasi-snapshot-preview1
|
||||||
|
wasi-0.9.0+wasi-snapshot-preview1
|
||||||
|
winapi-0.2.8
|
||||||
|
winapi-0.3.9
|
||||||
|
winapi-build-0.1.1
|
||||||
|
winapi-i686-pc-windows-gnu-0.4.0
|
||||||
|
winapi-util-0.1.5
|
||||||
|
winapi-x86_64-pc-windows-gnu-0.4.0
|
||||||
|
ws2_32-sys-0.2.1
|
||||||
|
yaml-rust-0.4.4
|
||||||
|
"
|
||||||
|
|
||||||
|
inherit cargo
|
||||||
|
|
||||||
|
DESCRIPTION="Generate string of text from Markov chain fed by stdin"
|
||||||
|
# Double check the homepage as the cargo_metadata crate
|
||||||
|
# does not provide this value so instead repository is used
|
||||||
|
HOMEPAGE="homepage field in Cargo.toml inaccessible to cargo metadata"
|
||||||
|
SRC_URI="$(cargo_crate_uris ${CRATES})"
|
||||||
|
RESTRICT="mirror"
|
||||||
|
# License set may be more restrictive as OR is not respected
|
||||||
|
# use cargo-license for a more accurate license picture
|
||||||
|
LICENSE="Apache-2.0 Apache-2.0 WITH LLVM-exception BSD-2-Clause BSD-3-Clause BSL-1.0 CC0-1.0 ISC MIT Unlicense Zlib gpl-3.0-or-later"
|
||||||
|
SLOT="0"
|
||||||
|
KEYWORDS="~amd64"
|
||||||
|
IUSE=""
|
||||||
|
|
||||||
|
DEPEND=""
|
||||||
|
RDEPEND=""
|
@ -1,34 +1,46 @@
|
|||||||
//! Generating the strings
|
//! Generating the strings
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use tokio::sync::mpsc::error::SendError;
|
||||||
|
use futures::StreamExt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct GenBodyError(pub String);
|
pub struct GenBodyError(Option<String>);
|
||||||
|
|
||||||
impl error::Error for GenBodyError{}
|
impl error::Error for GenBodyError{}
|
||||||
impl fmt::Display for GenBodyError
|
impl fmt::Display for GenBodyError
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
{
|
{
|
||||||
write!(f, "failed to write {:?} to body", self.0)
|
if let Some(z) = &self.0 {
|
||||||
|
write!(f, "failed to write read string {:?} to body", z)
|
||||||
|
} else {
|
||||||
|
write!(f, "failed to read string from chain. it might be empty.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub async fn body(state: State, num: Option<usize>, mut output: mpsc::Sender<String>) -> Result<(), GenBodyError>
|
pub async fn body(state: State, num: Option<usize>, mut output: mpsc::Sender<String>) -> Result<(), GenBodyError>
|
||||||
{
|
{
|
||||||
let chain = state.chain().read().await;
|
let mut chain = state.chain_read();
|
||||||
if !chain.is_empty() {
|
let filter = state.outbound_filter();
|
||||||
let filter = state.outbound_filter();
|
match num {
|
||||||
match num {
|
Some(num) if num < state.config().max_gen_size => {
|
||||||
Some(num) if num < state.config().max_gen_size => {
|
let mut chain = chain.take(num);
|
||||||
//This could DoS `full_body` and writes, potentially.
|
while let Some(string) = chain.next().await {
|
||||||
for string in chain.str_iter_for(num) {
|
output.send(filter.filter_owned(string)).await?;
|
||||||
output.send(filter.filter_owned(string)).await.map_err(|e| GenBodyError(e.0))?;
|
}
|
||||||
}
|
},
|
||||||
},
|
_ => output.send(filter.filter_owned(chain.next().await.ok_or_else(GenBodyError::default)?)).await?,
|
||||||
_ => output.send(filter.filter_owned(chain.generate_str())).await.map_err(|e| GenBodyError(e.0))?,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl From<SendError<String>> for GenBodyError
|
||||||
|
{
|
||||||
|
#[inline] fn from(from: SendError<String>) -> Self
|
||||||
|
{
|
||||||
|
Self(Some(from.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -0,0 +1,392 @@
|
|||||||
|
//! Chain handler.
|
||||||
|
use super::*;
|
||||||
|
use std::{
|
||||||
|
marker::Send,
|
||||||
|
sync::Weak,
|
||||||
|
num::NonZeroUsize,
|
||||||
|
task::{Poll, Context,},
|
||||||
|
pin::Pin,
|
||||||
|
};
|
||||||
|
use tokio::{
|
||||||
|
sync::{
|
||||||
|
RwLock,
|
||||||
|
RwLockReadGuard,
|
||||||
|
mpsc::{
|
||||||
|
self,
|
||||||
|
error::SendError,
|
||||||
|
},
|
||||||
|
watch,
|
||||||
|
Notify,
|
||||||
|
},
|
||||||
|
task::JoinHandle,
|
||||||
|
time::{
|
||||||
|
self,
|
||||||
|
Duration,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use futures::StreamExt;
|
||||||
|
|
||||||
|
pub const DEFAULT_TIMEOUT: Duration= Duration::from_secs(5);
|
||||||
|
|
||||||
|
/// Settings for chain handler
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Settings
|
||||||
|
{
|
||||||
|
pub backlog: usize,
|
||||||
|
pub internal_backlog: usize,
|
||||||
|
pub capacity: usize,
|
||||||
|
pub timeout: Duration,
|
||||||
|
pub throttle: Option<Duration>,
|
||||||
|
pub bounds: range::DynRange<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Settings
|
||||||
|
{
|
||||||
|
/// Should we keep this string.
|
||||||
|
#[inline] fn matches(&self, _s: &str) -> bool
|
||||||
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Settings
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
backlog: 32,
|
||||||
|
internal_backlog: 8,
|
||||||
|
capacity: 4,
|
||||||
|
timeout: Duration::from_secs(5),
|
||||||
|
throttle: Some(Duration::from_millis(200)),
|
||||||
|
bounds: feed::DEFAULT_FEED_BOUNDS.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct HostInner<T>
|
||||||
|
{
|
||||||
|
input: mpsc::Receiver<Vec<T>>,
|
||||||
|
shutdown: watch::Receiver<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Handle<T: Send+ chain::Chainable>
|
||||||
|
{
|
||||||
|
chain: RwLock<chain::Chain<T>>,
|
||||||
|
input: mpsc::Sender<Vec<T>>,
|
||||||
|
opt: Settings,
|
||||||
|
notify_write: Arc<Notify>,
|
||||||
|
push_now: Arc<Notify>,
|
||||||
|
shutdown: watch::Sender<bool>,
|
||||||
|
|
||||||
|
/// Data used only for the worker task.
|
||||||
|
host: msg::Once<HostInner<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ChainHandle<T: Send + chain::Chainable>(Arc<Box<Handle<T>>>);
|
||||||
|
|
||||||
|
impl<T: Send+ chain::Chainable + 'static> ChainHandle<T>
|
||||||
|
{
|
||||||
|
pub fn with_settings(chain: chain::Chain<T>, opt: Settings) -> Self
|
||||||
|
{
|
||||||
|
let (shutdown_tx, shutdown) = watch::channel(false);
|
||||||
|
let (itx, irx) = mpsc::channel(opt.backlog);
|
||||||
|
Self(Arc::new(Box::new(Handle{
|
||||||
|
chain: RwLock::new(chain),
|
||||||
|
input: itx,
|
||||||
|
opt,
|
||||||
|
push_now: Arc::new(Notify::new()),
|
||||||
|
notify_write: Arc::new(Notify::new()),
|
||||||
|
shutdown: shutdown_tx,
|
||||||
|
|
||||||
|
host: msg::Once::new(HostInner{
|
||||||
|
input: irx,
|
||||||
|
shutdown,
|
||||||
|
})
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Acquire the chain read lock
|
||||||
|
async fn chain(&self) -> RwLockReadGuard<'_, chain::Chain<T>>
|
||||||
|
{
|
||||||
|
self.0.chain.read().await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A reference to the chain
|
||||||
|
pub fn chain_ref(&self) -> &RwLock<chain::Chain<T>>
|
||||||
|
{
|
||||||
|
&self.0.chain
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a stream that reads generated values forever.
|
||||||
|
pub fn read(&self) -> ChainStream<T>
|
||||||
|
{
|
||||||
|
ChainStream{
|
||||||
|
chain: Arc::downgrade(&self.0),
|
||||||
|
buffer: Vec::with_capacity(self.0.opt.backlog),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send this buffer to the chain
|
||||||
|
pub fn write(&self, buf: Vec<T>) -> impl futures::Future<Output = Result<(), SendError<Vec<T>>>> + 'static
|
||||||
|
{
|
||||||
|
let mut write = self.0.input.clone();
|
||||||
|
async move {
|
||||||
|
write.send(buf).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send this stream buffer to the chain
|
||||||
|
pub fn write_stream<'a, I: Stream<Item=T>>(&self, buf: I) -> impl futures::Future<Output = Result<(), SendError<Vec<T>>>> + 'a
|
||||||
|
where I: 'a
|
||||||
|
{
|
||||||
|
let mut write = self.0.input.clone();
|
||||||
|
async move {
|
||||||
|
write.send(buf.collect().await).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send this buffer to the chain
|
||||||
|
pub async fn write_in_place(&self, buf: Vec<T>) -> Result<(), SendError<Vec<T>>>
|
||||||
|
{
|
||||||
|
self.0.input.clone().send(buf).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A referencer for the notifier
|
||||||
|
pub fn notify_when(&self) -> &Arc<Notify>
|
||||||
|
{
|
||||||
|
&self.0.notify_write
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Force the pending buffers to be written to the chain now
|
||||||
|
pub fn push_now(&self)
|
||||||
|
{
|
||||||
|
self.0.push_now.notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hang the worker thread, preventing it from taking any more inputs and also flushing it.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// If there was no worker thread.
|
||||||
|
pub fn hang(&self)
|
||||||
|
{
|
||||||
|
trace!("Communicating hang request");
|
||||||
|
self.0.shutdown.broadcast(true).expect("Failed to communicate hang");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChainHandle<String>
|
||||||
|
{
|
||||||
|
#[deprecated = "use read() pls"]
|
||||||
|
pub async fn generate_body(&self, state: &state::State, num: Option<usize>, mut output: mpsc::Sender<String>) -> Result<(), SendError<String>>
|
||||||
|
{
|
||||||
|
let chain = self.chain().await;
|
||||||
|
if !chain.is_empty() {
|
||||||
|
let filter = state.outbound_filter();
|
||||||
|
match num {
|
||||||
|
Some(num) if num < state.config().max_gen_size => {
|
||||||
|
//This could DoS writes, potentially.
|
||||||
|
for string in chain.str_iter_for(num) {
|
||||||
|
output.send(filter.filter_owned(string)).await?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => output.send(filter.filter_owned(chain.generate_str())).await?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Host this handle on the current task.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// If `from` has already been hosted.
|
||||||
|
pub async fn host(from: ChainHandle<String>)
|
||||||
|
{
|
||||||
|
let opt = from.0.opt.clone();
|
||||||
|
let mut data = from.0.host.unwrap().await;
|
||||||
|
|
||||||
|
let (mut tx, mut child) = {
|
||||||
|
// The `real` input channel.
|
||||||
|
let from = from.clone();
|
||||||
|
let opt = opt.clone();
|
||||||
|
let (tx, rx) = mpsc::channel::<Vec<Vec<_>>>(opt.internal_backlog);
|
||||||
|
(tx, tokio::spawn(async move {
|
||||||
|
let mut rx = if let Some(thr) = opt.throttle {
|
||||||
|
time::throttle(thr, rx).boxed()
|
||||||
|
} else {
|
||||||
|
rx.boxed()
|
||||||
|
};
|
||||||
|
trace!("child: Begin waiting on parent");
|
||||||
|
while let Some(item) = rx.next().await {
|
||||||
|
if item.len() > 0 {
|
||||||
|
info!("Write lock acq");
|
||||||
|
let mut lock = from.0.chain.write().await;
|
||||||
|
for item in item.into_iter()
|
||||||
|
{
|
||||||
|
use std::ops::DerefMut;
|
||||||
|
for item in item.into_iter() {
|
||||||
|
feed::feed(lock.deref_mut(), item, &from.0.opt.bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace!("Signalling write");
|
||||||
|
from.0.notify_write.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace!("child: exiting");
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!("Begin polling on child");
|
||||||
|
tokio::select!{
|
||||||
|
v = &mut child => {
|
||||||
|
match v {
|
||||||
|
/*#[cold]*/ Ok(_) => {warn!("Child exited before we have? This should probably never happen.")},//Should never happen.
|
||||||
|
Err(e) => {error!("Child exited abnormally. Aborting: {}", e)}, //Child panic or cancel.
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ = async move {
|
||||||
|
let mut rx = data.input.chunk(opt.capacity); //we don't even need this tbh, oh well.
|
||||||
|
|
||||||
|
if !data.shutdown.recv().await.unwrap_or(true) { //first shutdown we get for free
|
||||||
|
while Arc::strong_count(&from.0) > 2 {
|
||||||
|
if *data.shutdown.borrow() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tokio::select!{
|
||||||
|
Some(true) = data.shutdown.recv() => {
|
||||||
|
debug!("Got shutdown (hang) request. Sending now then breaking");
|
||||||
|
|
||||||
|
let mut rest = {
|
||||||
|
let irx = rx.get_mut();
|
||||||
|
irx.close(); //accept no more inputs
|
||||||
|
let mut output = Vec::with_capacity(opt.capacity);
|
||||||
|
while let Ok(item) = irx.try_recv() {
|
||||||
|
output.push(item);
|
||||||
|
}
|
||||||
|
output
|
||||||
|
};
|
||||||
|
rest.extend(rx.take_now());
|
||||||
|
if rest.len() > 0 {
|
||||||
|
if let Err(err) = tx.send(rest).await {
|
||||||
|
error!("Failed to force send buffer, exiting now: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ = time::delay_for(opt.timeout) => {
|
||||||
|
trace!("Setting push now");
|
||||||
|
rx.push_now();
|
||||||
|
}
|
||||||
|
_ = from.0.push_now.notified() => {
|
||||||
|
debug!("Got force push signal");
|
||||||
|
let take =rx.take_now();
|
||||||
|
rx.push_now();
|
||||||
|
if take.len() > 0 {
|
||||||
|
if let Err(err) = tx.send(take).await {
|
||||||
|
error!("Failed to force send buffer: {}", err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(buffer) = rx.next() => {
|
||||||
|
debug!("Sending {} (cap {})", buffer.len(), buffer.capacity());
|
||||||
|
if let Err(err) = tx.send(buffer).await {
|
||||||
|
// Receive closed?
|
||||||
|
//
|
||||||
|
// This probably shouldn't happen, as we `select!` for it up there and child never calls `close()` on `rx`.
|
||||||
|
// In any case, it means we should abort.
|
||||||
|
/*#[cold]*/ error!("Failed to send buffer: {}", err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let last = rx.into_buffer();
|
||||||
|
if last.len() > 0 {
|
||||||
|
if let Err(err) = tx.send(last).await {
|
||||||
|
error!("Failed to force send last part of buffer: {}", err);
|
||||||
|
} else {
|
||||||
|
trace!("Sent rest of buffer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} => {
|
||||||
|
// Normal exit
|
||||||
|
trace!("Normal exit")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
trace!("Waiting on child");
|
||||||
|
// No more handles except child, no more possible inputs.
|
||||||
|
child.await.expect("Child panic");
|
||||||
|
trace!("Returning");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Spawn a new chain handler for this chain.
|
||||||
|
pub fn spawn(from: chain::Chain<String>, opt: Settings) -> (JoinHandle<()>, ChainHandle<String>)
|
||||||
|
{
|
||||||
|
debug!("Spawning with opt: {:?}", opt);
|
||||||
|
let handle = ChainHandle::with_settings(from, opt);
|
||||||
|
(tokio::spawn(host(handle.clone())), handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ChainStream<T: Send + chain::Chainable>
|
||||||
|
{
|
||||||
|
chain: Weak<Box<Handle<T>>>,
|
||||||
|
buffer: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChainStream<String>
|
||||||
|
{
|
||||||
|
async fn try_pull(&mut self, n: usize) -> Option<NonZeroUsize>
|
||||||
|
{
|
||||||
|
if n == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if let Some(read) = self.chain.upgrade() {
|
||||||
|
let chain = read.chain.read().await;
|
||||||
|
if chain.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let n = if n == 1 {
|
||||||
|
self.buffer.push(chain.generate_str());
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
self.buffer.extend(chain.str_iter_for(n));
|
||||||
|
n //for now
|
||||||
|
};
|
||||||
|
Some(unsafe{NonZeroUsize::new_unchecked(n)})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stream for ChainStream<String>
|
||||||
|
{
|
||||||
|
type Item = String;
|
||||||
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
use futures::Future;
|
||||||
|
let this = self.get_mut();
|
||||||
|
|
||||||
|
if this.buffer.len() == 0 {
|
||||||
|
let pull = this.try_pull(this.buffer.capacity());
|
||||||
|
tokio::pin!(pull);
|
||||||
|
match pull.poll(cx) {
|
||||||
|
Poll::Ready(Some(_)) => {},
|
||||||
|
Poll::Pending => return Poll::Pending,
|
||||||
|
_ => return Poll::Ready(None),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
debug_assert!(this.buffer.len()>0);
|
||||||
|
Poll::Ready(Some(this.buffer.remove(0)))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,181 @@
|
|||||||
|
//! Filter accepts and denies based on cidr masks.
|
||||||
|
use super::*;
|
||||||
|
use cidr::{
|
||||||
|
Cidr,
|
||||||
|
IpCidr,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
net::{
|
||||||
|
IpAddr,
|
||||||
|
},
|
||||||
|
error,
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct IpFilterDeniedError(IpAddr, Option<IpCidr>);
|
||||||
|
|
||||||
|
impl warp::reject::Reject for IpFilterDeniedError{}
|
||||||
|
impl error::Error for IpFilterDeniedError{}
|
||||||
|
impl fmt::Display for IpFilterDeniedError
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, "Denied {} due to ", self.0)?;
|
||||||
|
match &self.1 {
|
||||||
|
Some(cidr) => write!(f, "matching rule {}", cidr),
|
||||||
|
None => write!(f, "non-matching accept rule"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
|
pub enum Rule
|
||||||
|
{
|
||||||
|
Accept,
|
||||||
|
Deny,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Rule
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self
|
||||||
|
{
|
||||||
|
Self::Deny
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rule
|
||||||
|
{
|
||||||
|
fn into_result<'a>(self, net: Option<&'a IpCidr>) -> Result<Option<&'a IpCidr>, Option<IpCidr>>
|
||||||
|
{
|
||||||
|
if let Self::Accept = self {
|
||||||
|
Ok(net)
|
||||||
|
} else {
|
||||||
|
Err(net.cloned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
|
pub struct IpFilter
|
||||||
|
{
|
||||||
|
/// The default fallback rule
|
||||||
|
pub default: Rule,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
accept: Vec<IpCidr>,
|
||||||
|
#[serde(default)]
|
||||||
|
deny: Vec<IpCidr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline] fn find_in<'a>(needle: &IpAddr, haystack: &'a [IpCidr]) -> Option<&'a IpCidr>
|
||||||
|
{
|
||||||
|
for x in haystack.iter()
|
||||||
|
{
|
||||||
|
if x.contains(needle) {
|
||||||
|
return Some(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for IpFilter
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
default: Rule::Deny,
|
||||||
|
accept: vec![cidr::Cidr::new_host([127,0,0,1].into())],
|
||||||
|
deny: Vec::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IpFilter
|
||||||
|
{
|
||||||
|
/// Create a new CIDR filter with thie default rule.
|
||||||
|
///
|
||||||
|
/// Use `default()` to use with default rule.
|
||||||
|
pub fn new(fallback: Rule) -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
default: fallback,
|
||||||
|
accept: Vec::new(),
|
||||||
|
deny: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks the rule for this IP, returns a result if it should accept or not.
|
||||||
|
///
|
||||||
|
/// If acceptance rule is met, return the CIDR match that caused the acceptance if applicable
|
||||||
|
///
|
||||||
|
/// If acceptance rule is not met, return in the error which CIDR match cause the deny if applicable
|
||||||
|
pub fn check(&self, ip: &IpAddr) -> Result<Option<&'_ IpCidr>, IpFilterDeniedError>
|
||||||
|
{
|
||||||
|
let accept = find_in(ip, &self.accept[..]);
|
||||||
|
let deny = find_in(ip, &self.deny[..]);
|
||||||
|
|
||||||
|
let (rule, cidr) = match (accept, deny) {
|
||||||
|
(None, Some(net)) => (Rule::Deny, Some(net)),
|
||||||
|
(Some(net), None) => (Rule::Accept, Some(net)),
|
||||||
|
(Some(ac), Some(den)) if ac != den => {
|
||||||
|
if ac.network_length() > den.network_length() {
|
||||||
|
(Rule::Accept, Some(ac))
|
||||||
|
} else {
|
||||||
|
(Rule::Deny, Some(den))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => (self.default, None)
|
||||||
|
};
|
||||||
|
rule.into_result(cidr)
|
||||||
|
.map_err(|cidr| IpFilterDeniedError(*ip, cidr))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accept_mask(&self) -> &[IpCidr]
|
||||||
|
{
|
||||||
|
&self.accept[..]
|
||||||
|
}
|
||||||
|
pub fn deny_mask(&self) -> &[IpCidr]
|
||||||
|
{
|
||||||
|
&self.deny[..]
|
||||||
|
}
|
||||||
|
pub fn accept_range(&mut self, items: impl IntoIterator<Item = IpCidr>)
|
||||||
|
{
|
||||||
|
self.accept.extend(items)
|
||||||
|
}
|
||||||
|
pub fn deny_range(&mut self, items: impl IntoIterator<Item = IpCidr>)
|
||||||
|
{
|
||||||
|
self.deny.extend(items)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accept_one(&mut self, item: IpCidr)
|
||||||
|
{
|
||||||
|
self.accept.push(item)
|
||||||
|
}
|
||||||
|
pub fn deny_one(&mut self, items: IpCidr)
|
||||||
|
{
|
||||||
|
self.deny.push(items)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Can any connection ever be accepted?
|
||||||
|
pub fn possible(&self) -> bool
|
||||||
|
{
|
||||||
|
//TODO: Test this
|
||||||
|
!(self.default == Rule::Deny && self.accept.len() == 0) &&
|
||||||
|
!(self.deny.iter().find(|x| x.network_length() == 0).is_some() && self.accept.len() == 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn recover(err: warp::Rejection) -> Result<impl warp::Reply, warp::Rejection>
|
||||||
|
{
|
||||||
|
if let Some(t) = err.find::<IpFilterDeniedError>() {
|
||||||
|
error!("Denying access to {} because of {:?} (403)", t.0, t.1);
|
||||||
|
Ok(warp::http::Response::builder()
|
||||||
|
.status(status!(403))
|
||||||
|
.body(format!("Access denied: {}", t)))
|
||||||
|
} else {
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,210 @@
|
|||||||
|
//! Message passing things
|
||||||
|
use super::*;
|
||||||
|
use tokio::{
|
||||||
|
sync::{
|
||||||
|
watch,
|
||||||
|
Mutex,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
task::{Poll, Context},
|
||||||
|
pin::Pin,
|
||||||
|
fmt,
|
||||||
|
error,
|
||||||
|
};
|
||||||
|
use futures::{
|
||||||
|
future::{
|
||||||
|
Future,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InitError;
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InitWaitError;
|
||||||
|
|
||||||
|
impl error::Error for InitError{}
|
||||||
|
impl fmt::Display for InitError
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, "failed to set init value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl error::Error for InitWaitError{}
|
||||||
|
impl fmt::Display for InitWaitError
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, "failed to receive init value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provides a method of waiting on and setting a single initialisation.
|
||||||
|
///
|
||||||
|
/// In general, it should only be set once, as multiple sets do nothing but hog `Arc`s.
|
||||||
|
/// Dropping the `Initialiser` after waiting or setting should generally be done immediately.
|
||||||
|
/// Choose the `into_wait()` and `set()` varients over the non-consuming ones.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Initialiser
|
||||||
|
{
|
||||||
|
tx: Arc<watch::Sender<bool>>,
|
||||||
|
rx: watch::Receiver<bool>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Initialiser
|
||||||
|
{
|
||||||
|
/// Create a new, unset initialiser
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
let (tx, rx) = watch::channel(false);
|
||||||
|
Self {
|
||||||
|
tx: Arc::new(tx),
|
||||||
|
rx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a pre-set initialiser. Calls to `wait()` will immediately resolve.
|
||||||
|
pub fn new_set() -> Self
|
||||||
|
{
|
||||||
|
let (tx, rx) = watch::channel(true);
|
||||||
|
Self {
|
||||||
|
tx: Arc::new(tx),
|
||||||
|
rx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume into a future that completes when init is set.
|
||||||
|
pub fn into_wait(self) -> impl Future<Output=Result<(), InitWaitError>> + 'static
|
||||||
|
{
|
||||||
|
let mut rx = self.rx;
|
||||||
|
async move {
|
||||||
|
if !*rx.borrow() {
|
||||||
|
while !rx.recv().await.ok_or_else(|| InitWaitError)? {
|
||||||
|
//tokio::task::yield_now().await;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clone into a future that completes when init is set.
|
||||||
|
///
|
||||||
|
/// This method does not clone any `Arc`s and is prefered to `self.clone().into_wait()`.
|
||||||
|
/// Use this when the `Initialiser` you want to wait on is behind a shared reference.
|
||||||
|
pub fn clone_into_wait(&self) -> impl Future<Output=Result<(), InitWaitError>> + 'static
|
||||||
|
{
|
||||||
|
let mut rx = self.rx.clone();
|
||||||
|
async move {
|
||||||
|
if !*rx.borrow() {
|
||||||
|
while !rx.recv().await.ok_or_else(|| InitWaitError)? {
|
||||||
|
//tokio::task::yield_now().await;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Completes when init is set
|
||||||
|
pub async fn wait(&mut self) -> Result<(), InitWaitError>
|
||||||
|
{
|
||||||
|
if !*self.rx.borrow() {
|
||||||
|
while !self.rx.recv().await.ok_or_else(|| InitWaitError)? {
|
||||||
|
//tokio::task::yield_now().await;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is init set?
|
||||||
|
pub fn is_set(&self) -> bool
|
||||||
|
{
|
||||||
|
*self.rx.borrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume and set init if it's not already set
|
||||||
|
pub fn set(self) -> Result<(), InitError>
|
||||||
|
{
|
||||||
|
if !*self.rx.borrow() {
|
||||||
|
self.tx.broadcast(true).map_err(|_| InitError)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set init without consuming.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
/// It is prefered to use `set()`, as this method may make `Arc`s hang around longer than they need to.
|
||||||
|
/// Calling this multiple times is useless.
|
||||||
|
pub fn set_in_place(&self) -> Result<(), InitError>
|
||||||
|
{
|
||||||
|
if !*self.rx.borrow() {
|
||||||
|
self.tx.broadcast(true).map_err(|_| InitError)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Future for Initialiser
|
||||||
|
{
|
||||||
|
type Output = Result<(), InitWaitError>;
|
||||||
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let uhh = self.wait();
|
||||||
|
tokio::pin!(uhh);
|
||||||
|
uhh.poll(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A value that can be consumed once.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Once<T>(Mutex<Option<T>>);
|
||||||
|
|
||||||
|
impl<T> Once<T>
|
||||||
|
{
|
||||||
|
/// Create a new instance
|
||||||
|
pub fn new(from: T) -> Self
|
||||||
|
{
|
||||||
|
Self(Mutex::new(Some(from)))
|
||||||
|
}
|
||||||
|
/// Consume into the instance from behind a potentially shared reference.
|
||||||
|
pub async fn consume_shared(self: Arc<Self>) -> Option<T>
|
||||||
|
{
|
||||||
|
match Arc::try_unwrap(self) {
|
||||||
|
Ok(x) => x.0.into_inner(),
|
||||||
|
Err(x) => x.0.lock().await.take(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume from a shared reference and panic if the value has already been consumed.
|
||||||
|
pub async fn unwrap_shared(self: Arc<Self>) -> T
|
||||||
|
{
|
||||||
|
self.consume_shared().await.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume into the instance.
|
||||||
|
pub async fn consume(&self) -> Option<T>
|
||||||
|
{
|
||||||
|
self.0.lock().await.take()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume and panic if the value has already been consumed.
|
||||||
|
pub async fn unwrap(&self) -> T
|
||||||
|
{
|
||||||
|
self.consume().await.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume into the inner value
|
||||||
|
pub fn into_inner(self) -> Option<T>
|
||||||
|
{
|
||||||
|
self.0.into_inner()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,296 @@
|
|||||||
|
//! Workarounds for ridiculously janky `std::ops::Range*` polymorphism
|
||||||
|
use super::*;
|
||||||
|
use std::{
|
||||||
|
ops::{
|
||||||
|
Range,
|
||||||
|
RangeFrom,
|
||||||
|
RangeInclusive,
|
||||||
|
RangeTo,
|
||||||
|
RangeToInclusive,
|
||||||
|
RangeFull,
|
||||||
|
|
||||||
|
Bound,
|
||||||
|
RangeBounds,
|
||||||
|
},
|
||||||
|
str::{
|
||||||
|
FromStr,
|
||||||
|
},
|
||||||
|
fmt,
|
||||||
|
error,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum DynRange<T>
|
||||||
|
{
|
||||||
|
Range(Range<T>),
|
||||||
|
From(RangeFrom<T>),
|
||||||
|
Inclusive(RangeInclusive<T>),
|
||||||
|
To(RangeTo<T>),
|
||||||
|
ToInclusive(RangeToInclusive<T>),
|
||||||
|
Full(RangeFull),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export] macro_rules! impl_from {
|
||||||
|
(Full, RangeFull) => {
|
||||||
|
impl<T> From<RangeFull> for DynRange<T>
|
||||||
|
{
|
||||||
|
#[inline] fn from(from: RangeFull) -> Self
|
||||||
|
{
|
||||||
|
Self::Full(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($name:ident, $range:tt) => {
|
||||||
|
|
||||||
|
impl<T> From<$range <T>> for DynRange<T>
|
||||||
|
{
|
||||||
|
#[inline] fn from(from: $range<T>) -> Self
|
||||||
|
{
|
||||||
|
Self::$name(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from!(Range, Range);
|
||||||
|
impl_from!(From, RangeFrom);
|
||||||
|
impl_from!(Inclusive, RangeInclusive);
|
||||||
|
impl_from!(To, RangeTo);
|
||||||
|
impl_from!(ToInclusive, RangeToInclusive);
|
||||||
|
impl_from!(Full, RangeFull);
|
||||||
|
|
||||||
|
macro_rules! bounds {
|
||||||
|
($self:ident, $bound:ident) => {
|
||||||
|
match $self {
|
||||||
|
DynRange::Range(from) => from.$bound(),
|
||||||
|
DynRange::From(from) => from.$bound(),
|
||||||
|
DynRange::Inclusive(i) => i.$bound(),
|
||||||
|
DynRange::To(i) => i.$bound(),
|
||||||
|
DynRange::ToInclusive(i) => i.$bound(),
|
||||||
|
DynRange::Full(_) => (..).$bound(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> RangeBounds<T> for DynRange<T>
|
||||||
|
{
|
||||||
|
fn start_bound(&self) -> Bound<&T> {
|
||||||
|
bounds!(self, start_bound)
|
||||||
|
}
|
||||||
|
fn end_bound(&self) -> Bound<&T> {
|
||||||
|
bounds!(self, end_bound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> RangeBounds<T> for &'a DynRange<T>
|
||||||
|
{
|
||||||
|
fn start_bound(&self) -> Bound<&T> {
|
||||||
|
bounds!(self, start_bound)
|
||||||
|
}
|
||||||
|
fn end_bound(&self) -> Bound<&T> {
|
||||||
|
bounds!(self, end_bound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Display> fmt::Display for DynRange<T>
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Range(from) => write!(f, "{}..{}", from.start, from.end),
|
||||||
|
Self::From(from) => write!(f, "{}..", from.start),
|
||||||
|
Self::Inclusive(from) => write!(f, "{}..={}", from.start(), from.end()),
|
||||||
|
Self::To(from) => write!(f, "..{}", from.end),
|
||||||
|
Self::ToInclusive(from) => write!(f, "..={}", from.end),
|
||||||
|
Self::Full(_) => write!(f, ".."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::any::{
|
||||||
|
Any,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<T: 'static> DynRange<T>
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
pub fn into_boxed(self) -> Box<dyn Any /*TODO: + Send + Sync */+ 'static>
|
||||||
|
{
|
||||||
|
self.into_inner()
|
||||||
|
}
|
||||||
|
fn into_inner(self) -> Box<dyn Any + 'static>
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Range(from) => Box::new(from),
|
||||||
|
Self::From(from) => Box::new(from),
|
||||||
|
Self::Inclusive(from) => Box::new(from),
|
||||||
|
Self::To(from) => Box::new(from),
|
||||||
|
Self::ToInclusive(from) => Box::new(from),
|
||||||
|
Self::Full(_) => Box::new(..),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn inner_mut(&mut self) -> &mut dyn Any
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Range(from) => from,
|
||||||
|
Self::From(from) => from,
|
||||||
|
Self::Inclusive(from) => from,
|
||||||
|
Self::To(from) => from,
|
||||||
|
Self::ToInclusive(from) => from,
|
||||||
|
Self::Full(f) => f,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn inner_ref(&self) -> &dyn Any
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Range(from) => from,
|
||||||
|
Self::From(from) => from,
|
||||||
|
Self::Inclusive(from) => from,
|
||||||
|
Self::To(from) => from,
|
||||||
|
Self::ToInclusive(from) => from,
|
||||||
|
Self::Full(_) => &(..),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn downcast_ref<R: RangeBounds<T> + 'static>(&self) -> Option<&R>
|
||||||
|
{
|
||||||
|
self.inner_ref().downcast_ref()
|
||||||
|
}
|
||||||
|
pub fn downcast_mut<R: RangeBounds<T> + 'static>(&mut self) -> Option<&mut R>
|
||||||
|
{
|
||||||
|
self.inner_mut().downcast_mut()
|
||||||
|
}
|
||||||
|
pub fn downcast<R: RangeBounds<T> + 'static>(self) -> Result<R, Self>
|
||||||
|
{
|
||||||
|
self.into_inner().downcast::<R>()
|
||||||
|
.map(|x| *x)
|
||||||
|
.map_err(|b| {
|
||||||
|
todo!("make this bullshit properly unboxable ehh...")
|
||||||
|
})
|
||||||
|
//Box::<(dyn std::any::Any + 'static)>::downcast(Box::new(self)).map_ok(|ok| *ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ParseError(DynRange<()>, Option<Box<dyn error::Error+'static>>);
|
||||||
|
|
||||||
|
impl ParseError
|
||||||
|
{
|
||||||
|
fn new<R: Into<DynRange<()>>>(which: R, err: impl error::Error + 'static) -> Self
|
||||||
|
{
|
||||||
|
Self(which.into(), Some(Box::new(err)))
|
||||||
|
}
|
||||||
|
fn none(which: impl Into<DynRange<()>>) -> Self
|
||||||
|
{
|
||||||
|
Self(which.into(), None)
|
||||||
|
}
|
||||||
|
fn map<T: Into<DynRange<()>>>(self, to: T) -> Self
|
||||||
|
{
|
||||||
|
Self (to.into(), self.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl error::Error for ParseError
|
||||||
|
{
|
||||||
|
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||||
|
if let Some(this) = self.1.as_ref() {
|
||||||
|
Some(this.as_ref())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ParseError
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, "failed to parse range in format `{:?}`", self.0)?;
|
||||||
|
if let Some(this) = self.1.as_ref() {
|
||||||
|
write!(f, ": {}", this)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<T: FromStr> FromStr for DynRange<T>
|
||||||
|
where T::Err: error::Error + 'static
|
||||||
|
{
|
||||||
|
type Err = ParseError;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
if s== ".." {
|
||||||
|
Ok(Self::Full(..))
|
||||||
|
} else if s.starts_with("..=") {
|
||||||
|
Ok(Self::ToInclusive(..=T::from_str(&s[3..]).map_err(|x| ParseError::new(..=(), x))?))
|
||||||
|
} else if s.starts_with("..") {
|
||||||
|
Ok(Self::To(..(T::from_str(&s[2..])).map_err(|x| ParseError::new(..(), x))?))
|
||||||
|
} else if s.ends_with("..") {
|
||||||
|
Ok(Self::From(T::from_str(&s[..s.len()-2]).map_err(|x| ParseError::new(().., x))?..))
|
||||||
|
} else {
|
||||||
|
fn try_next_incl<'a, T: FromStr>(m: &mut impl Iterator<Item=&'a str>) -> Result<RangeInclusive<T>, ParseError>
|
||||||
|
where T::Err: error::Error + 'static
|
||||||
|
{
|
||||||
|
let (first, second) = if let Some(first) = m.next() {
|
||||||
|
if let Some(seocond) = m.next() {
|
||||||
|
(first,seocond)
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::none(()..=()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::none(()..=()));
|
||||||
|
};
|
||||||
|
|
||||||
|
let first: T = first.parse().map_err(|x| ParseError::new(()..=(), x))?;
|
||||||
|
let second: T = second.parse().map_err(|x| ParseError::new(()..=(), x))?;
|
||||||
|
|
||||||
|
Ok(first..=second)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_next<'a, T: FromStr>(m: &mut impl Iterator<Item=&'a str>) -> Result<Range<T>, ParseError>
|
||||||
|
where T::Err: error::Error + 'static
|
||||||
|
{
|
||||||
|
let (first, second) = if let Some(first) = m.next() {
|
||||||
|
if let Some(seocond) = m.next() {
|
||||||
|
(first,seocond)
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::none(()..()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::none(()..()));
|
||||||
|
};
|
||||||
|
|
||||||
|
let first: T = first.parse().map_err(|x| ParseError::new(()..(), x))?;
|
||||||
|
let second: T = second.parse().map_err(|x| ParseError::new(()..(), x))?;
|
||||||
|
|
||||||
|
Ok(first..second)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let mut split = s.split("..=").fuse();
|
||||||
|
|
||||||
|
let mut last_err = ParseError::none(()..());
|
||||||
|
match loop {
|
||||||
|
match try_next_incl(&mut split) {
|
||||||
|
Err(ParseError(_, None)) => break Err(last_err), // iter empty
|
||||||
|
Err(other) => last_err = other,
|
||||||
|
Ok(value) => break Ok(Self::Inclusive(value)),
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
Ok(v) => return Ok(v),
|
||||||
|
Err(e) => last_err = e,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut split = s.split("..").fuse();
|
||||||
|
match loop {
|
||||||
|
match try_next(&mut split) {
|
||||||
|
Err(ParseError(_, None)) => break Err(last_err), // iter empty
|
||||||
|
Err(other) => last_err = other,
|
||||||
|
Ok(value) => break Ok(Self::Range(value)),
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
Ok(v) => Ok(v),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue