mirror of
https://github.com/Noratrieb/icefun.git
synced 2026-03-16 00:56:03 +01:00
loop
This commit is contained in:
parent
7af1274587
commit
189f24e53b
58 changed files with 1489 additions and 12529 deletions
|
|
@ -1,151 +1,71 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::io::IoSlice;
|
||||
|
||||
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
||||
|
||||
pub(crate) struct BufList<T> {
|
||||
bufs: VecDeque<T>,
|
||||
}
|
||||
|
||||
impl<T: Buf> BufList<T> {
|
||||
pub(crate) fn new() -> BufList<T> {
|
||||
BufList {
|
||||
bufs: VecDeque::new(),
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn push(&mut self, buf: T) {
|
||||
debug_assert!(buf.has_remaining());
|
||||
self.bufs.push_back(buf);
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(feature = "http1")]
|
||||
pub(crate) fn bufs_cnt(&self) -> usize {
|
||||
self.bufs.len()
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Buf> Buf for BufList<T> {
|
||||
#[inline]
|
||||
fn remaining(&self) -> usize {
|
||||
self.bufs.iter().map(|buf| buf.remaining()).sum()
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn chunk(&self) -> &[u8] {
|
||||
self.bufs.front().map(Buf::chunk).unwrap_or_default()
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance(&mut self, mut cnt: usize) {
|
||||
while cnt > 0 {
|
||||
{
|
||||
let front = &mut self.bufs[0];
|
||||
let rem = front.remaining();
|
||||
if rem > cnt {
|
||||
front.advance(cnt);
|
||||
return;
|
||||
} else {
|
||||
front.advance(rem);
|
||||
cnt -= rem;
|
||||
}
|
||||
}
|
||||
self.bufs.pop_front();
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn chunks_vectored<'t>(&'t self, dst: &mut [IoSlice<'t>]) -> usize {
|
||||
if dst.is_empty() {
|
||||
return 0;
|
||||
}
|
||||
let mut vecs = 0;
|
||||
for buf in &self.bufs {
|
||||
vecs += buf.chunks_vectored(&mut dst[vecs..]);
|
||||
if vecs == dst.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
vecs
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_to_bytes(&mut self, len: usize) -> Bytes {
|
||||
// Our inner buffer may have an optimized version of copy_to_bytes, and if the whole
|
||||
// request can be fulfilled by the front buffer, we can take advantage.
|
||||
match self.bufs.front_mut() {
|
||||
Some(front) if front.remaining() == len => {
|
||||
let b = front.copy_to_bytes(len);
|
||||
self.bufs.pop_front();
|
||||
b
|
||||
}
|
||||
Some(front) if front.remaining() > len => front.copy_to_bytes(len),
|
||||
_ => {
|
||||
assert!(len <= self.remaining(), "`len` greater than remaining");
|
||||
let mut bm = BytesMut::with_capacity(len);
|
||||
bm.put(self.take(len));
|
||||
bm.freeze()
|
||||
}
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::ptr;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn hello_world_buf() -> BufList<Bytes> {
|
||||
BufList {
|
||||
bufs: vec![Bytes::from("Hello"), Bytes::from(" "), Bytes::from("World")].into(),
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_bytes_shorter() {
|
||||
let mut bufs = hello_world_buf();
|
||||
let old_ptr = bufs.chunk().as_ptr();
|
||||
let start = bufs.copy_to_bytes(4);
|
||||
assert_eq!(start, "Hell");
|
||||
assert!(ptr::eq(old_ptr, start.as_ptr()));
|
||||
assert_eq!(bufs.chunk(), b"o");
|
||||
assert!(ptr::eq(old_ptr.wrapping_add(4), bufs.chunk().as_ptr()));
|
||||
assert_eq!(bufs.remaining(), 7);
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_bytes_eq() {
|
||||
let mut bufs = hello_world_buf();
|
||||
let old_ptr = bufs.chunk().as_ptr();
|
||||
let start = bufs.copy_to_bytes(5);
|
||||
assert_eq!(start, "Hello");
|
||||
assert!(ptr::eq(old_ptr, start.as_ptr()));
|
||||
assert_eq!(bufs.chunk(), b" ");
|
||||
assert_eq!(bufs.remaining(), 6);
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_bytes_longer() {
|
||||
let mut bufs = hello_world_buf();
|
||||
let start = bufs.copy_to_bytes(7);
|
||||
assert_eq!(start, "Hello W");
|
||||
assert_eq!(bufs.remaining(), 4);
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_long_buf_to_bytes() {
|
||||
let mut buf = BufList::new();
|
||||
buf.push(b"Hello World" as &[_]);
|
||||
assert_eq!(buf.copy_to_bytes(5), "Hello");
|
||||
assert_eq!(buf.chunk(), b" World");
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "`len` greater than remaining")]
|
||||
fn buf_to_bytes_too_many() {
|
||||
hello_world_buf().copy_to_bytes(42);
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,123 +2,67 @@ use std::cell::RefCell;
|
|||
use std::fmt::{self, Write};
|
||||
use std::str;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
#[cfg(feature = "http2")]
|
||||
use http::header::HeaderValue;
|
||||
use httpdate::HttpDate;
|
||||
|
||||
// "Sun, 06 Nov 1994 08:49:37 GMT".len()
|
||||
pub(crate) const DATE_VALUE_LENGTH: usize = 29;
|
||||
|
||||
#[cfg(feature = "http1")]
|
||||
pub(crate) fn extend(dst: &mut Vec<u8>) {
|
||||
CACHED.with(|cache| {
|
||||
dst.extend_from_slice(cache.borrow().buffer());
|
||||
})
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[cfg(feature = "http1")]
|
||||
pub(crate) fn update() {
|
||||
CACHED.with(|cache| {
|
||||
cache.borrow_mut().check();
|
||||
})
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[cfg(feature = "http2")]
|
||||
pub(crate) fn update_and_header_value() -> HeaderValue {
|
||||
CACHED.with(|cache| {
|
||||
let mut cache = cache.borrow_mut();
|
||||
cache.check();
|
||||
HeaderValue::from_bytes(cache.buffer()).expect("Date format should be valid HeaderValue")
|
||||
})
|
||||
loop {}
|
||||
}
|
||||
|
||||
struct CachedDate {
|
||||
bytes: [u8; DATE_VALUE_LENGTH],
|
||||
pos: usize,
|
||||
next_update: SystemTime,
|
||||
}
|
||||
|
||||
thread_local!(static CACHED: RefCell<CachedDate> = RefCell::new(CachedDate::new()));
|
||||
|
||||
thread_local!(static CACHED : RefCell < CachedDate > = RefCell::new(CachedDate::new()));
|
||||
impl CachedDate {
|
||||
fn new() -> Self {
|
||||
let mut cache = CachedDate {
|
||||
bytes: [0; DATE_VALUE_LENGTH],
|
||||
pos: 0,
|
||||
next_update: SystemTime::now(),
|
||||
};
|
||||
cache.update(cache.next_update);
|
||||
cache
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn buffer(&self) -> &[u8] {
|
||||
&self.bytes[..]
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn check(&mut self) {
|
||||
let now = SystemTime::now();
|
||||
if now > self.next_update {
|
||||
self.update(now);
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn update(&mut self, now: SystemTime) {
|
||||
self.render(now);
|
||||
self.next_update = now + Duration::new(1, 0);
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn render(&mut self, now: SystemTime) {
|
||||
self.pos = 0;
|
||||
let _ = write!(self, "{}", HttpDate::from(now));
|
||||
debug_assert!(self.pos == DATE_VALUE_LENGTH);
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for CachedDate {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
let len = s.len();
|
||||
self.bytes[self.pos..self.pos + len].copy_from_slice(s.as_bytes());
|
||||
self.pos += len;
|
||||
Ok(())
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use test::Bencher;
|
||||
|
||||
#[test]
|
||||
fn test_date_len() {
|
||||
assert_eq!(DATE_VALUE_LENGTH, "Sun, 06 Nov 1994 08:49:37 GMT".len());
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[bench]
|
||||
fn bench_date_check(b: &mut Bencher) {
|
||||
let mut date = CachedDate::new();
|
||||
// cache the first update
|
||||
date.check();
|
||||
|
||||
b.iter(|| {
|
||||
date.check();
|
||||
});
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[bench]
|
||||
fn bench_date_render(b: &mut Bencher) {
|
||||
let mut date = CachedDate::new();
|
||||
let now = SystemTime::now();
|
||||
date.render(now);
|
||||
b.bytes = date.buffer().len() as u64;
|
||||
|
||||
b.iter(|| {
|
||||
date.render(now);
|
||||
test::black_box(&date);
|
||||
});
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,217 +1,80 @@
|
|||
use std::mem;
|
||||
|
||||
use pin_project_lite::pin_project;
|
||||
use tokio::sync::watch;
|
||||
|
||||
use super::{task, Future, Pin, Poll};
|
||||
|
||||
pub(crate) fn channel() -> (Signal, Watch) {
|
||||
let (tx, rx) = watch::channel(());
|
||||
(Signal { tx }, Watch { rx })
|
||||
loop {}
|
||||
}
|
||||
|
||||
pub(crate) struct Signal {
|
||||
tx: watch::Sender<()>,
|
||||
}
|
||||
|
||||
pub(crate) struct Draining(Pin<Box<dyn Future<Output = ()> + Send + Sync>>);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Watch {
|
||||
rx: watch::Receiver<()>,
|
||||
}
|
||||
|
||||
pin_project! {
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Watching<F, FN> {
|
||||
#[pin]
|
||||
future: F,
|
||||
state: State<FN>,
|
||||
watch: Pin<Box<dyn Future<Output = ()> + Send + Sync>>,
|
||||
_rx: watch::Receiver<()>,
|
||||
}
|
||||
#[allow(missing_debug_implementations)] pub struct Watching < F, FN > { #[pin] future
|
||||
: F, state : State < FN >, watch : Pin < Box < dyn Future < Output = () > + Send +
|
||||
Sync >>, _rx : watch::Receiver < () >, }
|
||||
}
|
||||
|
||||
enum State<F> {
|
||||
Watch(F),
|
||||
Draining,
|
||||
}
|
||||
|
||||
impl Signal {
|
||||
pub(crate) fn drain(self) -> Draining {
|
||||
let _ = self.tx.send(());
|
||||
Draining(Box::pin(async move { self.tx.closed().await }))
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Future for Draining {
|
||||
type Output = ();
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
|
||||
Pin::new(&mut self.as_mut().0).poll(cx)
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Watch {
|
||||
pub(crate) fn watch<F, FN>(self, future: F, on_drain: FN) -> Watching<F, FN>
|
||||
where
|
||||
F: Future,
|
||||
FN: FnOnce(Pin<&mut F>),
|
||||
{
|
||||
let Self { mut rx } = self;
|
||||
let _rx = rx.clone();
|
||||
Watching {
|
||||
future,
|
||||
state: State::Watch(on_drain),
|
||||
watch: Box::pin(async move {
|
||||
let _ = rx.changed().await;
|
||||
}),
|
||||
// Keep the receiver alive until the future completes, so that
|
||||
// dropping it can signal that draining has completed.
|
||||
_rx,
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, FN> Future for Watching<F, FN>
|
||||
where
|
||||
F: Future,
|
||||
FN: FnOnce(Pin<&mut F>),
|
||||
{
|
||||
type Output = F::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
|
||||
let mut me = self.project();
|
||||
loop {
|
||||
match mem::replace(me.state, State::Draining) {
|
||||
State::Watch(on_drain) => {
|
||||
match Pin::new(&mut me.watch).poll(cx) {
|
||||
Poll::Ready(()) => {
|
||||
// Drain has been triggered!
|
||||
on_drain(me.future.as_mut());
|
||||
}
|
||||
Poll::Pending => {
|
||||
*me.state = State::Watch(on_drain);
|
||||
return me.future.poll(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
State::Draining => return me.future.poll(cx),
|
||||
}
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
struct TestMe {
|
||||
draining: bool,
|
||||
finished: bool,
|
||||
poll_cnt: usize,
|
||||
}
|
||||
|
||||
impl Future for TestMe {
|
||||
type Output = ();
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, _: &mut task::Context<'_>) -> Poll<Self::Output> {
|
||||
self.poll_cnt += 1;
|
||||
if self.finished {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
fn poll(
|
||||
mut self: Pin<&mut Self>,
|
||||
_: &mut task::Context<'_>,
|
||||
) -> Poll<Self::Output> {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn watch() {
|
||||
let mut mock = tokio_test::task::spawn(());
|
||||
mock.enter(|cx, _| {
|
||||
let (tx, rx) = channel();
|
||||
let fut = TestMe {
|
||||
draining: false,
|
||||
finished: false,
|
||||
poll_cnt: 0,
|
||||
};
|
||||
|
||||
let mut watch = rx.watch(fut, |mut fut| {
|
||||
fut.draining = true;
|
||||
});
|
||||
|
||||
assert_eq!(watch.future.poll_cnt, 0);
|
||||
|
||||
// First poll should poll the inner future
|
||||
assert!(Pin::new(&mut watch).poll(cx).is_pending());
|
||||
assert_eq!(watch.future.poll_cnt, 1);
|
||||
|
||||
// Second poll should poll the inner future again
|
||||
assert!(Pin::new(&mut watch).poll(cx).is_pending());
|
||||
assert_eq!(watch.future.poll_cnt, 2);
|
||||
|
||||
let mut draining = tx.drain();
|
||||
// Drain signaled, but needs another poll to be noticed.
|
||||
assert!(!watch.future.draining);
|
||||
assert_eq!(watch.future.poll_cnt, 2);
|
||||
|
||||
// Now, poll after drain has been signaled.
|
||||
assert!(Pin::new(&mut watch).poll(cx).is_pending());
|
||||
assert_eq!(watch.future.poll_cnt, 3);
|
||||
assert!(watch.future.draining);
|
||||
|
||||
// Draining is not ready until watcher completes
|
||||
assert!(Pin::new(&mut draining).poll(cx).is_pending());
|
||||
|
||||
// Finishing up the watch future
|
||||
watch.future.finished = true;
|
||||
assert!(Pin::new(&mut watch).poll(cx).is_ready());
|
||||
assert_eq!(watch.future.poll_cnt, 4);
|
||||
drop(watch);
|
||||
|
||||
assert!(Pin::new(&mut draining).poll(cx).is_ready());
|
||||
})
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn watch_clones() {
|
||||
let mut mock = tokio_test::task::spawn(());
|
||||
mock.enter(|cx, _| {
|
||||
let (tx, rx) = channel();
|
||||
|
||||
let fut1 = TestMe {
|
||||
draining: false,
|
||||
finished: false,
|
||||
poll_cnt: 0,
|
||||
};
|
||||
let fut2 = TestMe {
|
||||
draining: false,
|
||||
finished: false,
|
||||
poll_cnt: 0,
|
||||
};
|
||||
|
||||
let watch1 = rx.clone().watch(fut1, |mut fut| {
|
||||
fut.draining = true;
|
||||
});
|
||||
let watch2 = rx.watch(fut2, |mut fut| {
|
||||
fut.draining = true;
|
||||
});
|
||||
|
||||
let mut draining = tx.drain();
|
||||
|
||||
// Still 2 outstanding watchers
|
||||
assert!(Pin::new(&mut draining).poll(cx).is_pending());
|
||||
|
||||
// drop 1 for whatever reason
|
||||
drop(watch1);
|
||||
|
||||
// Still not ready, 1 other watcher still pending
|
||||
assert!(Pin::new(&mut draining).poll(cx).is_pending());
|
||||
|
||||
drop(watch2);
|
||||
|
||||
// Now all watchers are gone, draining is complete
|
||||
assert!(Pin::new(&mut draining).poll(cx).is_ready());
|
||||
});
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,23 +32,12 @@ impl Exec {
|
|||
where
|
||||
F: Future<Output = ()> + Send + 'static,
|
||||
{
|
||||
match *self {
|
||||
Exec::Default => {
|
||||
#[cfg(feature = "tcp")]
|
||||
{
|
||||
tokio::task::spawn(fut);
|
||||
}
|
||||
#[cfg(not(feature = "tcp"))] { panic!("executor must be set") }
|
||||
}
|
||||
Exec::Executor(ref e) => {
|
||||
e.execute(Box::pin(fut));
|
||||
}
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for Exec {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Exec").finish()
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "server")]
|
||||
|
|
@ -58,7 +47,7 @@ where
|
|||
B: HttpBody,
|
||||
{
|
||||
fn execute_h2stream(&mut self, fut: H2Stream<F, B>) {
|
||||
self.execute(fut)
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
#[cfg(all(feature = "server", any(feature = "http1", feature = "http2")))]
|
||||
|
|
@ -80,7 +69,7 @@ where
|
|||
B: HttpBody,
|
||||
{
|
||||
fn execute_h2stream(&mut self, fut: H2Stream<F, B>) {
|
||||
self.execute(fut)
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
#[cfg(all(feature = "server", any(feature = "http1", feature = "http2")))]
|
||||
|
|
@ -111,6 +100,6 @@ where
|
|||
self: Pin<&mut Self>,
|
||||
_cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<Self::Output> {
|
||||
unreachable!()
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,49 +1,30 @@
|
|||
use std::marker::Unpin;
|
||||
use std::{cmp, io};
|
||||
|
||||
use bytes::{Buf, Bytes};
|
||||
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
||||
|
||||
use crate::common::{task, Pin, Poll};
|
||||
|
||||
/// Combine a buffer with an IO, rewinding reads to use the buffer.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Rewind<T> {
|
||||
pre: Option<Bytes>,
|
||||
inner: T,
|
||||
}
|
||||
|
||||
impl<T> Rewind<T> {
|
||||
#[cfg(any(all(feature = "http2", feature = "server"), test))]
|
||||
pub(crate) fn new(io: T) -> Self {
|
||||
Rewind {
|
||||
pre: None,
|
||||
inner: io,
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
|
||||
pub(crate) fn new_buffered(io: T, buf: Bytes) -> Self {
|
||||
Rewind {
|
||||
pre: Some(buf),
|
||||
inner: io,
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[cfg(any(all(feature = "http1", feature = "http2", feature = "server"), test))]
|
||||
pub(crate) fn rewind(&mut self, bs: Bytes) {
|
||||
debug_assert!(self.pre.is_none());
|
||||
self.pre = Some(bs);
|
||||
loop {}
|
||||
}
|
||||
|
||||
pub(crate) fn into_inner(self) -> (T, Bytes) {
|
||||
(self.inner, self.pre.unwrap_or_else(Bytes::new))
|
||||
loop {}
|
||||
}
|
||||
|
||||
// pub(crate) fn get_mut(&mut self) -> &mut T {
|
||||
// &mut self.inner
|
||||
// }
|
||||
}
|
||||
|
||||
impl<T> AsyncRead for Rewind<T>
|
||||
where
|
||||
T: AsyncRead + Unpin,
|
||||
|
|
@ -53,25 +34,9 @@ where
|
|||
cx: &mut task::Context<'_>,
|
||||
buf: &mut ReadBuf<'_>,
|
||||
) -> Poll<io::Result<()>> {
|
||||
if let Some(mut prefix) = self.pre.take() {
|
||||
// If there are no remaining bytes, let the bytes get dropped.
|
||||
if !prefix.is_empty() {
|
||||
let copy_len = cmp::min(prefix.len(), buf.remaining());
|
||||
// TODO: There should be a way to do following two lines cleaner...
|
||||
buf.put_slice(&prefix[..copy_len]);
|
||||
prefix.advance(copy_len);
|
||||
// Put back what's left
|
||||
if !prefix.is_empty() {
|
||||
self.pre = Some(prefix);
|
||||
}
|
||||
|
||||
return Poll::Ready(Ok(()));
|
||||
}
|
||||
}
|
||||
Pin::new(&mut self.inner).poll_read(cx, buf)
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsyncWrite for Rewind<T>
|
||||
where
|
||||
T: AsyncWrite + Unpin,
|
||||
|
|
@ -81,75 +46,42 @@ where
|
|||
cx: &mut task::Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
Pin::new(&mut self.inner).poll_write(cx, buf)
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn poll_write_vectored(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut task::Context<'_>,
|
||||
bufs: &[io::IoSlice<'_>],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
Pin::new(&mut self.inner).poll_write_vectored(cx, bufs)
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
|
||||
Pin::new(&mut self.inner).poll_flush(cx)
|
||||
fn poll_flush(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut task::Context<'_>,
|
||||
) -> Poll<io::Result<()>> {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
|
||||
Pin::new(&mut self.inner).poll_shutdown(cx)
|
||||
fn poll_shutdown(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut task::Context<'_>,
|
||||
) -> Poll<io::Result<()>> {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn is_write_vectored(&self) -> bool {
|
||||
self.inner.is_write_vectored()
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// FIXME: re-implement tests with `async/await`, this import should
|
||||
// trigger a warning to remind us
|
||||
use super::Rewind;
|
||||
use bytes::Bytes;
|
||||
use tokio::io::AsyncReadExt;
|
||||
|
||||
#[tokio::test]
|
||||
async fn partial_rewind() {
|
||||
let underlying = [104, 101, 108, 108, 111];
|
||||
|
||||
let mock = tokio_test::io::Builder::new().read(&underlying).build();
|
||||
|
||||
let mut stream = Rewind::new(mock);
|
||||
|
||||
// Read off some bytes, ensure we filled o1
|
||||
let mut buf = [0; 2];
|
||||
stream.read_exact(&mut buf).await.expect("read1");
|
||||
|
||||
// Rewind the stream so that it is as if we never read in the first place.
|
||||
stream.rewind(Bytes::copy_from_slice(&buf[..]));
|
||||
|
||||
let mut buf = [0; 5];
|
||||
stream.read_exact(&mut buf).await.expect("read1");
|
||||
|
||||
// At this point we should have read everything that was in the MockStream
|
||||
assert_eq!(&buf, &underlying);
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn full_rewind() {
|
||||
let underlying = [104, 101, 108, 108, 111];
|
||||
|
||||
let mock = tokio_test::io::Builder::new().read(&underlying).build();
|
||||
|
||||
let mut stream = Rewind::new(mock);
|
||||
|
||||
let mut buf = [0; 5];
|
||||
stream.read_exact(&mut buf).await.expect("read1");
|
||||
|
||||
// Rewind the stream so that it is as if we never read in the first place.
|
||||
stream.rewind(Bytes::copy_from_slice(&buf[..]));
|
||||
|
||||
let mut buf = [0; 5];
|
||||
stream.read_exact(&mut buf).await.expect("read1");
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,76 +1,39 @@
|
|||
use pin_project_lite::pin_project;
|
||||
|
||||
use super::{task, Future, Pin, Poll};
|
||||
|
||||
pub(crate) trait Started: Future {
|
||||
fn started(&self) -> bool;
|
||||
}
|
||||
|
||||
pub(crate) fn lazy<F, R>(func: F) -> Lazy<F, R>
|
||||
where
|
||||
F: FnOnce() -> R,
|
||||
R: Future + Unpin,
|
||||
{
|
||||
Lazy {
|
||||
inner: Inner::Init { func },
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
|
||||
// FIXME: allow() required due to `impl Trait` leaking types to this lint
|
||||
pin_project! {
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub(crate) struct Lazy<F, R> {
|
||||
#[pin]
|
||||
inner: Inner<F, R>,
|
||||
}
|
||||
#[allow(missing_debug_implementations)] pub (crate) struct Lazy < F, R > { #[pin]
|
||||
inner : Inner < F, R >, }
|
||||
}
|
||||
|
||||
pin_project! {
|
||||
#[project = InnerProj]
|
||||
#[project_replace = InnerProjReplace]
|
||||
enum Inner<F, R> {
|
||||
Init { func: F },
|
||||
Fut { #[pin] fut: R },
|
||||
Empty,
|
||||
}
|
||||
#[project = InnerProj] #[project_replace = InnerProjReplace] enum Inner < F, R > {
|
||||
Init { func : F }, Fut { #[pin] fut : R }, Empty, }
|
||||
}
|
||||
|
||||
impl<F, R> Started for Lazy<F, R>
|
||||
where
|
||||
F: FnOnce() -> R,
|
||||
R: Future,
|
||||
{
|
||||
fn started(&self) -> bool {
|
||||
match self.inner {
|
||||
Inner::Init { .. } => false,
|
||||
Inner::Fut { .. } | Inner::Empty => true,
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, R> Future for Lazy<F, R>
|
||||
where
|
||||
F: FnOnce() -> R,
|
||||
R: Future,
|
||||
{
|
||||
type Output = R::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
|
||||
let mut this = self.project();
|
||||
|
||||
if let InnerProj::Fut { fut } = this.inner.as_mut().project() {
|
||||
return fut.poll(cx);
|
||||
}
|
||||
|
||||
match this.inner.as_mut().project_replace(Inner::Empty) {
|
||||
InnerProjReplace::Init { func } => {
|
||||
this.inner.set(Inner::Fut { fut: func() });
|
||||
if let InnerProj::Fut { fut } = this.inner.project() {
|
||||
return fut.poll(cx);
|
||||
}
|
||||
unreachable!()
|
||||
}
|
||||
_ => unreachable!("lazy state wrong"),
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,17 @@
|
|||
//! An uninhabitable type meaning it can never happen.
|
||||
//!
|
||||
//! To be replaced with `!` once it is stable.
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Never {}
|
||||
|
||||
impl fmt::Display for Never {
|
||||
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {}
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for Never {
|
||||
fn description(&self) -> &str {
|
||||
match *self {}
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,3 @@
|
|||
/*
|
||||
* This is a copy of the sync_wrapper crate.
|
||||
*/
|
||||
|
||||
/// A mutual exclusion primitive that relies on static type information only
|
||||
///
|
||||
/// In some cases synchronization can be proven statically: whenever you hold an exclusive `&mut`
|
||||
|
|
@ -42,7 +38,6 @@
|
|||
/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
|
||||
#[repr(transparent)]
|
||||
pub(crate) struct SyncWrapper<T>(T);
|
||||
|
||||
impl<T> SyncWrapper<T> {
|
||||
/// Creates a new SyncWrapper containing the given value.
|
||||
///
|
||||
|
|
@ -54,9 +49,8 @@ impl<T> SyncWrapper<T> {
|
|||
/// let wrapped = SyncWrapper::new(42);
|
||||
/// ```
|
||||
pub(crate) fn new(value: T) -> Self {
|
||||
Self(value)
|
||||
loop {}
|
||||
}
|
||||
|
||||
/// Acquires a reference to the protected value.
|
||||
///
|
||||
/// This is safe because it requires an exclusive reference to the wrapper. Therefore this method
|
||||
|
|
@ -78,9 +72,8 @@ impl<T> SyncWrapper<T> {
|
|||
/// assert_eq!(*wrapped.get_mut(), 0);
|
||||
/// ```
|
||||
pub(crate) fn get_mut(&mut self) -> &mut T {
|
||||
&mut self.0
|
||||
loop {}
|
||||
}
|
||||
|
||||
/// Consumes this wrapper, returning the underlying data.
|
||||
///
|
||||
/// This is safe because it requires ownership of the wrapper, aherefore this method will neither
|
||||
|
|
@ -101,10 +94,7 @@ impl<T> SyncWrapper<T> {
|
|||
/// ```
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn into_inner(self) -> T {
|
||||
self.0
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
// this is safe because the only operations permitted on this data structure require exclusive
|
||||
// access or ownership
|
||||
unsafe impl<T: Send> Sync for SyncWrapper<T> {}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
#[cfg(feature = "http1")]
|
||||
use super::Never;
|
||||
pub(crate) use std::task::{Context, Poll};
|
||||
|
||||
/// A function to help "yield" a future, such that it is re-scheduled immediately.
|
||||
///
|
||||
/// Useful for spin counts, so a future doesn't hog too much time.
|
||||
#[cfg(feature = "http1")]
|
||||
pub(crate) fn yield_now(cx: &mut Context<'_>) -> Poll<Never> {
|
||||
cx.waker().wake_by_ref();
|
||||
Poll::Pending
|
||||
loop {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,71 +3,42 @@
|
|||
//! - The value can only be a `usize`.
|
||||
//! - The consumer is only notified if the value is different.
|
||||
//! - The value `0` is reserved for closed.
|
||||
|
||||
use futures_util::task::AtomicWaker;
|
||||
use std::sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
Arc,
|
||||
};
|
||||
use std::task;
|
||||
|
||||
type Value = usize;
|
||||
|
||||
pub(crate) const CLOSED: usize = 0;
|
||||
|
||||
pub(crate) fn channel(initial: Value) -> (Sender, Receiver) {
|
||||
debug_assert!(
|
||||
initial != CLOSED,
|
||||
"watch::channel initial state of 0 is reserved"
|
||||
);
|
||||
|
||||
let shared = Arc::new(Shared {
|
||||
value: AtomicUsize::new(initial),
|
||||
waker: AtomicWaker::new(),
|
||||
});
|
||||
|
||||
(
|
||||
Sender {
|
||||
shared: shared.clone(),
|
||||
},
|
||||
Receiver { shared },
|
||||
)
|
||||
loop {}
|
||||
}
|
||||
|
||||
pub(crate) struct Sender {
|
||||
shared: Arc<Shared>,
|
||||
}
|
||||
|
||||
pub(crate) struct Receiver {
|
||||
shared: Arc<Shared>,
|
||||
}
|
||||
|
||||
struct Shared {
|
||||
value: AtomicUsize,
|
||||
waker: AtomicWaker,
|
||||
}
|
||||
|
||||
impl Sender {
|
||||
pub(crate) fn send(&mut self, value: Value) {
|
||||
if self.shared.value.swap(value, Ordering::SeqCst) != value {
|
||||
self.shared.waker.wake();
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Sender {
|
||||
fn drop(&mut self) {
|
||||
self.send(CLOSED);
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Receiver {
|
||||
pub(crate) fn load(&mut self, cx: &mut task::Context<'_>) -> Value {
|
||||
self.shared.waker.register(cx.waker());
|
||||
self.shared.value.load(Ordering::SeqCst)
|
||||
loop {}
|
||||
}
|
||||
|
||||
pub(crate) fn peek(&self) -> Value {
|
||||
self.shared.value.load(Ordering::Relaxed)
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue