Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1098302

Browse files
author
Stjepan Glavina
committedJun 22, 2020
Initial commit
0 parents  commit 1098302

File tree

3 files changed

+174
-0
lines changed

3 files changed

+174
-0
lines changed
 

‎.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target
2+
Cargo.lock

‎Cargo.toml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "futures-lite"
3+
version = "0.1.1"
4+
authors = ["Stjepan Glavina <stjepang@gmail.com>"]
5+
edition = "2018"
6+
description = "A lightweight subset of the futures crate"
7+
license = "Apache-2.0 OR MIT"
8+
9+
[features]
10+
default = ["std"]
11+
std = []
12+
13+
[dependencies]
14+
futures-core = "0.3.5"
15+
futures-io = { version = "0.3.5", default-features = false, features = ["std"] }

‎src/lib.rs

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
use std::fmt;
2+
use std::pin::Pin;
3+
use std::task::{Context, Poll};
4+
5+
pub use futures_core::{Future, Stream};
6+
pub use futures_io::{AsyncRead, AsyncSeek, AsyncWrite};
7+
8+
#[macro_export]
9+
macro_rules! ready {
10+
($e:expr $(,)?) => {
11+
match $e {
12+
std::task::Poll::Ready(t) => t,
13+
std::task::Poll::Pending => return std::task::Poll::Pending,
14+
}
15+
};
16+
}
17+
18+
#[macro_export]
19+
macro_rules! pin {
20+
($($x:ident),* $(,)?) => {
21+
$(
22+
let mut $x = $x;
23+
24+
#[allow(unused_mut)]
25+
let mut $x = unsafe {
26+
std::pin::Pin::new_unchecked(&mut $x)
27+
};
28+
)*
29+
}
30+
}
31+
32+
pub mod future {
33+
use super::*;
34+
35+
/// Future for the [`poll_fn`] function.
36+
#[must_use = "futures do nothing unless you `.await` or poll them"]
37+
pub struct PollFn<F> {
38+
f: F,
39+
}
40+
41+
impl<F> Unpin for PollFn<F> {}
42+
43+
/// Creates a new future wrapping around a function returning [`Poll`].
44+
///
45+
/// Polling the returned future delegates to the wrapped function.
46+
pub fn poll_fn<T, F>(f: F) -> PollFn<F>
47+
where
48+
F: FnMut(&mut Context<'_>) -> Poll<T>,
49+
{
50+
PollFn { f }
51+
}
52+
53+
impl<F> fmt::Debug for PollFn<F> {
54+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55+
f.debug_struct("PollFn").finish()
56+
}
57+
}
58+
59+
impl<T, F> Future for PollFn<F>
60+
where
61+
F: FnMut(&mut Context<'_>) -> Poll<T>,
62+
{
63+
type Output = T;
64+
65+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
66+
(&mut self.f)(cx)
67+
}
68+
}
69+
}
70+
71+
pub mod stream {
72+
use super::*;
73+
74+
/// Creates a `Stream` from a seed and a closure returning a `Future`.
75+
///
76+
/// This function is the dual for the `Stream::fold()` adapter: while
77+
/// `Stream::fold()` reduces a `Stream` to one single value, `unfold()` creates a
78+
/// `Stream` from a seed value.
79+
///
80+
/// `unfold()` will call the provided closure with the provided seed, then wait
81+
/// for the returned `Future` to complete with `(a, b)`. It will then yield the
82+
/// value `a`, and use `b` as the next internal state.
83+
///
84+
/// If the closure returns `None` instead of `Some(Future)`, then the `unfold()`
85+
/// will stop producing items and return `Poll::Ready(None)` in future
86+
/// calls to `poll()`.
87+
///
88+
/// This function can typically be used when wanting to go from the "world of
89+
/// futures" to the "world of streams": the provided closure can build a
90+
/// `Future` using other library functions working on futures, and `unfold()`
91+
/// will turn it into a `Stream` by repeating the operation.
92+
pub fn unfold<T, F, Fut, Item>(init: T, f: F) -> Unfold<T, F, Fut>
93+
where
94+
F: FnMut(T) -> Fut,
95+
Fut: Future<Output = Option<(Item, T)>>,
96+
{
97+
Unfold {
98+
f,
99+
state: Some(init),
100+
fut: None,
101+
}
102+
}
103+
104+
/// Stream for the [`unfold`] function.
105+
#[must_use = "streams do nothing unless polled"]
106+
pub struct Unfold<T, F, Fut> {
107+
f: F,
108+
state: Option<T>,
109+
fut: Option<Fut>,
110+
}
111+
112+
impl<T, F, Fut> fmt::Debug for Unfold<T, F, Fut>
113+
where
114+
T: fmt::Debug,
115+
Fut: fmt::Debug,
116+
{
117+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118+
f.debug_struct("Unfold")
119+
.field("state", &self.state)
120+
.field("fut", &self.fut)
121+
.finish()
122+
}
123+
}
124+
125+
impl<T, F, Fut, Item> Stream for Unfold<T, F, Fut>
126+
where
127+
F: FnMut(T) -> Fut,
128+
Fut: Future<Output = Option<(Item, T)>>,
129+
{
130+
type Item = Item;
131+
132+
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
133+
let mut this = unsafe { self.get_unchecked_mut() };
134+
135+
if let Some(state) = this.state.take() {
136+
this.fut = Some((this.f)(state));
137+
}
138+
139+
let fut = unsafe {
140+
Pin::new_unchecked(
141+
this.fut
142+
.as_mut()
143+
.expect("Unfold must not be polled after it returned `Poll::Ready(None)`"),
144+
)
145+
};
146+
let step = futures_core::ready!(fut.poll(cx));
147+
this.fut = None;
148+
149+
if let Some((item, next_state)) = step {
150+
this.state = Some(next_state);
151+
Poll::Ready(Some(item))
152+
} else {
153+
Poll::Ready(None)
154+
}
155+
}
156+
}
157+
}

0 commit comments

Comments
 (0)
Please sign in to comment.