From 07764d4deb29449a6c89cf3658d9a7c8096caf78 Mon Sep 17 00:00:00 2001 From: Avril Date: Sun, 17 Apr 2022 00:51:33 +0100 Subject: [PATCH] Added `DurationProvider`, `ThrottleProvider` traits. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fortune for throttle's current commit: Half blessing − 半吉 --- .gitignore | 1 + Cargo.lock | 75 +++++++++++++++++++++++++ Cargo.toml | 9 +++ src/main.rs | 7 +++ src/prov.rs | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/stream.rs | 9 +++ 6 files changed, 249 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs create mode 100644 src/prov.rs create mode 100644 src/stream.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..55f8c56 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "throttle" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4ab93b7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "throttle" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..bf49002 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,7 @@ + +mod prov; +mod stream; + +fn main() { + println!("Hello, world!"); +} diff --git a/src/prov.rs b/src/prov.rs new file mode 100644 index 0000000..5122b8f --- /dev/null +++ b/src/prov.rs @@ -0,0 +1,148 @@ +//! Throttle provider +use std::time::Duration; +use std::iter; + +pub trait DurationProvider +{ + fn get_next_duration(&mut self) -> Option; +} + +/// An iterator adaptor for a `DurationProvider`. +#[derive(Debug, Clone)] +pub struct DurationProviderIter(T); + +impl DurationProviderIter +{ + /// Consume into the backing `DurationProvider` + #[inline(always)] + pub fn into_inner(self) -> T + { + self.0 + } +} + +impl Iterator for DurationProviderIter +{ + type Item = Duration; + #[inline(always)] + fn next(&mut self) -> Option + { + self.0.get_next_duration() + } +} + + +pub trait DurationProviderIterExt<'a> +{ + type Iter: iter::Iterator + 'a; + fn get_all_durations(self) -> Self::Iter; +} + +pub trait DurationProviderExt<'a> +{ + fn get_all_durations_dyn(self: Box) -> Box + 'a>; +} + +impl<'a, T: DurationProvider + 'a> DurationProviderIterExt<'a> for T +{ + type Iter = DurationProviderIter; + #[inline(always)] + fn get_all_durations(self) -> Self::Iter { + DurationProviderIter(self) + } +} + +impl<'a, T: ?Sized + DurationProvider + 'a> DurationProviderExt<'a> for T +{ + #[inline] + fn get_all_durations_dyn(self: Box) -> Box + 'a> + { + #[derive(Debug)] + struct Iter(Box); + impl Iterator for Iter + { + type Item = Duration; + fn next(&mut self) -> Option + { + self.0.get_next_duration() + } + } + + Box::new(Iter(self)) + } +} + +impl DurationProvider for Duration +{ + #[inline(always)] + fn get_next_duration(&mut self) -> Option { + Some(*self) + } +} + +pub trait ThrottleProvider +{ + type Timer: DurationProvider; + fn get_timeout(&self) -> Self::Timer; +} + + +pub trait DynThrottleProvider +{ + fn get_timeout(&self) -> Box; +} +impl DynThrottleProvider for T +where T: ThrottleProvider +{ + #[inline(always)] + fn get_timeout(&self) -> Box + { + Box::new(ThrottleProvider::get_timeout(&self)) + } +} + +impl<'a, T: ?Sized> ThrottleProvider for &'a T +where T: ThrottleProvider +{ + type Timer = T::Timer; + #[inline(always)] + fn get_timeout(&self) -> Self::Timer { + T::get_timeout(self) + } +} + +impl ThrottleProvider for Duration +{ + type Timer = Self; + fn get_timeout(&self) -> Self::Timer { + self.clone() + } +} + +/// Provides a throttle adaptor that returns a uniformly-distributed `T` each time `get_timeout()` is called. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct UniformThrottleProvider>(R, std::marker::PhantomData); + +impl From for UniformThrottleProvider +where T: DurationProvider, + R: std::ops::RangeBounds +{ + #[inline(always)] + fn from(from: R) -> Self + { + Self(from, std::marker::PhantomData) + } +} + +impl ThrottleProvider for UniformThrottleProvider +where T: DurationProvider + rand::distributions::uniform::SampleUniform, + R: std::ops::RangeBounds, +for <'r> &'r R: rand::distributions::uniform::SampleRange, +{ + type Timer = T; + #[inline] + fn get_timeout(&self) -> Self::Timer { + use rand::prelude::*; + rand::thread_rng().gen_range(&self.0) + } +} diff --git a/src/stream.rs b/src/stream.rs new file mode 100644 index 0000000..c2a9845 --- /dev/null +++ b/src/stream.rs @@ -0,0 +1,9 @@ +//! Stream adaptors +use super::*; + + +pub struct ThrottleAdaptor +{ + reader: R, + timeout_provider: T +}