Merge branch 'master' into tyler_elastic_threadpool

tosocketaddrs
Stjepan Glavina 5 years ago committed by GitHub
commit ae84fd4498
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at stjepang@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

@ -7,25 +7,26 @@ license = "Apache-2.0/MIT"
repository = "https://github.com/stjepang/async-std"
homepage = "https://github.com/stjepang/async-std"
documentation = "https://docs.rs/async-std"
description = "Asynchronous standard library"
keywords = []
categories = ["asynchronous", "concurrency"]
description = "Async version of the Rust standard library"
keywords = ["async", "await", "future", "std", "task"]
categories = ["asynchronous", "concurrency", "network-programming"]
[package.metadata.docs.rs]
features = ["docs.rs"]
rustdoc-args = ["--features docs.rs"]
features = ["docs"]
rustdoc-args = ["--features docs"]
[features]
"docs.rs" = []
docs = []
[dependencies]
async-task = { path = "async-task" }
async-task = { path = "../async-task" }
cfg-if = "0.1.9"
crossbeam = "0.7.1"
futures-preview = "0.3.0-alpha.17"
futures-timer = "0.3.0"
lazy_static = "1.3.0"
log = { version = "0.4.8", features = ["kv_unstable"] }
memchr = "2.2.1"
mio = "0.6.19"
mio-uds = "0.6.7"
num_cpus = "1.10.0"
@ -36,9 +37,3 @@ slab = "0.4.2"
femme = "1.1.0"
# surf = { git = "ssh://github.com/yoshuawuyts/surf" }
tempdir = "0.3.7"
[workspace]
members = [
".",
"async-task",
]

@ -1,4 +1,4 @@
# Async version of Rust's standard library
# Async version of the Rust standard library
<!-- [![Build Status](https://travis-ci.org/stjepang/async-std.svg?branch=master)]( -->
<!-- https://travis-ci.org/stjepang/async-std) -->
@ -25,7 +25,7 @@ git clone git@github.com:stjepang/async-std.git && cd async-std
Read the docs:
```
cargo doc --features docs.rs --open
cargo doc --features docs --open
```
Check out the [examples](examples). To run an example:

@ -1,20 +0,0 @@
[package]
name = "async-task"
version = "0.1.0"
authors = ["Stjepan Glavina <stjepang@gmail.com>"]
edition = "2018"
license = "Apache-2.0/MIT"
repository = "https://github.com/stjepang/async-task"
homepage = "https://github.com/stjepang/async-task"
documentation = "https://docs.rs/async-task"
description = "Task abstraction for building executors"
keywords = ["future", "task", "executor", "spawn"]
categories = ["asynchronous", "concurrency"]
[dependencies]
crossbeam-utils = "0.6.5"
[dev-dependencies]
crossbeam = "0.7.1"
futures-preview = "0.3.0-alpha.17"
lazy_static = "1.3.0"

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -1,23 +0,0 @@
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

@ -1,21 +0,0 @@
# async-task
A task abstraction for building executors.
This crate makes it possible to build an efficient and extendable executor in few lines of
code.
## License
Licensed under either of
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
#### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

@ -1,43 +0,0 @@
#![feature(async_await, test)]
extern crate test;
use futures::channel::oneshot;
use futures::executor;
use futures::future::TryFutureExt;
use test::Bencher;
#[bench]
fn task_create(b: &mut Bencher) {
b.iter(|| {
async_task::spawn(async {}, drop, ());
});
}
#[bench]
fn task_run(b: &mut Bencher) {
b.iter(|| {
let (task, handle) = async_task::spawn(async {}, drop, ());
task.run();
executor::block_on(handle).unwrap();
});
}
#[bench]
fn oneshot_create(b: &mut Bencher) {
b.iter(|| {
let (tx, _rx) = oneshot::channel::<()>();
let _task = Box::new(async move { tx.send(()).map_err(|_| ()) });
});
}
#[bench]
fn oneshot_run(b: &mut Bencher) {
b.iter(|| {
let (tx, rx) = oneshot::channel::<()>();
let task = Box::new(async move { tx.send(()).map_err(|_| ()) });
let future = task.and_then(|_| rx.map_err(|_| ()));
executor::block_on(future).unwrap();
});
}

@ -1,75 +0,0 @@
//! A single-threaded executor where join handles propagate panics from tasks.
#![feature(async_await)]
use std::future::Future;
use std::panic::{resume_unwind, AssertUnwindSafe};
use std::pin::Pin;
use std::task::{Context, Poll};
use std::thread;
use crossbeam::channel::{unbounded, Sender};
use futures::executor;
use futures::future::FutureExt;
use lazy_static::lazy_static;
/// Spawns a future on the executor.
fn spawn<F, R>(future: F) -> JoinHandle<R>
where
F: Future<Output = R> + Send + 'static,
R: Send + 'static,
{
lazy_static! {
// A channel that holds scheduled tasks.
static ref QUEUE: Sender<async_task::Task<()>> = {
let (sender, receiver) = unbounded::<async_task::Task<()>>();
// Start the executor thread.
thread::spawn(|| {
for task in receiver {
// No need for `catch_unwind()` here because panics are already caught.
task.run();
}
});
sender
};
}
// Create a future that catches panics within itself.
let future = AssertUnwindSafe(future).catch_unwind();
// Create a task that is scheduled by sending itself into the channel.
let schedule = |t| QUEUE.send(t).unwrap();
let (task, handle) = async_task::spawn(future, schedule, ());
// Schedule the task by sending it into the channel.
task.schedule();
// Wrap the handle into one that propagates panics.
JoinHandle(handle)
}
/// A join handle that propagates panics inside the task.
struct JoinHandle<R>(async_task::JoinHandle<thread::Result<R>, ()>);
impl<R> Future for JoinHandle<R> {
type Output = Option<R>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match Pin::new(&mut self.0).poll(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(None) => Poll::Ready(None),
Poll::Ready(Some(Ok(val))) => Poll::Ready(Some(val)),
Poll::Ready(Some(Err(err))) => resume_unwind(err),
}
}
}
fn main() {
// Spawn a future that panics and block on it.
let handle = spawn(async {
panic!("Ooops!");
});
executor::block_on(handle);
}

@ -1,74 +0,0 @@
//! A single-threaded executor where join handles catch panics inside tasks.
#![feature(async_await)]
use std::future::Future;
use std::panic::AssertUnwindSafe;
use std::thread;
use crossbeam::channel::{unbounded, Sender};
use futures::executor;
use futures::future::FutureExt;
use lazy_static::lazy_static;
/// Spawns a future on the executor.
fn spawn<F, R>(future: F) -> async_task::JoinHandle<thread::Result<R>, ()>
where
F: Future<Output = R> + Send + 'static,
R: Send + 'static,
{
lazy_static! {
// A channel that holds scheduled tasks.
static ref QUEUE: Sender<async_task::Task<()>> = {
let (sender, receiver) = unbounded::<async_task::Task<()>>();
// Start the executor thread.
thread::spawn(|| {
for task in receiver {
// No need for `catch_unwind()` here because panics are already caught.
task.run();
}
});
sender
};
}
// Create a future that catches panics within itself.
let future = AssertUnwindSafe(future).catch_unwind();
// Create a task that is scheduled by sending itself into the channel.
let schedule = |t| QUEUE.send(t).unwrap();
let (task, handle) = async_task::spawn(future, schedule, ());
// Schedule the task by sending it into the channel.
task.schedule();
handle
}
fn main() {
// Spawn a future that completes succesfully.
let handle = spawn(async {
println!("Hello, world!");
});
// Block on the future and report its result.
match executor::block_on(handle) {
None => println!("The task was cancelled."),
Some(Ok(val)) => println!("The task completed with {:?}", val),
Some(Err(_)) => println!("The task has panicked"),
}
// Spawn a future that panics.
let handle = spawn(async {
panic!("Ooops!");
});
// Block on the future and report its result.
match executor::block_on(handle) {
None => println!("The task was cancelled."),
Some(Ok(val)) => println!("The task completed with {:?}", val),
Some(Err(_)) => println!("The task has panicked"),
}
}

@ -1,55 +0,0 @@
//! A function that runs a future to completion on a dedicated thread.
#![feature(async_await)]
use std::future::Future;
use std::sync::Arc;
use std::thread;
use crossbeam::channel;
use futures::executor;
/// Spawns a future on a new dedicated thread.
///
/// The returned handle can be used to await the output of the future.
fn spawn_on_thread<F, R>(future: F) -> async_task::JoinHandle<R, ()>
where
F: Future<Output = R> + Send + 'static,
R: Send + 'static,
{
// Create a channel that holds the task when it is scheduled for running.
let (sender, receiver) = channel::unbounded();
let sender = Arc::new(sender);
let s = Arc::downgrade(&sender);
// Wrap the future into one that disconnects the channel on completion.
let future = async move {
// When the inner future completes, the sender gets dropped and disconnects the channel.
let _sender = sender;
future.await
};
// Create a task that is scheduled by sending itself into the channel.
let schedule = move |t| s.upgrade().unwrap().send(t).unwrap();
let (task, handle) = async_task::spawn(future, schedule, ());
// Schedule the task by sending it into the channel.
task.schedule();
// Spawn a thread running the task to completion.
thread::spawn(move || {
// Keep taking the task from the channel and running it until completion.
for task in receiver {
task.run();
}
});
handle
}
fn main() {
// Spawn a future on a dedicated thread.
executor::block_on(spawn_on_thread(async {
println!("Hello, world!");
}));
}

@ -1,52 +0,0 @@
//! A simple single-threaded executor.
#![feature(async_await)]
use std::future::Future;
use std::panic::catch_unwind;
use std::thread;
use crossbeam::channel::{unbounded, Sender};
use futures::executor;
use lazy_static::lazy_static;
/// Spawns a future on the executor.
fn spawn<F, R>(future: F) -> async_task::JoinHandle<R, ()>
where
F: Future<Output = R> + Send + 'static,
R: Send + 'static,
{
lazy_static! {
// A channel that holds scheduled tasks.
static ref QUEUE: Sender<async_task::Task<()>> = {
let (sender, receiver) = unbounded::<async_task::Task<()>>();
// Start the executor thread.
thread::spawn(|| {
for task in receiver {
// Ignore panics for simplicity.
let _ignore_panic = catch_unwind(|| task.run());
}
});
sender
};
}
// Create a task that is scheduled by sending itself into the channel.
let schedule = |t| QUEUE.send(t).unwrap();
let (task, handle) = async_task::spawn(future, schedule, ());
// Schedule the task by sending it into the channel.
task.schedule();
handle
}
fn main() {
// Spawn a future and await its result.
let handle = spawn(async {
println!("Hello, world!");
});
executor::block_on(handle);
}

@ -1,88 +0,0 @@
//! An executor that assigns an ID to every spawned task.
#![feature(async_await)]
use std::cell::Cell;
use std::future::Future;
use std::panic::catch_unwind;
use std::thread;
use crossbeam::atomic::AtomicCell;
use crossbeam::channel::{unbounded, Sender};
use futures::executor;
use lazy_static::lazy_static;
#[derive(Clone, Copy, Debug)]
struct TaskId(usize);
thread_local! {
/// The ID of the current task.
static TASK_ID: Cell<Option<TaskId>> = Cell::new(None);
}
/// Returns the ID of the currently executing task.
///
/// Returns `None` if called outside the runtime.
fn task_id() -> Option<TaskId> {
TASK_ID.with(|id| id.get())
}
/// Spawns a future on the executor.
fn spawn<F, R>(future: F) -> async_task::JoinHandle<R, TaskId>
where
F: Future<Output = R> + Send + 'static,
R: Send + 'static,
{
lazy_static! {
// A channel that holds scheduled tasks.
static ref QUEUE: Sender<async_task::Task<TaskId>> = {
let (sender, receiver) = unbounded::<async_task::Task<TaskId>>();
// Start the executor thread.
thread::spawn(|| {
TASK_ID.with(|id| {
for task in receiver {
// Store the task ID into the thread-local before running.
id.set(Some(*task.tag()));
// Ignore panics for simplicity.
let _ignore_panic = catch_unwind(|| task.run());
}
})
});
sender
};
// A counter that assigns IDs to spawned tasks.
static ref COUNTER: AtomicCell<usize> = AtomicCell::new(0);
}
// Reserve an ID for the new task.
let id = TaskId(COUNTER.fetch_add(1));
// Create a task that is scheduled by sending itself into the channel.
let schedule = |task| QUEUE.send(task).unwrap();
let (task, handle) = async_task::spawn(future, schedule, id);
// Schedule the task by sending it into the channel.
task.schedule();
handle
}
fn main() {
let mut handles = vec![];
// Spawn a bunch of tasks.
for _ in 0..10 {
handles.push(spawn(async move {
println!("Hello from task with {:?}", task_id());
}));
}
// Wait for the tasks to finish.
for handle in handles {
executor::block_on(handle);
}
}

@ -1,158 +0,0 @@
use std::alloc::Layout;
use std::cell::Cell;
use std::fmt;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::task::Waker;
use crossbeam_utils::Backoff;
use crate::raw::TaskVTable;
use crate::state::*;
use crate::utils::{abort_on_panic, extend};
/// The header of a task.
///
/// This header is stored right at the beginning of every heap-allocated task.
pub(crate) struct Header {
/// Current state of the task.
///
/// Contains flags representing the current state and the reference count.
pub(crate) state: AtomicUsize,
/// The task that is blocked on the `JoinHandle`.
///
/// This waker needs to be woken once the task completes or is closed.
pub(crate) awaiter: Cell<Option<Waker>>,
/// The virtual table.
///
/// In addition to the actual waker virtual table, it also contains pointers to several other
/// methods necessary for bookkeeping the heap-allocated task.
pub(crate) vtable: &'static TaskVTable,
}
impl Header {
/// Cancels the task.
///
/// This method will only mark the task as closed and will notify the awaiter, but it won't
/// reschedule the task if it's not completed.
pub(crate) fn cancel(&self) {
let mut state = self.state.load(Ordering::Acquire);
loop {
// If the task has been completed or closed, it can't be cancelled.
if state & (COMPLETED | CLOSED) != 0 {
break;
}
// Mark the task as closed.
match self.state.compare_exchange_weak(
state,
state | CLOSED,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
// Notify the awaiter that the task has been closed.
if state & AWAITER != 0 {
self.notify();
}
break;
}
Err(s) => state = s,
}
}
}
/// Notifies the task blocked on the task.
///
/// If there is a registered waker, it will be removed from the header and woken.
#[inline]
pub(crate) fn notify(&self) {
if let Some(waker) = self.swap_awaiter(None) {
// We need a safeguard against panics because waking can panic.
abort_on_panic(|| {
waker.wake();
});
}
}
/// Notifies the task blocked on the task unless its waker matches `current`.
///
/// If there is a registered waker, it will be removed from the header.
#[inline]
pub(crate) fn notify_unless(&self, current: &Waker) {
if let Some(waker) = self.swap_awaiter(None) {
if !waker.will_wake(current) {
// We need a safeguard against panics because waking can panic.
abort_on_panic(|| {
waker.wake();
});
}
}
}
/// Swaps the awaiter and returns the previous value.
#[inline]
pub(crate) fn swap_awaiter(&self, new: Option<Waker>) -> Option<Waker> {
let new_is_none = new.is_none();
// We're about to try acquiring the lock in a loop. If it's already being held by another
// thread, we'll have to spin for a while so it's best to employ a backoff strategy.
let backoff = Backoff::new();
loop {
// Acquire the lock. If we're storing an awaiter, then also set the awaiter flag.
let state = if new_is_none {
self.state.fetch_or(LOCKED, Ordering::Acquire)
} else {
self.state.fetch_or(LOCKED | AWAITER, Ordering::Acquire)
};
// If the lock was acquired, break from the loop.
if state & LOCKED == 0 {
break;
}
// Snooze for a little while because the lock is held by another thread.
backoff.snooze();
}
// Replace the awaiter.
let old = self.awaiter.replace(new);
// Release the lock. If we've cleared the awaiter, then also unset the awaiter flag.
if new_is_none {
self.state.fetch_and(!LOCKED & !AWAITER, Ordering::Release);
} else {
self.state.fetch_and(!LOCKED, Ordering::Release);
}
old
}
/// Returns the offset at which the tag of type `T` is stored.
#[inline]
pub(crate) fn offset_tag<T>() -> usize {
let layout_header = Layout::new::<Header>();
let layout_t = Layout::new::<T>();
let (_, offset_t) = extend(layout_header, layout_t);
offset_t
}
}
impl fmt::Debug for Header {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let state = self.state.load(Ordering::SeqCst);
f.debug_struct("Header")
.field("scheduled", &(state & SCHEDULED != 0))
.field("running", &(state & RUNNING != 0))
.field("completed", &(state & COMPLETED != 0))
.field("closed", &(state & CLOSED != 0))
.field("awaiter", &(state & AWAITER != 0))
.field("handle", &(state & HANDLE != 0))
.field("ref_count", &(state / REFERENCE))
.finish()
}
}

@ -1,333 +0,0 @@
use std::fmt;
use std::future::Future;
use std::marker::{PhantomData, Unpin};
use std::pin::Pin;
use std::ptr::NonNull;
use std::sync::atomic::Ordering;
use std::task::{Context, Poll};
use crate::header::Header;
use crate::state::*;
use crate::utils::abort_on_panic;
/// A handle that awaits the result of a task.
///
/// If the task has completed with `value`, the handle returns it as `Some(value)`. If the task was
/// cancelled or has panicked, the handle returns `None`. Otherwise, the handle has to wait until
/// the task completes, panics, or gets cancelled.
///
/// # Examples
///
/// ```
/// #![feature(async_await)]
///
/// use crossbeam::channel;
/// use futures::executor;
///
/// // The future inside the task.
/// let future = async { 1 + 2 };
///
/// // If the task gets woken, it will be sent into this channel.
/// let (s, r) = channel::unbounded();
/// let schedule = move |task| s.send(task).unwrap();
///
/// // Create a task with the future and the schedule function.
/// let (task, handle) = async_task::spawn(future, schedule, ());
///
/// // Run the task. In this example, it will complete after a single run.
/// task.run();
/// assert!(r.is_empty());
///
/// // Await the result of the task.
/// let result = executor::block_on(handle);
/// assert_eq!(result, Some(3));
/// ```
pub struct JoinHandle<R, T> {
/// A raw task pointer.
pub(crate) raw_task: NonNull<()>,
/// A marker capturing the generic type `R`.
pub(crate) _marker: PhantomData<(R, T)>,
}
unsafe impl<R, T> Send for JoinHandle<R, T> {}
unsafe impl<R, T> Sync for JoinHandle<R, T> {}
impl<R, T> Unpin for JoinHandle<R, T> {}
impl<R, T> JoinHandle<R, T> {
/// Cancels the task.
///
/// When cancelled, the task won't be scheduled again even if a [`Waker`] wakes it. An attempt
/// to run it won't do anything. And if it's completed, awaiting its result evaluates to
/// `None`.
///
/// [`Waker`]: https://doc.rust-lang.org/std/task/struct.Waker.html
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// use crossbeam::channel;
/// use futures::executor;
///
/// // The future inside the task.
/// let future = async { 1 + 2 };
///
/// // If the task gets woken, it will be sent into this channel.
/// let (s, r) = channel::unbounded();
/// let schedule = move |task| s.send(task).unwrap();
///
/// // Create a task with the future and the schedule function.
/// let (task, handle) = async_task::spawn(future, schedule, ());
///
/// // Cancel the task.
/// handle.cancel();
///
/// // Running a cancelled task does nothing.
/// task.run();
///
/// // Await the result of the task.
/// let result = executor::block_on(handle);
/// assert_eq!(result, None);
/// ```
pub fn cancel(&self) {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
unsafe {
let mut state = (*header).state.load(Ordering::Acquire);
loop {
// If the task has been completed or closed, it can't be cancelled.
if state & (COMPLETED | CLOSED) != 0 {
break;
}
// If the task is not scheduled nor running, we'll need to schedule it.
let new = if state & (SCHEDULED | RUNNING) == 0 {
(state | SCHEDULED | CLOSED) + REFERENCE
} else {
state | CLOSED
};
// Mark the task as closed.
match (*header).state.compare_exchange_weak(
state,
new,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
// If the task is not scheduled nor running, schedule it so that its future
// gets dropped by the executor.
if state & (SCHEDULED | RUNNING) == 0 {
((*header).vtable.schedule)(ptr);
}
// Notify the awaiter that the task has been closed.
if state & AWAITER != 0 {
(*header).notify();
}
break;
}
Err(s) => state = s,
}
}
}
}
/// Returns a reference to the tag stored inside the task.
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// use crossbeam::channel;
///
/// // The future inside the task.
/// let future = async { 1 + 2 };
///
/// // If the task gets woken, it will be sent into this channel.
/// let (s, r) = channel::unbounded();
/// let schedule = move |task| s.send(task).unwrap();
///
/// // Create a task with the future and the schedule function.
/// let (task, handle) = async_task::spawn(future, schedule, "a simple task");
///
/// // Access the tag.
/// assert_eq!(*handle.tag(), "a simple task");
/// ```
pub fn tag(&self) -> &T {
let offset = Header::offset_tag::<T>();
let ptr = self.raw_task.as_ptr();
unsafe {
let raw = (ptr as *mut u8).add(offset) as *const T;
&*raw
}
}
}
impl<R, T> Drop for JoinHandle<R, T> {
fn drop(&mut self) {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
// A place where the output will be stored in case it needs to be dropped.
let mut output = None;
unsafe {
// Optimistically assume the `JoinHandle` is being dropped just after creating the
// task. This is a common case so if the handle is not used, the overhead of it is only
// one compare-exchange operation.
if let Err(mut state) = (*header).state.compare_exchange_weak(
SCHEDULED | HANDLE | REFERENCE,
SCHEDULED | REFERENCE,
Ordering::AcqRel,
Ordering::Acquire,
) {
loop {
// If the task has been completed but not yet closed, that means its output
// must be dropped.
if state & COMPLETED != 0 && state & CLOSED == 0 {
// Mark the task as closed in order to grab its output.
match (*header).state.compare_exchange_weak(
state,
state | CLOSED,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
// Read the output.
output =
Some((((*header).vtable.get_output)(ptr) as *mut R).read());
// Update the state variable because we're continuing the loop.
state |= CLOSED;
}
Err(s) => state = s,
}
} else {
// If this is the last reference to task and it's not closed, then close
// it and schedule one more time so that its future gets dropped by the
// executor.
let new = if state & (!(REFERENCE - 1) | CLOSED) == 0 {
SCHEDULED | CLOSED | REFERENCE
} else {
state & !HANDLE
};
// Unset the handle flag.
match (*header).state.compare_exchange_weak(
state,
new,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
// If this is the last reference to the task, we need to either
// schedule dropping its future or destroy it.
if state & !(REFERENCE - 1) == 0 {
if state & CLOSED == 0 {
((*header).vtable.schedule)(ptr);
} else {
((*header).vtable.destroy)(ptr);
}
}
break;
}
Err(s) => state = s,
}
}
}
}
}
// Drop the output if it was taken out of the task.
drop(output);
}
}
impl<R, T> Future for JoinHandle<R, T> {
type Output = Option<R>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
unsafe {
let mut state = (*header).state.load(Ordering::Acquire);
loop {
// If the task has been closed, notify the awaiter and return `None`.
if state & CLOSED != 0 {
// Even though the awaiter is most likely the current task, it could also be
// another task.
(*header).notify_unless(cx.waker());
return Poll::Ready(None);
}
// If the task is not completed, register the current task.
if state & COMPLETED == 0 {
// Replace the waker with one associated with the current task. We need a
// safeguard against panics because dropping the previous waker can panic.
abort_on_panic(|| {
(*header).swap_awaiter(Some(cx.waker().clone()));
});
// Reload the state after registering. It is possible that the task became
// completed or closed just before registration so we need to check for that.
state = (*header).state.load(Ordering::Acquire);
// If the task has been closed, notify the awaiter and return `None`.
if state & CLOSED != 0 {
// Even though the awaiter is most likely the current task, it could also
// be another task.
(*header).notify_unless(cx.waker());
return Poll::Ready(None);
}
// If the task is still not completed, we're blocked on it.
if state & COMPLETED == 0 {
return Poll::Pending;
}
}
// Since the task is now completed, mark it as closed in order to grab its output.
match (*header).state.compare_exchange(
state,
state | CLOSED,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
// Notify the awaiter. Even though the awaiter is most likely the current
// task, it could also be another task.
if state & AWAITER != 0 {
(*header).notify_unless(cx.waker());
}
// Take the output from the task.
let output = ((*header).vtable.get_output)(ptr) as *mut R;
return Poll::Ready(Some(output.read()));
}
Err(s) => state = s,
}
}
}
}
}
impl<R, T> fmt::Debug for JoinHandle<R, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
f.debug_struct("JoinHandle")
.field("header", unsafe { &(*header) })
.finish()
}
}

@ -1,149 +0,0 @@
//! Task abstraction for building executors.
//!
//! # What is an executor?
//!
//! An async block creates a future and an async function returns one. But futures don't do
//! anything unless they are awaited inside other async blocks or async functions. So the question
//! arises: who or what awaits the main future that awaits others?
//!
//! One solution is to call [`block_on()`] on the main future, which will block
//! the current thread and keep polling the future until it completes. But sometimes we don't want
//! to block the current thread and would prefer to *spawn* the future to let a background thread
//! block on it instead.
//!
//! This is where executors step in - they create a number of threads (typically equal to the
//! number of CPU cores on the system) that are dedicated to polling spawned futures. Each executor
//! thread keeps polling spawned futures in a loop and only blocks when all spawned futures are
//! either sleeping or running.
//!
//! # What is a task?
//!
//! In order to spawn a future on an executor, one needs to allocate the future on the heap and
//! keep some state alongside it, like whether the future is ready for polling, waiting to be woken
//! up, or completed. This allocation is usually called a *task*.
//!
//! The executor then runs the spawned task by polling its future. If the future is pending on a
//! resource, a [`Waker`] associated with the task will be registered somewhere so that the task
//! can be woken up and run again at a later time.
//!
//! For example, if the future wants to read something from a TCP socket that is not ready yet, the
//! networking system will clone the task's waker and wake it up once the socket becomes ready.
//!
//! # Task construction
//!
//! A task is constructed with [`Task::create()`]:
//!
//! ```
//! # #![feature(async_await)]
//! let future = async { 1 + 2 };
//! let schedule = |task| unimplemented!();
//!
//! let (task, handle) = async_task::spawn(future, schedule, ());
//! ```
//!
//! The first argument to the constructor, `()` in this example, is an arbitrary piece of data
//! called a *tag*. This can be a task identifier, a task name, task-local storage, or something
//! of similar nature.
//!
//! The second argument is the future that gets polled when the task is run.
//!
//! The third argument is the schedule function, which is called every time when the task gets
//! woken up. This function should push the received task into some kind of queue of runnable
//! tasks.
//!
//! The constructor returns a runnable [`Task`] and a [`JoinHandle`] that can await the result of
//! the future.
//!
//! # Task scheduling
//!
//! TODO
//!
//! # Join handles
//!
//! TODO
//!
//! # Cancellation
//!
//! TODO
//!
//! # Performance
//!
//! TODO: explain single allocation, etc.
//!
//! Task [construction] incurs a single allocation only. The [`Task`] can then be run and its
//! result awaited through the [`JoinHandle`]. When woken, the task gets automatically rescheduled.
//! It's also possible to cancel the task so that it stops running and can't be awaited anymore.
//!
//! [construction]: struct.Task.html#method.create
//! [`JoinHandle`]: struct.JoinHandle.html
//! [`Task`]: struct.Task.html
//! [`Future`]: https://doc.rust-lang.org/nightly/std/future/trait.Future.html
//! [`Waker`]: https://doc.rust-lang.org/nightly/std/task/struct.Waker.html
//! [`block_on()`]: https://docs.rs/futures-preview/*/futures/executor/fn.block_on.html
//!
//! # Examples
//!
//! A simple single-threaded executor:
//!
//! ```
//! # #![feature(async_await)]
//! use std::future::Future;
//! use std::panic::catch_unwind;
//! use std::thread;
//!
//! use async_task::{JoinHandle, Task};
//! use crossbeam::channel::{unbounded, Sender};
//! use futures::executor;
//! use lazy_static::lazy_static;
//!
//! /// Spawns a future on the executor.
//! fn spawn<F, R>(future: F) -> JoinHandle<R, ()>
//! where
//! F: Future<Output = R> + Send + 'static,
//! R: Send + 'static,
//! {
//! lazy_static! {
//! // A channel that holds scheduled tasks.
//! static ref QUEUE: Sender<Task<()>> = {
//! let (sender, receiver) = unbounded::<Task<()>>();
//!
//! // Start the executor thread.
//! thread::spawn(|| {
//! for task in receiver {
//! // Ignore panics for simplicity.
//! let _ignore_panic = catch_unwind(|| task.run());
//! }
//! });
//!
//! sender
//! };
//! }
//!
//! // Create a task that is scheduled by sending itself into the channel.
//! let schedule = |t| QUEUE.send(t).unwrap();
//! let (task, handle) = async_task::spawn(future, schedule, ());
//!
//! // Schedule the task by sending it into the channel.
//! task.schedule();
//!
//! handle
//! }
//!
//! // Spawn a future and await its result.
//! let handle = spawn(async {
//! println!("Hello, world!");
//! });
//! executor::block_on(handle);
//! ```
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
mod header;
mod join_handle;
mod raw;
mod state;
mod task;
mod utils;
pub use crate::join_handle::JoinHandle;
pub use crate::task::{spawn, Task};

@ -1,629 +0,0 @@
use std::alloc::{self, Layout};
use std::cell::Cell;
use std::future::Future;
use std::marker::PhantomData;
use std::mem::{self, ManuallyDrop};
use std::pin::Pin;
use std::ptr::NonNull;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use crate::header::Header;
use crate::state::*;
use crate::utils::{abort_on_panic, extend};
use crate::Task;
/// The vtable for a task.
pub(crate) struct TaskVTable {
/// The raw waker vtable.
pub(crate) raw_waker: RawWakerVTable,
/// Schedules the task.
pub(crate) schedule: unsafe fn(*const ()),
/// Drops the future inside the task.
pub(crate) drop_future: unsafe fn(*const ()),
/// Returns a pointer to the output stored after completion.
pub(crate) get_output: unsafe fn(*const ()) -> *const (),
/// Drops a waker or a task.
pub(crate) decrement: unsafe fn(ptr: *const ()),
/// Destroys the task.
pub(crate) destroy: unsafe fn(*const ()),
/// Runs the task.
pub(crate) run: unsafe fn(*const ()),
}
/// Memory layout of a task.
///
/// This struct contains the information on:
///
/// 1. How to allocate and deallocate the task.
/// 2. How to access the fields inside the task.
#[derive(Clone, Copy)]
pub(crate) struct TaskLayout {
/// Memory layout of the whole task.
pub(crate) layout: Layout,
/// Offset into the task at which the tag is stored.
pub(crate) offset_t: usize,
/// Offset into the task at which the schedule function is stored.
pub(crate) offset_s: usize,
/// Offset into the task at which the future is stored.
pub(crate) offset_f: usize,
/// Offset into the task at which the output is stored.
pub(crate) offset_r: usize,
}
/// Raw pointers to the fields of a task.
pub(crate) struct RawTask<F, R, S, T> {
/// The task header.
pub(crate) header: *const Header,
/// The schedule function.
pub(crate) schedule: *const S,
/// The tag inside the task.
pub(crate) tag: *mut T,
/// The future.
pub(crate) future: *mut F,
/// The output of the future.
pub(crate) output: *mut R,
}
impl<F, R, S, T> Copy for RawTask<F, R, S, T> {}
impl<F, R, S, T> Clone for RawTask<F, R, S, T> {
fn clone(&self) -> Self {
Self {
header: self.header,
schedule: self.schedule,
tag: self.tag,
future: self.future,
output: self.output,
}
}
}
impl<F, R, S, T> RawTask<F, R, S, T>
where
F: Future<Output = R> + Send + 'static,
R: Send + 'static,
S: Fn(Task<T>) + Send + Sync + 'static,
T: Send + 'static,
{
/// Allocates a task with the given `future` and `schedule` function.
///
/// It is assumed there are initially only the `Task` reference and the `JoinHandle`.
pub(crate) fn allocate(tag: T, future: F, schedule: S) -> NonNull<()> {
// Compute the layout of the task for allocation. Abort if the computation fails.
let task_layout = abort_on_panic(|| Self::task_layout());
unsafe {
// Allocate enough space for the entire task.
let raw_task = match NonNull::new(alloc::alloc(task_layout.layout) as *mut ()) {
None => std::process::abort(),
Some(p) => p,
};
let raw = Self::from_ptr(raw_task.as_ptr());
// Write the header as the first field of the task.
(raw.header as *mut Header).write(Header {
state: AtomicUsize::new(SCHEDULED | HANDLE | REFERENCE),
awaiter: Cell::new(None),
vtable: &TaskVTable {
raw_waker: RawWakerVTable::new(
Self::clone_waker,
Self::wake,
Self::wake_by_ref,
Self::decrement,
),
schedule: Self::schedule,
drop_future: Self::drop_future,
get_output: Self::get_output,
decrement: Self::decrement,
destroy: Self::destroy,
run: Self::run,
},
});
// Write the tag as the second field of the task.
(raw.tag as *mut T).write(tag);
// Write the schedule function as the third field of the task.
(raw.schedule as *mut S).write(schedule);
// Write the future as the fourth field of the task.
raw.future.write(future);
raw_task
}
}
/// Creates a `RawTask` from a raw task pointer.
#[inline]
pub(crate) fn from_ptr(ptr: *const ()) -> Self {
let task_layout = Self::task_layout();
let p = ptr as *const u8;
unsafe {
Self {
header: p as *const Header,
tag: p.add(task_layout.offset_t) as *mut T,
schedule: p.add(task_layout.offset_s) as *const S,
future: p.add(task_layout.offset_f) as *mut F,
output: p.add(task_layout.offset_r) as *mut R,
}
}
}
/// Returns the memory layout for a task.
#[inline]
fn task_layout() -> TaskLayout {
// Compute the layouts for `Header`, `T`, `S`, `F`, and `R`.
let layout_header = Layout::new::<Header>();
let layout_t = Layout::new::<T>();
let layout_s = Layout::new::<S>();
let layout_f = Layout::new::<F>();
let layout_r = Layout::new::<R>();
// Compute the layout for `union { F, R }`.
let size_union = layout_f.size().max(layout_r.size());
let align_union = layout_f.align().max(layout_r.align());
let layout_union = unsafe { Layout::from_size_align_unchecked(size_union, align_union) };
// Compute the layout for `Header` followed by `T`, then `S`, then `union { F, R }`.
let layout = layout_header;
let (layout, offset_t) = extend(layout, layout_t);
let (layout, offset_s) = extend(layout, layout_s);
let (layout, offset_union) = extend(layout, layout_union);
let offset_f = offset_union;
let offset_r = offset_union;
TaskLayout {
layout,
offset_t,
offset_s,
offset_f,
offset_r,
}
}
/// Wakes a waker.
unsafe fn wake(ptr: *const ()) {
let raw = Self::from_ptr(ptr);
let mut state = (*raw.header).state.load(Ordering::Acquire);
loop {
// If the task is completed or closed, it can't be woken.
if state & (COMPLETED | CLOSED) != 0 {
// Drop the waker.
Self::decrement(ptr);
break;
}
// If the task is already scheduled, we just need to synchronize with the thread that
// will run the task by "publishing" our current view of the memory.
if state & SCHEDULED != 0 {
// Update the state without actually modifying it.
match (*raw.header).state.compare_exchange_weak(
state,
state,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
// Drop the waker.
Self::decrement(ptr);
break;
}
Err(s) => state = s,
}
} else {
// Mark the task as scheduled.
match (*raw.header).state.compare_exchange_weak(
state,
state | SCHEDULED,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
// If the task is not yet scheduled and isn't currently running, now is the
// time to schedule it.
if state & (SCHEDULED | RUNNING) == 0 {
// Schedule the task.
let task = Task {
raw_task: NonNull::new_unchecked(ptr as *mut ()),
_marker: PhantomData,
};
(*raw.schedule)(task);
} else {
// Drop the waker.
Self::decrement(ptr);
}
break;
}
Err(s) => state = s,
}
}
}
}
/// Wakes a waker by reference.
unsafe fn wake_by_ref(ptr: *const ()) {
let raw = Self::from_ptr(ptr);
let mut state = (*raw.header).state.load(Ordering::Acquire);
loop {
// If the task is completed or closed, it can't be woken.
if state & (COMPLETED | CLOSED) != 0 {
break;
}
// If the task is already scheduled, we just need to synchronize with the thread that
// will run the task by "publishing" our current view of the memory.
if state & SCHEDULED != 0 {
// Update the state without actually modifying it.
match (*raw.header).state.compare_exchange_weak(
state,
state,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => break,
Err(s) => state = s,
}
} else {
// If the task is not scheduled nor running, we'll need to schedule after waking.
let new = if state & (SCHEDULED | RUNNING) == 0 {
(state | SCHEDULED) + REFERENCE
} else {
state | SCHEDULED
};
// Mark the task as scheduled.
match (*raw.header).state.compare_exchange_weak(
state,
new,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
// If the task is not scheduled nor running, now is the time to schedule.
if state & (SCHEDULED | RUNNING) == 0 {
// If the reference count overflowed, abort.
if state > isize::max_value() as usize {
std::process::abort();
}
// Schedule the task.
let task = Task {
raw_task: NonNull::new_unchecked(ptr as *mut ()),
_marker: PhantomData,
};
(*raw.schedule)(task);
}
break;
}
Err(s) => state = s,
}
}
}
}
/// Clones a waker.
unsafe fn clone_waker(ptr: *const ()) -> RawWaker {
let raw = Self::from_ptr(ptr);
let raw_waker = &(*raw.header).vtable.raw_waker;
// Increment the reference count. With any kind of reference-counted data structure,
// relaxed ordering is fine when the reference is being cloned.
let state = (*raw.header).state.fetch_add(REFERENCE, Ordering::Relaxed);
// If the reference count overflowed, abort.
if state > isize::max_value() as usize {
std::process::abort();
}
RawWaker::new(ptr, raw_waker)
}
/// Drops a waker or a task.
///
/// This function will decrement the reference count. If it drops down to zero and the
/// associated join handle has been dropped too, then the task gets destroyed.
#[inline]
unsafe fn decrement(ptr: *const ()) {
let raw = Self::from_ptr(ptr);
// Decrement the reference count.
let new = (*raw.header).state.fetch_sub(REFERENCE, Ordering::AcqRel) - REFERENCE;
// If this was the last reference to the task and the `JoinHandle` has been dropped as
// well, then destroy task.
if new & !(REFERENCE - 1) == 0 && new & HANDLE == 0 {
Self::destroy(ptr);
}
}
/// Schedules a task for running.
///
/// This function doesn't modify the state of the task. It only passes the task reference to
/// its schedule function.
unsafe fn schedule(ptr: *const ()) {
let raw = Self::from_ptr(ptr);
(*raw.schedule)(Task {
raw_task: NonNull::new_unchecked(ptr as *mut ()),
_marker: PhantomData,
});
}
/// Drops the future inside a task.
#[inline]
unsafe fn drop_future(ptr: *const ()) {
let raw = Self::from_ptr(ptr);
// We need a safeguard against panics because the destructor can panic.
abort_on_panic(|| {
raw.future.drop_in_place();
})
}
/// Returns a pointer to the output inside a task.
unsafe fn get_output(ptr: *const ()) -> *const () {
let raw = Self::from_ptr(ptr);
raw.output as *const ()
}
/// Cleans up task's resources and deallocates it.
///
/// If the task has not been closed, then its future or the output will be dropped. The
/// schedule function and the tag get dropped too.
#[inline]
unsafe fn destroy(ptr: *const ()) {
let raw = Self::from_ptr(ptr);
let task_layout = Self::task_layout();
// We need a safeguard against panics because destructors can panic.
abort_on_panic(|| {
// Drop the schedule function.
(raw.schedule as *mut S).drop_in_place();
// Drop the tag.
(raw.tag as *mut T).drop_in_place();
});
// Finally, deallocate the memory reserved by the task.
alloc::dealloc(ptr as *mut u8, task_layout.layout);
}
/// Runs a task.
///
/// If polling its future panics, the task will be closed and the panic propagated into the
/// caller.
unsafe fn run(ptr: *const ()) {
let raw = Self::from_ptr(ptr);
// Create a context from the raw task pointer and the vtable inside the its header.
let waker = ManuallyDrop::new(Waker::from_raw(RawWaker::new(
ptr,
&(*raw.header).vtable.raw_waker,
)));
let cx = &mut Context::from_waker(&waker);
let mut state = (*raw.header).state.load(Ordering::Acquire);
// Update the task's state before polling its future.
loop {
// If the task has been closed, drop the task reference and return.
if state & CLOSED != 0 {
// Notify the awaiter that the task has been closed.
if state & AWAITER != 0 {
(*raw.header).notify();
}
// Drop the future.
Self::drop_future(ptr);
// Drop the task reference.
Self::decrement(ptr);
return;
}
// Mark the task as unscheduled and running.
match (*raw.header).state.compare_exchange_weak(
state,
(state & !SCHEDULED) | RUNNING,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
// Update the state because we're continuing with polling the future.
state = (state & !SCHEDULED) | RUNNING;
break;
}
Err(s) => state = s,
}
}
// Poll the inner future, but surround it with a guard that closes the task in case polling
// panics.
let guard = Guard(raw);
let poll = <F as Future>::poll(Pin::new_unchecked(&mut *raw.future), cx);
mem::forget(guard);
match poll {
Poll::Ready(out) => {
// Replace the future with its output.
Self::drop_future(ptr);
raw.output.write(out);
// A place where the output will be stored in case it needs to be dropped.
let mut output = None;
// The task is now completed.
loop {
// If the handle is dropped, we'll need to close it and drop the output.
let new = if state & HANDLE == 0 {
(state & !RUNNING & !SCHEDULED) | COMPLETED | CLOSED
} else {
(state & !RUNNING & !SCHEDULED) | COMPLETED
};
// Mark the task as not running and completed.
match (*raw.header).state.compare_exchange_weak(
state,
new,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
// If the handle is dropped or if the task was closed while running,
// now it's time to drop the output.
if state & HANDLE == 0 || state & CLOSED != 0 {
// Read the output.
output = Some(raw.output.read());
}
// Notify the awaiter that the task has been completed.
if state & AWAITER != 0 {
(*raw.header).notify();
}
// Drop the task reference.
Self::decrement(ptr);
break;
}
Err(s) => state = s,
}
}
// Drop the output if it was taken out of the task.
drop(output);
}
Poll::Pending => {
// The task is still not completed.
loop {
// If the task was closed while running, we'll need to unschedule in case it
// was woken and then clean up its resources.
let new = if state & CLOSED != 0 {
state & !RUNNING & !SCHEDULED
} else {
state & !RUNNING
};
// Mark the task as not running.
match (*raw.header).state.compare_exchange_weak(
state,
new,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(state) => {
// If the task was closed while running, we need to drop its future.
// If the task was woken while running, we need to schedule it.
// Otherwise, we just drop the task reference.
if state & CLOSED != 0 {
// The thread that closed the task didn't drop the future because
// it was running so now it's our responsibility to do so.
Self::drop_future(ptr);
// Drop the task reference.
Self::decrement(ptr);
} else if state & SCHEDULED != 0 {
// The thread that has woken the task didn't reschedule it because
// it was running so now it's our responsibility to do so.
Self::schedule(ptr);
} else {
// Drop the task reference.
Self::decrement(ptr);
}
break;
}
Err(s) => state = s,
}
}
}
}
/// A guard that closes the task if polling its future panics.
struct Guard<F, R, S, T>(RawTask<F, R, S, T>)
where
F: Future<Output = R> + Send + 'static,
R: Send + 'static,
S: Fn(Task<T>) + Send + Sync + 'static,
T: Send + 'static;
impl<F, R, S, T> Drop for Guard<F, R, S, T>
where
F: Future<Output = R> + Send + 'static,
R: Send + 'static,
S: Fn(Task<T>) + Send + Sync + 'static,
T: Send + 'static,
{
fn drop(&mut self) {
let raw = self.0;
let ptr = raw.header as *const ();
unsafe {
let mut state = (*raw.header).state.load(Ordering::Acquire);
loop {
// If the task was closed while running, then unschedule it, drop its
// future, and drop the task reference.
if state & CLOSED != 0 {
// We still need to unschedule the task because it is possible it was
// woken while running.
(*raw.header).state.fetch_and(!SCHEDULED, Ordering::AcqRel);
// The thread that closed the task didn't drop the future because it
// was running so now it's our responsibility to do so.
RawTask::<F, R, S, T>::drop_future(ptr);
// Drop the task reference.
RawTask::<F, R, S, T>::decrement(ptr);
break;
}
// Mark the task as not running, not scheduled, and closed.
match (*raw.header).state.compare_exchange_weak(
state,
(state & !RUNNING & !SCHEDULED) | CLOSED,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(state) => {
// Drop the future because the task is now closed.
RawTask::<F, R, S, T>::drop_future(ptr);
// Notify the awaiter that the task has been closed.
if state & AWAITER != 0 {
(*raw.header).notify();
}
// Drop the task reference.
RawTask::<F, R, S, T>::decrement(ptr);
break;
}
Err(s) => state = s,
}
}
}
}
}
}
}

@ -1,65 +0,0 @@
/// Set if the task is scheduled for running.
///
/// A task is considered to be scheduled whenever its `Task` reference exists. It is in scheduled
/// state at the moment of creation and when it gets unapused either by its `JoinHandle` or woken
/// by a `Waker`.
///
/// This flag can't be set when the task is completed. However, it can be set while the task is
/// running, in which case it will be rescheduled as soon as polling finishes.
pub(crate) const SCHEDULED: usize = 1 << 0;
/// Set if the task is running.
///
/// A task is running state while its future is being polled.
///
/// This flag can't be set when the task is completed. However, it can be in scheduled state while
/// it is running, in which case it will be rescheduled when it stops being polled.
pub(crate) const RUNNING: usize = 1 << 1;
/// Set if the task has been completed.
///
/// This flag is set when polling returns `Poll::Ready`. The output of the future is then stored
/// inside the task until it becomes stopped. In fact, `JoinHandle` picks the output up by marking
/// the task as stopped.
///
/// This flag can't be set when the task is scheduled or completed.
pub(crate) const COMPLETED: usize = 1 << 2;
/// Set if the task is closed.
///
/// If a task is closed, that means its either cancelled or its output has been consumed by the
/// `JoinHandle`. A task becomes closed when:
///
/// 1. It gets cancelled by `Task::cancel()` or `JoinHandle::cancel()`.
/// 2. Its output is awaited by the `JoinHandle`.
/// 3. It panics while polling the future.
/// 4. It is completed and the `JoinHandle` is dropped.
pub(crate) const CLOSED: usize = 1 << 3;
/// Set if the `JoinHandle` still exists.
///
/// The `JoinHandle` is a special case in that it is only tracked by this flag, while all other
/// task references (`Task` and `Waker`s) are tracked by the reference count.
pub(crate) const HANDLE: usize = 1 << 4;
/// Set if the `JoinHandle` is awaiting the output.
///
/// This flag is set while there is a registered awaiter of type `Waker` inside the task. When the
/// task gets closed or completed, we need to wake the awaiter. This flag can be used as a fast
/// check that tells us if we need to wake anyone without acquiring the lock inside the task.
pub(crate) const AWAITER: usize = 1 << 5;
/// Set if the awaiter is locked.
///
/// This lock is acquired before a new awaiter is registered or the existing one is woken.
pub(crate) const LOCKED: usize = 1 << 6;
/// A single reference.
///
/// The lower bits in the state contain various flags representing the task state, while the upper
/// bits contain the reference count. The value of `REFERENCE` represents a single reference in the
/// total reference count.
///
/// Note that the reference counter only tracks the `Task` and `Waker`s. The `JoinHandle` is
/// tracked separately by the `HANDLE` flag.
pub(crate) const REFERENCE: usize = 1 << 7;

@ -1,390 +0,0 @@
use std::fmt;
use std::future::Future;
use std::marker::PhantomData;
use std::mem;
use std::ptr::NonNull;
use crate::header::Header;
use crate::raw::RawTask;
use crate::JoinHandle;
/// Creates a new task.
///
/// This constructor returns a `Task` reference that runs the future and a [`JoinHandle`] that
/// awaits its result.
///
/// The `tag` is stored inside the allocated task.
///
/// When run, the task polls `future`. When woken, it gets scheduled for running by the
/// `schedule` function.
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// use crossbeam::channel;
///
/// // The future inside the task.
/// let future = async {
/// println!("Hello, world!");
/// };
///
/// // If the task gets woken, it will be sent into this channel.
/// let (s, r) = channel::unbounded();
/// let schedule = move |task| s.send(task).unwrap();
///
/// // Create a task with the future and the schedule function.
/// let (task, handle) = async_task::spawn(future, schedule, ());
/// ```
///
/// [`JoinHandle`]: struct.JoinHandle.html
pub fn spawn<F, R, S, T>(future: F, schedule: S, tag: T) -> (Task<T>, JoinHandle<R, T>)
where
F: Future<Output = R> + Send + 'static,
R: Send + 'static,
S: Fn(Task<T>) + Send + Sync + 'static,
T: Send + Sync + 'static,
{
let raw_task = RawTask::<F, R, S, T>::allocate(tag, future, schedule);
let task = Task {
raw_task,
_marker: PhantomData,
};
let handle = JoinHandle {
raw_task,
_marker: PhantomData,
};
(task, handle)
}
/// A task that runs a future.
///
/// # Construction
///
/// A task is a heap-allocated structure containing:
///
/// * A reference counter.
/// * The state of the task.
/// * Arbitrary piece of data called a *tag*.
/// * A function that schedules the task when woken.
/// * A future or its result if polling has completed.
///
/// Constructor [`Task::create()`] returns a [`Task`] and a [`JoinHandle`]. Those two references
/// are like two sides of the task: one runs the future and the other awaits its result.
///
/// # Behavior
///
/// The [`Task`] reference "owns" the task itself and is used to [run] it. Running consumes the
/// [`Task`] reference and polls its internal future. If the future is still pending after being
/// polled, the [`Task`] reference will be recreated when woken by a [`Waker`]. If the future
/// completes, its result becomes available to the [`JoinHandle`].
///
/// The [`JoinHandle`] is a [`Future`] that awaits the result of the task.
///
/// When the task is woken, its [`Task`] reference is recreated and passed to the schedule function
/// provided during construction. In most executors, scheduling simply pushes the [`Task`] into a
/// queue of runnable tasks.
///
/// If the [`Task`] reference is dropped without being run, the task is cancelled.
///
/// Both [`Task`] and [`JoinHandle`] have methods that cancel the task. When cancelled, the task
/// won't be scheduled again even if a [`Waker`] wakes it or the [`JoinHandle`] is polled. An
/// attempt to run a cancelled task won't do anything. And if the cancelled task has already
/// completed, awaiting its result through [`JoinHandle`] will return `None`.
///
/// If polling the task's future panics, it gets cancelled automatically.
///
/// # Task states
///
/// A task can be in the following states:
///
/// * Sleeping: The [`Task`] reference doesn't exist and is waiting to be scheduled by a [`Waker`].
/// * Scheduled: The [`Task`] reference exists and is waiting to be [run].
/// * Completed: The [`Task`] reference doesn't exist anymore and can't be rescheduled, but its
/// result is available to the [`JoinHandle`].
/// * Cancelled: The [`Task`] reference may or may not exist, but running it does nothing and
/// awaiting the [`JoinHandle`] returns `None`.
///
/// When constructed, the task is initially in the scheduled state.
///
/// # Destruction
///
/// The future inside the task gets dropped in the following cases:
///
/// * When [`Task`] is dropped.
/// * When [`Task`] is run to completion.
///
/// If the future hasn't been dropped and the last [`Waker`] or [`JoinHandle`] is dropped, or if
/// a [`JoinHandle`] cancels the task, then the task will be scheduled one last time so that its
/// future gets dropped by the executor. In other words, the task's future can be dropped only by
/// [`Task`].
///
/// When the task completes, the result of its future is stored inside the allocation. This result
/// is taken out when the [`JoinHandle`] awaits it. When the task is cancelled or the
/// [`JoinHandle`] is dropped without being awaited, the result gets dropped too.
///
/// The task gets deallocated when all references to it are dropped, which includes the [`Task`],
/// the [`JoinHandle`], and any associated [`Waker`]s.
///
/// The tag inside the task and the schedule function get dropped at the time of deallocation.
///
/// # Panics
///
/// If polling the inner future inside [`run()`] panics, the panic will be propagated into
/// the caller. Likewise, a panic inside the task result's destructor will be propagated. All other
/// panics result in the process being aborted.
///
/// More precisely, the process is aborted if a panic occurs:
///
/// * Inside the schedule function.
/// * While dropping the tag.
/// * While dropping the future.
/// * While dropping the schedule function.
/// * While waking the task awaiting the [`JoinHandle`].
///
/// [`run()`]: struct.Task.html#method.run
/// [run]: struct.Task.html#method.run
/// [`JoinHandle`]: struct.JoinHandle.html
/// [`Task`]: struct.Task.html
/// [`Task::create()`]: struct.Task.html#method.create
/// [`Future`]: https://doc.rust-lang.org/std/future/trait.Future.html
/// [`Waker`]: https://doc.rust-lang.org/std/task/struct.Waker.html
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// use async_task::Task;
/// use crossbeam::channel;
/// use futures::executor;
///
/// // The future inside the task.
/// let future = async {
/// println!("Hello, world!");
/// };
///
/// // If the task gets woken, it will be sent into this channel.
/// let (s, r) = channel::unbounded();
/// let schedule = move |task| s.send(task).unwrap();
///
/// // Create a task with the future and the schedule function.
/// let (task, handle) = async_task::spawn(future, schedule, ());
///
/// // Run the task. In this example, it will complete after a single run.
/// task.run();
/// assert!(r.is_empty());
///
/// // Await its result.
/// executor::block_on(handle);
/// ```
pub struct Task<T> {
/// A pointer to the heap-allocated task.
pub(crate) raw_task: NonNull<()>,
/// A marker capturing the generic type `T`.
pub(crate) _marker: PhantomData<T>,
}
unsafe impl<T> Send for Task<T> {}
unsafe impl<T> Sync for Task<T> {}
impl<T> Task<T> {
/// Schedules the task.
///
/// This is a convenience method that simply reschedules the task by passing it to its schedule
/// function.
///
/// If the task is cancelled, this method won't do anything.
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// use crossbeam::channel;
///
/// // The future inside the task.
/// let future = async {
/// println!("Hello, world!");
/// };
///
/// // If the task gets woken, it will be sent into this channel.
/// let (s, r) = channel::unbounded();
/// let schedule = move |task| s.send(task).unwrap();
///
/// // Create a task with the future and the schedule function.
/// let (task, handle) = async_task::spawn(future, schedule, ());
///
/// // Send the task into the channel.
/// task.schedule();
///
/// // Retrieve the task back from the channel.
/// let task = r.recv().unwrap();
/// ```
pub fn schedule(self) {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
mem::forget(self);
unsafe {
((*header).vtable.schedule)(ptr);
}
}
/// Runs the task.
///
/// This method polls the task's future. If the future completes, its result will become
/// available to the [`JoinHandle`]. And if the future is still pending, the task will have to
/// be woken in order to be rescheduled and then run again.
///
/// If the task is cancelled, running it won't do anything.
///
/// # Panics
///
/// It is possible that polling the future panics, in which case the panic will be propagated
/// into the caller. It is advised that invocations of this method are wrapped inside
/// [`catch_unwind`].
///
/// If a panic occurs, the task is automatically cancelled.
///
/// [`catch_unwind`]: https://doc.rust-lang.org/std/panic/fn.catch_unwind.html
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// use crossbeam::channel;
/// use futures::executor;
///
/// // The future inside the task.
/// let future = async { 1 + 2 };
///
/// // If the task gets woken, it will be sent into this channel.
/// let (s, r) = channel::unbounded();
/// let schedule = move |task| s.send(task).unwrap();
///
/// // Create a task with the future and the schedule function.
/// let (task, handle) = async_task::spawn(future, schedule, ());
///
/// // Run the task. In this example, it will complete after a single run.
/// task.run();
/// assert!(r.is_empty());
///
/// // Await the result of the task.
/// let result = executor::block_on(handle);
/// assert_eq!(result, Some(3));
/// ```
pub fn run(self) {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
mem::forget(self);
unsafe {
((*header).vtable.run)(ptr);
}
}
/// Cancels the task.
///
/// When cancelled, the task won't be scheduled again even if a [`Waker`] wakes it. An attempt
/// to run it won't do anything. And if it's completed, awaiting its result evaluates to
/// `None`.
///
/// [`Waker`]: https://doc.rust-lang.org/std/task/struct.Waker.html
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// use crossbeam::channel;
/// use futures::executor;
///
/// // The future inside the task.
/// let future = async { 1 + 2 };
///
/// // If the task gets woken, it will be sent into this channel.
/// let (s, r) = channel::unbounded();
/// let schedule = move |task| s.send(task).unwrap();
///
/// // Create a task with the future and the schedule function.
/// let (task, handle) = async_task::spawn(future, schedule, ());
///
/// // Cancel the task.
/// task.cancel();
///
/// // Running a cancelled task does nothing.
/// task.run();
///
/// // Await the result of the task.
/// let result = executor::block_on(handle);
/// assert_eq!(result, None);
/// ```
pub fn cancel(&self) {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
unsafe {
(*header).cancel();
}
}
/// Returns a reference to the tag stored inside the task.
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// use crossbeam::channel;
///
/// // The future inside the task.
/// let future = async { 1 + 2 };
///
/// // If the task gets woken, it will be sent into this channel.
/// let (s, r) = channel::unbounded();
/// let schedule = move |task| s.send(task).unwrap();
///
/// // Create a task with the future and the schedule function.
/// let (task, handle) = async_task::spawn(future, schedule, "a simple task");
///
/// // Access the tag.
/// assert_eq!(*task.tag(), "a simple task");
/// ```
pub fn tag(&self) -> &T {
let offset = Header::offset_tag::<T>();
let ptr = self.raw_task.as_ptr();
unsafe {
let raw = (ptr as *mut u8).add(offset) as *const T;
&*raw
}
}
}
impl<T> Drop for Task<T> {
fn drop(&mut self) {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
unsafe {
// Cancel the task.
(*header).cancel();
// Drop the future.
((*header).vtable.drop_future)(ptr);
// Drop the task reference.
((*header).vtable.decrement)(ptr);
}
}
}
impl<T: fmt::Debug> fmt::Debug for Task<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
f.debug_struct("Task")
.field("header", unsafe { &(*header) })
.field("tag", self.tag())
.finish()
}
}

@ -1,48 +0,0 @@
use std::alloc::Layout;
use std::mem;
/// Calls a function and aborts if it panics.
///
/// This is useful in unsafe code where we can't recover from panics.
#[inline]
pub(crate) fn abort_on_panic<T>(f: impl FnOnce() -> T) -> T {
struct Bomb;
impl Drop for Bomb {
fn drop(&mut self) {
std::process::abort();
}
}
let bomb = Bomb;
let t = f();
mem::forget(bomb);
t
}
/// Returns the layout for `a` followed by `b` and the offset of `b`.
///
/// This function was adapted from the currently unstable `Layout::extend()`:
/// https://doc.rust-lang.org/nightly/std/alloc/struct.Layout.html#method.extend
#[inline]
pub(crate) fn extend(a: Layout, b: Layout) -> (Layout, usize) {
let new_align = a.align().max(b.align());
let pad = padding_needed_for(a, b.align());
let offset = a.size().checked_add(pad).unwrap();
let new_size = offset.checked_add(b.size()).unwrap();
let layout = Layout::from_size_align(new_size, new_align).unwrap();
(layout, offset)
}
/// Returns the padding after `layout` that aligns the following address to `align`.
///
/// This function was adapted from the currently unstable `Layout::padding_needed_for()`:
/// https://doc.rust-lang.org/nightly/std/alloc/struct.Layout.html#method.padding_needed_for
#[inline]
pub(crate) fn padding_needed_for(layout: Layout, align: usize) -> usize {
let len = layout.size();
let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
len_rounded_up.wrapping_sub(len)
}

@ -1,314 +0,0 @@
#![feature(async_await)]
use std::future::Future;
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::task::{Context, Poll};
use async_task::Task;
use crossbeam::atomic::AtomicCell;
use crossbeam::channel;
use futures::future;
use lazy_static::lazy_static;
// Creates a future with event counters.
//
// Usage: `future!(f, POLL, DROP)`
//
// The future `f` always returns `Poll::Ready`.
// When it gets polled, `POLL` is incremented.
// When it gets dropped, `DROP` is incremented.
macro_rules! future {
($name:pat, $poll:ident, $drop:ident) => {
lazy_static! {
static ref $poll: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let $name = {
struct Fut(Box<i32>);
impl Future for Fut {
type Output = Box<i32>;
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
$poll.fetch_add(1);
Poll::Ready(Box::new(0))
}
}
impl Drop for Fut {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
Fut(Box::new(0))
};
};
}
// Creates a schedule function with event counters.
//
// Usage: `schedule!(s, SCHED, DROP)`
//
// The schedule function `s` does nothing.
// When it gets invoked, `SCHED` is incremented.
// When it gets dropped, `DROP` is incremented.
macro_rules! schedule {
($name:pat, $sched:ident, $drop:ident) => {
lazy_static! {
static ref $sched: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let $name = {
struct Guard(Box<i32>);
impl Drop for Guard {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
let guard = Guard(Box::new(0));
move |_task| {
&guard;
$sched.fetch_add(1);
}
};
};
}
// Creates a task with event counters.
//
// Usage: `task!(task, handle f, s, DROP)`
//
// A task with future `f` and schedule function `s` is created.
// The `Task` and `JoinHandle` are bound to `task` and `handle`, respectively.
// When the tag inside the task gets dropped, `DROP` is incremented.
macro_rules! task {
($task:pat, $handle: pat, $future:expr, $schedule:expr, $drop:ident) => {
lazy_static! {
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let ($task, $handle) = {
struct Tag(Box<i32>);
impl Drop for Tag {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
async_task::spawn($future, $schedule, Tag(Box::new(0)))
};
};
}
#[test]
fn cancel_and_drop_handle() {
future!(f, POLL, DROP_F);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
task.cancel();
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
drop(handle);
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
drop(task);
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
}
#[test]
fn run_and_drop_handle() {
future!(f, POLL, DROP_F);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
drop(handle);
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
}
#[test]
fn drop_handle_and_run() {
future!(f, POLL, DROP_F);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
drop(handle);
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
}
#[test]
fn cancel_and_run() {
future!(f, POLL, DROP_F);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
handle.cancel();
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
drop(handle);
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
task.run();
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
}
#[test]
fn run_and_cancel() {
future!(f, POLL, DROP_F);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
handle.cancel();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
drop(handle);
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
}
#[test]
fn schedule() {
let (s, r) = channel::unbounded();
let schedule = move |t| s.send(t).unwrap();
let (task, _handle) = async_task::spawn(
future::poll_fn(|_| Poll::<()>::Pending),
schedule,
Box::new(0),
);
assert!(r.is_empty());
task.schedule();
let task = r.recv().unwrap();
assert!(r.is_empty());
task.schedule();
let task = r.recv().unwrap();
assert!(r.is_empty());
task.schedule();
r.recv().unwrap();
}
#[test]
fn tag() {
let (s, r) = channel::unbounded();
let schedule = move |t| s.send(t).unwrap();
let (task, handle) = async_task::spawn(
future::poll_fn(|_| Poll::<()>::Pending),
schedule,
AtomicUsize::new(7),
);
assert!(r.is_empty());
task.schedule();
let task = r.recv().unwrap();
assert!(r.is_empty());
handle.tag().fetch_add(1, Ordering::SeqCst);
task.schedule();
let task = r.recv().unwrap();
assert_eq!(task.tag().load(Ordering::SeqCst), 8);
assert!(r.is_empty());
task.schedule();
r.recv().unwrap();
}
#[test]
fn schedule_counter() {
let (s, r) = channel::unbounded();
let schedule = move |t: Task<AtomicUsize>| {
t.tag().fetch_add(1, Ordering::SeqCst);
s.send(t).unwrap();
};
let (task, handle) = async_task::spawn(
future::poll_fn(|_| Poll::<()>::Pending),
schedule,
AtomicUsize::new(0),
);
task.schedule();
assert_eq!(handle.tag().load(Ordering::SeqCst), 1);
r.recv().unwrap().schedule();
assert_eq!(handle.tag().load(Ordering::SeqCst), 2);
r.recv().unwrap().schedule();
assert_eq!(handle.tag().load(Ordering::SeqCst), 3);
r.recv().unwrap();
}

@ -1,454 +0,0 @@
#![feature(async_await)]
use std::cell::Cell;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::thread;
use std::time::Duration;
use async_task::Task;
use crossbeam::atomic::AtomicCell;
use futures::executor::block_on;
use futures::future;
use lazy_static::lazy_static;
// Creates a future with event counters.
//
// Usage: `future!(f, POLL, DROP_F, DROP_O)`
//
// The future `f` outputs `Poll::Ready`.
// When it gets polled, `POLL` is incremented.
// When it gets dropped, `DROP_F` is incremented.
// When the output gets dropped, `DROP_O` is incremented.
macro_rules! future {
($name:pat, $poll:ident, $drop_f:ident, $drop_o:ident) => {
lazy_static! {
static ref $poll: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop_f: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop_o: AtomicCell<usize> = AtomicCell::new(0);
}
let $name = {
struct Fut(Box<i32>);
impl Future for Fut {
type Output = Out;
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
$poll.fetch_add(1);
Poll::Ready(Out(Box::new(0)))
}
}
impl Drop for Fut {
fn drop(&mut self) {
$drop_f.fetch_add(1);
}
}
struct Out(Box<i32>);
impl Drop for Out {
fn drop(&mut self) {
$drop_o.fetch_add(1);
}
}
Fut(Box::new(0))
};
};
}
// Creates a schedule function with event counters.
//
// Usage: `schedule!(s, SCHED, DROP)`
//
// The schedule function `s` does nothing.
// When it gets invoked, `SCHED` is incremented.
// When it gets dropped, `DROP` is incremented.
macro_rules! schedule {
($name:pat, $sched:ident, $drop:ident) => {
lazy_static! {
static ref $sched: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let $name = {
struct Guard(Box<i32>);
impl Drop for Guard {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
let guard = Guard(Box::new(0));
move |task: Task<_>| {
&guard;
task.schedule();
$sched.fetch_add(1);
}
};
};
}
// Creates a task with event counters.
//
// Usage: `task!(task, handle f, s, DROP)`
//
// A task with future `f` and schedule function `s` is created.
// The `Task` and `JoinHandle` are bound to `task` and `handle`, respectively.
// When the tag inside the task gets dropped, `DROP` is incremented.
macro_rules! task {
($task:pat, $handle: pat, $future:expr, $schedule:expr, $drop:ident) => {
lazy_static! {
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let ($task, $handle) = {
struct Tag(Box<i32>);
impl Drop for Tag {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
async_task::spawn($future, $schedule, Tag(Box::new(0)))
};
};
}
fn ms(ms: u64) -> Duration {
Duration::from_millis(ms)
}
#[test]
fn cancel_and_join() {
future!(f, POLL, DROP_F, DROP_O);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
assert_eq!(DROP_O.load(), 0);
task.cancel();
drop(task);
assert_eq!(DROP_O.load(), 0);
assert!(block_on(handle).is_none());
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(DROP_O.load(), 0);
}
#[test]
fn run_and_join() {
future!(f, POLL, DROP_F, DROP_O);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
assert_eq!(DROP_O.load(), 0);
task.run();
assert_eq!(DROP_O.load(), 0);
assert!(block_on(handle).is_some());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(DROP_O.load(), 1);
}
#[test]
fn drop_handle_and_run() {
future!(f, POLL, DROP_F, DROP_O);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
assert_eq!(DROP_O.load(), 0);
drop(handle);
assert_eq!(DROP_O.load(), 0);
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(DROP_O.load(), 1);
}
#[test]
fn join_twice() {
future!(f, POLL, DROP_F, DROP_O);
schedule!(s, SCHEDULE, DROP_S);
task!(task, mut handle, f, s, DROP_D);
assert_eq!(DROP_O.load(), 0);
task.run();
assert_eq!(DROP_O.load(), 0);
assert!(block_on(&mut handle).is_some());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(DROP_O.load(), 1);
assert!(block_on(&mut handle).is_none());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(DROP_O.load(), 1);
drop(handle);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
}
#[test]
fn join_and_cancel() {
future!(f, POLL, DROP_F, DROP_O);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
crossbeam::scope(|scope| {
scope.spawn(|_| {
thread::sleep(ms(100));
task.cancel();
drop(task);
thread::sleep(ms(200));
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_O.load(), 0);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
});
assert!(block_on(handle).is_none());
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
thread::sleep(ms(100));
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_O.load(), 0);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
})
.unwrap();
}
#[test]
fn join_and_run() {
future!(f, POLL, DROP_F, DROP_O);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
crossbeam::scope(|scope| {
scope.spawn(|_| {
thread::sleep(ms(200));
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
thread::sleep(ms(100));
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
});
assert!(block_on(handle).is_some());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_O.load(), 1);
thread::sleep(ms(100));
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
})
.unwrap();
}
#[test]
fn try_join_and_run_and_join() {
future!(f, POLL, DROP_F, DROP_O);
schedule!(s, SCHEDULE, DROP_S);
task!(task, mut handle, f, s, DROP_D);
crossbeam::scope(|scope| {
scope.spawn(|_| {
thread::sleep(ms(200));
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
thread::sleep(ms(100));
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
});
block_on(future::select(&mut handle, future::ready(())));
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(DROP_O.load(), 0);
assert!(block_on(handle).is_some());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_O.load(), 1);
thread::sleep(ms(100));
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
})
.unwrap();
}
#[test]
fn try_join_and_cancel_and_run() {
future!(f, POLL, DROP_F, DROP_O);
schedule!(s, SCHEDULE, DROP_S);
task!(task, mut handle, f, s, DROP_D);
crossbeam::scope(|scope| {
scope.spawn(|_| {
thread::sleep(ms(200));
task.run();
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
});
block_on(future::select(&mut handle, future::ready(())));
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(DROP_O.load(), 0);
handle.cancel();
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(DROP_O.load(), 0);
drop(handle);
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(DROP_O.load(), 0);
})
.unwrap();
}
#[test]
fn try_join_and_run_and_cancel() {
future!(f, POLL, DROP_F, DROP_O);
schedule!(s, SCHEDULE, DROP_S);
task!(task, mut handle, f, s, DROP_D);
crossbeam::scope(|scope| {
scope.spawn(|_| {
thread::sleep(ms(200));
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
});
block_on(future::select(&mut handle, future::ready(())));
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(DROP_O.load(), 0);
thread::sleep(ms(400));
handle.cancel();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(DROP_O.load(), 0);
drop(handle);
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(DROP_O.load(), 1);
})
.unwrap();
}
#[test]
fn await_output() {
struct Fut<T>(Cell<Option<T>>);
impl<T> Fut<T> {
fn new(t: T) -> Fut<T> {
Fut(Cell::new(Some(t)))
}
}
impl<T> Future for Fut<T> {
type Output = T;
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Ready(self.0.take().unwrap())
}
}
for i in 0..10 {
let (task, handle) = async_task::spawn(Fut::new(i), drop, Box::new(0));
task.run();
assert_eq!(block_on(handle), Some(i));
}
for i in 0..10 {
let (task, handle) = async_task::spawn(Fut::new(vec![7; i]), drop, Box::new(0));
task.run();
assert_eq!(block_on(handle), Some(vec![7; i]));
}
let (task, handle) = async_task::spawn(Fut::new("foo".to_string()), drop, Box::new(0));
task.run();
assert_eq!(block_on(handle), Some("foo".to_string()));
}

@ -1,288 +0,0 @@
#![feature(async_await)]
use std::future::Future;
use std::panic::catch_unwind;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::thread;
use std::time::Duration;
use async_task::Task;
use crossbeam::atomic::AtomicCell;
use futures::executor::block_on;
use futures::future;
use lazy_static::lazy_static;
// Creates a future with event counters.
//
// Usage: `future!(f, POLL, DROP)`
//
// The future `f` sleeps for 200 ms and then panics.
// When it gets polled, `POLL` is incremented.
// When it gets dropped, `DROP` is incremented.
macro_rules! future {
($name:pat, $poll:ident, $drop:ident) => {
lazy_static! {
static ref $poll: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let $name = {
struct Fut(Box<i32>);
impl Future for Fut {
type Output = ();
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
$poll.fetch_add(1);
thread::sleep(ms(200));
panic!()
}
}
impl Drop for Fut {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
Fut(Box::new(0))
};
};
}
// Creates a schedule function with event counters.
//
// Usage: `schedule!(s, SCHED, DROP)`
//
// The schedule function `s` does nothing.
// When it gets invoked, `SCHED` is incremented.
// When it gets dropped, `DROP` is incremented.
macro_rules! schedule {
($name:pat, $sched:ident, $drop:ident) => {
lazy_static! {
static ref $sched: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let $name = {
struct Guard(Box<i32>);
impl Drop for Guard {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
let guard = Guard(Box::new(0));
move |_task: Task<_>| {
&guard;
$sched.fetch_add(1);
}
};
};
}
// Creates a task with event counters.
//
// Usage: `task!(task, handle f, s, DROP)`
//
// A task with future `f` and schedule function `s` is created.
// The `Task` and `JoinHandle` are bound to `task` and `handle`, respectively.
// When the tag inside the task gets dropped, `DROP` is incremented.
macro_rules! task {
($task:pat, $handle: pat, $future:expr, $schedule:expr, $drop:ident) => {
lazy_static! {
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let ($task, $handle) = {
struct Tag(Box<i32>);
impl Drop for Tag {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
async_task::spawn($future, $schedule, Tag(Box::new(0)))
};
};
}
fn ms(ms: u64) -> Duration {
Duration::from_millis(ms)
}
#[test]
fn cancel_during_run() {
future!(f, POLL, DROP_F);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
crossbeam::scope(|scope| {
scope.spawn(|_| {
assert!(catch_unwind(|| task.run()).is_err());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
});
thread::sleep(ms(100));
handle.cancel();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
drop(handle);
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
})
.unwrap();
}
#[test]
fn run_and_join() {
future!(f, POLL, DROP_F);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
assert!(catch_unwind(|| task.run()).is_err());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert!(block_on(handle).is_none());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
}
#[test]
fn try_join_and_run_and_join() {
future!(f, POLL, DROP_F);
schedule!(s, SCHEDULE, DROP_S);
task!(task, mut handle, f, s, DROP_D);
block_on(future::select(&mut handle, future::ready(())));
assert_eq!(POLL.load(), 0);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert!(catch_unwind(|| task.run()).is_err());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert!(block_on(handle).is_none());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
}
#[test]
fn join_during_run() {
future!(f, POLL, DROP_F);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
crossbeam::scope(|scope| {
scope.spawn(|_| {
assert!(catch_unwind(|| task.run()).is_err());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
thread::sleep(ms(100));
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
});
thread::sleep(ms(100));
assert!(block_on(handle).is_none());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
thread::sleep(ms(100));
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
})
.unwrap();
}
#[test]
fn try_join_during_run() {
future!(f, POLL, DROP_F);
schedule!(s, SCHEDULE, DROP_S);
task!(task, mut handle, f, s, DROP_D);
crossbeam::scope(|scope| {
scope.spawn(|_| {
assert!(catch_unwind(|| task.run()).is_err());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
});
thread::sleep(ms(100));
block_on(future::select(&mut handle, future::ready(())));
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
drop(handle);
})
.unwrap();
}
#[test]
fn drop_handle_during_run() {
future!(f, POLL, DROP_F);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
crossbeam::scope(|scope| {
scope.spawn(|_| {
assert!(catch_unwind(|| task.run()).is_err());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
});
thread::sleep(ms(100));
drop(handle);
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
})
.unwrap();
}

@ -1,265 +0,0 @@
#![feature(async_await)]
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::thread;
use std::time::Duration;
use async_task::Task;
use crossbeam::atomic::AtomicCell;
use futures::executor::block_on;
use futures::future;
use lazy_static::lazy_static;
// Creates a future with event counters.
//
// Usage: `future!(f, POLL, DROP_F, DROP_O)`
//
// The future `f` sleeps for 200 ms and outputs `Poll::Ready`.
// When it gets polled, `POLL` is incremented.
// When it gets dropped, `DROP_F` is incremented.
// When the output gets dropped, `DROP_O` is incremented.
macro_rules! future {
($name:pat, $poll:ident, $drop_f:ident, $drop_o:ident) => {
lazy_static! {
static ref $poll: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop_f: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop_o: AtomicCell<usize> = AtomicCell::new(0);
}
let $name = {
struct Fut(Box<i32>);
impl Future for Fut {
type Output = Out;
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
$poll.fetch_add(1);
thread::sleep(ms(200));
Poll::Ready(Out(Box::new(0)))
}
}
impl Drop for Fut {
fn drop(&mut self) {
$drop_f.fetch_add(1);
}
}
struct Out(Box<i32>);
impl Drop for Out {
fn drop(&mut self) {
$drop_o.fetch_add(1);
}
}
Fut(Box::new(0))
};
};
}
// Creates a schedule function with event counters.
//
// Usage: `schedule!(s, SCHED, DROP)`
//
// The schedule function `s` does nothing.
// When it gets invoked, `SCHED` is incremented.
// When it gets dropped, `DROP` is incremented.
macro_rules! schedule {
($name:pat, $sched:ident, $drop:ident) => {
lazy_static! {
static ref $sched: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let $name = {
struct Guard(Box<i32>);
impl Drop for Guard {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
let guard = Guard(Box::new(0));
move |_task: Task<_>| {
&guard;
$sched.fetch_add(1);
}
};
};
}
// Creates a task with event counters.
//
// Usage: `task!(task, handle f, s, DROP)`
//
// A task with future `f` and schedule function `s` is created.
// The `Task` and `JoinHandle` are bound to `task` and `handle`, respectively.
// When the tag inside the task gets dropped, `DROP` is incremented.
macro_rules! task {
($task:pat, $handle: pat, $future:expr, $schedule:expr, $drop:ident) => {
lazy_static! {
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let ($task, $handle) = {
struct Tag(Box<i32>);
impl Drop for Tag {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
async_task::spawn($future, $schedule, Tag(Box::new(0)))
};
};
}
fn ms(ms: u64) -> Duration {
Duration::from_millis(ms)
}
#[test]
fn cancel_during_run() {
future!(f, POLL, DROP_F, DROP_O);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
crossbeam::scope(|scope| {
scope.spawn(|_| {
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(DROP_O.load(), 1);
});
thread::sleep(ms(100));
handle.cancel();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(DROP_O.load(), 0);
thread::sleep(ms(200));
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(DROP_O.load(), 1);
drop(handle);
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(DROP_O.load(), 1);
})
.unwrap();
}
#[test]
fn join_during_run() {
future!(f, POLL, DROP_F, DROP_O);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
crossbeam::scope(|scope| {
scope.spawn(|_| {
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
thread::sleep(ms(100));
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
});
thread::sleep(ms(100));
assert!(block_on(handle).is_some());
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_O.load(), 1);
thread::sleep(ms(100));
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
})
.unwrap();
}
#[test]
fn try_join_during_run() {
future!(f, POLL, DROP_F, DROP_O);
schedule!(s, SCHEDULE, DROP_S);
task!(task, mut handle, f, s, DROP_D);
crossbeam::scope(|scope| {
scope.spawn(|_| {
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(DROP_O.load(), 1);
});
thread::sleep(ms(100));
block_on(future::select(&mut handle, future::ready(())));
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(DROP_O.load(), 0);
drop(handle);
})
.unwrap();
}
#[test]
fn drop_handle_during_run() {
future!(f, POLL, DROP_F, DROP_O);
schedule!(s, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
crossbeam::scope(|scope| {
scope.spawn(|_| {
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(DROP_O.load(), 1);
});
thread::sleep(ms(100));
drop(handle);
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(DROP_O.load(), 0);
})
.unwrap();
}

@ -1,357 +0,0 @@
#![feature(async_await)]
use std::cell::Cell;
use std::future::Future;
use std::panic::catch_unwind;
use std::pin::Pin;
use std::task::Waker;
use std::task::{Context, Poll};
use std::thread;
use std::time::Duration;
use async_task::Task;
use crossbeam::atomic::AtomicCell;
use crossbeam::channel;
use lazy_static::lazy_static;
// Creates a future with event counters.
//
// Usage: `future!(f, waker, POLL, DROP)`
//
// The future `f` always sleeps for 200 ms, and panics the second time it is polled.
// When it gets polled, `POLL` is incremented.
// When it gets dropped, `DROP` is incremented.
//
// Every time the future is run, it stores the waker into a global variable.
// This waker can be extracted using the `waker` function.
macro_rules! future {
($name:pat, $waker:pat, $poll:ident, $drop:ident) => {
lazy_static! {
static ref $poll: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
static ref WAKER: AtomicCell<Option<Waker>> = AtomicCell::new(None);
}
let ($name, $waker) = {
struct Fut(Cell<bool>, Box<i32>);
impl Future for Fut {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
WAKER.store(Some(cx.waker().clone()));
$poll.fetch_add(1);
thread::sleep(ms(200));
if self.0.get() {
panic!()
} else {
self.0.set(true);
Poll::Pending
}
}
}
impl Drop for Fut {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
(Fut(Cell::new(false), Box::new(0)), || {
WAKER.swap(None).unwrap()
})
};
};
}
// Creates a schedule function with event counters.
//
// Usage: `schedule!(s, chan, SCHED, DROP)`
//
// The schedule function `s` pushes the task into `chan`.
// When it gets invoked, `SCHED` is incremented.
// When it gets dropped, `DROP` is incremented.
//
// Receiver `chan` extracts the task when it is scheduled.
macro_rules! schedule {
($name:pat, $chan:pat, $sched:ident, $drop:ident) => {
lazy_static! {
static ref $sched: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let ($name, $chan) = {
let (s, r) = channel::unbounded();
struct Guard(Box<i32>);
impl Drop for Guard {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
let guard = Guard(Box::new(0));
let sched = move |task: Task<_>| {
&guard;
$sched.fetch_add(1);
s.send(task).unwrap();
};
(sched, r)
};
};
}
// Creates a task with event counters.
//
// Usage: `task!(task, handle f, s, DROP)`
//
// A task with future `f` and schedule function `s` is created.
// The `Task` and `JoinHandle` are bound to `task` and `handle`, respectively.
// When the tag inside the task gets dropped, `DROP` is incremented.
macro_rules! task {
($task:pat, $handle: pat, $future:expr, $schedule:expr, $drop:ident) => {
lazy_static! {
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let ($task, $handle) = {
struct Tag(Box<i32>);
impl Drop for Tag {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
async_task::spawn($future, $schedule, Tag(Box::new(0)))
};
};
}
fn ms(ms: u64) -> Duration {
Duration::from_millis(ms)
}
#[test]
fn wake_during_run() {
future!(f, waker, POLL, DROP_F);
schedule!(s, chan, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
task.run();
let w = waker();
w.wake_by_ref();
let task = chan.recv().unwrap();
crossbeam::scope(|scope| {
scope.spawn(|_| {
assert!(catch_unwind(|| task.run()).is_err());
drop(waker());
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
});
thread::sleep(ms(100));
w.wake();
drop(handle);
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
thread::sleep(ms(200));
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
})
.unwrap();
}
#[test]
fn cancel_during_run() {
future!(f, waker, POLL, DROP_F);
schedule!(s, chan, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
task.run();
let w = waker();
w.wake();
let task = chan.recv().unwrap();
crossbeam::scope(|scope| {
scope.spawn(|_| {
assert!(catch_unwind(|| task.run()).is_err());
drop(waker());
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
});
thread::sleep(ms(100));
handle.cancel();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
drop(handle);
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
thread::sleep(ms(200));
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
})
.unwrap();
}
#[test]
fn wake_and_cancel_during_run() {
future!(f, waker, POLL, DROP_F);
schedule!(s, chan, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
task.run();
let w = waker();
w.wake_by_ref();
let task = chan.recv().unwrap();
crossbeam::scope(|scope| {
scope.spawn(|_| {
assert!(catch_unwind(|| task.run()).is_err());
drop(waker());
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
});
thread::sleep(ms(100));
w.wake();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
handle.cancel();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
drop(handle);
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
thread::sleep(ms(200));
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
})
.unwrap();
}
#[test]
fn cancel_and_wake_during_run() {
future!(f, waker, POLL, DROP_F);
schedule!(s, chan, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
task.run();
let w = waker();
w.wake_by_ref();
let task = chan.recv().unwrap();
crossbeam::scope(|scope| {
scope.spawn(|_| {
assert!(catch_unwind(|| task.run()).is_err());
drop(waker());
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
});
thread::sleep(ms(100));
handle.cancel();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
drop(handle);
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
w.wake();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
thread::sleep(ms(200));
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
})
.unwrap();
}

@ -1,348 +0,0 @@
#![feature(async_await)]
use std::future::Future;
use std::pin::Pin;
use std::task::Waker;
use std::task::{Context, Poll};
use std::thread;
use std::time::Duration;
use async_task::Task;
use crossbeam::atomic::AtomicCell;
use crossbeam::channel;
use lazy_static::lazy_static;
// Creates a future with event counters.
//
// Usage: `future!(f, waker, POLL, DROP)`
//
// The future `f` always sleeps for 200 ms and returns `Poll::Pending`.
// When it gets polled, `POLL` is incremented.
// When it gets dropped, `DROP` is incremented.
//
// Every time the future is run, it stores the waker into a global variable.
// This waker can be extracted using the `waker` function.
macro_rules! future {
($name:pat, $waker:pat, $poll:ident, $drop:ident) => {
lazy_static! {
static ref $poll: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
static ref WAKER: AtomicCell<Option<Waker>> = AtomicCell::new(None);
}
let ($name, $waker) = {
struct Fut(Box<i32>);
impl Future for Fut {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
WAKER.store(Some(cx.waker().clone()));
$poll.fetch_add(1);
thread::sleep(ms(200));
Poll::Pending
}
}
impl Drop for Fut {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
(Fut(Box::new(0)), || WAKER.swap(None).unwrap())
};
};
}
// Creates a schedule function with event counters.
//
// Usage: `schedule!(s, chan, SCHED, DROP)`
//
// The schedule function `s` pushes the task into `chan`.
// When it gets invoked, `SCHED` is incremented.
// When it gets dropped, `DROP` is incremented.
//
// Receiver `chan` extracts the task when it is scheduled.
macro_rules! schedule {
($name:pat, $chan:pat, $sched:ident, $drop:ident) => {
lazy_static! {
static ref $sched: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let ($name, $chan) = {
let (s, r) = channel::unbounded();
struct Guard(Box<i32>);
impl Drop for Guard {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
let guard = Guard(Box::new(0));
let sched = move |task: Task<_>| {
&guard;
$sched.fetch_add(1);
s.send(task).unwrap();
};
(sched, r)
};
};
}
// Creates a task with event counters.
//
// Usage: `task!(task, handle f, s, DROP)`
//
// A task with future `f` and schedule function `s` is created.
// The `Task` and `JoinHandle` are bound to `task` and `handle`, respectively.
// When the tag inside the task gets dropped, `DROP` is incremented.
macro_rules! task {
($task:pat, $handle: pat, $future:expr, $schedule:expr, $drop:ident) => {
lazy_static! {
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let ($task, $handle) = {
struct Tag(Box<i32>);
impl Drop for Tag {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
async_task::spawn($future, $schedule, Tag(Box::new(0)))
};
};
}
fn ms(ms: u64) -> Duration {
Duration::from_millis(ms)
}
#[test]
fn wake_during_run() {
future!(f, waker, POLL, DROP_F);
schedule!(s, chan, SCHEDULE, DROP_S);
task!(task, _handle, f, s, DROP_D);
task.run();
let w = waker();
w.wake_by_ref();
let task = chan.recv().unwrap();
crossbeam::scope(|scope| {
scope.spawn(|_| {
task.run();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 2);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 1);
});
thread::sleep(ms(100));
w.wake_by_ref();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
thread::sleep(ms(200));
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 2);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 1);
})
.unwrap();
chan.recv().unwrap();
drop(waker());
}
#[test]
fn cancel_during_run() {
future!(f, waker, POLL, DROP_F);
schedule!(s, chan, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
task.run();
let w = waker();
w.wake();
let task = chan.recv().unwrap();
crossbeam::scope(|scope| {
scope.spawn(|_| {
task.run();
drop(waker());
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
});
thread::sleep(ms(100));
handle.cancel();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
drop(handle);
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
thread::sleep(ms(200));
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
})
.unwrap();
}
#[test]
fn wake_and_cancel_during_run() {
future!(f, waker, POLL, DROP_F);
schedule!(s, chan, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
task.run();
let w = waker();
w.wake_by_ref();
let task = chan.recv().unwrap();
crossbeam::scope(|scope| {
scope.spawn(|_| {
task.run();
drop(waker());
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
});
thread::sleep(ms(100));
w.wake();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
handle.cancel();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
drop(handle);
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
thread::sleep(ms(200));
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
})
.unwrap();
}
#[test]
fn cancel_and_wake_during_run() {
future!(f, waker, POLL, DROP_F);
schedule!(s, chan, SCHEDULE, DROP_S);
task!(task, handle, f, s, DROP_D);
task.run();
let w = waker();
w.wake_by_ref();
let task = chan.recv().unwrap();
crossbeam::scope(|scope| {
scope.spawn(|_| {
task.run();
drop(waker());
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
});
thread::sleep(ms(100));
handle.cancel();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
drop(handle);
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
w.wake();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
thread::sleep(ms(200));
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
})
.unwrap();
}

@ -1,328 +0,0 @@
#![feature(async_await)]
use std::cell::Cell;
use std::future::Future;
use std::pin::Pin;
use std::task::Waker;
use std::task::{Context, Poll};
use std::thread;
use std::time::Duration;
use async_task::Task;
use crossbeam::atomic::AtomicCell;
use crossbeam::channel;
use lazy_static::lazy_static;
// Creates a future with event counters.
//
// Usage: `future!(f, waker, POLL, DROP)`
//
// The future `f` always sleeps for 200 ms, and returns `Poll::Ready` the second time it is polled.
// When it gets polled, `POLL` is incremented.
// When it gets dropped, `DROP` is incremented.
//
// Every time the future is run, it stores the waker into a global variable.
// This waker can be extracted using the `waker` function.
macro_rules! future {
($name:pat, $waker:pat, $poll:ident, $drop:ident) => {
lazy_static! {
static ref $poll: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
static ref WAKER: AtomicCell<Option<Waker>> = AtomicCell::new(None);
}
let ($name, $waker) = {
struct Fut(Cell<bool>, Box<i32>);
impl Future for Fut {
type Output = Box<i32>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
WAKER.store(Some(cx.waker().clone()));
$poll.fetch_add(1);
thread::sleep(ms(200));
if self.0.get() {
Poll::Ready(Box::new(0))
} else {
self.0.set(true);
Poll::Pending
}
}
}
impl Drop for Fut {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
(Fut(Cell::new(false), Box::new(0)), || {
WAKER.swap(None).unwrap()
})
};
};
}
// Creates a schedule function with event counters.
//
// Usage: `schedule!(s, chan, SCHED, DROP)`
//
// The schedule function `s` pushes the task into `chan`.
// When it gets invoked, `SCHED` is incremented.
// When it gets dropped, `DROP` is incremented.
//
// Receiver `chan` extracts the task when it is scheduled.
macro_rules! schedule {
($name:pat, $chan:pat, $sched:ident, $drop:ident) => {
lazy_static! {
static ref $sched: AtomicCell<usize> = AtomicCell::new(0);
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let ($name, $chan) = {
let (s, r) = channel::unbounded();
struct Guard(Box<i32>);
impl Drop for Guard {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
let guard = Guard(Box::new(0));
let sched = move |task: Task<_>| {
&guard;
$sched.fetch_add(1);
s.send(task).unwrap();
};
(sched, r)
};
};
}
// Creates a task with event counters.
//
// Usage: `task!(task, handle f, s, DROP)`
//
// A task with future `f` and schedule function `s` is created.
// The `Task` and `JoinHandle` are bound to `task` and `handle`, respectively.
// When the tag inside the task gets dropped, `DROP` is incremented.
macro_rules! task {
($task:pat, $handle: pat, $future:expr, $schedule:expr, $drop:ident) => {
lazy_static! {
static ref $drop: AtomicCell<usize> = AtomicCell::new(0);
}
let ($task, $handle) = {
struct Tag(Box<i32>);
impl Drop for Tag {
fn drop(&mut self) {
$drop.fetch_add(1);
}
}
async_task::spawn($future, $schedule, Tag(Box::new(0)))
};
};
}
fn ms(ms: u64) -> Duration {
Duration::from_millis(ms)
}
#[test]
fn wake() {
future!(f, waker, POLL, DROP_F);
schedule!(s, chan, SCHEDULE, DROP_S);
task!(mut task, _, f, s, DROP_D);
assert!(chan.is_empty());
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
waker().wake();
task = chan.recv().unwrap();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
task.run();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
waker().wake();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
}
#[test]
fn wake_by_ref() {
future!(f, waker, POLL, DROP_F);
schedule!(s, chan, SCHEDULE, DROP_S);
task!(mut task, _, f, s, DROP_D);
assert!(chan.is_empty());
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
waker().wake_by_ref();
task = chan.recv().unwrap();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
task.run();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
waker().wake_by_ref();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
}
#[test]
fn clone() {
future!(f, waker, POLL, DROP_F);
schedule!(s, chan, SCHEDULE, DROP_S);
task!(mut task, _, f, s, DROP_D);
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
let w2 = waker().clone();
let w3 = w2.clone();
let w4 = w3.clone();
w4.wake();
task = chan.recv().unwrap();
task.run();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
w3.wake();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
drop(w2);
drop(waker());
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
}
#[test]
fn wake_cancelled() {
future!(f, waker, POLL, DROP_F);
schedule!(s, chan, SCHEDULE, DROP_S);
task!(task, _, f, s, DROP_D);
task.run();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
let w = waker();
w.wake_by_ref();
chan.recv().unwrap().cancel();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
w.wake();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
}
#[test]
fn wake_completed() {
future!(f, waker, POLL, DROP_F);
schedule!(s, chan, SCHEDULE, DROP_S);
task!(task, _, f, s, DROP_D);
task.run();
let w = waker();
assert_eq!(POLL.load(), 1);
assert_eq!(SCHEDULE.load(), 0);
assert_eq!(DROP_F.load(), 0);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
w.wake();
chan.recv().unwrap().run();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 0);
assert_eq!(DROP_D.load(), 0);
assert_eq!(chan.len(), 0);
waker().wake();
assert_eq!(POLL.load(), 2);
assert_eq!(SCHEDULE.load(), 1);
assert_eq!(DROP_F.load(), 1);
assert_eq!(DROP_S.load(), 1);
assert_eq!(DROP_D.load(), 1);
assert_eq!(chan.len(), 0);
}

@ -0,0 +1,29 @@
//! Counts the number of lines in a file given as an argument.
#![feature(async_await)]
use std::env::args;
use async_std::fs::File;
use async_std::io::{self, BufReader};
use async_std::prelude::*;
use async_std::task;
fn main() -> io::Result<()> {
let path = args().nth(1).expect("missing path argument");
task::block_on(async {
let file = BufReader::new(File::open(&path).await?);
let mut lines = file.lines();
let mut count = 0u64;
while let Some(line) = lines.next().await {
line?;
count += 1;
}
println!("The file contains {} lines.", count);
Ok(())
})
}

@ -4,7 +4,7 @@
use std::env::args;
use async_std::{fs, io, prelude::*, task};
use async_std::{fs::File, io, prelude::*, task};
const LEN: usize = 4 * 1024 * 1024; // 4 Mb
@ -12,7 +12,7 @@ fn main() -> io::Result<()> {
let path = args().nth(1).expect("missing path argument");
task::block_on(async {
let mut file = fs::File::open(&path).await?;
let mut file = File::open(&path).await?;
let mut stdout = io::stdout();
let mut buf = vec![0u8; LEN];
@ -23,7 +23,6 @@ fn main() -> io::Result<()> {
// If this is the end of file, clean up and return.
if n == 0 {
stdout.flush().await?;
file.close().await?;
return Ok(());
}

@ -14,11 +14,11 @@
#![feature(async_await)]
use async_std::{io, net, prelude::*, task};
use async_std::{io, net::TcpStream, prelude::*, task};
fn main() -> io::Result<()> {
task::block_on(async {
let mut stream = net::TcpStream::connect("127.0.0.1:8080").await?;
let mut stream = TcpStream::connect("127.0.0.1:8080").await?;
println!("Connected to {}", &stream.peer_addr()?);
let msg = "hello world";

@ -8,9 +8,10 @@
#![feature(async_await)]
use async_std::{io, net, prelude::*, task};
use async_std::net::{TcpListener, TcpStream};
use async_std::{io, prelude::*, task};
async fn process(stream: net::TcpStream) -> io::Result<()> {
async fn process(stream: TcpStream) -> io::Result<()> {
println!("Accepted from: {}", stream.peer_addr()?);
let (reader, writer) = &mut (&stream, &stream);
@ -21,7 +22,7 @@ async fn process(stream: net::TcpStream) -> io::Result<()> {
fn main() -> io::Result<()> {
task::block_on(async {
let listener = net::TcpListener::bind("127.0.0.1:8080").await?;
let listener = TcpListener::bind("127.0.0.1:8080").await?;
println!("Listening on {}", listener.local_addr()?);
let mut incoming = listener.incoming();

@ -14,11 +14,11 @@
#![feature(async_await)]
use async_std::{io, net, task};
use async_std::{io, net::UdpSocket, task};
fn main() -> io::Result<()> {
task::block_on(async {
let socket = net::UdpSocket::bind("127.0.0.1:8081").await?;
let socket = UdpSocket::bind("127.0.0.1:8081").await?;
println!("Listening on {}", socket.local_addr()?);
let msg = "hello world";

@ -8,11 +8,11 @@
#![feature(async_await)]
use async_std::{io, net, task};
use async_std::{io, net::UdpSocket, task};
fn main() -> io::Result<()> {
task::block_on(async {
let socket = net::UdpSocket::bind("127.0.0.1:8080").await?;
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
let mut buf = vec![0u8; 1024];
println!("Listening on {}", socket.local_addr()?);

@ -0,0 +1,38 @@
use std::fs;
use std::path::{Path, PathBuf};
use crate::io;
use crate::task::blocking;
/// Returns the canonical form of a path.
///
/// The returned path is in absolute form with all intermediate components normalized and symbolic
/// links resolved.
///
/// This function is an async version of [`std::fs::canonicalize`].
///
/// [`std::fs::canonicalize`]: https://doc.rust-lang.org/std/fs/fn.canonicalize.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` does not exist.
/// * A non-final component in path is not a directory.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let path = fs::canonicalize(".").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::canonicalize(path) }).await
}

@ -0,0 +1,43 @@
use std::fs;
use std::path::Path;
use crate::io;
use crate::task::blocking;
/// Copies the contents and permissions of one file to another.
///
/// On success, the total number of bytes copied is returned and equals the length of the `from`
/// file.
///
/// The old contents of `to` will be overwritten. If `from` and `to` both point to the same file,
/// then the file will likely get truncated by this operation.
///
/// This function is an async version of [`std::fs::copy`].
///
/// [`std::fs::copy`]: https://doc.rust-lang.org/std/fs/fn.copy.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * The `from` path is not a file.
/// * The `from` file does not exist.
/// * The current process lacks permissions to access `from` or write `to`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let bytes_copied = fs::copy("a.txt", "b.txt").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
let from = from.as_ref().to_owned();
let to = to.as_ref().to_owned();
blocking::spawn(async move { fs::copy(&from, &to) }).await
}

@ -0,0 +1,36 @@
use std::fs;
use std::path::Path;
use crate::io;
use crate::task::blocking;
/// Creates a new, empty directory.
///
/// This function is an async version of [`std::fs::create_dir`].
///
/// [`std::fs::create_dir`]: https://doc.rust-lang.org/std/fs/fn.create_dir.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` already exists.
/// * A parent of the given path does not exist.
/// * The current process lacks permissions to create directory at `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// fs::create_dir("./some/dir").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::create_dir(path) }).await
}

@ -0,0 +1,35 @@
use std::fs;
use std::path::{Path, PathBuf};
use crate::task::blocking;
use crate::io;
/// Creates a new, empty directory and all of its parents if they are missing.
///
/// This function is an async version of [`std::fs::create_dir_all`].
///
/// [`std::fs::create_dir_all`]: https://doc.rust-lang.org/std/fs/fn.create_dir_all.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * The parent directories do not exists and couldn't be created.
/// * The current process lacks permissions to create directory at `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// fs::create_dir_all("./some/dir").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::create_dir_all(path) }).await
}

@ -1,10 +1,10 @@
use std::fs;
use std::future::Future;
use std::io;
use std::path::Path;
use cfg_if::cfg_if;
use crate::future::Future;
use crate::io;
use crate::task::blocking;
/// A builder for creating directories in various manners.
@ -74,19 +74,16 @@ impl DirBuilder {
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::{metadata, DirBuilder};
///
/// # futures::executor::block_on(async {
/// let path = "/tmp/foo/bar/baz";
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::DirBuilder;
///
/// DirBuilder::new()
/// .recursive(true)
/// .create(path)
/// .create("/tmp/foo/bar/baz")
/// .await?;
///
/// assert!(metadata(path).await?.is_dir());
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn create<P: AsRef<Path>>(&self, path: P) -> impl Future<Output = io::Result<()>> {
let mut builder = fs::DirBuilder::new();
@ -105,16 +102,16 @@ impl DirBuilder {
}
cfg_if! {
if #[cfg(feature = "docs.rs")] {
if #[cfg(feature = "docs")] {
use crate::os::unix::fs::DirBuilderExt;
} else if #[cfg(unix)] {
use std::os::unix::fs::DirBuilderExt;
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(unix)))]
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs.rs"))] {
if #[cfg(any(unix, feature = "docs"))] {
impl DirBuilderExt for DirBuilder {
fn mode(&mut self, mode: u32) -> &mut Self {
self.mode = Some(mode);

@ -1,16 +1,15 @@
use std::ffi::OsString;
use std::fs;
use std::future::Future;
use std::io;
use std::path::PathBuf;
use std::pin::Pin;
use std::sync::Mutex;
use std::task::Poll;
use cfg_if::cfg_if;
use futures::prelude::*;
use futures::future::{self, FutureExt, TryFutureExt};
use crate::task::blocking;
use crate::future::Future;
use crate::io;
use crate::task::{blocking, Poll};
/// An entry inside a directory.
///
@ -76,18 +75,18 @@ impl DirEntry {
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::read_dir;
/// use async_std::prelude::*;
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs, prelude::*};
///
/// # futures::executor::block_on(async {
/// let mut dir = read_dir(".").await?;
/// let mut dir = fs::read_dir(".").await?;
///
/// while let Some(entry) = dir.next().await {
/// let entry = entry?;
/// println!("{:?}", entry.path());
/// }
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn path(&self) -> PathBuf {
self.path.clone()
@ -101,18 +100,18 @@ impl DirEntry {
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::read_dir;
/// use async_std::prelude::*;
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs, prelude::*};
///
/// # futures::executor::block_on(async {
/// let mut dir = read_dir(".").await?;
/// let mut dir = fs::read_dir(".").await?;
///
/// while let Some(entry) = dir.next().await {
/// let entry = entry?;
/// println!("{:?}", entry.metadata().await?);
/// }
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn metadata(&self) -> io::Result<fs::Metadata> {
future::poll_fn(|cx| {
@ -154,18 +153,18 @@ impl DirEntry {
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::read_dir;
/// use async_std::prelude::*;
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs, prelude::*};
///
/// # futures::executor::block_on(async {
/// let mut dir = read_dir(".").await?;
/// let mut dir = fs::read_dir(".").await?;
///
/// while let Some(entry) = dir.next().await {
/// let entry = entry?;
/// println!("{:?}", entry.file_type().await?);
/// }
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn file_type(&self) -> io::Result<fs::FileType> {
future::poll_fn(|cx| {
@ -205,18 +204,18 @@ impl DirEntry {
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::read_dir;
/// use async_std::prelude::*;
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs, prelude::*};
///
/// # futures::executor::block_on(async {
/// let mut dir = read_dir(".").await?;
/// let mut dir = fs::read_dir(".").await?;
///
/// while let Some(entry) = dir.next().await {
/// let entry = entry?;
/// println!("{:?}", entry.file_name());
/// }
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn file_name(&self) -> OsString {
self.file_name.clone()
@ -229,16 +228,16 @@ fn io_error(err: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Err
}
cfg_if! {
if #[cfg(feature = "docs.rs")] {
if #[cfg(feature = "docs")] {
use crate::os::unix::fs::DirEntryExt;
} else if #[cfg(unix)] {
use std::os::unix::fs::DirEntryExt;
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(unix)))]
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs.rs"))] {
if #[cfg(any(unix, feature = "docs"))] {
impl DirEntryExt for DirEntry {
fn ino(&self) -> u64 {
self.ino

@ -1,18 +1,18 @@
//! Types for working with files.
use std::fs;
use std::future::Future;
use std::io::{self, SeekFrom};
use std::io::{Read as _, Seek, SeekFrom, Write as _};
use std::path::Path;
use std::pin::Pin;
use std::sync::Mutex;
use std::task::{Context, Poll};
use cfg_if::cfg_if;
use futures::io::Initializer;
use futures::prelude::*;
use futures::future::{self, FutureExt, TryFutureExt};
use futures::io::{AsyncSeek, Initializer};
use crate::task::blocking;
use crate::future::Future;
use crate::io;
use crate::task::{blocking, Context, Poll};
/// A reference to a file on the filesystem.
///
@ -34,29 +34,31 @@ use crate::task::blocking;
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::prelude::*;
///
/// # futures::executor::block_on(async {
/// let mut file = File::create("foo.txt").await?;
/// let mut file = File::create("a.txt").await?;
/// file.write_all(b"Hello, world!").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
///
/// Read the contents of a file into a `Vec<u8>`:
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::prelude::*;
///
/// # futures::executor::block_on(async {
/// let mut file = File::open("foo.txt").await?;
/// let mut file = File::open("a.txt").await?;
/// let mut contents = Vec::new();
/// file.read_to_end(&mut contents).await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
#[derive(Debug)]
pub struct File {
@ -123,12 +125,13 @@ impl File {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
///
/// # futures::executor::block_on(async {
/// let file = File::open("foo.txt").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// let file = File::open("a.txt").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
let path = path.as_ref().to_owned();
@ -169,12 +172,13 @@ impl File {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
///
/// # futures::executor::block_on(async {
/// let file = File::create("foo.txt").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// let file = File::create("a.txt").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
let path = path.as_ref().to_owned();
@ -215,15 +219,16 @@ impl File {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::prelude::*;
///
/// # futures::executor::block_on(async {
/// let mut file = File::create("foo.txt").await?;
/// let mut file = File::create("a.txt").await?;
/// file.write_all(b"Hello, world!").await?;
/// file.sync_all().await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn sync_all(&self) -> io::Result<()> {
future::poll_fn(|cx| {
@ -270,15 +275,16 @@ impl File {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::prelude::*;
///
/// # futures::executor::block_on(async {
/// let mut file = File::create("foo.txt").await?;
/// let mut file = File::create("a.txt").await?;
/// file.write_all(b"Hello, world!").await?;
/// file.sync_data().await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn sync_data(&self) -> io::Result<()> {
future::poll_fn(|cx| {
@ -329,14 +335,15 @@ impl File {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::prelude::*;
///
/// # futures::executor::block_on(async {
/// let mut file = File::create("foo.txt").await?;
/// let mut file = File::create("a.txt").await?;
/// file.set_len(10).await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn set_len(&self, size: u64) -> io::Result<()> {
future::poll_fn(|cx| {
@ -376,13 +383,14 @@ impl File {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
///
/// # futures::executor::block_on(async {
/// let file = File::open("foo.txt").await?;
/// let file = File::open("a.txt").await?;
/// let metadata = file.metadata().await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn metadata(&self) -> io::Result<fs::Metadata> {
future::poll_fn(|cx| {
@ -427,16 +435,17 @@ impl File {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::prelude::*;
///
/// # futures::executor::block_on(async {
/// let mut file = File::create("foo.txt").await?;
/// let mut file = File::create("a.txt").await?;
/// let mut perms = file.metadata().await?.permissions();
/// perms.set_readonly(true);
/// file.set_permissions(perms).await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn set_permissions(&self, perm: fs::Permissions) -> io::Result<()> {
let mut perm = Some(perm);
@ -474,7 +483,7 @@ impl File {
}
}
impl AsyncRead for File {
impl futures::io::AsyncRead for File {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
@ -489,7 +498,7 @@ impl AsyncRead for File {
}
}
impl AsyncRead for &File {
impl futures::io::AsyncRead for &File {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
@ -535,10 +544,10 @@ impl AsyncRead for &File {
*state = State::Busy(blocking::spawn(async move {
if offset > 0 {
let pos = SeekFrom::Current(-(offset as i64));
let _ = io::Seek::seek(&mut inner.file, pos);
let _ = Seek::seek(&mut inner.file, pos);
}
let res = io::Read::read(&mut inner.file, &mut inner.buf);
let res = inner.file.read(&mut inner.buf);
inner.last_op = Some(Operation::Read(res));
State::Idle(Some(inner))
}));
@ -555,7 +564,7 @@ impl AsyncRead for &File {
}
}
impl AsyncWrite for File {
impl futures::io::AsyncWrite for File {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
@ -573,7 +582,7 @@ impl AsyncWrite for File {
}
}
impl AsyncWrite for &File {
impl futures::io::AsyncWrite for &File {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
@ -613,7 +622,7 @@ impl AsyncWrite for &File {
// Start the operation asynchronously.
*state = State::Busy(blocking::spawn(async move {
let res = io::Write::write(&mut inner.file, &mut inner.buf);
let res = inner.file.write(&mut inner.buf);
inner.last_op = Some(Operation::Write(res));
State::Idle(Some(inner))
}));
@ -646,7 +655,7 @@ impl AsyncWrite for &File {
// Start the operation asynchronously.
*state = State::Busy(blocking::spawn(async move {
let res = io::Write::flush(&mut inner.file);
let res = inner.file.flush();
inner.last_op = Some(Operation::Flush(res));
State::Idle(Some(inner))
}));
@ -684,7 +693,7 @@ impl AsyncWrite for &File {
}
}
impl AsyncSeek for File {
impl futures::io::AsyncSeek for File {
fn poll_seek(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
@ -717,7 +726,7 @@ impl AsyncSeek for &File {
// Start the operation asynchronously.
*state = State::Busy(blocking::spawn(async move {
let res = io::Seek::seek(&mut inner.file, pos);
let res = inner.file.seek(pos);
inner.last_op = Some(Operation::Seek(res));
State::Idle(Some(inner))
}));
@ -763,7 +772,7 @@ impl From<std::fs::File> for File {
}
cfg_if! {
if #[cfg(feature = "docs.rs")] {
if #[cfg(feature = "docs")] {
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
} else if #[cfg(unix)] {
@ -773,9 +782,9 @@ cfg_if! {
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(unix)))]
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs.rs"))] {
if #[cfg(any(unix, feature = "docs"))] {
impl AsRawFd for File {
fn as_raw_fd(&self) -> RawFd {
self.raw_fd
@ -796,9 +805,9 @@ cfg_if! {
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(windows)))]
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
cfg_if! {
if #[cfg(any(windows, feature = "docs.rs"))] {
if #[cfg(any(windows, feature = "docs"))] {
impl AsRawHandle for File {
fn as_raw_handle(&self) -> RawHandle {
self.raw_handle.0

@ -0,0 +1,38 @@
use std::fs;
use std::path::Path;
use crate::io;
use crate::task::blocking;
/// Creates a new hard link on the filesystem.
///
/// The `dst` path will be a link pointing to the `src` path. Note that systems often require these
/// two paths to both be located on the same filesystem.
///
/// This function is an async version of [`std::fs::hard_link`].
///
/// [`std::fs::hard_link`]: https://doc.rust-lang.org/std/fs/fn.hard_link.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * The `src` path is not a file or doesn't exist.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// fs::hard_link("a.txt", "b.txt").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
let from = from.as_ref().to_owned();
let to = to.as_ref().to_owned();
blocking::spawn(async move { fs::hard_link(&from, &to) }).await
}

@ -0,0 +1,37 @@
use std::fs::{self, Metadata};
use std::path::Path;
use crate::io;
use crate::task::blocking;
/// Queries the metadata for a path.
///
/// This function will traverse symbolic links to query information about the file or directory.
///
/// This function is an async version of [`std::fs::metadata`].
///
/// [`std::fs::metadata`]: https://doc.rust-lang.org/std/fs/fn.metadata.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` does not exist.
/// * The current process lacks permissions to query metadata for `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let perm = fs::metadata("a.txt").await?.permissions();
/// #
/// # Ok(()) }) }
/// ```
pub async fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::metadata(path) }).await
}

@ -10,569 +10,60 @@
//!
//! ```no_run
//! # #![feature(async_await)]
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! use async_std::fs::File;
//! use async_std::prelude::*;
//!
//! # futures::executor::block_on(async {
//! let mut file = File::create("foo.txt").await?;
//! let mut file = File::create("a.txt").await?;
//! file.write_all(b"Hello, world!").await?;
//! # std::io::Result::Ok(())
//! # }).unwrap();
//! #
//! # Ok(()) }) }
//! ```
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use crate::task::blocking;
pub use dir_builder::DirBuilder;
pub use dir_entry::DirEntry;
pub use file::File;
pub use open_options::OpenOptions;
pub use read_dir::ReadDir;
#[doc(inline)]
pub use std::fs::{FileType, Metadata, Permissions};
pub use canonicalize::canonicalize;
pub use copy::copy;
pub use create_dir::create_dir;
pub use hard_link::hard_link;
pub use metadata::metadata;
pub use read::read;
pub use read_dir::read_dir;
pub use read_link::read_link;
pub use read_to_string::read_to_string;
pub use remove_dir::remove_dir;
pub use remove_dir_all::remove_dir_all;
pub use remove_file::remove_file;
pub use rename::rename;
pub use set_permissions::set_permissions;
pub use symlink_metadata::symlink_metadata;
pub use write::write;
mod canonicalize;
mod copy;
mod create_dir;
mod dir_builder;
mod dir_entry;
mod file;
mod hard_link;
mod metadata;
mod open_options;
mod read;
mod read_dir;
#[doc(inline)]
pub use std::fs::{FileType, Metadata, Permissions};
/// Returns the canonical form of a path.
///
/// The returned path is in absolute form with all intermediate components normalized and symbolic
/// links resolved.
///
/// This function is an async version of [`std::fs::canonicalize`].
///
/// [`std::fs::canonicalize`]: https://doc.rust-lang.org/std/fs/fn.canonicalize.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` does not exist.
/// * A non-final component in path is not a directory.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::canonicalize;
///
/// # futures::executor::block_on(async {
/// let path = canonicalize(".").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::canonicalize(path) }).await
}
/// Creates a new, empty directory.
///
/// This function is an async version of [`std::fs::create_dir`].
///
/// [`std::fs::create_dir`]: https://doc.rust-lang.org/std/fs/fn.create_dir.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` already exists.
/// * A parent of the given path does not exist.
/// * The current process lacks permissions to create directory at `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::create_dir;
///
/// # futures::executor::block_on(async {
/// create_dir("./some/dir").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::create_dir(path) }).await
}
/// Creates a new, empty directory and all of its parents if they are missing.
///
/// This function is an async version of [`std::fs::create_dir_all`].
///
/// [`std::fs::create_dir_all`]: https://doc.rust-lang.org/std/fs/fn.create_dir_all.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * The parent directories do not exists and couldn't be created.
/// * The current process lacks permissions to create directory at `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::create_dir_all;
///
/// # futures::executor::block_on(async {
/// create_dir_all("./some/dir").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::create_dir_all(path) }).await
}
/// Creates a new hard link on the filesystem.
///
/// The `dst` path will be a link pointing to the `src` path. Note that systems often require these
/// two paths to both be located on the same filesystem.
///
/// This function is an async version of [`std::fs::hard_link`].
///
/// [`std::fs::hard_link`]: https://doc.rust-lang.org/std/fs/fn.hard_link.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * The `src` path is not a file or doesn't exist.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::hard_link;
///
/// # futures::executor::block_on(async {
/// hard_link("a.txt", "b.txt").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
let from = from.as_ref().to_owned();
let to = to.as_ref().to_owned();
blocking::spawn(async move { fs::hard_link(&from, &to) }).await
}
/// Copies the contents and permissions of one file to another.
///
/// On success, the total number of bytes copied is returned and equals the length of the `from`
/// file.
///
/// The old contents of `to` will be overwritten. If `from` and `to` both point to the same file,
/// then the file will likely get truncated by this operation.
///
/// This function is an async version of [`std::fs::copy`].
///
/// [`std::fs::copy`]: https://doc.rust-lang.org/std/fs/fn.copy.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * The `from` path is not a file.
/// * The `from` file does not exist.
/// * The current process lacks permissions to access `from` or write `to`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::copy;
///
/// # futures::executor::block_on(async {
/// let bytes_copied = copy("foo.txt", "bar.txt").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
let from = from.as_ref().to_owned();
let to = to.as_ref().to_owned();
blocking::spawn(async move { fs::copy(&from, &to) }).await
}
/// Queries the metadata for a path.
///
/// This function will traverse symbolic links to query information about the file or directory.
///
/// This function is an async version of [`std::fs::metadata`].
///
/// [`std::fs::metadata`]: https://doc.rust-lang.org/std/fs/fn.metadata.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` does not exist.
/// * The current process lacks permissions to query metadata for `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::metadata;
///
/// # futures::executor::block_on(async {
/// let perm = metadata("foo.txt").await?.permissions();
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::metadata(path) }).await
}
/// Read the entire contents of a file into a bytes vector.
///
/// This is a convenience function for reading entire files. It pre-allocates a buffer based on the
/// file size when available, so it is generally faster than manually opening a file and reading
/// into a `Vec`.
///
/// This function is an async version of [`std::fs::read`].
///
/// [`std::fs::read`]: https://doc.rust-lang.org/std/fs/fn.read.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` does not exist.
/// * The current process lacks permissions to read `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::read;
///
/// # futures::executor::block_on(async {
/// let contents = read("foo.txt").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::read(path) }).await
}
/// Returns a stream over the entries within a directory.
///
/// The stream yields items of type [`io::Result`]`<`[`DirEntry`]`>`. New errors may be encountered
/// after a stream is initially constructed.
///
/// This function is an async version of [`std::fs::read_dir`].
///
/// [`io::Result`]: https://doc.rust-lang.org/std/io/type.Result.html
/// [`DirEntry`]: struct.DirEntry.html
/// [`std::fs::read_dir`]: https://doc.rust-lang.org/std/fs/fn.read_dir.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` does not exist.
/// * `path` does not point at a directory.
/// * The current process lacks permissions to view the contents of `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::read_dir;
/// use async_std::prelude::*;
///
/// # futures::executor::block_on(async {
/// let mut dir = read_dir(".").await?;
///
/// while let Some(entry) = dir.next().await {
/// let entry = entry?;
/// println!("{:?}", entry.file_name());
/// }
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::read_dir(path) })
.await
.map(ReadDir::new)
}
/// Reads a symbolic link, returning the path it points to.
///
/// This function is an async version of [`std::fs::read_link`].
///
/// [`std::fs::read_link`]: https://doc.rust-lang.org/std/fs/fn.read_link.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` is not a symbolic link.
/// * `path` does not exist.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::read_link;
///
/// # futures::executor::block_on(async {
/// let path = read_link("foo.txt").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::read_link(path) }).await
}
/// Read the entire contents of a file into a string.
///
/// This function is an async version of [`std::fs::read_to_string`].
///
/// [`std::fs::read_to_string`]: https://doc.rust-lang.org/std/fs/fn.read_to_string.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` is not a file.
/// * The current process lacks permissions to read `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::read_to_string;
///
/// # futures::executor::block_on(async {
/// let contents = read_to_string("foo.txt").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::read_to_string(path) }).await
}
/// Removes an existing, empty directory.
///
/// This function is an async version of [`std::fs::remove_dir`].
///
/// [`std::fs::remove_dir`]: https://doc.rust-lang.org/std/fs/fn.remove_dir.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` is not an empty directory.
/// * The current process lacks permissions to remove directory at `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::remove_dir;
///
/// # futures::executor::block_on(async {
/// remove_dir("./some/dir").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::remove_dir(path) }).await
}
/// Removes an directory and all of its contents.
///
/// This function is an async version of [`std::fs::remove_dir_all`].
///
/// [`std::fs::remove_dir_all`]: https://doc.rust-lang.org/std/fs/fn.remove_dir_all.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` is not a directory.
/// * The current process lacks permissions to remove directory at `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::remove_dir_all;
///
/// # futures::executor::block_on(async {
/// remove_dir_all("./some/dir").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::remove_dir_all(path) }).await
}
/// Removes a file from the filesystem.
///
/// This function is an async version of [`std::fs::remove_file`].
///
/// [`std::fs::remove_file`]: https://doc.rust-lang.org/std/fs/fn.remove_file.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` is not a file.
/// * The current process lacks permissions to remove file at `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::remove_file;
///
/// # futures::executor::block_on(async {
/// remove_file("foo.txt").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::remove_file(path) }).await
}
/// Renames a file or directory to a new name, replacing the original if it already exists.
///
/// This function is an async version of [`std::fs::rename`].
///
/// [`std::fs::rename`]: https://doc.rust-lang.org/std/fs/fn.rename.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `from` does not exist.
/// * `from` and `to` are on different filesystems.
/// * The current process lacks permissions to rename `from` to `to`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::rename;
///
/// # futures::executor::block_on(async {
/// rename("a.txt", "b.txt").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
let from = from.as_ref().to_owned();
let to = to.as_ref().to_owned();
blocking::spawn(async move { fs::rename(&from, &to) }).await
}
/// Changes the permissions on a file or directory.
///
/// This function is an async version of [`std::fs::set_permissions`].
///
/// [`std::fs::set_permissions`]: https://doc.rust-lang.org/std/fs/fn.set_permissions.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` does not exist.
/// * The current process lacks permissions to change attributes of `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::{metadata, set_permissions};
///
/// # futures::executor::block_on(async {
/// let mut perm = metadata("foo.txt").await?.permissions();
/// perm.set_readonly(true);
///
/// set_permissions("foo.txt", perm).await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn set_permissions<P: AsRef<Path>>(path: P, perm: fs::Permissions) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::set_permissions(path, perm) }).await
}
/// Queries the metadata for a path without following symlinks.
///
/// This function is an async version of [`std::fs::symlink_metadata`].
///
/// [`std::fs::symlink_metadata`]: https://doc.rust-lang.org/std/fs/fn.symlink_metadata.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` does not exist.
/// * The current process lacks permissions to query metadata for `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::symlink_metadata;
///
/// # futures::executor::block_on(async {
/// let perm = symlink_metadata("foo.txt").await?.permissions();
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::symlink_metadata(path) }).await
}
/// Writes a slice of bytes as the entire contents of a file.
///
/// This function will create a file if it does not exist, and will entirely replace its contents
/// if it does.
///
/// This function is an async version of [`std::fs::write`].
///
/// [`std::fs::write`]: https://doc.rust-lang.org/std/fs/fn.write.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * The current process lacks permissions to write into `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::write;
///
/// # futures::executor::block_on(async {
/// write("foo.txt", b"Lorem ipsum").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
let path = path.as_ref().to_owned();
let contents = contents.as_ref().to_owned();
blocking::spawn(async move { fs::write(path, contents) }).await
}
mod read_link;
mod read_to_string;
mod remove_dir;
mod remove_dir_all;
mod remove_file;
mod rename;
mod set_permissions;
mod symlink_metadata;
mod write;

@ -1,11 +1,11 @@
use std::fs;
use std::future::Future;
use std::io;
use std::path::Path;
use cfg_if::cfg_if;
use super::File;
use crate::future::Future;
use crate::task::blocking;
/// Options and flags which for configuring how a file is opened.
@ -33,32 +33,34 @@ use crate::task::blocking;
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::OpenOptions;
///
/// # futures::executor::block_on(async {
/// let file = OpenOptions::new()
/// .read(true)
/// .open("foo.txt")
/// .open("a.txt")
/// .await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
///
/// Opening a file for both reading and writing, creating it if it doesn't exist:
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::OpenOptions;
///
/// # futures::executor::block_on(async {
/// let file = OpenOptions::new()
/// .read(true)
/// .write(true)
/// .create(true)
/// .open("foo.txt")
/// .open("a.txt")
/// .await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
#[derive(Clone, Debug)]
pub struct OpenOptions(fs::OpenOptions);
@ -72,15 +74,16 @@ impl OpenOptions {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::OpenOptions;
///
/// # futures::executor::block_on(async {
/// let file = OpenOptions::new()
/// .read(true)
/// .open("foo.txt")
/// .open("a.txt")
/// .await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn new() -> OpenOptions {
OpenOptions(fs::OpenOptions::new())
@ -94,15 +97,16 @@ impl OpenOptions {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::OpenOptions;
///
/// # futures::executor::block_on(async {
/// let file = OpenOptions::new()
/// .read(true)
/// .open("foo.txt")
/// .open("a.txt")
/// .await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn read(&mut self, read: bool) -> &mut OpenOptions {
self.0.read(read);
@ -120,15 +124,16 @@ impl OpenOptions {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::OpenOptions;
///
/// # futures::executor::block_on(async {
/// let file = OpenOptions::new()
/// .write(true)
/// .open("foo.txt")
/// .open("a.txt")
/// .await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn write(&mut self, write: bool) -> &mut OpenOptions {
self.0.write(write);
@ -165,15 +170,16 @@ impl OpenOptions {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::OpenOptions;
///
/// # futures::executor::block_on(async {
/// let file = OpenOptions::new()
/// .append(true)
/// .open("foo.txt")
/// .open("a.txt")
/// .await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn append(&mut self, append: bool) -> &mut OpenOptions {
self.0.append(append);
@ -191,16 +197,17 @@ impl OpenOptions {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::OpenOptions;
///
/// # futures::executor::block_on(async {
/// let file = OpenOptions::new()
/// .write(true)
/// .truncate(true)
/// .open("foo.txt")
/// .open("a.txt")
/// .await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
self.0.truncate(truncate);
@ -220,16 +227,17 @@ impl OpenOptions {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::OpenOptions;
///
/// # futures::executor::block_on(async {
/// let file = OpenOptions::new()
/// .write(true)
/// .create(true)
/// .open("foo.txt")
/// .open("a.txt")
/// .await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn create(&mut self, create: bool) -> &mut OpenOptions {
self.0.create(create);
@ -256,16 +264,17 @@ impl OpenOptions {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::OpenOptions;
///
/// # futures::executor::block_on(async {
/// let file = OpenOptions::new()
/// .write(true)
/// .create_new(true)
/// .open("foo.txt")
/// .open("a.txt")
/// .await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions {
self.0.create_new(create_new);
@ -308,12 +317,13 @@ impl OpenOptions {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::OpenOptions;
///
/// # futures::executor::block_on(async {
/// let file = OpenOptions::new().open("foo.txt").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// let file = OpenOptions::new().open("a.txt").await?;
/// #
/// # Ok(()) }) }
/// ```
pub fn open<P: AsRef<Path>>(&self, path: P) -> impl Future<Output = io::Result<File>> {
let path = path.as_ref().to_owned();
@ -323,16 +333,16 @@ impl OpenOptions {
}
cfg_if! {
if #[cfg(feature = "docs.rs")] {
if #[cfg(feature = "docs")] {
use crate::os::unix::fs::OpenOptionsExt;
} else if #[cfg(unix)] {
use std::os::unix::fs::OpenOptionsExt;
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(unix)))]
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs.rs"))] {
if #[cfg(any(unix, feature = "docs"))] {
impl OpenOptionsExt for OpenOptions {
fn mode(&mut self, mode: u32) -> &mut Self {
self.0.mode(mode);

@ -0,0 +1,39 @@
use std::fs;
use std::path::Path;
use crate::io;
use crate::task::blocking;
/// Read the entire contents of a file into a bytes vector.
///
/// This is a convenience function for reading entire files. It pre-allocates a buffer based on the
/// file size when available, so it is generally faster than manually opening a file and reading
/// into a `Vec`.
///
/// This function is an async version of [`std::fs::read`].
///
/// [`std::fs::read`]: https://doc.rust-lang.org/std/fs/fn.read.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` does not exist.
/// * The current process lacks permissions to read `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let contents = fs::read("a.txt").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::read(path) }).await
}

@ -1,15 +1,56 @@
use std::fs;
use std::future::Future;
use std::io;
use std::path::Path;
use std::pin::Pin;
use std::sync::Mutex;
use std::task::{Context, Poll};
use futures::Stream;
use super::DirEntry;
use crate::task::blocking;
use crate::future::Future;
use crate::io;
use crate::task::{blocking, Context, Poll};
/// Returns a stream over the entries within a directory.
///
/// The stream yields items of type [`io::Result`]`<`[`DirEntry`]`>`. New errors may be encountered
/// after a stream is initially constructed.
///
/// This function is an async version of [`std::fs::read_dir`].
///
/// [`io::Result`]: https://doc.rust-lang.org/std/io/type.Result.html
/// [`DirEntry`]: struct.DirEntry.html
/// [`std::fs::read_dir`]: https://doc.rust-lang.org/std/fs/fn.read_dir.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` does not exist.
/// * `path` does not point at a directory.
/// * The current process lacks permissions to view the contents of `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs, prelude::*};
///
/// let mut dir = fs::read_dir(".").await?;
///
/// while let Some(entry) = dir.next().await {
/// let entry = entry?;
/// println!("{:?}", entry.file_name());
/// }
/// #
/// # Ok(()) }) }
/// ```
pub async fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::read_dir(path) })
.await
.map(ReadDir::new)
}
/// A stream over entries in a directory.
///
@ -55,7 +96,7 @@ impl ReadDir {
}
}
impl Stream for ReadDir {
impl futures::Stream for ReadDir {
type Item = io::Result<DirEntry>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {

@ -0,0 +1,35 @@
use std::fs;
use std::path::{Path, PathBuf};
use crate::io;
use crate::task::blocking;
/// Reads a symbolic link, returning the path it points to.
///
/// This function is an async version of [`std::fs::read_link`].
///
/// [`std::fs::read_link`]: https://doc.rust-lang.org/std/fs/fn.read_link.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` is not a symbolic link.
/// * `path` does not exist.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let path = fs::read_link("a.txt").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::read_link(path) }).await
}

@ -0,0 +1,34 @@
use std::fs;
use std::path::Path;
use crate::io;
use crate::task::blocking;
/// Read the entire contents of a file into a string.
///
/// This function is an async version of [`std::fs::read_to_string`].
///
/// [`std::fs::read_to_string`]: https://doc.rust-lang.org/std/fs/fn.read_to_string.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` is not a file.
/// * The current process lacks permissions to read `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::fs::read_to_string;
///
/// # futures::executor::block_on(async {
/// let contents = read_to_string("a.txt").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::read_to_string(path) }).await
}

@ -0,0 +1,35 @@
use std::fs;
use std::path::Path;
use crate::io;
use crate::task::blocking;
/// Removes an existing, empty directory.
///
/// This function is an async version of [`std::fs::remove_dir`].
///
/// [`std::fs::remove_dir`]: https://doc.rust-lang.org/std/fs/fn.remove_dir.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` is not an empty directory.
/// * The current process lacks permissions to remove directory at `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// fs::remove_dir("./some/dir").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::remove_dir(path) }).await
}

@ -0,0 +1,35 @@
use std::fs;
use std::path::Path;
use crate::io;
use crate::task::blocking;
/// Removes an directory and all of its contents.
///
/// This function is an async version of [`std::fs::remove_dir_all`].
///
/// [`std::fs::remove_dir_all`]: https://doc.rust-lang.org/std/fs/fn.remove_dir_all.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` is not a directory.
/// * The current process lacks permissions to remove directory at `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// fs::remove_dir_all("./some/dir").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::remove_dir_all(path) }).await
}

@ -0,0 +1,35 @@
use std::fs;
use std::path::Path;
use crate::io;
use crate::task::blocking;
/// Removes a file from the filesystem.
///
/// This function is an async version of [`std::fs::remove_file`].
///
/// [`std::fs::remove_file`]: https://doc.rust-lang.org/std/fs/fn.remove_file.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` is not a file.
/// * The current process lacks permissions to remove file at `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// fs::remove_file("a.txt").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::remove_file(path) }).await
}

@ -0,0 +1,37 @@
use std::fs;
use std::path::Path;
use crate::io;
use crate::task::blocking;
/// Renames a file or directory to a new name, replacing the original if it already exists.
///
/// This function is an async version of [`std::fs::rename`].
///
/// [`std::fs::rename`]: https://doc.rust-lang.org/std/fs/fn.rename.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `from` does not exist.
/// * `from` and `to` are on different filesystems.
/// * The current process lacks permissions to rename `from` to `to`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// fs::rename("a.txt", "b.txt").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
let from = from.as_ref().to_owned();
let to = to.as_ref().to_owned();
blocking::spawn(async move { fs::rename(&from, &to) }).await
}

@ -0,0 +1,38 @@
use std::fs;
use std::path::Path;
use crate::io;
use crate::task::blocking;
/// Changes the permissions on a file or directory.
///
/// This function is an async version of [`std::fs::set_permissions`].
///
/// [`std::fs::set_permissions`]: https://doc.rust-lang.org/std/fs/fn.set_permissions.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` does not exist.
/// * The current process lacks permissions to change attributes of `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let mut perm = fs::metadata("a.txt").await?.permissions();
/// perm.set_readonly(true);
///
/// fs::set_permissions("a.txt", perm).await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn set_permissions<P: AsRef<Path>>(path: P, perm: fs::Permissions) -> io::Result<()> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::set_permissions(path, perm) }).await
}

@ -0,0 +1,35 @@
use std::fs::{self, Metadata};
use std::path::Path;
use crate::io;
use crate::task::blocking;
/// Queries the metadata for a path without following symlinks.
///
/// This function is an async version of [`std::fs::symlink_metadata`].
///
/// [`std::fs::symlink_metadata`]: https://doc.rust-lang.org/std/fs/fn.symlink_metadata.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * `path` does not exist.
/// * The current process lacks permissions to query metadata for `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let perm = fs::symlink_metadata("a.txt").await?.permissions();
/// #
/// # Ok(()) }) }
/// ```
pub async fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
let path = path.as_ref().to_owned();
blocking::spawn(async move { fs::symlink_metadata(path) }).await
}

@ -0,0 +1,38 @@
use std::fs;
use std::path::Path;
use crate::io;
use crate::task::blocking;
/// Writes a slice of bytes as the entire contents of a file.
///
/// This function will create a file if it does not exist, and will entirely replace its contents
/// if it does.
///
/// This function is an async version of [`std::fs::write`].
///
/// [`std::fs::write`]: https://doc.rust-lang.org/std/fs/fn.write.html
///
/// # Errors
///
/// An error will be returned in the following situations (not an exhaustive list):
///
/// * The current process lacks permissions to write into `path`.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// fs::write("a.txt", b"Lorem ipsum").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
let path = path.as_ref().to_owned();
let contents = contents.as_ref().to_owned();
blocking::spawn(async move { fs::write(path, contents) }).await
}

@ -3,40 +3,8 @@
#[doc(inline)]
pub use std::future::Future;
/// Never resolves to a value.
///
/// # Examples
/// ```
/// # #![feature(async_await)]
/// use async_std::future::pending;
/// use async_std::prelude::*;
/// use std::time::Duration;
///
/// # async_std::task::block_on(async {
/// let dur = Duration::from_secs(1);
/// assert!(pending::<()>().timeout(dur).await.is_err());
/// # })
/// ```
pub async fn pending<T>() -> T {
futures::future::pending::<T>().await
}
pub use pending::pending;
pub use ready::ready;
/// Resolves to the provided value.
///
/// This function is an async version of [`std::convert::identity`].
///
/// [`std::convert::identity`]: https://doc.rust-lang.org/std/convert/fn.identity.html
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// use async_std::future::ready;
///
/// # async_std::task::block_on(async {
/// assert_eq!(ready(10).await, 10);
/// # })
/// ```
pub async fn ready<T>(val: T) -> T {
val
}
mod pending;
mod ready;

@ -0,0 +1,19 @@
/// Never resolves to a value.
///
/// # Examples
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::future::pending;
/// use async_std::prelude::*;
/// use std::time::Duration;
///
/// let dur = Duration::from_secs(1);
/// assert!(pending::<()>().timeout(dur).await.is_err());
/// #
/// # }) }
/// ```
pub async fn pending<T>() -> T {
futures::future::pending::<T>().await
}

@ -0,0 +1,21 @@
/// Resolves to the provided value.
///
/// This function is an async version of [`std::convert::identity`].
///
/// [`std::convert::identity`]: https://doc.rust-lang.org/std/convert/fn.identity.html
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::future::ready;
///
/// assert_eq!(ready(10).await, 10);
/// #
/// # }) }
/// ```
pub async fn ready<T>(val: T) -> T {
val
}

@ -0,0 +1,321 @@
use std::io;
use std::mem;
use std::pin::Pin;
use std::str;
use cfg_if::cfg_if;
use futures::io::AsyncBufRead;
use crate::future::Future;
use crate::task::{Context, Poll};
cfg_if! {
if #[cfg(feature = "docs")] {
#[doc(hidden)]
pub struct ImplFuture<'a, T>(std::marker::PhantomData<&'a T>);
macro_rules! ret {
($a:lifetime, $f:tt, $o:ty) => (ImplFuture<$a, $o>);
}
} else {
macro_rules! ret {
($a:lifetime, $f:tt, $o:ty) => ($f<$a, Self>);
}
}
}
/// Allows reading from a buffered byte stream.
///
/// This trait is an async version of [`std::io::BufRead`].
///
/// While it is currently not possible to implement this trait directly, it gets implemented
/// automatically for all types that implement [`futures::io::AsyncBufRead`].
///
/// [`std::io::BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html
/// [`futures::io::AsyncBufRead`]:
/// https://docs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncBufRead.html
pub trait BufRead {
/// Reads all bytes into `buf` until the delimiter `byte` or EOF is reached.
///
/// This function will read bytes from the underlying stream until the delimiter or EOF is
/// found. Once found, all bytes up to, and including, the delimiter (if found) will be
/// appended to `buf`.
///
/// If successful, this function will return the total number of bytes read.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs::File, io::BufReader, prelude::*};
///
/// let mut f = BufReader::new(File::open("a.txt").await?);
///
/// let mut buf = vec![0; 1024];
/// let n = f.read_until(b'\n', &mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
fn read_until<'a>(
&'a mut self,
byte: u8,
buf: &'a mut Vec<u8>,
) -> ret!('a, ReadUntilFuture, io::Result<usize>)
where
Self: Unpin,
{
ReadUntilFuture {
reader: self,
byte,
buf,
read: 0,
}
}
/// Reads all bytes and appends them into `buf` until a newline (the 0xA byte) is reached.
///
/// This function will read bytes from the underlying stream until the newline delimiter (the
/// 0xA byte) or EOF is found. Once found, all bytes up to, and including, the delimiter (if
/// found) will be appended to `buf`.
///
/// If successful, this function will return the total number of bytes read.
///
/// If this function returns `Ok(0)`, the stream has reached EOF.
///
/// # Errors
///
/// This function has the same error semantics as [`read_until`] and will also return an error
/// if the read bytes are not valid UTF-8. If an I/O error is encountered then `buf` may
/// contain some bytes already read in the event that all data read so far was valid UTF-8.
///
/// [`read_until`]: #method.read_until
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs::File, io::BufReader, prelude::*};
///
/// let mut f = BufReader::new(File::open("a.txt").await?);
///
/// let mut buf = String::new();
/// f.read_line(&mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
fn read_line<'a>(
&'a mut self,
buf: &'a mut String,
) -> ret!('a, ReadLineFuture, io::Result<usize>)
where
Self: Unpin,
{
ReadLineFuture {
reader: self,
bytes: unsafe { mem::replace(buf.as_mut_vec(), Vec::new()) },
buf,
read: 0,
}
}
/// Returns a stream over the lines of this byte stream.
///
/// The stream returned from this function will yield instances of
/// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline byte (the
/// 0xA byte) or CRLF (0xD, 0xA bytes) at the end.
///
/// [`io::Result`]: type.Result.html
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs::File, io::BufReader, prelude::*};
///
/// let mut f = BufReader::new(File::open("a.txt").await?);
///
/// let mut lines = f.lines();
/// let mut count = 0;
///
/// for line in lines.next().await {
/// line?;
/// count += 1;
/// }
/// #
/// # Ok(()) }) }
/// ```
fn lines(self) -> Lines<Self>
where
Self: Unpin + Sized,
{
Lines {
reader: self,
buf: String::new(),
bytes: Vec::new(),
read: 0,
}
}
}
impl<T: AsyncBufRead + Unpin + ?Sized> BufRead for T {}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct ReadUntilFuture<'a, T: Unpin + ?Sized> {
reader: &'a mut T,
byte: u8,
buf: &'a mut Vec<u8>,
read: usize,
}
impl<T: AsyncBufRead + Unpin + ?Sized> Future for ReadUntilFuture<'_, T> {
type Output = io::Result<usize>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let Self {
reader,
byte,
buf,
read,
} = &mut *self;
read_until_internal(Pin::new(reader), cx, *byte, buf, read)
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct ReadLineFuture<'a, T: Unpin + ?Sized> {
reader: &'a mut T,
buf: &'a mut String,
bytes: Vec<u8>,
read: usize,
}
impl<T: AsyncBufRead + Unpin + ?Sized> Future for ReadLineFuture<'_, T> {
type Output = io::Result<usize>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let Self {
reader,
buf,
bytes,
read,
} = &mut *self;
let reader = Pin::new(reader);
let ret = futures::ready!(read_until_internal(reader, cx, b'\n', bytes, read));
if str::from_utf8(&bytes).is_err() {
Poll::Ready(ret.and_then(|_| {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"stream did not contain valid UTF-8",
))
}))
} else {
debug_assert!(buf.is_empty());
debug_assert_eq!(*read, 0);
// Safety: `bytes` is a valid UTF-8 because `str::from_utf8` returned `Ok`.
mem::swap(unsafe { buf.as_mut_vec() }, bytes);
Poll::Ready(ret)
}
}
}
/// A stream of lines in a byte stream.
///
/// This stream is created by the [`lines`] method on types that implement [`BufRead`].
///
/// This type is an async version of [`std::io::Lines`].
///
/// [`lines`]: trait.BufRead.html#method.lines
/// [`BufRead`]: trait.BufRead.html
/// [`std::io::Lines`]: https://doc.rust-lang.org/nightly/std/io/struct.Lines.html
#[derive(Debug)]
pub struct Lines<R> {
reader: R,
buf: String,
bytes: Vec<u8>,
read: usize,
}
impl<R: AsyncBufRead> futures::Stream for Lines<R> {
type Item = io::Result<String>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let Self {
reader,
buf,
bytes,
read,
} = unsafe { self.get_unchecked_mut() };
let reader = unsafe { Pin::new_unchecked(reader) };
let n = futures::ready!(read_line_internal(reader, cx, buf, bytes, read))?;
if n == 0 && buf.is_empty() {
return Poll::Ready(None);
}
if buf.ends_with('\n') {
buf.pop();
if buf.ends_with('\r') {
buf.pop();
}
}
Poll::Ready(Some(Ok(mem::replace(buf, String::new()))))
}
}
pub fn read_line_internal<R: AsyncBufRead + ?Sized>(
reader: Pin<&mut R>,
cx: &mut Context<'_>,
buf: &mut String,
bytes: &mut Vec<u8>,
read: &mut usize,
) -> Poll<io::Result<usize>> {
let ret = futures::ready!(read_until_internal(reader, cx, b'\n', bytes, read));
if str::from_utf8(&bytes).is_err() {
Poll::Ready(ret.and_then(|_| {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"stream did not contain valid UTF-8",
))
}))
} else {
debug_assert!(buf.is_empty());
debug_assert_eq!(*read, 0);
// Safety: `bytes` is a valid UTF-8 because `str::from_utf8` returned `Ok`.
mem::swap(unsafe { buf.as_mut_vec() }, bytes);
Poll::Ready(ret)
}
}
pub fn read_until_internal<R: AsyncBufRead + ?Sized>(
mut reader: Pin<&mut R>,
cx: &mut Context<'_>,
byte: u8,
buf: &mut Vec<u8>,
read: &mut usize,
) -> Poll<io::Result<usize>> {
loop {
let (done, used) = {
let available = futures::ready!(reader.as_mut().poll_fill_buf(cx))?;
if let Some(i) = memchr::memchr(byte, available) {
buf.extend_from_slice(&available[..=i]);
(true, i + 1)
} else {
buf.extend_from_slice(available);
(false, available.len())
}
};
reader.as_mut().consume(used);
*read += used;
if done || used == 0 {
return Poll::Ready(Ok(mem::replace(read, 0)));
}
}
}

@ -0,0 +1,349 @@
use std::io::{IoSliceMut, Read as _, SeekFrom};
use std::pin::Pin;
use std::{cmp, fmt};
use futures::io::{AsyncBufRead, AsyncRead, AsyncSeek, Initializer};
use crate::io;
use crate::task::{Context, Poll};
const DEFAULT_CAPACITY: usize = 8 * 1024;
/// Adds buffering to any reader.
///
/// It can be excessively inefficient to work directly with a [`Read`] instance. A `BufReader`
/// performs large, infrequent reads on the underlying [`Read`] and maintains an in-memory buffer
/// of the incoming byte stream.
///
/// `BufReader` can improve the speed of programs that make *small* and *repeated* read calls to
/// the same file or network socket. It does not help when reading very large amounts at once, or
/// reading just one or a few times. It also provides no advantage when reading from a source that
/// is already in memory, like a `Vec<u8>`.
///
/// When the `BufReader` is dropped, the contents of its buffer will be discarded. Creating
/// multiple instances of a `BufReader` on the same stream can cause data loss.
///
/// This type is an async version of [`std::io::BufReader`].
///
/// [`Read`]: trait.Read.html
/// [`std::io::BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::io::BufReader;
/// use async_std::prelude::*;
///
/// let mut f = BufReader::new(File::open("a.txt").await?);
///
/// let mut line = String::new();
/// f.read_line(&mut line).await?;
/// #
/// # Ok(()) }) }
/// ```
pub struct BufReader<R> {
inner: R,
buf: Box<[u8]>,
pos: usize,
cap: usize,
}
impl<R: AsyncRead> BufReader<R> {
/// Creates a buffered reader with default buffer capacity.
///
/// The default capacity is currently 8 KB, but may change in the future.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::io::BufReader;
///
/// let f = BufReader::new(File::open("a.txt").await?);
/// #
/// # Ok(()) }) }
/// ```
pub fn new(inner: R) -> BufReader<R> {
BufReader::with_capacity(DEFAULT_CAPACITY, inner)
}
/// Creates a new buffered reader with the specified capacity.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::io::BufReader;
///
/// let f = BufReader::with_capacity(1024, File::open("a.txt").await?);
/// #
/// # Ok(()) }) }
/// ```
pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
unsafe {
let mut buffer = Vec::with_capacity(capacity);
buffer.set_len(capacity);
inner.initializer().initialize(&mut buffer);
BufReader {
inner,
buf: buffer.into_boxed_slice(),
pos: 0,
cap: 0,
}
}
}
}
impl<R> BufReader<R> {
pin_utils::unsafe_pinned!(inner: R);
pin_utils::unsafe_unpinned!(pos: usize);
pin_utils::unsafe_unpinned!(cap: usize);
/// Gets a reference to the underlying reader.
///
/// It is inadvisable to directly read from the underlying reader.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::io::BufReader;
///
/// let f = BufReader::new(File::open("a.txt").await?);
/// let inner = f.get_ref();
/// #
/// # Ok(()) }) }
/// ```
pub fn get_ref(&self) -> &R {
&self.inner
}
/// Gets a mutable reference to the underlying reader.
///
/// It is inadvisable to directly read from the underlying reader.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::io::BufReader;
///
/// let mut f = BufReader::new(File::open("a.txt").await?);
/// let inner = f.get_mut();
/// #
/// # Ok(()) }) }
/// ```
pub fn get_mut(&mut self) -> &mut R {
&mut self.inner
}
/// Returns a reference to the internal buffer.
///
/// This function will not attempt to fill the buffer if it is empty.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::io::BufReader;
///
/// let f = BufReader::new(File::open("a.txt").await?);
/// let buffer = f.buffer();
/// #
/// # Ok(()) }) }
/// ```
pub fn buffer(&self) -> &[u8] {
&self.buf[self.pos..self.cap]
}
/// Unwraps the buffered reader, returning the underlying reader.
///
/// Note that any leftover data in the internal buffer is lost.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::io::BufReader;
///
/// let f = BufReader::new(File::open("a.txt").await?);
/// let inner = f.into_inner();
/// #
/// # Ok(()) }) }
/// ```
pub fn into_inner(self) -> R {
self.inner
}
/// Invalidates all data in the internal buffer.
#[inline]
fn discard_buffer(mut self: Pin<&mut Self>) {
*self.as_mut().pos() = 0;
*self.cap() = 0;
}
}
impl<R: AsyncRead> AsyncRead for BufReader<R> {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
// If we don't have any buffered data and we're doing a massive read
// (larger than our internal buffer), bypass our internal buffer
// entirely.
if self.pos == self.cap && buf.len() >= self.buf.len() {
let res = futures::ready!(self.as_mut().inner().poll_read(cx, buf));
self.discard_buffer();
return Poll::Ready(res);
}
let mut rem = futures::ready!(self.as_mut().poll_fill_buf(cx))?;
let nread = rem.read(buf)?;
self.consume(nread);
Poll::Ready(Ok(nread))
}
fn poll_read_vectored(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &mut [IoSliceMut<'_>],
) -> Poll<io::Result<usize>> {
let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
if self.pos == self.cap && total_len >= self.buf.len() {
let res = futures::ready!(self.as_mut().inner().poll_read_vectored(cx, bufs));
self.discard_buffer();
return Poll::Ready(res);
}
let mut rem = futures::ready!(self.as_mut().poll_fill_buf(cx))?;
let nread = rem.read_vectored(bufs)?;
self.consume(nread);
Poll::Ready(Ok(nread))
}
// we can't skip unconditionally because of the large buffer case in read.
unsafe fn initializer(&self) -> Initializer {
self.inner.initializer()
}
}
impl<R: AsyncRead> AsyncBufRead for BufReader<R> {
fn poll_fill_buf<'a>(
self: Pin<&'a mut Self>,
cx: &mut Context<'_>,
) -> Poll<io::Result<&'a [u8]>> {
let Self {
inner,
buf,
cap,
pos,
} = unsafe { self.get_unchecked_mut() };
let mut inner = unsafe { Pin::new_unchecked(inner) };
// If we've reached the end of our internal buffer then we need to fetch
// some more data from the underlying reader.
// Branch using `>=` instead of the more correct `==`
// to tell the compiler that the pos..cap slice is always valid.
if *pos >= *cap {
debug_assert!(*pos == *cap);
*cap = futures::ready!(inner.as_mut().poll_read(cx, buf))?;
*pos = 0;
}
Poll::Ready(Ok(&buf[*pos..*cap]))
}
fn consume(mut self: Pin<&mut Self>, amt: usize) {
*self.as_mut().pos() = cmp::min(self.pos + amt, self.cap);
}
}
impl<R: AsyncRead + fmt::Debug> fmt::Debug for BufReader<R> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BufReader")
.field("reader", &self.inner)
.field(
"buffer",
&format_args!("{}/{}", self.cap - self.pos, self.buf.len()),
)
.finish()
}
}
impl<R: AsyncSeek> AsyncSeek for BufReader<R> {
/// Seeks to an offset, in bytes, in the underlying reader.
///
/// The position used for seeking with `SeekFrom::Current(_)` is the position the underlying
/// reader would be at if the `BufReader` had no internal buffer.
///
/// Seeking always discards the internal buffer, even if the seek position would otherwise fall
/// within it. This guarantees that calling `.into_inner()` immediately after a seek yields the
/// underlying reader at the same position.
///
/// See [`Seek`] for more details.
///
/// Note: In the edge case where you're seeking with `SeekFrom::Current(n)` where `n` minus the
/// internal buffer length overflows an `i64`, two seeks will be performed instead of one. If
/// the second seek returns `Err`, the underlying reader will be left at the same position it
/// would have if you called `seek` with `SeekFrom::Current(0)`.
///
/// [`Seek`]: trait.Seek.html
fn poll_seek(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
pos: SeekFrom,
) -> Poll<io::Result<u64>> {
let result: u64;
if let SeekFrom::Current(n) = pos {
let remainder = (self.cap - self.pos) as i64;
// it should be safe to assume that remainder fits within an i64 as the alternative
// means we managed to allocate 8 exbibytes and that's absurd.
// But it's not out of the realm of possibility for some weird underlying reader to
// support seeking by i64::min_value() so we need to handle underflow when subtracting
// remainder.
if let Some(offset) = n.checked_sub(remainder) {
result = futures::ready!(
self.as_mut()
.inner()
.poll_seek(cx, SeekFrom::Current(offset))
)?;
} else {
// seek backwards by our remainder, and then by the offset
futures::ready!(
self.as_mut()
.inner()
.poll_seek(cx, SeekFrom::Current(-remainder))
)?;
self.as_mut().discard_buffer();
result =
futures::ready!(self.as_mut().inner().poll_seek(cx, SeekFrom::Current(n)))?;
}
} else {
// Seeking with Start/End doesn't care about our buffer length.
result = futures::ready!(self.as_mut().inner().poll_seek(cx, pos))?;
}
self.discard_buffer();
Poll::Ready(Ok(result))
}
}

@ -1,5 +1,6 @@
use futures::prelude::*;
use std::io;
use futures::io::{AsyncRead, AsyncReadExt, AsyncWrite};
use crate::io;
/// Copies the entire contents of a reader into a writer.
///
@ -28,19 +29,16 @@ use std::io;
///
/// ```
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{io, task};
///
/// fn main() -> std::io::Result<()> {
/// task::block_on(async {
/// let mut reader: &[u8] = b"hello";
/// let mut writer: Vec<u8> = vec![];
///
/// io::copy(&mut reader, &mut writer).await?;
/// let mut reader: &[u8] = b"hello";
/// let mut writer = io::stdout();
///
/// assert_eq!(&b"hello"[..], &writer[..]);
/// Ok(())
/// })
/// }
/// io::copy(&mut reader, &mut writer).await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn copy<R, W>(reader: &mut R, writer: &mut W) -> io::Result<u64>
where

@ -10,28 +10,36 @@
//!
//! ```no_run
//! # #![feature(async_await)]
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! use async_std::io;
//!
//! # futures::executor::block_on(async {
//! let stdin = io::stdin();
//! let mut line = String::new();
//! stdin.read_line(&mut line).await?;
//! # std::io::Result::Ok(())
//! # }).unwrap();
//! #
//! # Ok(()) }) }
//! ```
#[doc(inline)]
pub use futures::io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, SeekFrom};
pub use std::io::{empty, sink, Cursor, Empty, Error, ErrorKind, Result, SeekFrom, Sink};
pub use buf_read::{BufRead, Lines};
pub use buf_reader::BufReader;
pub use copy::copy;
pub use read::Read;
pub use seek::Seek;
pub use stderr::{stderr, Stderr};
pub use stdin::{stdin, Stdin};
pub use stdout::{stdout, Stdout};
pub use write::Write;
mod buf_read;
mod buf_reader;
mod copy;
mod read;
mod seek;
mod stderr;
mod stdin;
mod stdout;
#[doc(inline)]
pub use std::io::{empty, sink, Cursor, Empty, Error, ErrorKind, Result, Sink};
mod write;

@ -0,0 +1,394 @@
use std::io::IoSliceMut;
use std::mem;
use std::pin::Pin;
use std::str;
use cfg_if::cfg_if;
use futures::io::AsyncRead;
use crate::future::Future;
use crate::io;
use crate::task::{Context, Poll};
cfg_if! {
if #[cfg(feature = "docs")] {
#[doc(hidden)]
pub struct ImplFuture<'a, T>(std::marker::PhantomData<&'a T>);
macro_rules! ret {
($a:lifetime, $f:tt, $o:ty) => (ImplFuture<$a, $o>);
}
} else {
macro_rules! ret {
($a:lifetime, $f:tt, $o:ty) => ($f<$a, Self>);
}
}
}
/// Allows reading from a byte stream.
///
/// This trait is an async version of [`std::io::Read`].
///
/// While it is currently not possible to implement this trait directly, it gets implemented
/// automatically for all types that implement [`futures::io::AsyncRead`].
///
/// [`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
/// [`futures::io::AsyncRead`]:
/// https://docs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncRead.html
pub trait Read {
/// Reads some bytes from the byte stream.
///
/// Returns the number of bytes read from the start of the buffer.
///
/// If the return value is `Ok(n)`, then it must be guaranteed that `0 <= n <= buf.len()`. A
/// nonzero `n` value indicates that the buffer has been filled in with `n` bytes of data. If
/// `n` is `0`, then it can indicate one of two scenarios:
///
/// 1. This reader has reached its "end of file" and will likely no longer be able to produce
/// bytes. Note that this does not mean that the reader will always no longer be able to
/// produce bytes.
/// 2. The buffer specified was 0 bytes in length.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs::File, prelude::*};
///
/// let mut f = File::open("a.txt").await?;
///
/// let mut buf = vec![0; 1024];
/// let n = f.read(&mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> ret!('a, ReadFuture, io::Result<usize>)
where
Self: Unpin;
/// Like [`read`], except that it reads into a slice of buffers.
///
/// Data is copied to fill each buffer in order, with the final buffer written to possibly
/// being only partially filled. This method must behave as a single call to [`read`] with the
/// buffers concatenated would.
///
/// The default implementation calls [`read`] with either the first nonempty buffer provided,
/// or an empty one if none exists.
///
/// [`read`]: #tymethod.read
fn read_vectored<'a>(
&'a mut self,
bufs: &'a mut [IoSliceMut<'a>],
) -> ret!('a, ReadVectoredFuture, io::Result<usize>)
where
Self: Unpin,
{
ReadVectoredFuture { reader: self, bufs }
}
/// Reads all bytes from the byte stream.
///
/// All bytes read from this stream will be appended to the specified buffer `buf`. This
/// function will continuously call [`read`] to append more data to `buf` until [`read`]
/// returns either `Ok(0)` or an error.
///
/// If successful, this function will return the total number of bytes read.
///
/// [`read`]: #tymethod.read
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs::File, prelude::*};
///
/// let mut f = File::open("a.txt").await?;
///
/// let mut buf = Vec::new();
/// f.read_to_end(&mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
fn read_to_end<'a>(
&'a mut self,
buf: &'a mut Vec<u8>,
) -> ret!('a, ReadToEndFuture, io::Result<usize>)
where
Self: Unpin,
{
let start_len = buf.len();
ReadToEndFuture {
reader: self,
buf,
start_len,
}
}
/// Reads all bytes from the byte stream and appends them into a string.
///
/// If successful, this function will return the number of bytes read.
///
/// If the data in this stream is not valid UTF-8 then an error will be returned and `buf` will
/// be left unmodified.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs::File, prelude::*};
///
/// let mut f = File::open("a.txt").await?;
///
/// let mut buf = String::new();
/// f.read_to_string(&mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
fn read_to_string<'a>(
&'a mut self,
buf: &'a mut String,
) -> ret!('a, ReadToStringFuture, io::Result<usize>)
where
Self: Unpin,
{
let start_len = buf.len();
ReadToStringFuture {
reader: self,
bytes: unsafe { mem::replace(buf.as_mut_vec(), Vec::new()) },
buf,
start_len,
}
}
/// Reads the exact number of bytes required to fill `buf`.
///
/// This function reads as many bytes as necessary to completely fill the specified buffer
/// `buf`.
///
/// No guarantees are provided about the contents of `buf` when this function is called,
/// implementations cannot rely on any property of the contents of `buf` being true. It is
/// recommended that implementations only write data to `buf` instead of reading its contents.
///
/// If this function encounters an "end of file" before completely filling the buffer, it
/// returns an error of the kind [`ErrorKind::UnexpectedEof`]. The contents of `buf` are
/// unspecified in this case.
///
/// If any other read error is encountered then this function immediately returns. The contents
/// of `buf` are unspecified in this case.
///
/// If this function returns an error, it is unspecified how many bytes it has read, but it
/// will never read more than would be necessary to completely fill the buffer.
///
/// [`ErrorKind::UnexpectedEof`]: enum.ErrorKind.html#variant.UnexpectedEof
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs::File, prelude::*};
///
/// let mut f = File::open("a.txt").await?;
///
/// let mut buf = vec![0; 10];
/// f.read_exact(&mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ret!('a, ReadExactFuture, io::Result<()>)
where
Self: Unpin,
{
ReadExactFuture { reader: self, buf }
}
}
impl<T: AsyncRead + Unpin + ?Sized> Read for T {
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> ret!('a, ReadFuture, io::Result<usize>) {
ReadFuture { reader: self, buf }
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct ReadFuture<'a, T: Unpin + ?Sized> {
reader: &'a mut T,
buf: &'a mut [u8],
}
impl<T: AsyncRead + Unpin + ?Sized> Future for ReadFuture<'_, T> {
type Output = io::Result<usize>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let Self { reader, buf } = &mut *self;
Pin::new(reader).poll_read(cx, buf)
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct ReadVectoredFuture<'a, T: Unpin + ?Sized> {
reader: &'a mut T,
bufs: &'a mut [IoSliceMut<'a>],
}
impl<T: AsyncRead + Unpin + ?Sized> Future for ReadVectoredFuture<'_, T> {
type Output = io::Result<usize>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let Self { reader, bufs } = &mut *self;
Pin::new(reader).poll_read_vectored(cx, bufs)
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct ReadToEndFuture<'a, T: Unpin + ?Sized> {
reader: &'a mut T,
buf: &'a mut Vec<u8>,
start_len: usize,
}
impl<T: AsyncRead + Unpin + ?Sized> Future for ReadToEndFuture<'_, T> {
type Output = io::Result<usize>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let Self {
reader,
buf,
start_len,
} = &mut *self;
read_to_end_internal(Pin::new(reader), cx, buf, *start_len)
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct ReadToStringFuture<'a, T: Unpin + ?Sized> {
reader: &'a mut T,
buf: &'a mut String,
bytes: Vec<u8>,
start_len: usize,
}
impl<T: AsyncRead + Unpin + ?Sized> Future for ReadToStringFuture<'_, T> {
type Output = io::Result<usize>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let Self {
reader,
buf,
bytes,
start_len,
} = &mut *self;
let reader = Pin::new(reader);
let ret = futures::ready!(read_to_end_internal(reader, cx, bytes, *start_len));
if str::from_utf8(&bytes).is_err() {
Poll::Ready(ret.and_then(|_| {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"stream did not contain valid UTF-8",
))
}))
} else {
debug_assert!(buf.is_empty());
// Safety: `bytes` is a valid UTF-8 because `str::from_utf8` returned `Ok`.
mem::swap(unsafe { buf.as_mut_vec() }, bytes);
Poll::Ready(ret)
}
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct ReadExactFuture<'a, T: Unpin + ?Sized> {
reader: &'a mut T,
buf: &'a mut [u8],
}
impl<T: AsyncRead + Unpin + ?Sized> Future for ReadExactFuture<'_, T> {
type Output = io::Result<()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let Self { reader, buf } = &mut *self;
while !buf.is_empty() {
let n = futures::ready!(Pin::new(&mut *reader).poll_read(cx, buf))?;
let (_, rest) = mem::replace(buf, &mut []).split_at_mut(n);
*buf = rest;
if n == 0 {
return Poll::Ready(Err(io::ErrorKind::UnexpectedEof.into()));
}
}
Poll::Ready(Ok(()))
}
}
// This uses an adaptive system to extend the vector when it fills. We want to
// avoid paying to allocate and zero a huge chunk of memory if the reader only
// has 4 bytes while still making large reads if the reader does have a ton
// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
// time is 4,500 times (!) slower than this if the reader has a very small
// amount of data to return.
//
// Because we're extending the buffer with uninitialized data for trusted
// readers, we need to make sure to truncate that if any of this panics.
pub fn read_to_end_internal<R: AsyncRead + ?Sized>(
mut rd: Pin<&mut R>,
cx: &mut Context<'_>,
buf: &mut Vec<u8>,
start_len: usize,
) -> Poll<io::Result<usize>> {
struct Guard<'a> {
buf: &'a mut Vec<u8>,
len: usize,
}
impl Drop for Guard<'_> {
fn drop(&mut self) {
unsafe {
self.buf.set_len(self.len);
}
}
}
let mut g = Guard {
len: buf.len(),
buf,
};
let ret;
loop {
if g.len == g.buf.len() {
unsafe {
g.buf.reserve(32);
let capacity = g.buf.capacity();
g.buf.set_len(capacity);
rd.initializer().initialize(&mut g.buf[g.len..]);
}
}
match futures::ready!(rd.as_mut().poll_read(cx, &mut g.buf[g.len..])) {
Ok(0) => {
ret = Poll::Ready(Ok(g.len - start_len));
break;
}
Ok(n) => g.len += n,
Err(e) => {
ret = Poll::Ready(Err(e));
break;
}
}
}
ret
}

@ -0,0 +1,83 @@
use std::io::SeekFrom;
use std::pin::Pin;
use cfg_if::cfg_if;
use futures::io::AsyncSeek;
use crate::future::Future;
use crate::io;
use crate::task::{Context, Poll};
cfg_if! {
if #[cfg(feature = "docs")] {
#[doc(hidden)]
pub struct ImplFuture<'a, T>(std::marker::PhantomData<&'a T>);
macro_rules! ret {
($a:lifetime, $f:tt, $o:ty) => (ImplFuture<$a, $o>);
}
} else {
macro_rules! ret {
($a:lifetime, $f:tt, $o:ty) => ($f<$a, Self>);
}
}
}
/// Allows seeking through a byte stream.
///
/// This trait is an async version of [`std::io::Seek`].
///
/// While it is currently not possible to implement this trait directly, it gets implemented
/// automatically for all types that implement [`futures::io::AsyncSeek`].
///
/// [`std::io::Seek`]: https://doc.rust-lang.org/std/io/trait.Seek.html
/// [`futures::io::AsyncSeek`]:
/// https://docs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncSeek.html
pub trait Seek {
/// Seeks to a new position in a byte stream.
///
/// Returns the new position in the byte stream.
///
/// A seek beyond the end of stream is allowed, but behavior is defined by the
/// implementation.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs::File, io::SeekFrom, prelude::*};
///
/// let mut f = File::open("a.txt").await?;
///
/// let file_len = f.seek(SeekFrom::End(0)).await?;
/// #
/// # Ok(()) }) }
/// ```
fn seek(&mut self, pos: SeekFrom) -> ret!('_, SeekFuture, io::Result<u64>)
where
Self: Unpin;
}
impl<T: AsyncSeek + Unpin + ?Sized> Seek for T {
fn seek(&mut self, pos: SeekFrom) -> ret!('_, SeekFuture, io::Result<u64>) {
SeekFuture { seeker: self, pos }
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct SeekFuture<'a, T: Unpin + ?Sized> {
seeker: &'a mut T,
pos: SeekFrom,
}
impl<T: AsyncSeek + Unpin + ?Sized> Future for SeekFuture<'_, T> {
type Output = io::Result<u64>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let pos = self.pos;
Pin::new(&mut *self.seeker).poll_seek(cx, pos)
}
}

@ -1,13 +1,11 @@
use std::future::Future;
use std::io;
use std::pin::Pin;
use std::sync::Mutex;
use std::task::{Context, Poll};
use cfg_if::cfg_if;
use futures::prelude::*;
use crate::task::blocking;
use crate::future::Future;
use crate::task::{blocking, Context, Poll};
/// Constructs a new handle to the standard error of the current process.
///
@ -19,14 +17,14 @@ use crate::task::blocking;
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::io::stderr;
/// use async_std::prelude::*;
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{io, prelude::*};
///
/// # futures::executor::block_on(async {
/// let mut stderr = stderr();
/// let mut stderr = io::stderr();
/// stderr.write_all(b"Hello, world!").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn stderr() -> Stderr {
Stderr(Mutex::new(State::Idle(Some(Inner {
@ -81,7 +79,7 @@ enum Operation {
Flush(io::Result<()>),
}
impl AsyncWrite for Stderr {
impl futures::io::AsyncWrite for Stderr {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
@ -165,7 +163,7 @@ impl AsyncWrite for Stderr {
}
cfg_if! {
if #[cfg(feature = "docs.rs")] {
if #[cfg(feature = "docs")] {
use crate::os::unix::io::{AsRawFd, RawFd};
use crate::os::windows::io::{AsRawHandle, RawHandle};
} else if #[cfg(unix)] {
@ -175,9 +173,9 @@ cfg_if! {
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(unix)))]
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs.rs"))] {
if #[cfg(any(unix, feature = "docs"))] {
impl AsRawFd for Stderr {
fn as_raw_fd(&self) -> RawFd {
io::stderr().as_raw_fd()
@ -186,9 +184,9 @@ cfg_if! {
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(unix)))]
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(windows, feature = "docs.rs"))] {
if #[cfg(any(windows, feature = "docs"))] {
impl AsRawHandle for Stderr {
fn as_raw_handle(&self) -> RawHandle {
io::stderr().as_raw_handle()

@ -1,14 +1,13 @@
use std::future::Future;
use std::io;
use std::pin::Pin;
use std::sync::Mutex;
use std::task::{Context, Poll};
use cfg_if::cfg_if;
use futures::future;
use futures::io::Initializer;
use futures::prelude::*;
use crate::task::blocking;
use crate::future::Future;
use crate::task::{blocking, Context, Poll};
/// Constructs a new handle to the standard input of the current process.
///
@ -20,14 +19,15 @@ use crate::task::blocking;
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::io::stdin;
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::io;
///
/// # futures::executor::block_on(async {
/// let stdin = stdin();
/// let stdin = io::stdin();
/// let mut line = String::new();
/// stdin.read_line(&mut line).await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn stdin() -> Stdin {
Stdin(Mutex::new(State::Idle(Some(Inner {
@ -139,7 +139,7 @@ impl Stdin {
}
}
impl AsyncRead for Stdin {
impl futures::io::AsyncRead for Stdin {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
@ -195,7 +195,7 @@ impl AsyncRead for Stdin {
}
cfg_if! {
if #[cfg(feature = "docs.rs")] {
if #[cfg(feature = "docs")] {
use crate::os::unix::io::{AsRawFd, RawFd};
use crate::os::windows::io::{AsRawHandle, RawHandle};
} else if #[cfg(unix)] {
@ -205,9 +205,9 @@ cfg_if! {
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(unix)))]
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs.rs"))] {
if #[cfg(any(unix, feature = "docs"))] {
impl AsRawFd for Stdin {
fn as_raw_fd(&self) -> RawFd {
io::stdin().as_raw_fd()
@ -216,9 +216,9 @@ cfg_if! {
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(unix)))]
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(windows, feature = "docs.rs"))] {
if #[cfg(any(windows, feature = "docs"))] {
impl AsRawHandle for Stdin {
fn as_raw_handle(&self) -> RawHandle {
io::stdin().as_raw_handle()

@ -1,13 +1,11 @@
use std::future::Future;
use std::io;
use std::pin::Pin;
use std::sync::Mutex;
use std::task::{Context, Poll};
use cfg_if::cfg_if;
use futures::prelude::*;
use crate::task::blocking;
use crate::future::Future;
use crate::task::{blocking, Context, Poll};
/// Constructs a new handle to the standard output of the current process.
///
@ -19,14 +17,14 @@ use crate::task::blocking;
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::io::stdout;
/// use async_std::prelude::*;
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{io, prelude::*};
///
/// # futures::executor::block_on(async {
/// let mut stdout = stdout();
/// let mut stdout = io::stdout();
/// stdout.write_all(b"Hello, world!").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn stdout() -> Stdout {
Stdout(Mutex::new(State::Idle(Some(Inner {
@ -81,7 +79,7 @@ enum Operation {
Flush(io::Result<()>),
}
impl AsyncWrite for Stdout {
impl futures::io::AsyncWrite for Stdout {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
@ -165,7 +163,7 @@ impl AsyncWrite for Stdout {
}
cfg_if! {
if #[cfg(feature = "docs.rs")] {
if #[cfg(feature = "docs")] {
use crate::os::unix::io::{AsRawFd, RawFd};
use crate::os::windows::io::{AsRawHandle, RawHandle};
} else if #[cfg(unix)] {
@ -175,9 +173,9 @@ cfg_if! {
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(unix)))]
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs.rs"))] {
if #[cfg(any(unix, feature = "docs"))] {
impl AsRawFd for Stdout {
fn as_raw_fd(&self) -> RawFd {
io::stdout().as_raw_fd()
@ -186,9 +184,9 @@ cfg_if! {
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(unix)))]
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(windows, feature = "docs.rs"))] {
if #[cfg(any(windows, feature = "docs"))] {
impl AsRawHandle for Stdout {
fn as_raw_handle(&self) -> RawHandle {
io::stdout().as_raw_handle()

@ -0,0 +1,215 @@
use std::io::IoSlice;
use std::mem;
use std::pin::Pin;
use cfg_if::cfg_if;
use futures::io::AsyncWrite;
use crate::future::Future;
use crate::io;
use crate::task::{Context, Poll};
cfg_if! {
if #[cfg(feature = "docs")] {
#[doc(hidden)]
pub struct ImplFuture<'a, T>(std::marker::PhantomData<&'a T>);
macro_rules! ret {
($a:lifetime, $f:tt, $o:ty) => (ImplFuture<$a, $o>);
}
} else {
macro_rules! ret {
($a:lifetime, $f:tt, $o:ty) => ($f<$a, Self>);
}
}
}
/// Allows writing to a byte stream.
///
/// This trait is an async version of [`std::io::Write`].
///
/// While it is currently not possible to implement this trait directly, it gets implemented
/// automatically for all types that implement [`futures::io::AsyncWrite`].
///
/// [`std::io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
/// [`futures::io::AsyncWrite`]:
/// https://docs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncWrite.html
pub trait Write {
/// Writes some bytes into the byte stream.
///
/// Returns the number of bytes written from the start of the buffer.
///
/// If the return value is `Ok(n)` then it must be guaranteed that `0 <= n <= buf.len()`. A
/// return value of `0` typically means that the underlying object is no longer able to accept
/// bytes and will likely not be able to in the future as well, or that the buffer provided is
/// empty.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs::File, prelude::*};
///
/// let mut f = File::create("a.txt").await?;
///
/// let n = f.write(b"hello world").await?;
/// #
/// # Ok(()) }) }
/// ```
fn write<'a>(&'a mut self, buf: &'a [u8]) -> ret!('a, WriteFuture, io::Result<usize>)
where
Self: Unpin;
/// Flushes the stream to ensure that all buffered contents reach their destination.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs::File, prelude::*};
///
/// let mut f = File::create("a.txt").await?;
///
/// f.write_all(b"hello world").await?;
/// f.flush().await?;
/// #
/// # Ok(()) }) }
/// ```
fn flush(&mut self) -> ret!('_, FlushFuture, io::Result<()>)
where
Self: Unpin;
/// Like [`write`], except that it writes from a slice of buffers.
///
/// Data is copied from each buffer in order, with the final buffer read from possibly being
/// only partially consumed. This method must behave as a call to [`write`] with the buffers
/// concatenated would.
///
/// The default implementation calls [`write`] with either the first nonempty buffer provided,
/// or an empty one if none exists.
///
/// [`write`]: #tymethod.write
fn write_vectored<'a>(
&'a mut self,
bufs: &'a [IoSlice<'a>],
) -> ret!('a, WriteVectoredFuture, io::Result<usize>)
where
Self: Unpin,
{
WriteVectoredFuture { writer: self, bufs }
}
/// Writes an entire buffer into the byte stream.
///
/// This method will continuously call [`write`] until there is no more data to be written or
/// an error is returned. This method will not return until the entire buffer has been
/// successfully written or such an error occurs.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{fs::File, prelude::*};
///
/// let mut f = File::create("a.txt").await?;
///
/// f.write_all(b"hello world").await?;
/// #
/// # Ok(()) }) }
/// ```
fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> ret!('a, WriteAllFuture, io::Result<()>)
where
Self: Unpin,
{
WriteAllFuture { writer: self, buf }
}
}
impl<T: AsyncWrite + Unpin + ?Sized> Write for T {
fn write<'a>(&'a mut self, buf: &'a [u8]) -> ret!('a, WriteFuture, io::Result<usize>) {
WriteFuture { writer: self, buf }
}
fn flush(&mut self) -> ret!('_, FlushFuture, io::Result<()>) {
FlushFuture { writer: self }
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct WriteFuture<'a, T: Unpin + ?Sized> {
writer: &'a mut T,
buf: &'a [u8],
}
impl<T: AsyncWrite + Unpin + ?Sized> Future for WriteFuture<'_, T> {
type Output = io::Result<usize>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let buf = self.buf;
Pin::new(&mut *self.writer).poll_write(cx, buf)
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct FlushFuture<'a, T: Unpin + ?Sized> {
writer: &'a mut T,
}
impl<T: AsyncWrite + Unpin + ?Sized> Future for FlushFuture<'_, T> {
type Output = io::Result<()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Pin::new(&mut *self.writer).poll_flush(cx)
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct WriteVectoredFuture<'a, T: Unpin + ?Sized> {
writer: &'a mut T,
bufs: &'a [IoSlice<'a>],
}
impl<T: AsyncWrite + Unpin + ?Sized> Future for WriteVectoredFuture<'_, T> {
type Output = io::Result<usize>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let bufs = self.bufs;
Pin::new(&mut *self.writer).poll_write_vectored(cx, bufs)
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct WriteAllFuture<'a, T: Unpin + ?Sized> {
writer: &'a mut T,
buf: &'a [u8],
}
impl<T: AsyncWrite + Unpin + ?Sized> Future for WriteAllFuture<'_, T> {
type Output = io::Result<()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let Self { writer, buf } = &mut *self;
while !buf.is_empty() {
let n = futures::ready!(Pin::new(&mut **writer).poll_write(cx, buf))?;
let (_, rest) = mem::replace(buf, &[]).split_at(n);
*buf = rest;
if n == 0 {
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
}
}
Poll::Ready(Ok(()))
}
}

@ -1,4 +1,4 @@
//! Asynchronous standard library.
//! Async version of the Rust standard library.
//!
//! This crate is an async version of [`std`].
//!
@ -20,9 +20,9 @@
//! ```
#![feature(async_await)]
#![cfg_attr(feature = "docs.rs", feature(doc_cfg))]
#![cfg_attr(feature = "docs", feature(doc_cfg))]
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
#![doc(html_playground_url = "https://play.rust-lang.org")]
#![doc(html_logo_url = "https://async.rs/images/logo--hero.svg")]
pub mod fs;
pub mod future;

@ -1,15 +1,16 @@
use std::fmt;
use std::io::{self, prelude::*};
use std::io::{Read as _, Write as _};
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll, Waker};
use futures::{prelude::*, ready};
use futures::io::{AsyncRead, AsyncWrite};
use lazy_static::lazy_static;
use mio::{self, Evented};
use slab::Slab;
use crate::io;
use crate::task::{Context, Poll, Waker};
use crate::utils::abort_on_panic;
/// Data associated with a registered I/O handle.
@ -296,13 +297,13 @@ impl<T: Evented + fmt::Debug> fmt::Debug for IoHandle<T> {
}
}
impl<T: Evented + Unpin + Read> AsyncRead for IoHandle<T> {
impl<T: Evented + std::io::Read + Unpin> AsyncRead for IoHandle<T> {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
ready!(Pin::new(&mut *self).poll_readable(cx)?);
futures::ready!(Pin::new(&mut *self).poll_readable(cx)?);
match self.source.read(buf) {
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
@ -316,14 +317,14 @@ impl<T: Evented + Unpin + Read> AsyncRead for IoHandle<T> {
impl<'a, T: Evented + Unpin> AsyncRead for &'a IoHandle<T>
where
&'a T: Read,
&'a T: std::io::Read,
{
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
ready!(Pin::new(&mut *self).poll_readable(cx)?);
futures::ready!(Pin::new(&mut *self).poll_readable(cx)?);
match (&self.source).read(buf) {
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
@ -335,13 +336,13 @@ where
}
}
impl<T: Evented + Unpin + Write> AsyncWrite for IoHandle<T> {
impl<T: Evented + std::io::Write + Unpin> AsyncWrite for IoHandle<T> {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
ready!(self.poll_writable(cx)?);
futures::ready!(self.poll_writable(cx)?);
match self.source.write(buf) {
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
@ -353,7 +354,7 @@ impl<T: Evented + Unpin + Write> AsyncWrite for IoHandle<T> {
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
ready!(self.poll_writable(cx)?);
futures::ready!(self.poll_writable(cx)?);
match self.source.flush() {
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
@ -371,14 +372,14 @@ impl<T: Evented + Unpin + Write> AsyncWrite for IoHandle<T> {
impl<'a, T: Evented + Unpin> AsyncWrite for &'a IoHandle<T>
where
&'a T: Write,
&'a T: std::io::Write,
{
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
ready!(self.poll_writable(cx)?);
futures::ready!(self.poll_writable(cx)?);
match (&self.source).write(buf) {
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
@ -390,7 +391,7 @@ where
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
ready!(self.poll_writable(cx)?);
futures::ready!(self.poll_writable(cx)?);
match (&self.source).flush() {
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {

@ -14,17 +14,19 @@
//!
//! ```no_run
//! # #![feature(async_await)]
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! use async_std::net::UdpSocket;
//!
//! # futures::executor::block_on(async {
//! let socket = UdpSocket::bind("127.0.0.1:8080").await?;
//! let mut buf = vec![0u8; 1024];
//!
//! loop {
//! let (n, peer) = socket.recv_from(&mut buf).await?;
//! socket.send_to(&buf[..n], &peer).await?;
//! }
//! # std::io::Result::Ok(())
//! # }).unwrap();
//! #
//! # Ok(()) }) }
//! ```
pub use tcp::{Incoming, TcpListener, TcpStream};

@ -0,0 +1,317 @@
use std::net::{self, SocketAddr, ToSocketAddrs};
use std::pin::Pin;
use cfg_if::cfg_if;
use futures::future;
use super::TcpStream;
use crate::future::Future;
use crate::io;
use crate::net::driver::IoHandle;
use crate::task::{Context, Poll};
/// A TCP socket server, listening for connections.
///
/// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens for incoming
/// TCP connections. These can be accepted by awaiting elements from the async stream of
/// [`incoming`] connections.
///
/// The socket will be closed when the value is dropped.
///
/// The Transmission Control Protocol is specified in [IETF RFC 793].
///
/// This type is an async version of [`std::net::TcpListener`].
///
/// [`bind`]: #method.bind
/// [`incoming`]: #method.incoming
/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
/// [`std::net::TcpListener`]: https://doc.rust-lang.org/std/net/struct.TcpListener.html
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{io, net::TcpListener, prelude::*};
///
/// let listener = TcpListener::bind("127.0.0.1:8080").await?;
/// let mut incoming = listener.incoming();
///
/// while let Some(stream) = incoming.next().await {
/// let stream = stream?;
/// let (reader, writer) = &mut (&stream, &stream);
/// io::copy(reader, writer).await?;
/// }
/// #
/// # Ok(()) }) }
/// ```
#[derive(Debug)]
pub struct TcpListener {
io_handle: IoHandle<mio::net::TcpListener>,
#[cfg(unix)]
raw_fd: std::os::unix::io::RawFd,
// #[cfg(windows)]
// raw_socket: std::os::windows::io::RawSocket,
}
impl TcpListener {
/// Creates a new `TcpListener` which will be bound to the specified address.
///
/// The returned listener is ready for accepting connections.
///
/// Binding with a port number of 0 will request that the OS assigns a port to this listener.
/// The port allocated can be queried via the [`local_addr`] method.
///
/// # Examples
/// Create a TCP listener bound to 127.0.0.1:0:
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::TcpListener;
///
/// let listener = TcpListener::bind("127.0.0.1:0").await?;
/// #
/// # Ok(()) }) }
/// ```
///
/// [`local_addr`]: #method.local_addr
pub async fn bind<A: ToSocketAddrs>(addrs: A) -> io::Result<TcpListener> {
let mut last_err = None;
for addr in addrs.to_socket_addrs()? {
match mio::net::TcpListener::bind(&addr) {
Ok(mio_listener) => {
#[cfg(unix)]
let listener = TcpListener {
raw_fd: mio_listener.as_raw_fd(),
io_handle: IoHandle::new(mio_listener),
};
#[cfg(windows)]
let listener = TcpListener {
// raw_socket: mio_listener.as_raw_socket(),
io_handle: IoHandle::new(mio_listener),
};
return Ok(listener);
}
Err(err) => last_err = Some(err),
}
}
Err(last_err.unwrap_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"could not resolve to any addresses",
)
}))
}
/// Accepts a new incoming connection to this listener.
///
/// When a connection is established, the corresponding stream and address will be returned.
///
/// ## Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::TcpListener;
///
/// let listener = TcpListener::bind("127.0.0.1:0").await?;
/// let (stream, addr) = listener.accept().await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
future::poll_fn(|cx| {
futures::ready!(self.io_handle.poll_readable(cx)?);
match self.io_handle.get_ref().accept_std() {
Ok((io, addr)) => {
let mio_stream = mio::net::TcpStream::from_stream(io)?;
#[cfg(unix)]
let stream = TcpStream {
raw_fd: mio_stream.as_raw_fd(),
io_handle: IoHandle::new(mio_stream),
};
#[cfg(windows)]
let stream = TcpStream {
// raw_socket: mio_stream.as_raw_socket(),
io_handle: IoHandle::new(mio_stream),
};
Poll::Ready(Ok((stream, addr)))
}
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
self.io_handle.clear_readable(cx)?;
Poll::Pending
}
Err(err) => Poll::Ready(Err(err)),
}
})
.await
}
/// Returns a stream of incoming connections.
///
/// Iterating over this stream is equivalent to calling [`accept`] in a loop. The stream of
/// connections is infinite, i.e awaiting the next connection will never result in [`None`].
///
/// [`accept`]: #method.accept
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
///
/// ## Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{net::TcpListener, prelude::*};
///
/// let listener = TcpListener::bind("127.0.0.1:0").await?;
/// let mut incoming = listener.incoming();
///
/// while let Some(stream) = incoming.next().await {
/// let mut stream = stream?;
/// stream.write_all(b"hello world").await?;
/// }
/// #
/// # Ok(()) }) }
/// ```
pub fn incoming(&self) -> Incoming<'_> {
Incoming(self)
}
/// Returns the local address that this listener is bound to.
///
/// This can be useful, for example, to identify when binding to port 0 which port was assigned
/// by the OS.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::TcpListener;
///
/// let listener = TcpListener::bind("127.0.0.1:8080").await?;
/// let addr = listener.local_addr()?;
/// #
/// # Ok(()) }) }
/// ```
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().local_addr()
}
}
/// A stream of incoming TCP connections.
///
/// This stream is infinite, i.e awaiting the next connection will never result in [`None`]. It is
/// created by the [`incoming`] method on [`TcpListener`].
///
/// This type is an async version of [`std::net::Incoming`].
///
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
/// [`incoming`]: struct.TcpListener.html#method.incoming
/// [`TcpListener`]: struct.TcpListener.html
/// [`std::net::Incoming`]: https://doc.rust-lang.org/std/net/struct.Incoming.html
#[derive(Debug)]
pub struct Incoming<'a>(&'a TcpListener);
impl<'a> futures::Stream for Incoming<'a> {
type Item = io::Result<TcpStream>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let future = self.0.accept();
pin_utils::pin_mut!(future);
let (socket, _) = futures::ready!(future.poll(cx))?;
Poll::Ready(Some(Ok(socket)))
}
}
impl From<net::TcpListener> for TcpListener {
/// Converts a `std::net::TcpListener` into its asynchronous equivalent.
fn from(listener: net::TcpListener) -> TcpListener {
let mio_listener = mio::net::TcpListener::from_std(listener).unwrap();
#[cfg(unix)]
let listener = TcpListener {
raw_fd: mio_listener.as_raw_fd(),
io_handle: IoHandle::new(mio_listener),
};
#[cfg(windows)]
let listener = TcpListener {
// raw_socket: mio_listener.as_raw_socket(),
io_handle: IoHandle::new(mio_listener),
};
listener
}
}
cfg_if! {
if #[cfg(feature = "docs")] {
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
} else if #[cfg(unix)] {
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
} else if #[cfg(windows)] {
// use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
}
}
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs"))] {
impl AsRawFd for TcpListener {
fn as_raw_fd(&self) -> RawFd {
self.raw_fd
}
}
impl FromRawFd for TcpListener {
unsafe fn from_raw_fd(fd: RawFd) -> TcpListener {
net::TcpListener::from_raw_fd(fd).into()
}
}
impl IntoRawFd for TcpListener {
fn into_raw_fd(self) -> RawFd {
self.raw_fd
}
}
}
}
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
cfg_if! {
if #[cfg(any(windows, feature = "docs"))] {
// impl AsRawSocket for TcpListener {
// fn as_raw_socket(&self) -> RawSocket {
// self.raw_socket
// }
// }
//
// impl FromRawSocket for TcpListener {
// unsafe fn from_raw_socket(handle: RawSocket) -> TcpListener {
// net::TcpListener::from_raw_socket(handle).try_into().unwrap()
// }
// }
//
// impl IntoRawSocket for TcpListener {
// fn into_raw_socket(self) -> RawSocket {
// self.raw_socket
// }
// }
}
}

@ -0,0 +1,5 @@
pub use listener::{Incoming, TcpListener};
pub use stream::TcpStream;
mod listener;
mod stream;

@ -1,13 +1,14 @@
use std::io::{self, IoSlice, IoSliceMut};
use std::io::{IoSlice, IoSliceMut};
use std::mem;
use std::net::{self, SocketAddr, ToSocketAddrs};
use std::pin::Pin;
use std::task::{Context, Poll};
use cfg_if::cfg_if;
use futures::{prelude::*, ready};
use futures::future;
use crate::io;
use crate::net::driver::IoHandle;
use crate::task::{Context, Poll};
/// A TCP stream between a local and a remote socket.
///
@ -23,9 +24,9 @@ use crate::net::driver::IoHandle;
/// [`connect`]: struct.TcpStream.html#method.connect
/// [accepting]: struct.TcpListener.html#method.accept
/// [listener]: struct.TcpListener.html
/// [`AsyncRead`]: https://docs.rs/futures-preview/0.3.0-alpha.13/futures/io/trait.AsyncRead.html
/// [`AsyncWrite`]: https://docs.rs/futures-preview/0.3.0-alpha.13/futures/io/trait.AsyncRead.html
/// [`futures::io`]: https://docs.rs/futures-preview/0.3.0-alpha.13/futures/io
/// [`AsyncRead`]: https://docs/futures-preview/0.3.0-alpha.13/futures/io/trait.AsyncRead.html
/// [`AsyncWrite`]: https://docs/futures-preview/0.3.0-alpha.13/futures/io/trait.AsyncRead.html
/// [`futures::io`]: https://docs/futures-preview/0.3.0-alpha.13/futures/io
/// [`shutdown`]: struct.TcpStream.html#method.shutdown
/// [`std::net::TcpStream`]: https://doc.rust-lang.org/std/net/struct.TcpStream.html
///
@ -33,31 +34,26 @@ use crate::net::driver::IoHandle;
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::net::TcpStream;
/// use async_std::prelude::*;
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{net::TcpStream, prelude::*};
///
/// # futures::executor::block_on(async {
/// let mut stream = TcpStream::connect("127.0.0.1:8080").await?;
/// println!("Connected to {}", &stream.peer_addr()?);
///
/// let msg = "hello world";
/// println!("<- {}", msg);
/// stream.write_all(msg.as_bytes()).await?;
/// stream.write_all(b"hello world").await?;
///
/// let mut buf = vec![0u8; 1024];
/// let n = stream.read(&mut buf).await?;
/// println!("-> {}\n", std::str::from_utf8(&buf[..n])?);
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
#[derive(Debug)]
pub struct TcpStream {
io_handle: IoHandle<mio::net::TcpStream>,
pub(super) io_handle: IoHandle<mio::net::TcpStream>,
#[cfg(unix)]
raw_fd: std::os::unix::io::RawFd,
pub(super) raw_fd: std::os::unix::io::RawFd,
// #[cfg(windows)]
// raw_socket: std::os::windows::io::RawSocket,
// pub(super) raw_socket: std::os::windows::io::RawSocket,
}
impl TcpStream {
@ -73,12 +69,13 @@ impl TcpStream {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::TcpStream;
///
/// # futures::executor::block_on(async {
/// let stream = TcpStream::connect("127.0.0.1:0").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn connect<A: ToSocketAddrs>(addrs: A) -> io::Result<TcpStream> {
enum State {
@ -157,16 +154,14 @@ impl TcpStream {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::TcpStream;
/// use std::net::{IpAddr, Ipv4Addr};
///
/// # futures::executor::block_on(async {
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// let expected = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
/// assert_eq!(stream.local_addr()?.ip(), expected);
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// let addr = stream.local_addr()?;
/// #
/// # Ok(()) }) }
/// ```
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().local_addr()
@ -178,16 +173,14 @@ impl TcpStream {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::TcpStream;
/// use std::net::{IpAddr, Ipv4Addr};
///
/// # futures::executor::block_on(async {
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// let expected = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
/// assert_eq!(stream.peer_addr()?.ip(), expected);
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// let peer = stream.peer_addr()?;
/// #
/// # Ok(()) }) }
/// ```
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().peer_addr()
@ -203,15 +196,16 @@ impl TcpStream {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::TcpStream;
///
/// # futures::executor::block_on(async {
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// stream.set_ttl(100)?;
/// assert_eq!(stream.ttl()?, 100);
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn ttl(&self) -> io::Result<u32> {
self.io_handle.get_ref().ttl()
@ -226,22 +220,25 @@ impl TcpStream {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::TcpStream;
///
/// # futures::executor::block_on(async {
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// stream.set_ttl(100)?;
/// assert_eq!(stream.ttl()?, 100);
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
self.io_handle.get_ref().set_ttl(ttl)
}
/// Receives data on the socket from the remote address to which it is connected, without
/// removing that data from the queue. On success, returns the number of bytes peeked.
/// removing that data from the queue.
///
/// On success, returns the number of bytes peeked.
///
/// Successive calls return the same data. This is accomplished by passing `MSG_PEEK` as a flag
/// to the underlying `recv` system call.
@ -250,19 +247,21 @@ impl TcpStream {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::TcpStream;
///
/// # futures::executor::block_on(async {
/// let stream = TcpStream::connect("127.0.0.1:8000").await?;
///
/// let mut buf = [0; 10];
/// let len = stream.peek(&mut buf).await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// let mut buf = vec![0; 1024];
/// let n = stream.peek(&mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
let res = future::poll_fn(|cx| {
ready!(self.io_handle.poll_readable(cx)?);
futures::ready!(self.io_handle.poll_readable(cx)?);
match self.io_handle.get_ref().peek(buf) {
Ok(len) => Poll::Ready(Ok(len)),
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
@ -286,15 +285,16 @@ impl TcpStream {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::TcpStream;
///
/// # futures::executor::block_on(async {
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// stream.set_nodelay(true)?;
/// assert_eq!(stream.nodelay()?, true);
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn nodelay(&self) -> io::Result<bool> {
self.io_handle.get_ref().nodelay()
@ -312,15 +312,16 @@ impl TcpStream {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::TcpStream;
///
/// # futures::executor::block_on(async {
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
///
/// stream.set_nodelay(true)?;
/// assert_eq!(stream.nodelay()?, true);
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
self.io_handle.get_ref().set_nodelay(nodelay)
@ -337,21 +338,22 @@ impl TcpStream {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::TcpStream;
/// use std::net::Shutdown;
///
/// # futures::executor::block_on(async {
/// let stream = TcpStream::connect("127.0.0.1:8080").await?;
/// stream.shutdown(Shutdown::Both)?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn shutdown(&self, how: std::net::Shutdown) -> std::io::Result<()> {
self.io_handle.get_ref().shutdown(how)
}
}
impl AsyncRead for TcpStream {
impl futures::io::AsyncRead for TcpStream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
@ -369,7 +371,7 @@ impl AsyncRead for TcpStream {
}
}
impl AsyncRead for &TcpStream {
impl futures::io::AsyncRead for &TcpStream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
@ -387,7 +389,7 @@ impl AsyncRead for &TcpStream {
}
}
impl AsyncWrite for TcpStream {
impl futures::io::AsyncWrite for TcpStream {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
@ -413,7 +415,7 @@ impl AsyncWrite for TcpStream {
}
}
impl AsyncWrite for &TcpStream {
impl futures::io::AsyncWrite for &TcpStream {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
@ -439,238 +441,6 @@ impl AsyncWrite for &TcpStream {
}
}
/// A TCP socket server, listening for connections.
///
/// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens for incoming
/// TCP connections. These can be accepted by awaiting elements from the async stream of
/// [`incoming`] connections.
///
/// The socket will be closed when the value is dropped.
///
/// The Transmission Control Protocol is specified in [IETF RFC 793].
///
/// This type is an async version of [`std::net::TcpListener`].
///
/// [`bind`]: #method.bind
/// [`incoming`]: #method.incoming
/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
/// [`std::net::TcpListener`]: https://doc.rust-lang.org/std/net/struct.TcpListener.html
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::io;
/// use async_std::net::TcpListener;
/// use async_std::prelude::*;
///
/// # futures::executor::block_on(async {
/// let listener = TcpListener::bind("127.0.0.1:8080").await?;
/// println!("Listening on {}", listener.local_addr()?);
///
/// let mut incoming = listener.incoming();
/// while let Some(stream) = incoming.next().await {
/// let stream = stream?;
/// println!("Accepting from: {}", stream.peer_addr()?);
///
/// let (reader, writer) = &mut (&stream, &stream);
/// io::copy(reader, writer).await?;
/// }
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
#[derive(Debug)]
pub struct TcpListener {
io_handle: IoHandle<mio::net::TcpListener>,
#[cfg(unix)]
raw_fd: std::os::unix::io::RawFd,
// #[cfg(windows)]
// raw_socket: std::os::windows::io::RawSocket,
}
impl TcpListener {
/// Creates a new `TcpListener` which will be bound to the specified address.
///
/// The returned listener is ready for accepting connections.
///
/// Binding with a port number of 0 will request that the OS assigns a port to this listener.
/// The port allocated can be queried via the [`local_addr`] method.
///
/// # Examples
/// Create a TCP listener bound to 127.0.0.1:0:
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::net::TcpListener;
///
/// # futures::executor::block_on(async {
/// let listener = TcpListener::bind("127.0.0.1:0").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
///
/// [`local_addr`]: #method.local_addr
pub async fn bind<A: ToSocketAddrs>(addrs: A) -> io::Result<TcpListener> {
let mut last_err = None;
for addr in addrs.to_socket_addrs()? {
match mio::net::TcpListener::bind(&addr) {
Ok(mio_listener) => {
#[cfg(unix)]
let listener = TcpListener {
raw_fd: mio_listener.as_raw_fd(),
io_handle: IoHandle::new(mio_listener),
};
#[cfg(windows)]
let listener = TcpListener {
// raw_socket: mio_listener.as_raw_socket(),
io_handle: IoHandle::new(mio_listener),
};
return Ok(listener);
}
Err(err) => last_err = Some(err),
}
}
Err(last_err.unwrap_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"could not resolve to any addresses",
)
}))
}
/// Accepts a new incoming connection to this listener.
///
/// When a connection is established, the corresponding stream and address will be returned.
///
/// ## Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::net::TcpListener;
///
/// # futures::executor::block_on(async {
/// let listener = TcpListener::bind("127.0.0.1:0").await?;
/// let (stream, addr) = listener.accept().await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
future::poll_fn(|cx| {
ready!(self.io_handle.poll_readable(cx)?);
match self.io_handle.get_ref().accept_std() {
Ok((io, addr)) => {
let mio_stream = mio::net::TcpStream::from_stream(io)?;
#[cfg(unix)]
let stream = TcpStream {
raw_fd: mio_stream.as_raw_fd(),
io_handle: IoHandle::new(mio_stream),
};
#[cfg(windows)]
let stream = TcpStream {
// raw_socket: mio_stream.as_raw_socket(),
io_handle: IoHandle::new(mio_stream),
};
Poll::Ready(Ok((stream, addr)))
}
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
self.io_handle.clear_readable(cx)?;
Poll::Pending
}
Err(err) => Poll::Ready(Err(err)),
}
})
.await
}
/// Returns a stream of incoming connections.
///
/// Iterating over this stream is equivalent to calling [`accept`] in a loop. The stream of
/// connections is infinite, i.e awaiting the next connection will never result in [`None`].
///
/// [`accept`]: #method.accept
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
///
/// ## Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::net::TcpListener;
/// use async_std::prelude::*;
///
/// # futures::executor::block_on(async {
/// let listener = TcpListener::bind("127.0.0.1:0").await?;
/// let mut incoming = listener.incoming();
///
/// while let Some(stream) = incoming.next().await {
/// let mut stream = stream?;
/// stream.write_all(b"hello world").await?;
/// }
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub fn incoming(&self) -> Incoming<'_> {
Incoming(self)
}
/// Returns the local address that this listener is bound to.
///
/// This can be useful, for example, to identify when binding to port 0 which port was assigned
/// by the OS.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::net::TcpListener;
/// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
///
/// # futures::executor::block_on(async {
/// let listener = TcpListener::bind("127.0.0.1:8080").await?;
///
/// let expected = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
/// assert_eq!(listener.local_addr()?, SocketAddr::V4(expected));
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().local_addr()
}
}
/// A stream of incoming TCP connections.
///
/// This stream is infinite, i.e awaiting the next connection will never result in [`None`]. It is
/// created by the [`incoming`] method on [`TcpListener`].
///
/// This type is an async version of [`std::net::Incoming`].
///
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
/// [`incoming`]: struct.TcpListener.html#method.incoming
/// [`TcpListener`]: struct.TcpListener.html
/// [`std::net::Incoming`]: https://doc.rust-lang.org/std/net/struct.Incoming.html
#[derive(Debug)]
pub struct Incoming<'a>(&'a TcpListener);
impl<'a> Stream for Incoming<'a> {
type Item = io::Result<TcpStream>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let future = self.0.accept();
pin_utils::pin_mut!(future);
let (socket, _) = ready!(future.poll(cx))?;
Poll::Ready(Some(Ok(socket)))
}
}
impl From<net::TcpStream> for TcpStream {
/// Converts a `std::net::TcpStream` into its asynchronous equivalent.
fn from(stream: net::TcpStream) -> TcpStream {
@ -692,29 +462,8 @@ impl From<net::TcpStream> for TcpStream {
}
}
impl From<net::TcpListener> for TcpListener {
/// Converts a `std::net::TcpListener` into its asynchronous equivalent.
fn from(listener: net::TcpListener) -> TcpListener {
let mio_listener = mio::net::TcpListener::from_std(listener).unwrap();
#[cfg(unix)]
let listener = TcpListener {
raw_fd: mio_listener.as_raw_fd(),
io_handle: IoHandle::new(mio_listener),
};
#[cfg(windows)]
let listener = TcpListener {
// raw_socket: mio_listener.as_raw_socket(),
io_handle: IoHandle::new(mio_listener),
};
listener
}
}
cfg_if! {
if #[cfg(feature = "docs.rs")] {
if #[cfg(feature = "docs")] {
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
} else if #[cfg(unix)] {
@ -724,27 +473,9 @@ cfg_if! {
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(unix)))]
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs.rs"))] {
impl AsRawFd for TcpListener {
fn as_raw_fd(&self) -> RawFd {
self.raw_fd
}
}
impl FromRawFd for TcpListener {
unsafe fn from_raw_fd(fd: RawFd) -> TcpListener {
net::TcpListener::from_raw_fd(fd).into()
}
}
impl IntoRawFd for TcpListener {
fn into_raw_fd(self) -> RawFd {
self.raw_fd
}
}
if #[cfg(any(unix, feature = "docs"))] {
impl AsRawFd for TcpStream {
fn as_raw_fd(&self) -> RawFd {
self.raw_fd
@ -765,27 +496,9 @@ cfg_if! {
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(windows)))]
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
cfg_if! {
if #[cfg(any(windows, feature = "docs.rs"))] {
// impl AsRawSocket for TcpListener {
// fn as_raw_socket(&self) -> RawSocket {
// self.raw_socket
// }
// }
//
// impl FromRawSocket for TcpListener {
// unsafe fn from_raw_socket(handle: RawSocket) -> TcpListener {
// net::TcpListener::from_raw_socket(handle).try_into().unwrap()
// }
// }
//
// impl IntoRawSocket for TcpListener {
// fn into_raw_socket(self) -> RawSocket {
// self.raw_socket
// }
// }
//
if #[cfg(any(windows, feature = "docs"))] {
// impl AsRawSocket for TcpStream {
// fn as_raw_socket(&self) -> RawSocket {
// self.raw_socket

@ -1,11 +1,11 @@
use std::io;
use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
use std::task::Poll;
use cfg_if::cfg_if;
use futures::{prelude::*, ready};
use futures::future;
use crate::net::driver::IoHandle;
use crate::task::Poll;
/// A UDP socket.
///
@ -30,21 +30,19 @@ use crate::net::driver::IoHandle;
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::UdpSocket;
///
/// # futures::executor::block_on(async {
/// let socket = UdpSocket::bind("127.0.0.1:8080").await?;
/// let mut buf = vec![0u8; 1024];
///
/// println!("Listening on {}", socket.local_addr()?);
///
/// loop {
/// let (n, peer) = socket.recv_from(&mut buf).await?;
/// let sent = socket.send_to(&buf[..n], &peer).await?;
/// println!("Sent {} out of {} bytes to {}", sent, n, peer);
/// socket.send_to(&buf[..n], &peer).await?;
/// }
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
#[derive(Debug)]
pub struct UdpSocket {
@ -68,12 +66,13 @@ impl UdpSocket {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::UdpSocket;
///
/// # futures::executor::block_on(async {
/// let socket = UdpSocket::bind("127.0.0.1:0").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
let mut last_err = None;
@ -116,13 +115,15 @@ impl UdpSocket {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::UdpSocket;
/// use std::net::IpAddr;
///
/// # futures::executor::block_on(async {
/// let socket = UdpSocket::bind("127.0.0.1:0").await?;
/// println!("Address: {:?}", socket.local_addr());
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// let addr = socket.local_addr()?;
/// #
/// # Ok(()) }) }
/// ```
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().local_addr()
@ -136,6 +137,8 @@ impl UdpSocket {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::UdpSocket;
///
/// const THE_MERCHANT_OF_VENICE: &[u8] = b"
@ -145,14 +148,13 @@ impl UdpSocket {
/// And if you wrong us, shall we not revenge?
/// ";
///
/// # futures::executor::block_on(async {
/// let socket = UdpSocket::bind("127.0.0.1:0").await?;
///
/// let addr = "127.0.0.1:7878";
/// let sent = socket.send_to(THE_MERCHANT_OF_VENICE, &addr).await?;
/// println!("Sent {} bytes to {}", sent, addr);
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addrs: A) -> io::Result<usize> {
let addr = match addrs.to_socket_addrs()?.next() {
@ -166,7 +168,7 @@ impl UdpSocket {
};
future::poll_fn(|cx| {
ready!(self.io_handle.poll_writable(cx)?);
futures::ready!(self.io_handle.poll_writable(cx)?);
match self.io_handle.get_ref().send_to(buf, &addr) {
Ok(n) => Poll::Ready(Ok(n)),
@ -188,20 +190,21 @@ impl UdpSocket {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::UdpSocket;
///
/// # futures::executor::block_on(async {
/// let socket = UdpSocket::bind("127.0.0.1:0").await?;
///
/// let mut buf = vec![0; 1024];
/// let (n, peer) = socket.recv_from(&mut buf).await?;
/// println!("Received {} bytes from {}", n, peer);
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
future::poll_fn(|cx| {
ready!(self.io_handle.poll_readable(cx)?);
futures::ready!(self.io_handle.poll_readable(cx)?);
match self.io_handle.get_ref().recv_from(buf) {
Ok(n) => Poll::Ready(Ok(n)),
@ -229,13 +232,14 @@ impl UdpSocket {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::UdpSocket;
///
/// # futures::executor::block_on(async {
/// let socket = UdpSocket::bind("127.0.0.1:0").await?;
/// socket.connect("127.0.0.1:8080").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn connect<A: ToSocketAddrs>(&self, addrs: A) -> io::Result<()> {
let mut last_err = None;
@ -263,6 +267,8 @@ impl UdpSocket {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::UdpSocket;
///
/// const THE_MERCHANT_OF_VENICE: &[u8] = b"
@ -272,18 +278,17 @@ impl UdpSocket {
/// And if you wrong us, shall we not revenge?
/// ";
///
/// # futures::executor::block_on(async {
/// let socket = UdpSocket::bind("127.0.0.1:0").await?;
///
/// let addr = "127.0.0.1:7878";
/// let sent = socket.send_to(THE_MERCHANT_OF_VENICE, &addr).await?;
/// println!("Sent {} bytes to {}", sent, addr);
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn send(&self, buf: &[u8]) -> io::Result<usize> {
future::poll_fn(|cx| {
ready!(self.io_handle.poll_writable(cx)?);
futures::ready!(self.io_handle.poll_writable(cx)?);
match self.io_handle.get_ref().send(buf) {
Ok(n) => Poll::Ready(Ok(n)),
@ -305,20 +310,21 @@ impl UdpSocket {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::UdpSocket;
///
/// # futures::executor::block_on(async {
/// let socket = UdpSocket::bind("127.0.0.1:0").await?;
///
/// let mut buf = vec![0; 1024];
/// let (n, peer) = socket.recv_from(&mut buf).await?;
/// println!("Received {} bytes from {}", n, peer);
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
future::poll_fn(|cx| {
ready!(self.io_handle.poll_readable(cx)?);
futures::ready!(self.io_handle.poll_readable(cx)?);
match self.io_handle.get_ref().recv(buf) {
Ok(n) => Poll::Ready(Ok(n)),
@ -438,17 +444,18 @@ impl UdpSocket {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::UdpSocket;
/// use std::net::Ipv4Addr;
///
/// # futures::executor::block_on(async {
/// let interface = Ipv4Addr::new(0, 0, 0, 0);
/// let mdns_addr = Ipv4Addr::new(224, 0, 0, 123);
///
/// let socket = UdpSocket::bind("127.0.0.1:0").await?;
/// socket.join_multicast_v4(&mdns_addr, &interface)?;
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
self.io_handle
@ -466,17 +473,18 @@ impl UdpSocket {
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::net::UdpSocket;
/// use std::net::{Ipv6Addr, SocketAddr};
///
/// # futures::executor::block_on(async {
/// let socket_addr = SocketAddr::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).into(), 0);
/// let mdns_addr = Ipv6Addr::new(0xFF02, 0, 0, 0, 0, 0, 0, 0x0123) ;
/// let socket = UdpSocket::bind(&socket_addr).await?;
///
/// socket.join_multicast_v6(&mdns_addr, 0)?;
/// # Ok::<_, Box<dyn std::error::Error>>(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
self.io_handle
@ -529,7 +537,7 @@ impl From<net::UdpSocket> for UdpSocket {
}
cfg_if! {
if #[cfg(feature = "docs.rs")] {
if #[cfg(feature = "docs")] {
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
// use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
} else if #[cfg(unix)] {
@ -539,9 +547,9 @@ cfg_if! {
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(unix)))]
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs.rs"))] {
if #[cfg(any(unix, feature = "docs"))] {
impl AsRawFd for UdpSocket {
fn as_raw_fd(&self) -> RawFd {
self.raw_fd
@ -562,9 +570,9 @@ cfg_if! {
}
}
#[cfg_attr(feature = "docs.rs", doc(cfg(windows)))]
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
cfg_if! {
if #[cfg(any(windows, feature = "docs.rs"))] {
if #[cfg(any(windows, feature = "docs"))] {
// use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
//
// impl AsRawSocket for UdpSocket {

@ -1,9 +1,9 @@
//! OS-specific extensions.
#[cfg(any(unix, feature = "docs.rs"))]
#[cfg_attr(feature = "docs.rs", doc(cfg(unix)))]
#[cfg(any(unix, feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
pub mod unix;
#[cfg(any(windows, feature = "docs.rs"))]
#[cfg_attr(feature = "docs.rs", doc(cfg(windows)))]
#[cfg(any(windows, feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(windows)))]
pub mod windows;

@ -1,10 +1,10 @@
//! Unix-specific filesystem extensions.
use std::io;
use std::path::Path;
use cfg_if::cfg_if;
use crate::io;
use crate::task::blocking;
/// Creates a new symbolic link on the filesystem.
@ -19,12 +19,13 @@ use crate::task::blocking;
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::fs::symlink;
///
/// # futures::executor::block_on(async {
/// symlink("a.txt", "b.txt").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
let src = src.as_ref().to_owned();
@ -33,7 +34,7 @@ pub async fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Resu
}
cfg_if! {
if #[cfg(feature = "docs.rs")] {
if #[cfg(feature = "docs")] {
/// Unix-specific extensions to `DirBuilder`.
pub trait DirBuilderExt {
/// Sets the mode to create new directories with. This option defaults to

@ -3,7 +3,7 @@
use cfg_if::cfg_if;
cfg_if! {
if #[cfg(feature = "docs.rs")] {
if #[cfg(feature = "docs")] {
/// Raw file descriptors.
pub type RawFd = std::os::raw::c_int;

@ -1,985 +0,0 @@
//! Unix-specific networking extensions.
use std::fmt;
use std::io;
use std::mem;
use std::net::Shutdown;
use std::path::Path;
use std::pin::Pin;
use std::task::{Context, Poll};
use cfg_if::cfg_if;
use futures::{prelude::*, ready};
use mio_uds;
use crate::net::driver::IoHandle;
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::task::blocking;
/// A Unix datagram socket.
///
/// After creating a `UnixDatagram` by [`bind`]ing it to a path, data can be [sent to] and
/// [received from] any other socket address.
///
/// This type is an async version of [`std::os::unix::net::UnixDatagram`].
///
/// [`std::os::unix::net::UnixDatagram`]:
/// https://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html
/// [`bind`]: #method.bind
/// [received from]: #method.recv_from
/// [sent to]: #method.send_to
///
/// ## Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixDatagram;
///
/// # futures::executor::block_on(async {
/// let socket = UnixDatagram::bind("/tmp/socket1").await?;
/// socket.send_to(b"hello world", "/tmp/socket2").await?;
///
/// let mut buf = vec![0u8; 1024];
/// let (n, peer) = socket.recv_from(&mut buf).await?;
/// println!("Received {} bytes from {:?}", n, peer);
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub struct UnixDatagram {
#[cfg(not(feature = "docs.rs"))]
io_handle: IoHandle<mio_uds::UnixDatagram>,
raw_fd: RawFd,
}
impl UnixDatagram {
#[cfg(not(feature = "docs.rs"))]
fn new(socket: mio_uds::UnixDatagram) -> UnixDatagram {
UnixDatagram {
raw_fd: socket.as_raw_fd(),
io_handle: IoHandle::new(socket),
}
}
/// Creates a Unix datagram socket bound to the given path.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixDatagram;
///
/// # futures::executor::block_on(async {
/// let socket = UnixDatagram::bind("/tmp/socket").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
let path = path.as_ref().to_owned();
let socket = blocking::spawn(async move { mio_uds::UnixDatagram::bind(path) }).await?;
Ok(UnixDatagram::new(socket))
}
/// Creates a Unix datagram which is not bound to any address.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixDatagram;
///
/// # futures::executor::block_on(async {
/// let socket = UnixDatagram::unbound()?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub fn unbound() -> io::Result<UnixDatagram> {
let socket = mio_uds::UnixDatagram::unbound()?;
Ok(UnixDatagram::new(socket))
}
/// Creates an unnamed pair of connected sockets.
///
/// Returns two sockets which are connected to each other.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixDatagram;
///
/// # futures::executor::block_on(async {
/// let (socket1, socket2) = UnixDatagram::pair()?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
let (a, b) = mio_uds::UnixDatagram::pair()?;
let a = UnixDatagram::new(a);
let b = UnixDatagram::new(b);
Ok((a, b))
}
/// Connects the socket to the specified address.
///
/// The [`send`] method may be used to send data to the specified address. [`recv`] and
/// [`recv_from`] will only receive data from that address.
///
/// [`send`]: #method.send
/// [`recv`]: #method.recv
/// [`recv_from`]: #method.recv_from
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixDatagram;
///
/// # futures::executor::block_on(async {
/// let socket = UnixDatagram::unbound()?;
/// socket.connect("/tmp/socket").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
// TODO(stjepang): Connect the socket on a blocking pool.
let p = path.as_ref();
self.io_handle.get_ref().connect(p)
}
/// Returns the address of this socket.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixDatagram;
///
/// # futures::executor::block_on(async {
/// let socket = UnixDatagram::bind("/tmp/socket").await?;
/// let addr = socket.local_addr()?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().local_addr()
}
/// Returns the address of this socket's peer.
///
/// The [`connect`] method will connect the socket to a peer.
///
/// [`connect`]: #method.connect
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixDatagram;
///
/// # futures::executor::block_on(async {
/// let mut socket = UnixDatagram::unbound()?;
/// socket.connect("/tmp/socket").await?;
/// let peer = socket.peer_addr()?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().peer_addr()
}
/// Receives data from the socket.
///
/// On success, returns the number of bytes read and the address from where the data came.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixDatagram;
///
/// # futures::executor::block_on(async {
/// let mut socket = UnixDatagram::unbound()?;
/// let mut buf = vec![0; 1024];
/// let (n, peer) = socket.recv_from(&mut buf).await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
future::poll_fn(|cx| {
ready!(self.io_handle.poll_readable(cx)?);
match self.io_handle.get_ref().recv_from(buf) {
Ok(n) => Poll::Ready(Ok(n)),
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
self.io_handle.clear_readable(cx)?;
Poll::Pending
}
Err(err) => Poll::Ready(Err(err)),
}
})
.await
}
/// Receives data from the socket.
///
/// On success, returns the number of bytes read.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixDatagram;
///
/// # futures::executor::block_on(async {
/// let socket = UnixDatagram::bind("/tmp/socket").await?;
/// let mut buf = vec![0; 1024];
/// let n = socket.recv(&mut buf).await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
future::poll_fn(|cx| {
ready!(self.io_handle.poll_writable(cx)?);
match self.io_handle.get_ref().recv(buf) {
Ok(n) => Poll::Ready(Ok(n)),
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
self.io_handle.clear_writable(cx)?;
Poll::Pending
}
Err(err) => Poll::Ready(Err(err)),
}
})
.await
}
/// Sends data on the socket to the specified address.
///
/// On success, returns the number of bytes written.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixDatagram;
///
/// # futures::executor::block_on(async {
/// let mut socket = UnixDatagram::unbound()?;
/// socket.send_to(b"hello world", "/tmp/socket").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
future::poll_fn(|cx| {
ready!(self.io_handle.poll_writable(cx)?);
match self.io_handle.get_ref().send_to(buf, path.as_ref()) {
Ok(n) => Poll::Ready(Ok(n)),
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
self.io_handle.clear_writable(cx)?;
Poll::Pending
}
Err(err) => Poll::Ready(Err(err)),
}
})
.await
}
/// Sends data on the socket to the socket's peer.
///
/// On success, returns the number of bytes written.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixDatagram;
///
/// # futures::executor::block_on(async {
/// let mut socket = UnixDatagram::unbound()?;
/// socket.connect("/tmp/socket").await?;
/// socket.send(b"hello world").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn send(&self, buf: &[u8]) -> io::Result<usize> {
future::poll_fn(|cx| {
ready!(self.io_handle.poll_writable(cx)?);
match self.io_handle.get_ref().send(buf) {
Ok(n) => Poll::Ready(Ok(n)),
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
self.io_handle.clear_writable(cx)?;
Poll::Pending
}
Err(err) => Poll::Ready(Err(err)),
}
})
.await
}
/// Shut down the read, write, or both halves of this connection.
///
/// This function will cause all pending and future I/O calls on the specified portions to
/// immediately return with an appropriate value (see the documentation of [`Shutdown`]).
///
/// [`Shutdown`]: https://doc.rust-lang.org/std/net/enum.Shutdown.html
///
/// ## Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixDatagram;
/// use std::net::Shutdown;
///
/// # futures::executor::block_on(async {
/// let socket = UnixDatagram::unbound()?;
/// socket.shutdown(Shutdown::Both)?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
self.io_handle.get_ref().shutdown(how)
}
}
impl fmt::Debug for UnixDatagram {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut builder = f.debug_struct("UnixDatagram");
builder.field("fd", &self.as_raw_fd());
if let Ok(addr) = self.local_addr() {
builder.field("local", &addr);
}
if let Ok(addr) = self.peer_addr() {
builder.field("peer", &addr);
}
builder.finish()
}
}
/// A Unix domain socket server, listening for connections.
///
/// After creating a `UnixListener` by [`bind`]ing it to a socket address, it listens for incoming
/// connections. These can be accepted by awaiting elements from the async stream of [`incoming`]
/// connections.
///
/// The socket will be closed when the value is dropped.
///
/// This type is an async version of [`std::os::unix::net::UnixListener`].
///
/// [`std::os::unix::net::UnixListener`]:
/// https://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html
/// [`bind`]: #method.bind
/// [`incoming`]: #method.incoming
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixListener;
/// use async_std::prelude::*;
///
/// # futures::executor::block_on(async {
/// let listener = UnixListener::bind("/tmp/socket").await?;
/// let mut incoming = listener.incoming();
///
/// while let Some(stream) = incoming.next().await {
/// let mut stream = stream?;
/// stream.write_all(b"hello world").await?;
/// }
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub struct UnixListener {
#[cfg(not(feature = "docs.rs"))]
io_handle: IoHandle<mio_uds::UnixListener>,
raw_fd: RawFd,
}
impl UnixListener {
/// Creates a Unix datagram listener bound to the given path.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixListener;
///
/// # futures::executor::block_on(async {
/// let listener = UnixListener::bind("/tmp/socket").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
let path = path.as_ref().to_owned();
let listener = blocking::spawn(async move { mio_uds::UnixListener::bind(path) }).await?;
Ok(UnixListener {
raw_fd: listener.as_raw_fd(),
io_handle: IoHandle::new(listener),
})
}
/// Accepts a new incoming connection to this listener.
///
/// When a connection is established, the corresponding stream and address will be returned.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixListener;
///
/// # futures::executor::block_on(async {
/// let listener = UnixListener::bind("/tmp/socket").await?;
/// let (socket, addr) = listener.accept().await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
future::poll_fn(|cx| {
ready!(self.io_handle.poll_readable(cx)?);
match self.io_handle.get_ref().accept_std() {
Ok(Some((io, addr))) => {
let mio_stream = mio_uds::UnixStream::from_stream(io)?;
let stream = UnixStream {
raw_fd: mio_stream.as_raw_fd(),
io_handle: IoHandle::new(mio_stream),
};
Poll::Ready(Ok((stream, addr)))
}
Ok(None) => {
self.io_handle.clear_readable(cx)?;
Poll::Pending
}
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
self.io_handle.clear_readable(cx)?;
Poll::Pending
}
Err(err) => Poll::Ready(Err(err)),
}
})
.await
}
/// Returns a stream of incoming connections.
///
/// Iterating over this stream is equivalent to calling [`accept`] in a loop. The stream of
/// connections is infinite, i.e awaiting the next connection will never result in [`None`].
///
/// [`accept`]: #method.accept
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixListener;
/// use async_std::prelude::*;
///
/// # futures::executor::block_on(async {
/// let listener = UnixListener::bind("/tmp/socket").await?;
/// let mut incoming = listener.incoming();
///
/// while let Some(stream) = incoming.next().await {
/// let mut stream = stream?;
/// stream.write_all(b"hello world").await?;
/// }
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub fn incoming(&self) -> Incoming<'_> {
Incoming(self)
}
/// Returns the local socket address of this listener.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixListener;
///
/// # futures::executor::block_on(async {
/// let listener = UnixListener::bind("/tmp/socket").await?;
/// let addr = listener.local_addr()?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().local_addr()
}
}
impl fmt::Debug for UnixListener {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut builder = f.debug_struct("UnixListener");
builder.field("fd", &self.as_raw_fd());
if let Ok(addr) = self.local_addr() {
builder.field("local", &addr);
}
builder.finish()
}
}
/// A stream of incoming Unix domain socket connections.
///
/// This stream is infinite, i.e awaiting the next connection will never result in [`None`]. It is
/// created by the [`incoming`] method on [`UnixListener`].
///
/// This type is an async version of [`std::os::unix::net::Incoming`].
///
/// [`std::os::unix::net::Incoming`]: https://doc.rust-lang.org/std/os/unix/net/struct.Incoming.html
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
/// [`incoming`]: struct.UnixListener.html#method.incoming
/// [`UnixListener`]: struct.UnixListener.html
#[derive(Debug)]
pub struct Incoming<'a>(&'a UnixListener);
impl Stream for Incoming<'_> {
type Item = io::Result<UnixStream>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let future = self.0.accept();
futures::pin_mut!(future);
let (socket, _) = ready!(future.poll(cx))?;
Poll::Ready(Some(Ok(socket)))
}
}
/// A Unix stream socket.
///
/// This type is an async version of [`std::os::unix::net::UnixStream`].
///
/// [`std::os::unix::net::UnixStream`]:
/// https://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixStream;
/// use async_std::prelude::*;
///
/// # futures::executor::block_on(async {
/// let mut stream = UnixStream::connect("/tmp/socket").await?;
/// stream.write_all(b"hello world").await?;
///
/// let mut response = Vec::new();
/// stream.read_to_end(&mut response).await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub struct UnixStream {
#[cfg(not(feature = "docs.rs"))]
io_handle: IoHandle<mio_uds::UnixStream>,
raw_fd: RawFd,
}
impl UnixStream {
/// Connects to the socket to the specified address.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixStream;
///
/// # futures::executor::block_on(async {
/// let stream = UnixStream::connect("/tmp/socket").await?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub async fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
enum State {
Waiting(UnixStream),
Error(io::Error),
Done,
}
let path = path.as_ref().to_owned();
let mut state = {
match blocking::spawn(async move { mio_uds::UnixStream::connect(path) }).await {
Ok(mio_stream) => State::Waiting(UnixStream {
raw_fd: mio_stream.as_raw_fd(),
io_handle: IoHandle::new(mio_stream),
}),
Err(err) => State::Error(err),
}
};
future::poll_fn(|cx| {
match &mut state {
State::Waiting(stream) => {
ready!(stream.io_handle.poll_writable(cx)?);
if let Some(err) = stream.io_handle.get_ref().take_error()? {
return Poll::Ready(Err(err));
}
}
State::Error(_) => {
let err = match mem::replace(&mut state, State::Done) {
State::Error(err) => err,
_ => unreachable!(),
};
return Poll::Ready(Err(err));
}
State::Done => panic!("`UnixStream::connect()` future polled after completion"),
}
match mem::replace(&mut state, State::Done) {
State::Waiting(stream) => Poll::Ready(Ok(stream)),
_ => unreachable!(),
}
})
.await
}
/// Creates an unnamed pair of connected sockets.
///
/// Returns two streams which are connected to each other.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixStream;
///
/// # futures::executor::block_on(async {
/// let stream = UnixStream::pair()?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
let (a, b) = mio_uds::UnixStream::pair()?;
let a = UnixStream {
raw_fd: a.as_raw_fd(),
io_handle: IoHandle::new(a),
};
let b = UnixStream {
raw_fd: b.as_raw_fd(),
io_handle: IoHandle::new(b),
};
Ok((a, b))
}
/// Returns the socket address of the local half of this connection.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixStream;
///
/// # futures::executor::block_on(async {
/// let stream = UnixStream::connect("/tmp/socket").await?;
/// let addr = stream.local_addr()?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().local_addr()
}
/// Returns the socket address of the remote half of this connection.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixStream;
///
/// # futures::executor::block_on(async {
/// let stream = UnixStream::connect("/tmp/socket").await?;
/// let peer = stream.peer_addr()?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().peer_addr()
}
/// Shuts down the read, write, or both halves of this connection.
///
/// This function will cause all pending and future I/O calls on the specified portions to
/// immediately return with an appropriate value (see the documentation of [`Shutdown`]).
///
/// [`Shutdown`]: https://doc.rust-lang.org/std/net/enum.Shutdown.html
///
/// ```no_run
/// # #![feature(async_await)]
/// use async_std::os::unix::net::UnixStream;
/// use std::net::Shutdown;
///
/// # futures::executor::block_on(async {
/// let stream = UnixStream::connect("/tmp/socket").await?;
/// stream.shutdown(Shutdown::Both)?;
/// # std::io::Result::Ok(())
/// # }).unwrap();
/// ```
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
self.io_handle.get_ref().shutdown(how)
}
}
impl AsyncRead for UnixStream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut &*self).poll_read(cx, buf)
}
}
impl AsyncRead for &UnixStream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut &self.io_handle).poll_read(cx, buf)
}
}
impl AsyncWrite for UnixStream {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut &*self).poll_write(cx, buf)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut &*self).poll_flush(cx)
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut &*self).poll_close(cx)
}
}
impl AsyncWrite for &UnixStream {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut &self.io_handle).poll_write(cx, buf)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut &self.io_handle).poll_flush(cx)
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut &self.io_handle).poll_close(cx)
}
}
impl fmt::Debug for UnixStream {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut builder = f.debug_struct("UnixStream");
builder.field("fd", &self.as_raw_fd());
if let Ok(addr) = self.local_addr() {
builder.field("local", &addr);
}
if let Ok(addr) = self.peer_addr() {
builder.field("peer", &addr);
}
builder.finish()
}
}
#[cfg(unix)]
impl From<std::os::unix::net::UnixStream> for UnixStream {
/// Converts a `std::os::unix::net::UnixStream` into its asynchronous equivalent.
fn from(stream: std::os::unix::net::UnixStream) -> UnixStream {
let mio_stream = mio_uds::UnixStream::from_stream(stream).unwrap();
UnixStream {
raw_fd: mio_stream.as_raw_fd(),
io_handle: IoHandle::new(mio_stream),
}
}
}
#[cfg(unix)]
impl From<std::os::unix::net::UnixDatagram> for UnixDatagram {
/// Converts a `std::os::unix::net::UnixDatagram` into its asynchronous equivalent.
fn from(datagram: std::os::unix::net::UnixDatagram) -> UnixDatagram {
let mio_datagram = mio_uds::UnixDatagram::from_datagram(datagram).unwrap();
UnixDatagram {
raw_fd: mio_datagram.as_raw_fd(),
io_handle: IoHandle::new(mio_datagram),
}
}
}
#[cfg(unix)]
impl From<std::os::unix::net::UnixListener> for UnixListener {
/// Converts a `std::os::unix::net::UnixListener` into its asynchronous equivalent.
fn from(listener: std::os::unix::net::UnixListener) -> UnixListener {
let mio_listener = mio_uds::UnixListener::from_listener(listener).unwrap();
UnixListener {
raw_fd: mio_listener.as_raw_fd(),
io_handle: IoHandle::new(mio_listener),
}
}
}
impl AsRawFd for UnixListener {
fn as_raw_fd(&self) -> RawFd {
self.raw_fd
}
}
impl FromRawFd for UnixListener {
unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
let listener = std::os::unix::net::UnixListener::from_raw_fd(fd);
listener.into()
}
}
impl IntoRawFd for UnixListener {
fn into_raw_fd(self) -> RawFd {
self.raw_fd
}
}
impl AsRawFd for UnixStream {
fn as_raw_fd(&self) -> RawFd {
self.raw_fd
}
}
impl FromRawFd for UnixStream {
unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
let stream = std::os::unix::net::UnixStream::from_raw_fd(fd);
stream.into()
}
}
impl IntoRawFd for UnixStream {
fn into_raw_fd(self) -> RawFd {
self.raw_fd
}
}
impl AsRawFd for UnixDatagram {
fn as_raw_fd(&self) -> RawFd {
self.raw_fd
}
}
impl FromRawFd for UnixDatagram {
unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram {
let datagram = std::os::unix::net::UnixDatagram::from_raw_fd(fd);
datagram.into()
}
}
impl IntoRawFd for UnixDatagram {
fn into_raw_fd(self) -> RawFd {
self.raw_fd
}
}
cfg_if! {
if #[cfg(feature = "docs.rs")] {
/// An address associated with a Unix socket.
///
/// # Examples
///
/// ```
/// use async_std::os::unix::net::UnixListener;
///
/// let socket = UnixListener::bind("/tmp/socket").await?;
/// let addr = socket.local_addr()?;
/// ```
#[derive(Clone)]
pub struct SocketAddr {
_private: (),
}
impl SocketAddr {
/// Returns `true` if the address is unnamed.
///
/// # Examples
///
/// A named address:
///
/// ```no_run
/// use async_std::os::unix::net::UnixListener;
///
/// let socket = UnixListener::bind("/tmp/socket").await?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.is_unnamed(), false);
/// ```
///
/// An unnamed address:
///
/// ```no_run
/// use async_std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::unbound().await?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.is_unnamed(), true);
/// ```
pub fn is_unnamed(&self) -> bool {
unreachable!()
}
/// Returns the contents of this address if it is a `pathname` address.
///
/// # Examples
///
/// With a pathname:
///
/// ```no_run
/// use async_std::os::unix::net::UnixListener;
/// use std::path::Path;
///
/// let socket = UnixListener::bind("/tmp/socket").await?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/socket")));
/// ```
///
/// Without a pathname:
///
/// ```
/// use async_std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::unbound()?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.as_pathname(), None);
/// ```
pub fn as_pathname(&self) -> Option<&Path> {
unreachable!()
}
}
impl fmt::Debug for SocketAddr {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
unreachable!()
}
}
} else {
#[doc(inline)]
pub use std::os::unix::net::SocketAddr;
}
}

@ -0,0 +1,400 @@
//! Unix-specific networking extensions.
use std::fmt;
use std::net::Shutdown;
use std::path::Path;
use futures::future;
use mio_uds;
use super::SocketAddr;
use crate::io;
use crate::net::driver::IoHandle;
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::task::{blocking, Poll};
/// A Unix datagram socket.
///
/// After creating a `UnixDatagram` by [`bind`]ing it to a path, data can be [sent to] and
/// [received from] any other socket address.
///
/// This type is an async version of [`std::os::unix::net::UnixDatagram`].
///
/// [`std::os::unix::net::UnixDatagram`]:
/// https://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html
/// [`bind`]: #method.bind
/// [received from]: #method.recv_from
/// [sent to]: #method.send_to
///
/// ## Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::bind("/tmp/socket1").await?;
/// socket.send_to(b"hello world", "/tmp/socket2").await?;
///
/// let mut buf = vec![0u8; 1024];
/// let (n, peer) = socket.recv_from(&mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
pub struct UnixDatagram {
#[cfg(not(feature = "docs"))]
io_handle: IoHandle<mio_uds::UnixDatagram>,
raw_fd: RawFd,
}
impl UnixDatagram {
#[cfg(not(feature = "docs"))]
fn new(socket: mio_uds::UnixDatagram) -> UnixDatagram {
UnixDatagram {
raw_fd: socket.as_raw_fd(),
io_handle: IoHandle::new(socket),
}
}
/// Creates a Unix datagram socket bound to the given path.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::bind("/tmp/socket").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
let path = path.as_ref().to_owned();
let socket = blocking::spawn(async move { mio_uds::UnixDatagram::bind(path) }).await?;
Ok(UnixDatagram::new(socket))
}
/// Creates a Unix datagram which is not bound to any address.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::unbound()?;
/// #
/// # Ok(()) }) }
/// ```
pub fn unbound() -> io::Result<UnixDatagram> {
let socket = mio_uds::UnixDatagram::unbound()?;
Ok(UnixDatagram::new(socket))
}
/// Creates an unnamed pair of connected sockets.
///
/// Returns two sockets which are connected to each other.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixDatagram;
///
/// let (socket1, socket2) = UnixDatagram::pair()?;
/// #
/// # Ok(()) }) }
/// ```
pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
let (a, b) = mio_uds::UnixDatagram::pair()?;
let a = UnixDatagram::new(a);
let b = UnixDatagram::new(b);
Ok((a, b))
}
/// Connects the socket to the specified address.
///
/// The [`send`] method may be used to send data to the specified address. [`recv`] and
/// [`recv_from`] will only receive data from that address.
///
/// [`send`]: #method.send
/// [`recv`]: #method.recv
/// [`recv_from`]: #method.recv_from
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::unbound()?;
/// socket.connect("/tmp/socket").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
// TODO(stjepang): Connect the socket on a blocking pool.
let p = path.as_ref();
self.io_handle.get_ref().connect(p)
}
/// Returns the address of this socket.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::bind("/tmp/socket").await?;
/// let addr = socket.local_addr()?;
/// #
/// # Ok(()) }) }
/// ```
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().local_addr()
}
/// Returns the address of this socket's peer.
///
/// The [`connect`] method will connect the socket to a peer.
///
/// [`connect`]: #method.connect
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixDatagram;
///
/// let mut socket = UnixDatagram::unbound()?;
/// socket.connect("/tmp/socket").await?;
/// let peer = socket.peer_addr()?;
/// #
/// # Ok(()) }) }
/// ```
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().peer_addr()
}
/// Receives data from the socket.
///
/// On success, returns the number of bytes read and the address from where the data came.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixDatagram;
///
/// let mut socket = UnixDatagram::unbound()?;
/// let mut buf = vec![0; 1024];
/// let (n, peer) = socket.recv_from(&mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
future::poll_fn(|cx| {
futures::ready!(self.io_handle.poll_readable(cx)?);
match self.io_handle.get_ref().recv_from(buf) {
Ok(n) => Poll::Ready(Ok(n)),
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
self.io_handle.clear_readable(cx)?;
Poll::Pending
}
Err(err) => Poll::Ready(Err(err)),
}
})
.await
}
/// Receives data from the socket.
///
/// On success, returns the number of bytes read.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::bind("/tmp/socket").await?;
/// let mut buf = vec![0; 1024];
/// let n = socket.recv(&mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
future::poll_fn(|cx| {
futures::ready!(self.io_handle.poll_writable(cx)?);
match self.io_handle.get_ref().recv(buf) {
Ok(n) => Poll::Ready(Ok(n)),
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
self.io_handle.clear_writable(cx)?;
Poll::Pending
}
Err(err) => Poll::Ready(Err(err)),
}
})
.await
}
/// Sends data on the socket to the specified address.
///
/// On success, returns the number of bytes written.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixDatagram;
///
/// let mut socket = UnixDatagram::unbound()?;
/// socket.send_to(b"hello world", "/tmp/socket").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
future::poll_fn(|cx| {
futures::ready!(self.io_handle.poll_writable(cx)?);
match self.io_handle.get_ref().send_to(buf, path.as_ref()) {
Ok(n) => Poll::Ready(Ok(n)),
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
self.io_handle.clear_writable(cx)?;
Poll::Pending
}
Err(err) => Poll::Ready(Err(err)),
}
})
.await
}
/// Sends data on the socket to the socket's peer.
///
/// On success, returns the number of bytes written.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixDatagram;
///
/// let mut socket = UnixDatagram::unbound()?;
/// socket.connect("/tmp/socket").await?;
/// socket.send(b"hello world").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn send(&self, buf: &[u8]) -> io::Result<usize> {
future::poll_fn(|cx| {
futures::ready!(self.io_handle.poll_writable(cx)?);
match self.io_handle.get_ref().send(buf) {
Ok(n) => Poll::Ready(Ok(n)),
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
self.io_handle.clear_writable(cx)?;
Poll::Pending
}
Err(err) => Poll::Ready(Err(err)),
}
})
.await
}
/// Shut down the read, write, or both halves of this connection.
///
/// This function will cause all pending and future I/O calls on the specified portions to
/// immediately return with an appropriate value (see the documentation of [`Shutdown`]).
///
/// [`Shutdown`]: https://doc.rust-lang.org/std/net/enum.Shutdown.html
///
/// ## Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixDatagram;
/// use std::net::Shutdown;
///
/// let socket = UnixDatagram::unbound()?;
/// socket.shutdown(Shutdown::Both)?;
/// #
/// # Ok(()) }) }
/// ```
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
self.io_handle.get_ref().shutdown(how)
}
}
impl fmt::Debug for UnixDatagram {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut builder = f.debug_struct("UnixDatagram");
builder.field("fd", &self.as_raw_fd());
if let Ok(addr) = self.local_addr() {
builder.field("local", &addr);
}
if let Ok(addr) = self.peer_addr() {
builder.field("peer", &addr);
}
builder.finish()
}
}
impl From<std::os::unix::net::UnixDatagram> for UnixDatagram {
/// Converts a `std::os::unix::net::UnixDatagram` into its asynchronous equivalent.
fn from(datagram: std::os::unix::net::UnixDatagram) -> UnixDatagram {
let mio_datagram = mio_uds::UnixDatagram::from_datagram(datagram).unwrap();
UnixDatagram {
raw_fd: mio_datagram.as_raw_fd(),
io_handle: IoHandle::new(mio_datagram),
}
}
}
impl AsRawFd for UnixDatagram {
fn as_raw_fd(&self) -> RawFd {
self.raw_fd
}
}
impl FromRawFd for UnixDatagram {
unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram {
let datagram = std::os::unix::net::UnixDatagram::from_raw_fd(fd);
datagram.into()
}
}
impl IntoRawFd for UnixDatagram {
fn into_raw_fd(self) -> RawFd {
self.raw_fd
}
}

@ -0,0 +1,246 @@
//! Unix-specific networking extensions.
use std::fmt;
use std::path::Path;
use std::pin::Pin;
use futures::future;
use mio_uds;
use super::SocketAddr;
use super::UnixStream;
use crate::future::Future;
use crate::io;
use crate::net::driver::IoHandle;
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::task::{blocking, Context, Poll};
/// A Unix domain socket server, listening for connections.
///
/// After creating a `UnixListener` by [`bind`]ing it to a socket address, it listens for incoming
/// connections. These can be accepted by awaiting elements from the async stream of [`incoming`]
/// connections.
///
/// The socket will be closed when the value is dropped.
///
/// This type is an async version of [`std::os::unix::net::UnixListener`].
///
/// [`std::os::unix::net::UnixListener`]:
/// https://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html
/// [`bind`]: #method.bind
/// [`incoming`]: #method.incoming
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixListener;
/// use async_std::prelude::*;
///
/// let listener = UnixListener::bind("/tmp/socket").await?;
/// let mut incoming = listener.incoming();
///
/// while let Some(stream) = incoming.next().await {
/// let mut stream = stream?;
/// stream.write_all(b"hello world").await?;
/// }
/// #
/// # Ok(()) }) }
/// ```
pub struct UnixListener {
#[cfg(not(feature = "docs"))]
io_handle: IoHandle<mio_uds::UnixListener>,
raw_fd: RawFd,
}
impl UnixListener {
/// Creates a Unix datagram listener bound to the given path.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixListener;
///
/// let listener = UnixListener::bind("/tmp/socket").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
let path = path.as_ref().to_owned();
let listener = blocking::spawn(async move { mio_uds::UnixListener::bind(path) }).await?;
Ok(UnixListener {
raw_fd: listener.as_raw_fd(),
io_handle: IoHandle::new(listener),
})
}
/// Accepts a new incoming connection to this listener.
///
/// When a connection is established, the corresponding stream and address will be returned.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixListener;
///
/// let listener = UnixListener::bind("/tmp/socket").await?;
/// let (socket, addr) = listener.accept().await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
future::poll_fn(|cx| {
futures::ready!(self.io_handle.poll_readable(cx)?);
match self.io_handle.get_ref().accept_std() {
Ok(Some((io, addr))) => {
let mio_stream = mio_uds::UnixStream::from_stream(io)?;
let stream = UnixStream {
raw_fd: mio_stream.as_raw_fd(),
io_handle: IoHandle::new(mio_stream),
};
Poll::Ready(Ok((stream, addr)))
}
Ok(None) => {
self.io_handle.clear_readable(cx)?;
Poll::Pending
}
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
self.io_handle.clear_readable(cx)?;
Poll::Pending
}
Err(err) => Poll::Ready(Err(err)),
}
})
.await
}
/// Returns a stream of incoming connections.
///
/// Iterating over this stream is equivalent to calling [`accept`] in a loop. The stream of
/// connections is infinite, i.e awaiting the next connection will never result in [`None`].
///
/// [`accept`]: #method.accept
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixListener;
/// use async_std::prelude::*;
///
/// let listener = UnixListener::bind("/tmp/socket").await?;
/// let mut incoming = listener.incoming();
///
/// while let Some(stream) = incoming.next().await {
/// let mut stream = stream?;
/// stream.write_all(b"hello world").await?;
/// }
/// #
/// # Ok(()) }) }
/// ```
pub fn incoming(&self) -> Incoming<'_> {
Incoming(self)
}
/// Returns the local socket address of this listener.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixListener;
///
/// let listener = UnixListener::bind("/tmp/socket").await?;
/// let addr = listener.local_addr()?;
/// #
/// # Ok(()) }) }
/// ```
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().local_addr()
}
}
impl fmt::Debug for UnixListener {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut builder = f.debug_struct("UnixListener");
builder.field("fd", &self.as_raw_fd());
if let Ok(addr) = self.local_addr() {
builder.field("local", &addr);
}
builder.finish()
}
}
/// A stream of incoming Unix domain socket connections.
///
/// This stream is infinite, i.e awaiting the next connection will never result in [`None`]. It is
/// created by the [`incoming`] method on [`UnixListener`].
///
/// This type is an async version of [`std::os::unix::net::Incoming`].
///
/// [`std::os::unix::net::Incoming`]: https://doc.rust-lang.org/std/os/unix/net/struct.Incoming.html
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
/// [`incoming`]: struct.UnixListener.html#method.incoming
/// [`UnixListener`]: struct.UnixListener.html
#[derive(Debug)]
pub struct Incoming<'a>(&'a UnixListener);
impl futures::Stream for Incoming<'_> {
type Item = io::Result<UnixStream>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let future = self.0.accept();
futures::pin_mut!(future);
let (socket, _) = futures::ready!(future.poll(cx))?;
Poll::Ready(Some(Ok(socket)))
}
}
impl From<std::os::unix::net::UnixListener> for UnixListener {
/// Converts a `std::os::unix::net::UnixListener` into its asynchronous equivalent.
fn from(listener: std::os::unix::net::UnixListener) -> UnixListener {
let mio_listener = mio_uds::UnixListener::from_listener(listener).unwrap();
UnixListener {
raw_fd: mio_listener.as_raw_fd(),
io_handle: IoHandle::new(mio_listener),
}
}
}
impl AsRawFd for UnixListener {
fn as_raw_fd(&self) -> RawFd {
self.raw_fd
}
}
impl FromRawFd for UnixListener {
unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
let listener = std::os::unix::net::UnixListener::from_raw_fd(fd);
listener.into()
}
}
impl IntoRawFd for UnixListener {
fn into_raw_fd(self) -> RawFd {
self.raw_fd
}
}

@ -0,0 +1,99 @@
//! Unix-specific networking extensions.
use cfg_if::cfg_if;
pub use datagram::UnixDatagram;
pub use listener::{Incoming, UnixListener};
pub use stream::UnixStream;
mod datagram;
mod listener;
mod stream;
cfg_if! {
if #[cfg(feature = "docs")] {
use std::fmt;
use std::path::Path;
/// An address associated with a Unix socket.
///
/// # Examples
///
/// ```
/// use async_std::os::unix::net::UnixListener;
///
/// let socket = UnixListener::bind("/tmp/socket").await?;
/// let addr = socket.local_addr()?;
/// ```
#[derive(Clone)]
pub struct SocketAddr {
_private: (),
}
impl SocketAddr {
/// Returns `true` if the address is unnamed.
///
/// # Examples
///
/// A named address:
///
/// ```no_run
/// use async_std::os::unix::net::UnixListener;
///
/// let socket = UnixListener::bind("/tmp/socket").await?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.is_unnamed(), false);
/// ```
///
/// An unnamed address:
///
/// ```no_run
/// use async_std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::unbound().await?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.is_unnamed(), true);
/// ```
pub fn is_unnamed(&self) -> bool {
unreachable!()
}
/// Returns the contents of this address if it is a `pathname` address.
///
/// # Examples
///
/// With a pathname:
///
/// ```no_run
/// use async_std::os::unix::net::UnixListener;
/// use std::path::Path;
///
/// let socket = UnixListener::bind("/tmp/socket").await?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/socket")));
/// ```
///
/// Without a pathname:
///
/// ```
/// use async_std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::unbound()?;
/// let addr = socket.local_addr()?;
/// assert_eq!(addr.as_pathname(), None);
/// ```
pub fn as_pathname(&self) -> Option<&Path> {
unreachable!()
}
}
impl fmt::Debug for SocketAddr {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
unreachable!()
}
}
} else {
#[doc(inline)]
pub use std::os::unix::net::SocketAddr;
}
}

@ -0,0 +1,302 @@
//! Unix-specific networking extensions.
use std::fmt;
use std::mem;
use std::net::Shutdown;
use std::path::Path;
use std::pin::Pin;
use futures::future;
use mio_uds;
use super::SocketAddr;
use crate::io;
use crate::net::driver::IoHandle;
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::task::{blocking, Context, Poll};
/// A Unix stream socket.
///
/// This type is an async version of [`std::os::unix::net::UnixStream`].
///
/// [`std::os::unix::net::UnixStream`]:
/// https://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixStream;
/// use async_std::prelude::*;
///
/// let mut stream = UnixStream::connect("/tmp/socket").await?;
/// stream.write_all(b"hello world").await?;
///
/// let mut response = Vec::new();
/// stream.read_to_end(&mut response).await?;
/// #
/// # Ok(()) }) }
/// ```
pub struct UnixStream {
#[cfg(not(feature = "docs"))]
pub(super) io_handle: IoHandle<mio_uds::UnixStream>,
pub(super) raw_fd: RawFd,
}
impl UnixStream {
/// Connects to the socket to the specified address.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixStream;
///
/// let stream = UnixStream::connect("/tmp/socket").await?;
/// #
/// # Ok(()) }) }
/// ```
pub async fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
enum State {
Waiting(UnixStream),
Error(io::Error),
Done,
}
let path = path.as_ref().to_owned();
let mut state = {
match blocking::spawn(async move { mio_uds::UnixStream::connect(path) }).await {
Ok(mio_stream) => State::Waiting(UnixStream {
raw_fd: mio_stream.as_raw_fd(),
io_handle: IoHandle::new(mio_stream),
}),
Err(err) => State::Error(err),
}
};
future::poll_fn(|cx| {
match &mut state {
State::Waiting(stream) => {
futures::ready!(stream.io_handle.poll_writable(cx)?);
if let Some(err) = stream.io_handle.get_ref().take_error()? {
return Poll::Ready(Err(err));
}
}
State::Error(_) => {
let err = match mem::replace(&mut state, State::Done) {
State::Error(err) => err,
_ => unreachable!(),
};
return Poll::Ready(Err(err));
}
State::Done => panic!("`UnixStream::connect()` future polled after completion"),
}
match mem::replace(&mut state, State::Done) {
State::Waiting(stream) => Poll::Ready(Ok(stream)),
_ => unreachable!(),
}
})
.await
}
/// Creates an unnamed pair of connected sockets.
///
/// Returns two streams which are connected to each other.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixStream;
///
/// let stream = UnixStream::pair()?;
/// #
/// # Ok(()) }) }
/// ```
pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
let (a, b) = mio_uds::UnixStream::pair()?;
let a = UnixStream {
raw_fd: a.as_raw_fd(),
io_handle: IoHandle::new(a),
};
let b = UnixStream {
raw_fd: b.as_raw_fd(),
io_handle: IoHandle::new(b),
};
Ok((a, b))
}
/// Returns the socket address of the local half of this connection.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixStream;
///
/// let stream = UnixStream::connect("/tmp/socket").await?;
/// let addr = stream.local_addr()?;
/// #
/// # Ok(()) }) }
/// ```
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().local_addr()
}
/// Returns the socket address of the remote half of this connection.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixStream;
///
/// let stream = UnixStream::connect("/tmp/socket").await?;
/// let peer = stream.peer_addr()?;
/// #
/// # Ok(()) }) }
/// ```
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.io_handle.get_ref().peer_addr()
}
/// Shuts down the read, write, or both halves of this connection.
///
/// This function will cause all pending and future I/O calls on the specified portions to
/// immediately return with an appropriate value (see the documentation of [`Shutdown`]).
///
/// [`Shutdown`]: https://doc.rust-lang.org/std/net/enum.Shutdown.html
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::os::unix::net::UnixStream;
/// use std::net::Shutdown;
///
/// let stream = UnixStream::connect("/tmp/socket").await?;
/// stream.shutdown(Shutdown::Both)?;
/// #
/// # Ok(()) }) }
/// ```
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
self.io_handle.get_ref().shutdown(how)
}
}
impl futures::io::AsyncRead for UnixStream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut &*self).poll_read(cx, buf)
}
}
impl futures::io::AsyncRead for &UnixStream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut &self.io_handle).poll_read(cx, buf)
}
}
impl futures::io::AsyncWrite for UnixStream {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut &*self).poll_write(cx, buf)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut &*self).poll_flush(cx)
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut &*self).poll_close(cx)
}
}
impl futures::io::AsyncWrite for &UnixStream {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut &self.io_handle).poll_write(cx, buf)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut &self.io_handle).poll_flush(cx)
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut &self.io_handle).poll_close(cx)
}
}
impl fmt::Debug for UnixStream {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut builder = f.debug_struct("UnixStream");
builder.field("fd", &self.as_raw_fd());
if let Ok(addr) = self.local_addr() {
builder.field("local", &addr);
}
if let Ok(addr) = self.peer_addr() {
builder.field("peer", &addr);
}
builder.finish()
}
}
impl From<std::os::unix::net::UnixStream> for UnixStream {
/// Converts a `std::os::unix::net::UnixStream` into its asynchronous equivalent.
fn from(stream: std::os::unix::net::UnixStream) -> UnixStream {
let mio_stream = mio_uds::UnixStream::from_stream(stream).unwrap();
UnixStream {
raw_fd: mio_stream.as_raw_fd(),
io_handle: IoHandle::new(mio_stream),
}
}
}
impl AsRawFd for UnixStream {
fn as_raw_fd(&self) -> RawFd {
self.raw_fd
}
}
impl FromRawFd for UnixStream {
unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
let stream = std::os::unix::net::UnixStream::from_raw_fd(fd);
stream.into()
}
}
impl IntoRawFd for UnixStream {
fn into_raw_fd(self) -> RawFd {
self.raw_fd
}
}

@ -3,7 +3,7 @@
use cfg_if::cfg_if;
cfg_if! {
if #[cfg(feature = "docs.rs")] {
if #[cfg(feature = "docs")] {
/// Raw HANDLEs.
pub type RawHandle = *mut std::os::raw::c_void;

@ -8,37 +8,33 @@
//!
//! ```no_run
//! # #![feature(async_await)]
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! use async_std::{io, prelude::*};
//! use std::time::Duration;
//!
//! # async_std::task::block_on(async {
//! let stdin = io::stdin();
//! let mut line = String::new();
//! let dur = Duration::from_secs(5);
//!
//! stdin.read_line(&mut line).timeout(dur).await??;
//! # std::io::Result::Ok(())
//! # }).unwrap();
//! #
//! # Ok(()) }) }
//! ```
//!
//! [`timeout`]: ../time/trait.Timeout.html#method.timeout
#[doc(no_inline)]
pub use futures::future::FutureExt as _;
pub use crate::future::Future;
#[doc(no_inline)]
pub use futures::future::TryFutureExt as _;
pub use crate::io::BufRead as _;
#[doc(no_inline)]
pub use futures::io::AsyncBufReadExt as _;
pub use crate::io::Read as _;
#[doc(no_inline)]
pub use futures::io::AsyncReadExt as _;
pub use crate::io::Seek as _;
#[doc(no_inline)]
pub use futures::io::AsyncSeekExt as _;
pub use crate::io::Write as _;
#[doc(no_inline)]
pub use futures::io::AsyncWriteExt as _;
#[doc(no_inline)]
pub use futures::stream::StreamExt as _;
#[doc(no_inline)]
pub use futures::stream::TryStreamExt as _;
pub use crate::stream::Stream;
#[doc(no_inline)]
pub use crate::time::Timeout as _;

@ -0,0 +1,44 @@
use std::marker::PhantomData;
use std::pin::Pin;
use crate::task::{Context, Poll};
/// Creates a stream that doesn't yield any items.
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::{prelude::*, stream};
///
/// let mut s = stream::empty::<i32>();
///
/// assert_eq!(s.next().await, None);
/// #
/// # }) }
/// ```
pub fn empty<T>() -> Empty<T> {
Empty {
_marker: PhantomData,
}
}
/// A stream that doesn't yield any items.
///
/// This stream is constructed by the [`empty`] function.
///
/// [`empty`]: fn.empty.html
#[derive(Debug)]
pub struct Empty<T> {
_marker: PhantomData<T>,
}
impl<T> futures::Stream for Empty<T> {
type Item = T;
fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Poll::Ready(None)
}
}

@ -1,4 +1,4 @@
//! Composable asynchronous iteration.
//! Asynchronous iteration.
//!
//! This module is an async version of [`std::iter`].
//!
@ -8,17 +8,25 @@
//!
//! ```
//! # #![feature(async_await)]
//! # use async_std::prelude::*;
//! # async_std::task::block_on(async {
//! use async_std::stream;
//! # fn main() { async_std::task::block_on(async {
//! #
//! use async_std::{prelude::*, stream};
//!
//! let mut stream = stream::repeat(9).take(3);
//! while let Some(num) = stream.next().await {
//! assert_eq!(num, 9);
//! let mut s = stream::repeat(9).take(3);
//!
//! while let Some(v) = s.next().await {
//! assert_eq!(v, 9);
//! }
//! # std::io::Result::Ok(())
//! # }).unwrap();
//! #
//! # }) }
//! ```
#[doc(inline)]
pub use futures::stream::{empty, once, repeat, Empty, Once, Repeat, Stream};
pub use empty::{empty, Empty};
pub use once::{once, Once};
pub use repeat::{repeat, Repeat};
pub use stream::{Stream, Take};
mod empty;
mod once;
mod repeat;
mod stream;

@ -0,0 +1,42 @@
use std::pin::Pin;
use crate::task::{Context, Poll};
/// Creates a stream that yields a single item.
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::{prelude::*, stream};
///
/// let mut s = stream::once(7);
///
/// assert_eq!(s.next().await, Some(7));
/// assert_eq!(s.next().await, None);
/// #
/// # }) }
/// ```
pub fn once<T>(t: T) -> Once<T> {
Once { value: Some(t) }
}
/// A stream that yields a single item.
///
/// This stream is constructed by the [`once`] function.
///
/// [`once`]: fn.once.html
#[derive(Debug)]
pub struct Once<T> {
value: Option<T>,
}
impl<T: Unpin> futures::Stream for Once<T> {
type Item = T;
fn poll_next(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<T>> {
Poll::Ready(self.value.take())
}
}

@ -0,0 +1,45 @@
use std::pin::Pin;
use crate::task::{Context, Poll};
/// Creates a stream that yields the same item repeatedly.
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::{prelude::*, stream};
///
/// let mut s = stream::repeat(7);
///
/// assert_eq!(s.next().await, Some(7));
/// assert_eq!(s.next().await, Some(7));
/// #
/// # }) }
/// ```
pub fn repeat<T>(item: T) -> Repeat<T>
where
T: Clone,
{
Repeat { item }
}
/// A stream that yields the same item repeatedly.
///
/// This stream is constructed by the [`repeat`] function.
///
/// [`repeat`]: fn.repeat.html
#[derive(Debug)]
pub struct Repeat<T> {
item: T,
}
impl<T: Clone> futures::Stream for Repeat<T> {
type Item = T;
fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Poll::Ready(Some(self.item.clone()))
}
}

@ -0,0 +1,170 @@
//! Asynchronous iteration.
//!
//! This module is an async version of [`std::iter`].
//!
//! [`std::iter`]: https://doc.rust-lang.org/std/iter/index.html
//!
//! # Examples
//!
//! ```
//! # #![feature(async_await)]
//! # fn main() { async_std::task::block_on(async {
//! #
//! use async_std::{prelude::*, stream};
//!
//! let mut s = stream::repeat(9).take(3);
//!
//! while let Some(v) = s.next().await {
//! assert_eq!(v, 9);
//! }
//! #
//! # }) }
//! ```
use std::pin::Pin;
use cfg_if::cfg_if;
use crate::future::Future;
use crate::task::{Context, Poll};
cfg_if! {
if #[cfg(feature = "docs")] {
#[doc(hidden)]
pub struct ImplFuture<'a, T>(std::marker::PhantomData<&'a T>);
macro_rules! ret {
($a:lifetime, $f:tt, $o:ty) => (ImplFuture<$a, $o>);
}
} else {
macro_rules! ret {
($a:lifetime, $f:tt, $o:ty) => ($f<$a, Self>);
}
}
}
/// An asynchronous stream of values.
///
/// This trait is an async version of [`std::iter::Iterator`].
///
/// While it is currently not possible to implement this trait directly, it gets implemented
/// automatically for all types that implement [`futures::stream::Stream`].
///
/// [`std::iter::Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
/// [`futures::stream::Stream`]:
/// https://docs/futures-preview/0.3.0-alpha.17/futures/stream/trait.Stream.html
pub trait Stream {
/// The type of items yielded by this stream.
type Item;
/// Advances the stream and returns the next value.
///
/// Returns [`None`] when iteration is finished. Individual stream implementations may
/// choose to resume iteration, and so calling `next()` again may or may not eventually
/// start returning more values.
///
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::{prelude::*, stream};
///
/// let mut s = stream::once(7);
///
/// assert_eq!(s.next().await, Some(7));
/// assert_eq!(s.next().await, None);
/// #
/// # }) }
/// ```
fn next<'a>(&'a mut self) -> ret!('a, NextFuture, Option<Self::Item>)
where
Self: Unpin;
/// Creates a stream that yields its first `n` elements.
///
/// # Examples
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::{prelude::*, stream};
///
/// let mut s = stream::repeat(9).take(3);
///
/// while let Some(v) = s.next().await {
/// assert_eq!(v, 9);
/// }
/// #
/// # }) }
/// ```
fn take(self, n: usize) -> Take<Self>
where
Self: Sized,
{
Take {
stream: self,
remaining: n,
}
}
}
impl<T: futures::Stream + Unpin + ?Sized> Stream for T {
type Item = <Self as futures::Stream>::Item;
fn next<'a>(&'a mut self) -> ret!('a, NextFuture, Option<Self::Item>)
where
Self: Unpin,
{
NextFuture { stream: self }
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct NextFuture<'a, T: Unpin + ?Sized> {
stream: &'a mut T,
}
impl<T: futures::Stream + Unpin + ?Sized> Future for NextFuture<'_, T> {
type Output = Option<T::Item>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Pin::new(&mut *self.stream).poll_next(cx)
}
}
/// A stream that yields the first `n` items of another stream.
#[derive(Clone, Debug)]
pub struct Take<S> {
stream: S,
remaining: usize,
}
impl<S: Unpin> Unpin for Take<S> {}
impl<S: futures::Stream> Take<S> {
pin_utils::unsafe_pinned!(stream: S);
pin_utils::unsafe_unpinned!(remaining: usize);
}
impl<S: futures::Stream> futures::Stream for Take<S> {
type Item = S::Item;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {
if self.remaining == 0 {
Poll::Ready(None)
} else {
let next = futures::ready!(self.as_mut().stream().poll_next(cx));
match next {
Some(_) => *self.as_mut().remaining() -= 1,
None => *self.as_mut().remaining() = 0,
}
Poll::Ready(next)
}
}
}

@ -10,10 +10,11 @@
//!
//! ```
//! # #![feature(async_await)]
//! # fn main() { async_std::task::block_on(async {
//! #
//! use async_std::{sync::Mutex, task};
//! use std::sync::Arc;
//!
//! # futures::executor::block_on(async {
//! let m1 = Arc::new(Mutex::new(0));
//! let m2 = m1.clone();
//!
@ -23,7 +24,8 @@
//! .await;
//!
//! assert_eq!(*m1.lock().await, 1);
//! # })
//! #
//! # }) }
//! ```
pub use mutex::{Mutex, MutexGuard};

@ -1,13 +1,14 @@
use std::cell::UnsafeCell;
use std::fmt;
use std::future::Future;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::task::{Context, Poll, Waker};
use slab::Slab;
use crate::future::Future;
use crate::task::{Context, Poll, Waker};
/// Set if the mutex is locked.
const LOCK: usize = 1 << 0;
@ -24,10 +25,11 @@ const BLOCKED: usize = 1 << 1;
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::{sync::Mutex, task};
/// use std::sync::Arc;
///
/// # futures::executor::block_on(async {
/// let m = Arc::new(Mutex::new(0));
/// let mut tasks = vec![];
///
@ -42,7 +44,8 @@ const BLOCKED: usize = 1 << 1;
/// t.await;
/// }
/// assert_eq!(*m.lock().await, 10);
/// # })
/// #
/// # }) }
/// ```
pub struct Mutex<T> {
state: AtomicUsize,
@ -79,10 +82,11 @@ impl<T> Mutex<T> {
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::{sync::Mutex, task};
/// use std::sync::Arc;
///
/// # futures::executor::block_on(async {
/// let m1 = Arc::new(Mutex::new(10));
/// let m2 = m1.clone();
///
@ -92,7 +96,8 @@ impl<T> Mutex<T> {
/// .await;
///
/// assert_eq!(*m2.lock().await, 20);
/// # })
/// #
/// # }) }
/// ```
pub async fn lock(&self) -> MutexGuard<'_, T> {
pub struct LockFuture<'a, T> {
@ -190,10 +195,11 @@ impl<T> Mutex<T> {
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::{sync::Mutex, task};
/// use std::sync::Arc;
///
/// # futures::executor::block_on(async {
/// let m1 = Arc::new(Mutex::new(10));
/// let m2 = m1.clone();
///
@ -207,7 +213,8 @@ impl<T> Mutex<T> {
/// .await;
///
/// assert_eq!(*m2.lock().await, 20);
/// # })
/// #
/// # }) }
/// ```
pub fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
if self.state.fetch_or(LOCK, Ordering::Acquire) & LOCK == 0 {
@ -241,13 +248,15 @@ impl<T> Mutex<T> {
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::sync::Mutex;
///
/// # futures::executor::block_on(async {
/// let mut mutex = Mutex::new(0);
/// *mutex.get_mut() = 10;
/// assert_eq!(*mutex.lock().await, 10);
/// });
/// #
/// # }) }
/// ```
pub fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.value.get() }

@ -1,13 +1,14 @@
use std::cell::UnsafeCell;
use std::fmt;
use std::future::Future;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::task::{Context, Poll, Waker};
use slab::Slab;
use crate::future::Future;
use crate::task::{Context, Poll, Waker};
/// Set if a write lock is held.
const WRITE_LOCK: usize = 1 << 0;
@ -33,9 +34,10 @@ const READ_COUNT_MASK: usize = !(ONE_READ - 1);
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::sync::RwLock;
///
/// # futures::executor::block_on(async {
/// let lock = RwLock::new(5);
///
/// // Multiple read locks can be held at a time.
@ -49,7 +51,8 @@ const READ_COUNT_MASK: usize = !(ONE_READ - 1);
/// let mut w = lock.write().await;
/// *w += 1;
/// assert_eq!(*w, 6);
/// # })
/// #
/// # }) }
/// ```
pub struct RwLock<T> {
state: AtomicUsize,
@ -88,16 +91,18 @@ impl<T> RwLock<T> {
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::sync::RwLock;
///
/// # futures::executor::block_on(async {
/// let lock = RwLock::new(1);
///
/// let n = lock.read().await;
/// assert_eq!(*n, 1);
///
/// assert!(lock.try_read().is_some());
/// # })
/// #
/// # }) }
/// ```
pub async fn read(&self) -> RwLockReadGuard<'_, T> {
pub struct LockFuture<'a, T> {
@ -209,16 +214,18 @@ impl<T> RwLock<T> {
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::sync::RwLock;
///
/// # futures::executor::block_on(async {
/// let lock = RwLock::new(1);
///
/// let mut n = lock.read().await;
/// assert_eq!(*n, 1);
///
/// assert!(lock.try_read().is_some());
/// # })
/// #
/// # }) }
/// ```
pub fn try_read(&self) -> Option<RwLockReadGuard<'_, T>> {
let mut state = self.state.load(Ordering::Acquire);
@ -250,16 +257,18 @@ impl<T> RwLock<T> {
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::sync::RwLock;
///
/// # futures::executor::block_on(async {
/// let lock = RwLock::new(1);
///
/// let mut n = lock.write().await;
/// *n = 2;
///
/// assert!(lock.try_read().is_none());
/// # })
/// #
/// # }) }
/// ```
pub async fn write(&self) -> RwLockWriteGuard<'_, T> {
pub struct LockFuture<'a, T> {
@ -370,16 +379,18 @@ impl<T> RwLock<T> {
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::sync::RwLock;
///
/// # futures::executor::block_on(async {
/// let lock = RwLock::new(1);
///
/// let mut n = lock.read().await;
/// assert_eq!(*n, 1);
///
/// assert!(lock.try_write().is_none());
/// # })
/// #
/// # }) }
/// ```
pub fn try_write(&self) -> Option<RwLockWriteGuard<'_, T>> {
let mut state = self.state.load(Ordering::Acquire);
@ -427,13 +438,15 @@ impl<T> RwLock<T> {
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::sync::RwLock;
///
/// # futures::executor::block_on(async {
/// let mut lock = RwLock::new(0);
/// *lock.get_mut() = 10;
/// assert_eq!(*lock.write().await, 10);
/// });
/// #
/// # }) }
/// ```
pub fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.value.get() }

@ -1,16 +1,16 @@
//! A thread pool for running blocking functions asynchronously.
use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::sync::atomic::{AtomicU64, Ordering};
use std::task::{Context, Poll};
use std::thread;
use std::time::Duration;
use crossbeam::channel::{bounded, Receiver, Sender};
use lazy_static::lazy_static;
use crate::future::Future;
use crate::task::{Context, Poll};
use crate::utils::abort_on_panic;
const MAX_THREADS: u64 = 10_000;

@ -94,11 +94,11 @@ impl<T: Send + 'static> LocalKey<T> {
/// use std::cell::Cell;
///
/// task_local! {
/// static FOO: Cell<u32> = Cell::new(5);
/// static NUMBER: Cell<u32> = Cell::new(5);
/// }
///
/// task::block_on(async {
/// let v = FOO.with(|c| c.get());
/// let v = NUMBER.with(|c| c.get());
/// assert_eq!(v, 5);
/// });
/// ```
@ -182,11 +182,7 @@ impl<T: Send + 'static> LocalKey<T> {
}
let key = self.__key.load(Ordering::Acquire);
if key == 0 {
init(&self.__key)
} else {
key
}
if key == 0 { init(&self.__key) } else { key }
}
}

@ -11,18 +11,19 @@
//!
//! ```
//! # #![feature(async_await)]
//! # fn main() { async_std::task::block_on(async {
//! #
//! use async_std::task;
//!
//! # async_std::task::block_on(async {
//! let handle = task::spawn(async {
//! 1 + 2
//! });
//! assert_eq!(handle.await, 3);
//! # });
//! #
//! # }) }
//! ```
#[doc(inline)]
pub use futures::task::{Context, Poll, Waker};
pub use std::task::{Context, Poll, Waker};
pub use local::{AccessError, LocalKey};
pub use pool::{block_on, current, spawn, Builder};

@ -1,7 +1,5 @@
use std::cell::{Cell, UnsafeCell};
use std::fmt::Arguments;
use std::future::Future;
use std::io;
use std::mem;
use std::panic::{self, AssertUnwindSafe};
use std::pin::Pin;
@ -9,11 +7,13 @@ use std::ptr;
use std::thread;
use crossbeam::channel::{unbounded, Sender};
use futures::prelude::*;
use futures::future::FutureExt;
use lazy_static::lazy_static;
use super::task;
use super::{JoinHandle, Task};
use crate::future::Future;
use crate::io;
/// Returns a handle to the current task.
///
@ -30,11 +30,14 @@ use super::{JoinHandle, Task};
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::task::current;
///
/// # async_std::task::block_on(async {
/// println!("The name of this task is {:?}", current().name());
/// # });
/// #
/// # }) }
/// ```
pub fn current() -> Task {
get_task(|task| task.clone()).expect("`task::current()` called outside the context of a task")
}
@ -49,15 +52,17 @@ pub fn current() -> Task {
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::task;
///
/// # async_std::task::block_on(async {
/// let handle = task::spawn(async {
/// 1 + 2
/// });
///
/// assert_eq!(handle.await, 3);
/// # });
/// #
/// # }) }
/// ```
pub fn spawn<F, T>(future: F) -> JoinHandle<T>
where

@ -1,6 +1,6 @@
use std::time::Duration;
use futures::prelude::*;
use futures::future;
use crate::time::Timeout;
@ -16,12 +16,14 @@ use crate::time::Timeout;
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::task;
/// use std::time::Duration;
///
/// # async_std::task::block_on(async {
/// task::sleep(Duration::from_secs(1)).await;
/// # });
/// #
/// # }) }
/// ```
pub async fn sleep(dur: Duration) {
let _ = future::pending::<()>().timeout(dur).await;

@ -1,14 +1,14 @@
use std::fmt;
use std::future::Future;
use std::i64;
use std::mem;
use std::num::NonZeroU64;
use std::pin::Pin;
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
use std::sync::Arc;
use std::task::{Context, Poll};
use super::local;
use crate::future::Future;
use crate::task::{Context, Poll};
/// A handle to a task.
#[derive(Clone)]
@ -66,14 +66,16 @@ impl<T> JoinHandle<T> {
///
/// ```
/// # #![feature(async_await)]
/// # fn main() { async_std::task::block_on(async {
/// #
/// use async_std::task;
///
/// # async_std::task::block_on(async {
/// let handle = task::spawn(async {
/// 1 + 2
/// });
/// println!("id = {}", handle.task().id());
/// # });
/// #
/// # }) }
pub fn task(&self) -> &Task {
self.0.tag().task()
}
@ -97,13 +99,12 @@ impl<T> Future for JoinHandle<T> {
///
/// ```
/// # #![feature(async_await)]
/// #
/// use async_std::task;
///
/// # async_std::task::block_on(async {
/// task::block_on(async {
/// println!("id = {:?}", task::current().id());
/// })
/// # });
/// ```
#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
pub struct TaskId(NonZeroU64);

@ -26,110 +26,6 @@
//! # Ok(()) }) }
//! ```
use std::error::Error;
use std::fmt;
use std::future::Future;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;
pub use timeout::{Timeout, TimeoutError};
use cfg_if::cfg_if;
use futures_timer::Delay;
use pin_utils::unsafe_pinned;
/// An error returned when a future times out.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct TimeoutError;
impl Error for TimeoutError {}
impl fmt::Display for TimeoutError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
"future has timed out".fmt(f)
}
}
impl From<TimeoutError> for io::Error {
fn from(_: TimeoutError) -> io::Error {
io::Error::new(io::ErrorKind::TimedOut, "future has timed out")
}
}
cfg_if! {
if #[cfg(feature = "docs.rs")] {
#[doc(hidden)]
pub struct ImplFuture<T>(std::marker::PhantomData<T>);
/// An extension trait that configures timeouts for futures.
pub trait Timeout: Future + Sized {
/// Awaits a future to completion or times out after a duration of time.
///
/// # Examples
///
/// ```no_run
/// # #![feature(async_await)]
/// # fn main() -> io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::{io, prelude::*};
/// use std::time::Duration;
///
/// let stdin = io::stdin();
/// let mut line = String::new();
///
/// let n = stdin
/// .read_line(&mut line)
/// .timeout(Duration::from_secs(5))
/// .await??;
/// #
/// # Ok(()) }) }
/// ```
fn timeout(self, dur: Duration) -> ImplFuture<Result<Self::Output, TimeoutError>> {
TimeoutFuture {
future: self,
delay: Delay::new(dur),
}
}
}
} else {
/// An extension trait that configures timeouts for futures.
pub trait Timeout: Future + Sized {
/// Awaits a future to completion or times out after a duration of time.
fn timeout(self, dur: Duration) -> TimeoutFuture<Self> {
TimeoutFuture {
future: self,
delay: Delay::new(dur),
}
}
}
/// A future that times out after a duration of time.
#[doc(hidden)]
#[derive(Debug)]
pub struct TimeoutFuture<F> {
future: F,
delay: Delay,
}
impl<F> TimeoutFuture<F> {
unsafe_pinned!(future: F);
unsafe_pinned!(delay: Delay);
}
impl<F: Future> Future for TimeoutFuture<F> {
type Output = Result<F::Output, TimeoutError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.as_mut().future().poll(cx) {
Poll::Ready(v) => Poll::Ready(Ok(v)),
Poll::Pending => match self.delay().poll(cx) {
Poll::Ready(_) => Poll::Ready(Err(TimeoutError)),
Poll::Pending => Poll::Pending,
},
}
}
}
}
}
impl<F: Future> Timeout for F {}
mod timeout;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save