Compare commits

...

866 Commits

Author SHA1 Message Date
Yoshua Wuyts 8aa5921dfa
Merge pull request #833 from OSSystems/topic/fix_channel_doc
channel doc: Fix misleading reference to None return on Receiver
5 years ago
Jonathas-Conceicao cd7fb9dec2 channel doc: Fix misleading reference to None return on Receiver
Signed-off-by: Jonathas-Conceicao <jonathas.conceicao@ossystems.com.br>
5 years ago
Yoshua Wuyts c82b1efb69
fix(stream): add send guards on collect
Closes #639 

Co-authored-by: dignifiedquire <me@dignifiedquire.com>
5 years ago
Friedel Ziegelmayer 8c4b425136
Merge pull request #826 from thibault-martinez/kv-log-macro-1.0.6
Update kv-log-macro to 1.0.6
5 years ago
Thibault Martinez 2ab08ebbbc Update kv-log-macro to 1.0.6 5 years ago
Friedel Ziegelmayer 0e7650a421
Merge pull request #822 from async-rs/async-extern-1 5 years ago
dignifiedquire 8f17e9275b test: try to stabilize CI 5 years ago
dignifiedquire 18dffe8b43 refactor: switch to async-mutex for Mutex implementation 5 years ago
Friedel Ziegelmayer 43de93312c
Merge pull request #825 from nbdd0121/master
Fix unused_mut warning in nightly
5 years ago
Gary Guo 2e7e804736 Fix unused_mut warning in nightly 5 years ago
Friedel Ziegelmayer 17ab958ac2
Merge pull request #820 from zhaxzhax/docs-#815 5 years ago
Friedel Ziegelmayer caa76af745
Merge pull request #821 from async-rs/1-6-2
chore: release v1.6.2
5 years ago
dignifiedquire e495ba46b3 chore: release v1.6.2 5 years ago
Afirez 0c2ce52ac4 fix doc missing in #815 5 years ago
Friedel Ziegelmayer 5f418f07ac
Merge pull request #819 from async-rs/fix-sockets 5 years ago
dignifiedquire 06a2fb8c4f fix export 5 years ago
dignifiedquire 1c1c168e1b fix(timer): ensure the runtime is working for timers 5 years ago
Friedel Ziegelmayer 5d55fa7a47
Merge pull request #701 from olegnn/flat_map_fixed 5 years ago
dignifiedquire 093d640ad7 fix(net): ensure the reactor and runtime are running
If this is not done, then reactor is not running, resulting in the sockets not actually connecting.

Closes #818
5 years ago
Oleg Nosov 42425f6c1a
Another hotfix 5 years ago
Yoshua Wuyts a602a91d83
Merge pull request #816 from zhaxzhax/add-udpscket-peeraddr
Add UdpSocket::PeerAddr #307
5 years ago
Afirez 9fa3ce3fd6 Add UdpSocket::PeerAddr #307 5 years ago
Oleg Nosov df22d87d09
Removed unnecessary links + hotfix 5 years ago
Oleg Nosov 924e5a3f41
Merge remote-tracking branch 'origin/master' into flat_map_fixed 5 years ago
Oleg Nosov 2323ac9a8e
Apply suggestions from code review
Co-authored-by: nasa <htilcs1115@gmail.com>
5 years ago
Friedel Ziegelmayer 5c2a3de9e7
Merge pull request #814 from async-rs/1-6-1
chore: release v1.6.1
5 years ago
dignifiedquire e9c6ea873c chore: release v1.6.1 5 years ago
Friedel Ziegelmayer 0d98aac8f7
Merge pull request #812 from thibault-martinez/gh-actions-cache-v2 5 years ago
Thibault Martinez 4555f193a5 ci: update actions/cache to v2 5 years ago
Yoshua Wuyts 61fc2bae72
Merge pull request #809 from async-rs/fix/recursive-block-2
fix(rt): use task::block_on on spawned threads
5 years ago
dignifiedquire 5a1a681d68 fix(rt): use task::block_on on spawned threads
This makes sure to capture threads into the recursive block_on detection.
5 years ago
Friedel Ziegelmayer e12cf80ab0
fix: allow for recursive block-on calls
Fixes #798,#795,#760
5 years ago
Friedel Ziegelmayer 631105b650
Merge pull request #806 from async-rs/fix-feature-unstable 5 years ago
Friedel Ziegelmayer 0897b9184a
Merge pull request #804 from async-rs/tokio02-feature 5 years ago
Friedel Ziegelmayer 6ca7b0977c
Merge pull request #807 from xfix/remove-stdio-lock-methods
Remove stdio lock methods
5 years ago
Konrad Borowski 721760a7a6 Remove stdio lock methods
Fixes #805.
5 years ago
dignifiedquire 8389041414 fix 5 years ago
dignifiedquire 8943ba82dd fix nostd 5 years ago
dignifiedquire 52c72426c1 fix: do not require the runtime to use unstable features 5 years ago
Yoshua Wuyts 0df3c02b81 check tokio02 features 5 years ago
Yoshua Wuyts 166c469d1c Add the tokio02 feature flag 5 years ago
Friedel Ziegelmayer 0ec027dbff
Merge pull request #802 from jerry73204/fix-reading-buf-bug 5 years ago
jerry73204 d60e7cc27d Fix wrong slice index when reading a file 5 years ago
Friedel Ziegelmayer 6d2a43e336
Merge pull request #794 from async-rs/1-6-0 5 years ago
dignifiedquire e1c8638173 chore: release v1.6.0 5 years ago
dignifiedquire 06eea4225b feat: add PartialEq and Eq for channel Errors
Closes #792
5 years ago
Friedel Ziegelmayer 252140839b
Merge pull request #791 from Licenser/patch-1 5 years ago
Heinz N. Gies 69806403c6
Fix readme for BufRead
The `BufRead` readme points to `BufReadExt` being in `async_std::prelude` while it currently lives in `async_std::io::prelude`
5 years ago
Friedel Ziegelmayer 955befd746
Merge pull request #790 from async-rs/1-6-0-beta-2 5 years ago
nasa 70dac51938
Merge pull request #729 from k-nasa/fix_doc_test
Fix doc test
5 years ago
k-nasa d30603affe Merge branch 'master' into fix_doc_test 5 years ago
dignifiedquire c9ecb5bbbd prepare v1.6.0-beta.2 5 years ago
Jacob Rothstein 9e6a76af04
feat: add env vars to configure the runtime threadpool size and name 5 years ago
Friedel Ziegelmayer 2b6c7fedff
Merge pull request #772 from jbr/unixstream-clone 5 years ago
Friedel Ziegelmayer b3277954c7
Merge pull request #776 from azriel91/bugfix/775/wasm-timer-delay 5 years ago
Azriel Hoh baead51a28 Reduces duration in timeout test.
Tries to get CI to pass.
5 years ago
Azriel Hoh e9621af345 Updates `CHANGELOG.md`. 5 years ago
Azriel Hoh d3e59370e7 Switches `wasm-timer` for `futures-timer`. 5 years ago
Jacob Rothstein cd5e17fe87
make UnixStream Clone 5 years ago
Friedel Ziegelmayer e20b0f0d75
Merge pull request #768 from async-rs/fix/file-block
fix(fs): use smol::block_on for drop handling of File
5 years ago
dignifiedquire 19170aead4 use local file 5 years ago
dignifiedquire 2762ec5800 fix(fs): use smol::block_on for drop handling of File
Ref #766
5 years ago
dignifiedquire 247c94ca06 docs(changelog): add missing link 5 years ago
Friedel Ziegelmayer e404dcdd03
Merge pull request #765 from async-rs/feat/1-6-0 5 years ago
dignifiedquire bd6a7e200b prepare v1.6.0-beta.1 5 years ago
Friedel Ziegelmayer e4c4c93d29
Test and fix 32 bit targets 5 years ago
Thayne McCombs 6f6fced103
feat: implement Barrier using Condvar 5 years ago
Friedel Ziegelmayer 10f7abb3b6
Merge pull request #757 from dignifiedquire/feat/smol 5 years ago
dignifiedquire 27c605b4c9 cr: bring back trace call 5 years ago
dignifiedquire faea222b9c fix: use run instead of block_on 5 years ago
dignifiedquire 1214bc2dee increase timeouts 5 years ago
dignifiedquire 26f62aafd9 make wasm deps part of std 5 years ago
dignifiedquire e0928463b1 fix windows traits 5 years ago
dignifiedquire 92532612b7 mark spawn_local unstable 5 years ago
dignifiedquire 1a6d4f6a2f fix windows trait declarations for rawsocket 5 years ago
dignifiedquire 7a9afbd81c update smol 5 years ago
dignifiedquire 280b1a4344 remove invalid doc comment 5 years ago
dignifiedquire 48dd683535 fix feature settings 5 years ago
dignifiedquire 804a52b7fd use published smol 5 years ago
dignifiedquire e4df1405c1 feat: add basic wasm support 5 years ago
dignifiedquire 2cd2ba3530 remove unused dependencies 5 years ago
dignifiedquire 3161a4e449 add some missing windows imports 5 years ago
dignifiedquire 228cc59b3b feat: add spawn_local 5 years ago
dignifiedquire 0a7a52aed5 update to work on smol/master 5 years ago
dignifiedquire 10c8b9a6d8 silence must use 5 years ago
dignifiedquire fd6ae40817 add timeout stress test 5 years ago
dignifiedquire ab9d6554aa switch to smol::Timer 5 years ago
dignifiedquire f5fa0d7e4e avoid boxing futures 5 years ago
dignifiedquire b96afc41dc implement task locals 5 years ago
dignifiedquire 75ab7219df bring back random 5 years ago
dignifiedquire e082634b5e fix spawning 5 years ago
dignifiedquire fc9ee0dfdd keep std::sync::Arc 5 years ago
dignifiedquire 1308fbdf55 switch to smol instead of an internal runtime 5 years ago
dignifiedquire 690ab16587 add dependency 5 years ago
Florian Gilcher 370642ef3e
Merge pull request #734 from sunli829/master
Add async-graphql to the ecosystems inside the readme
5 years ago
Sunli 100c3423c1
Apply suggestions from code review
Thank you.😁

Co-Authored-By: Friedel Ziegelmayer <me@dignifiedquire.com>
5 years ago
nasa 7999e6bf4b
ci: speed up github actions 5 years ago
Fangdun Cai e707ea96e0
docs(readme): add ci status badge 5 years ago
Friedel Ziegelmayer b446cd0230
Merge pull request #748 from async-rs/fix/scheduler-2
fix(rt): bring back dynamic machines
5 years ago
Thayne McCombs db438abb8f
Implement async_std::sync::Condvar (#369)
* Implement async_std::sync::Condvar

Part of #217

* More rigourous detection of notification for condvar

* Use state of Waker instead of AtomicUsize to keep track of if task was
notified.

* Add test for notify_all

* Implement wait_timeout_until

And add warnings about spurious wakeups to wait and wait_timeout

* Use WakerSet for Condvar

This should also address concerns about spurious wakeups.

* Add test for wait_timeout with no lock held

* Add comments describing AwaitNotify struct

And remove an unnneded comment in a Debug implementation
5 years ago
dignifiedquire a4e07e345c fix(rt): bring back dynamic machines
Even if we do not make use of the progress blocking, we do need to make use of the dynamic restarting of machines as far as I understand.

Keeps the perf, while removing the regression from #747
5 years ago
Yoshua Wuyts aebba2bd95
Merge pull request #747 from async-rs/fix/scheduler-perf
Fix new scheduler loop
5 years ago
dignifiedquire 0c9a66c1f6 fix scheduler loop
This now matches more closely the logic as implemented in #631, and fixes the performance regression as far as I have observed.

Closes #746
5 years ago
Friedel Ziegelmayer fc4e472599
Merge pull request #733 from k-nasa/new-scheduler
New scheduler
5 years ago
nasa 6674dc0edf
Merge pull request #739 from devashishdxt/futures-timer-update
Update futures-timer to 3.0.2
5 years ago
k-nasa 088aa5662c refactor: Remove wrapping cell 5 years ago
Devashish Dixit 68fa054517 Update futures-timer to 3.0.2 5 years ago
k-nasa b88138b5d7 kick ci 5 years ago
k-nasa 11ee2a8985 fix 5 years ago
k-nasa 322911142c lock processor and remove unsafe Send, Sync 5 years ago
k-nasa cfaec2aa95 re add spin_lock 5 years ago
sunli 57c648cf01 Add async-graphql to the ecosystems inside the readme 5 years ago
k-nasa 6d3ca5a06f remove poll function 5 years ago
k-nasa f960776846 fix 5 years ago
k-nasa 5c6741724f Merge branch 'master' into new-scheduler 5 years ago
k-nasa 24c5dbf949 Remove scheduler state 5 years ago
nasa 2dbebe54ed
Merge pull request #721 from k-nasa/update_dep_crate
update dependence crates
5 years ago
k-nasa d7ee29a03f fix test code 5 years ago
k-nasa 2b44c1be2e refactor: swap to swap_and_compare 5 years ago
k-nasa b1ec1ea930 Move Spinlock to sync module 5 years ago
k-nasa 2ab075d027 refactor 5 years ago
k-nasa c0f18600cf run ignored test 5 years ago
k-nasa 6c8237276b fix doc test 5 years ago
k-nasa 98cbf7f8eb Restore task::spawn_blocking 5 years ago
k-nasa 84e5c5f351 Merge branch 'master' into new-scheduler 5 years ago
Yoshua Wuyts 3ff9e98f20
Merge pull request #585 from async-rs/try_channels
expose try_recv and try_send on channels
5 years ago
Yoshua Wuyts b7c7efc797 Update try_channel doctests 5 years ago
Yoshua Wuyts 19fd7a4084 fix channel tests
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 7885c245c5 recverror
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 7b7b959a6e mark channel errs as unstable
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 32dce319d3 expose try_recv and try_send on channels
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 49dd02b4de Make the split struct public 5 years ago
Yoshua Wuyts bb11c676a1 doctests pass 5 years ago
Yoshua Wuyts e026b7579a
Merge pull request #703 from spacekookie/recv-docs
channel/recv: improving function docs and code example
5 years ago
Yoshua Wuyts 51dd7ceb72
Merge pull request #727 from async-rs/revert-719-remove_re_export
Revert "Stabilize most stream method and remove unnecessary macros"
5 years ago
k-nasa 8931d1464e fix ci 5 years ago
nasa cc19592f80
Revert "Stabilize most stream method and remove unnecessary macros" 5 years ago
nasa f69887a50d
Update Cargo.toml 5 years ago
k-nasa 0b0531057d feat: update dependence crates 5 years ago
Yoshua Wuyts 61f9483cc5
Merge pull request #719 from k-nasa/remove_re_export
Stabilize most stream method and remove unnecessary macros
5 years ago
k-nasa f33d7f40ab fix test 5 years ago
k-nasa e3bf89fc05 $cargo fmt 5 years ago
k-nasa ec4b09ecd0 fix test code 5 years ago
k-nasa b95bd6c1fe fix: Remove unnecessary io modules 5 years ago
k-nasa 1e18839f1f fix warning 5 years ago
k-nasa f31878655e fix: Stabilize stream method 5 years ago
k-nasa 9a62df143f add whitespace 5 years ago
k-nasa 75223905bd fix: Stabilize stream most method 5 years ago
k-nasa be60dd9fe7 fix: Remove unnecessary re-export and macros 5 years ago
k-nasa 23b7c174f3 feat: Stabilize io::Std*Lock 5 years ago
Yoshua Wuyts 9167d42f4b
Merge pull request #708 from sunli829/master
Add Xactor to the ecosystems inside the readme
5 years ago
Yoshua Wuyts 4034d58709
Merge pull request #714 from abhijeetbhagat/patch-1
Add missing ? operator after handle.await
5 years ago
abhi 4742f461fe
Add missing ? operator after handle.await
According to line#118, there should be a `?` operator after `await`.
5 years ago
nasa efab39eeaf
Merge pull request #710 from k-nasa/fix_ci_failed
Fixed ci failing
5 years ago
k-nasa bd60cd9f81 run `cargo fmt` 5 years ago
sunli b9e4b6da3e Add Xactor to the ecosystems inside the readme 5 years ago
Yoshua Wuyts eb03f37e43
Merge pull request #697 from async-rs/core-docs
Document the core feature
5 years ago
Yoshua Wuyts d87e283215
Update src/lib.rs 5 years ago
Yoshua Wuyts 283a54a155
Update src/lib.rs 5 years ago
Yoshua Wuyts 3719484eba
Update src/lib.rs
Co-Authored-By: nasa <htilcs1115@gmail.com>
5 years ago
Katharina Fey aae835cc14
channel/recv: improving function docs and code example
At the moment it's not clear when and why recv returns Option<T>,
instead of just T. This changed comment makes it clear that None will
only be returned once no data will ever be sent again (i.e. after all
senders are gone).
5 years ago
Oleg Nosov 68063adddf
Add link to tests 5 years ago
Oleg Nosov d7cab38b67
`core` => `std` 5 years ago
Oleg Nosov 32068942a6
Fixed `flatten` 5 years ago
Oleg Nosov 85c32ef9d2
Use `assert` without `if`-clause 5 years ago
Oleg Nosov b68be72763
Use `assert` instead of `panic` 5 years ago
Oleg Nosov c80915e216
Dont spawn thread in tests 5 years ago
Oleg Nosov 303ac90b7c
Fixed `flat_map` 5 years ago
Yoshua Wuyts d026c44ea3 Document the core feature
Follow-up to https://github.com/async-rs/async-std/pull/680
5 years ago
Yoshua Wuyts 125fa5b0a0
Merge pull request #680 from k-nasa/no_std
Some modules support no_std
5 years ago
Yoshua Wuyts 39f2c6da78
V1.5.0 (#694)
* Update CHANGELOG.md

* v1.5.0

* Update CHANGELOG.md
5 years ago
k-nasa 3e24e0ba4e ci: fix no-std check 5 years ago
k-nasa 0d90cb07b9 fix: Move `extern crate alloc` to lib.rs 5 years ago
k-nasa f789f9d4f6 Select future-core featue according to feature 5 years ago
k-nasa ef985bc72e ci: fix no_std ci 5 years ago
Stjepan Glavina 1d875836a2
Implement Clone for TcpStream (#689)
* Implement Clone for TcpStream

* Update examples

* Remove accidentally added examples
5 years ago
k-nasa 7efe7caf66 fix: Change feature name no-std to alloc 5 years ago
k-nasa 22d929d481 fix import Future 5 years ago
k-nasa d622ec5d35 feat: Make the stream module no_std 5 years ago
k-nasa 880b7ee987 remove crate::prelude import 5 years ago
k-nasa 1762de285b feat: Make the future module no_std 5 years ago
k-nasa 6aa55fde59 feat: Make the task module no_std 5 years ago
k-nasa 41f114d9fe ci: Add no-std check 5 years ago
k-nasa 3d32fd81f4 feat: Make the utils module no_std 5 years ago
k-nasa 51b84a7620 feat: Add no_std attribute when not std feature 5 years ago
k-nasa 4996f29778 feat: Add no-std feature 5 years ago
Toralf Wittner 57974ae0b7 Use non-blocking connect for TcpStream. (#687)
* Use non-blocking connect for TcpStream.

Instead of spawning a background thread which is unaware of any timeouts
but continues to run until the TCP stack decides that the remote is not
reachable we use mio's non-blocking connect.

mio's `TcpStream::connect` returns immediately but the actual connection
is usually just in progress and we have to be sure the socket is
writeable before we can consider the connection as established.

* Add Watcher::{poll_read_ready, poll_write_ready}.

Following a suggestion of @stjepang we offer methods to check for
read/write readiness of a `Watcher` instead of the previous approach to
accept a set of `Waker`s when registering an event source. The changes
relative to master are smaller and both methods look more useful in
other contexts. Also the code is more robust w.r.t. wakeups of the
`Waker` from clones outside the `Reactor`.

I am not sure if we need to add protection mechanisms against spurious
wakeups from mio. Currently we treat the `Poll::Ready(())` of
`Watcher::poll_write_ready` as proof that the non-blocking connect has
finished, but if the event from mio was a spurious one, it might still
be ongoing.
5 years ago
Yoshua Wuyts 57f9fb7e93
Merge pull request #682 from k-nasa/impl_clone_for_dir_entry
Implement Clone trait for DirEntry
5 years ago
Yoshua Wuyts 6c1b5eb3ed
Merge pull request #667 from olegnn/option_take_while
Use `take_while` instead of `scan` in `impl` of `Product`, `Sum` and `FromStream` for `Option` and `Result`
5 years ago
Yoshua Wuyts beb8d240c2
Merge pull request #688 from ninj/patch-1
fix syntax problem for task::sleep
5 years ago
ninj b258215952
fix syntax problem for task::sleep 5 years ago
Florian Gilcher 1ababac97f
Merge branch 'accept_loop_pattern' 5 years ago
Florian Gilcher f9fe5c90cf
Fix some typos in accept-loop pattern chapter 5 years ago
Florian Gilcher 84fe94444b
Merge pull request #675 from k-nasa/add_timeout_example
Add stream::timeout example when timeout error
5 years ago
Florian Gilcher cad2880eb8
Merge pull request #550 from sclaire-1/master
Edit tutorial: implementing_a_client.md
5 years ago
Taiki Endo 6b860c370a Remove usage of unstable format_code_in_doc_comments option (#685) 5 years ago
Katharina Fey 81aa6d152a Changing task::block_on to park after a single poll (#684)
This was previously discussed in #605 and others as a source of high
CPU load when sleeping tasks because of the overhead created by
retrying a future in short succession.
5 years ago
k-nasa 2221441a4c feat: Implement Clone trait for DirEntry 5 years ago
Oleg Nosov ed7ddacb28
Rewrote `Result`s implementation using `take_while` and `filter_map` 5 years ago
nasa d283352a9a update broadcastor to 1.0.0 (#681) 5 years ago
Oleg Nosov ed248017b4
Use internal `scan` state in `Result`s implementation 5 years ago
Yoshua Wuyts 0eb5ca14ac
Merge pull request #676 from k-nasa/async_task_bump_to1.2.1
update async-task to 1.2.1
5 years ago
Oleg Nosov 38de0bfd22
Use `std::convert::identity` 5 years ago
Oleg Nosov 134089af2c
Use `filter_map(identity)` + other fixes 5 years ago
k-nasa b72dd83726 update async-task to 1.2.1 5 years ago
k-nasa ee102dfc9e docs: Add stream::timeout example when timeout error 5 years ago
nasa 1071e82132
Merge pull request #671 from Noah-Kennedy/udp-socket-send-doc
Fix docs for UdpSocket::send
5 years ago
noah 0a52864764 Revert "Fixes https://github.com/async-rs/async-std/issues/652"
This reverts commit a4f68066
5 years ago
noah 76993dd755 Revert "Fixes https://github.com/async-rs/async-std/issues/652"
This reverts commit a4f68066
5 years ago
Yoshua Wuyts 133e30e6f6
Merge pull request #615 from lqf96/pending-stream
Add an implementation of pending stream
5 years ago
nasa 76ed174fd5 Version up of dependent crate (#672) 5 years ago
k-nasa f53fcbb706 test,docs: Add stream::pending example code 5 years ago
k-nasa e9357c0307 style: Run `cargo fmt` 5 years ago
Qifan Lu 879e14c6ab Remove size_hint from Stream impl 5 years ago
Qifan Lu f8dd3d9816 Add stream::pending::{pending, Pending} 5 years ago
noah a4f6806605 Fixes https://github.com/async-rs/async-std/issues/652 5 years ago
Yoshua Wuyts 5d5064b871 add FromStream Result example (#643)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
nasa 0ed0d63094 Remove unnecessary trait bound on FlatMap (#651)
* Remove unnecessary trait bound on FlatMap

* test: upgrade test code
5 years ago
Paul Colomiets 0029037883 async-listen crate: Add `error_hint()` invocation 5 years ago
Oleg Nosov fb567a3a09
Recovered comments 5 years ago
Oleg Nosov 83afbab2ef
Use `take_while` instead of `scan` for `Option` 5 years ago
Paul Colomiets c8c075615c book: Add Production-ready Accept Loop section
Part of the #658 work
5 years ago
Yoshua Wuyts 98d45f4be1
Merge pull request #647 from dignifiedquire/feat/unstable-without-default
feat: do not require default feature for unstable
5 years ago
dignifiedquire 9c6ab5e7c3 fix 5 years ago
dignifiedquire 9c9ab90da3 feature gate random 5 years ago
dignifiedquire 5bf3d95313 feat: do not require default feature for unstable 5 years ago
Yoshua Wuyts 1f78efec64
Merge pull request #660 from mehcode/mehcode-ecosystem
Showcase the ecosystem
5 years ago
Yoshua Wuyts 383057b8ea
Merge pull request #659 from alfiedotwtf/master
Tiny grammar fix
5 years ago
Yoshua Wuyts 763862acc7
Merge pull request #661 from async-rs/fix-ci
remove usage of deprecated Error method to fix CI
5 years ago
Yoshua Wuyts e2bb79c207
Merge pull request #648 from spacekookie/master
Fixing inaccurate function description in udp::recv
5 years ago
Yoshua Wuyts 57a62797f2
Merge pull request #655 from u32i64/patch-1
Fix crate documentation typo
5 years ago
Yoshua Wuyts dfb0c8124c
remove usage of deprecated method
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Ryan Leckey d806a09599 Add a section on the async ecosystem to showcase crates that use async-std 5 years ago
Alfie John af2d46d9b9 Tiny grammar fix 5 years ago
Artem Varaksa 65d7950df1
Fix crate documentation typo 5 years ago
nasa 6d69a3e368
Merge pull request #650 from senden9/patch-1
Fix typo in stream documentation
5 years ago
Stefano Probst c3d5dba1b5
Fix typo in stream documentation 5 years ago
Katharina Fey 081166f204
Fixing inaccurate function description in udp::recv 5 years ago
Yoshua Wuyts fee3b6f603
Merge pull request #645 from async-rs/remove-tokio-mention
update stream::Interval internal comments left over from migration
5 years ago
Yoshua Wuyts b3942ecfa8
remove tokio mention
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 86d3d74180
Merge pull request #637 from async-rs/v1.4.0
1.4.0
5 years ago
Yoshua Wuyts 3fd6d8b02e
1.4.0
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
nasa 0d4b4cd260
Merge pull request #600 from miker1423/future-timeout
Adding timeout extension method to Future trait
5 years ago
Miguel Pérez García ef021dcb2b Changing test condition 5 years ago
Miguel Pérez García eedf1d3367 Fixing docs 5 years ago
Miguel Pérez García 97b4901b75 Fixing tests 5 years ago
Miguel Pérez García 1eeb1019e9 Fixing example 5 years ago
Miguel Pérez García 980a1f7834 Correcting docs on function 5 years ago
nasa d2c25f483a
Merge pull request #635 from async-rs/revert-629-update-log
Revert "upgrade log, remove kv-log-macro"
5 years ago
nasa d8befe24e8
Revert "upgrade log, remove kv-log-macro" 5 years ago
Florian Gilcher c7cf1934db
Merge pull request #629 from async-rs/update-log
upgrade log, remove kv-log-macro
5 years ago
Yoshua Wuyts 37d8a013de
Merge pull request #633 from k-nasa/fix_io_export
fix missing export for the return value
5 years ago
k-nasa 43f4f393af fix missing export for the return value 5 years ago
Stjepan Glavina ceba324bef Fix feature flags 5 years ago
Stjepan Glavina 36d24cd0e1 New scheduler resilient to blocking 5 years ago
Yoshua Wuyts 61eb52cb36
Merge pull request #625 from nbdd0121/sync_unsized
Use ?Sized in Mutex and RwLock
5 years ago
Yoshua Wuyts 6f4dcad6a0
Merge pull request #630 from async-rs/fix-ci-2
fix ci
5 years ago
Yoshua Wuyts 60de8e1082
up time limits
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts cac4e081cc
Merge pull request #628 from fenhl/patch-1
Make WriteFmtFuture must_use
5 years ago
Yoshua Wuyts 8ad1d23116
fix ci
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 019aa14898
Merge pull request #621 from async-rs/fix-doc-hiccup
fix stream doc hiccup
5 years ago
Yoshua Wuyts b7e55762d8
upgrade log, remove kv-log-macro
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts c70552ead5
unpub double_ended_stream
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Fenhl 07eb2c1280
Make WriteFmtFuture must_use
Fixes #627. Thanks to @jebrosen for pointing out the location of the issue.
5 years ago
Gary Guo 732ef10f98 Make code compile 5 years ago
Gary Guo 499a44ab3b Use ?Sized in Mutex and RwLock 5 years ago
Yoshua Wuyts 761029cd08
fix stream doc hiccup
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 83a488b290
Merge pull request #597 from k-nasa/fix_doc_test
Fix failed doc test and enable doc test on CI
5 years ago
Yoshua Wuyts 2f0907714d
Merge pull request #617 from async-rs/1.3.0
1.3.0
5 years ago
Yoshua Wuyts 055c64e8a7
1.3.0
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 96d6fc43d6
Merge pull request #618 from twittner/poll_close_shutdown
TcpStream: Shutdown write direction in poll_close.
5 years ago
Yoshua Wuyts 3d3bf914ea
Merge pull request #562 from felipesere/double_ended_ext
DoubleEndedStream extension
5 years ago
Miguel Pérez García 84b6d2b276 Removing duplicated tests 5 years ago
Miguel Pérez García 8de9f9b8e1 Merge branch 'future-timeout' of https://github.com/miker1423/async-std into future-timeout 5 years ago
Felipe Sere 182fe6896f No need for a custom impl for FromIter for DoubleEndedStream 5 years ago
Felipe Sere b0038e11be Only implement the DoubleEndedStream for once when the flag is on 5 years ago
Felipe Sere 8e5dedec34 Restructure package. No longer use a extension trait to match std.
Still outstanding: How do I hide the concrete structs from the trait?
5 years ago
Felipe Sere 41cf0f855b Make Once a DoubleEndedStream 5 years ago
Felipe Sere f9a4c35fd6 Silence warning about missing docs for the double_ended module 5 years ago
Felipe Sere 6e8236d0e1 Document from_iter for DoubleEndedStream 5 years ago
Felipe Sere 892c6008c2 Replace sample with a hidden from_iter implementation for double-ended-stream 5 years ago
Felipe Sere abd360893c Disable docs and Debug for unexposed structs 5 years ago
Felipe Sere 94893d2924 Move more of the documentation 5 years ago
Felipe Sere 02aa2f3d2a Fix next_back 5 years ago
Felipe Sere ee2f52f3ce Add next_back 5 years ago
Felipe Sere 55194edbf7 Add try_rfold 5 years ago
Felipe Sere c4b9a7f680 Add samples for some of the functions 5 years ago
Felipe Sere aabfefd015 Add a sample implementation of a double ended stream 5 years ago
Felipe Sere cc493df433 Sketch out rfold 5 years ago
Felipe Sere 78bafbb88f Sketch outch rfind 5 years ago
Felipe Sere d0ef48c753 Sketch out nth_back 5 years ago
Felipe Sere fa288931c6 Skeleton for DoubleEndedStreamExt trait 5 years ago
Toralf Wittner c90732a805 TcpStream: Shutdown write direction in poll_close.
Fixes #599.
5 years ago
Yoshua Wuyts 63b6a2b961
Merge pull request #614 from killzoner/doc-typo-await
fix: Fix typo in documentation
5 years ago
Yoshua Wuyts 1103c17e16
Merge pull request #613 from k-nasa/fix_readme
Readme example simply compile
5 years ago
Yoshua Wuyts a0f3b3b753 Remove unused macros (#610)
* replace async-macros with internals only

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* clean up MaybeDone

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* inline futures_core::ready

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* remove big commented blob

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Tomasz Miąsko f06ab9fbc4 Remove mention of task stack size configuration (#612) 5 years ago
svengrim 447c17128f
fix: Fix typo in documentation 5 years ago
k-nasa a04157850b fix readme 5 years ago
nasa 9311fd7fae
Merge pull request #595 from linkmauve/patch-1
docs: Replace mention of futures-preview crate
5 years ago
nasa f7b21a3e8d
Merge pull request #608 from dungph/master
fix link to `task/block_on` on README.md
5 years ago
Dung Pham f0bdcfec25
fix link 5 years ago
Miguel Pérez García 33e7c87dfc Adding example to docs 5 years ago
Miguel Pérez García cc85533f7c fixing format 5 years ago
Miguel Pérez García 4670388a56 Adding tests 5 years ago
Miguel Pérez García c14c377974 Changing method signature 5 years ago
Miguel Pérez García 54fa559554 Changing scope of disclosure 5 years ago
Yoshua Wuyts bce8688763
Merge pull request #603 from bluk/udp-socket-recv-doc
Change recv_from to recv in UdpSocket::recv doc
5 years ago
Bryant Luk fd86effb63
Change recv_from to recv in UdpSocket::recv doc 5 years ago
nasa 128a6bc6ce
Merge pull request #598 from povilasb/fix/docs
Fix a link in the docs
5 years ago
Yoshua Wuyts d51a135015
Merge pull request #309 from async-rs/stream-delay
Stream::delay
5 years ago
Miguel Pérez García 1c2055fff0 Merge remote-tracking branch 'original/master' into future-timeout 5 years ago
Povilas Balciunas 81e3c41826 Fix a link in the docs 5 years ago
k-nasa fb1fb6c903 test: Test the delay time 5 years ago
k-nasa c85e2496b1 Enable doc test on ci 5 years ago
k-nasa 7d9a063002 fix cargo test arguments on ci 5 years ago
k-nasa 44e38eae59 fix open_file test code 5 years ago
k-nasa fe04cf26b6 test: fix stream::throttle doc test 5 years ago
k-nasa 556d7992ce test: fix failed doc test 5 years ago
k-nasa da965e9ba4 fix indent 5 years ago
k-nasa 9f7c1833dc fix module 5 years ago
linkmauve 55560ea9b4
docs: Replace mention of futures-preview crate
It is now stable in 0.3.
5 years ago
Stjepan Glavina bf9ee88815 Fix a typo 5 years ago
Stjepan Glavina 9627826756 Bump the version to 1.2.0 5 years ago
Stjepan Glavina 4ed15d67c9 Fix links in the changelog 5 years ago
Stjepan Glavina 0165d7f6d1 Add missing items to the changelog 5 years ago
Yoshua Wuyts dba416608a 1.2.0 (#589)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 68005661d9 fix Stream::throttle hot loop (#584)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
nasa 794e331761 Refactor join type (#577)
* refactor: update future join type

* test: update future join test

* update future::try_join
5 years ago
Yoshua Wuyts 63f7ea3081
Merge pull request #587 from async-rs/contributing
link to our contribution guidelines
5 years ago
k-nasa 32765ece41 test: Add stream::delay test code 5 years ago
k-nasa 635c592950 feat: Add stream::delay 5 years ago
k-nasa 3b055f364e Merge branch 'master' into stream-delay 5 years ago
Yoshua Wuyts 46cafffc31
Merge pull request #571 from killercup/more-errors
Add context to more errors
5 years ago
boats 0f30ab8c0a Fix the docs and Debug output of BufWriter. (#588)
The BufWriter docs inaccurately stated that it flushes on drop, which it does
not do. This PR changes the docs, as well as the example, to highlight that
the user must explicitly flush a bufwriter.

There were also two places where the BufWriter code referred to it as a
BufReader: in the link to the std docs, and in the Debug output. Those have
also been fixed.
5 years ago
Yoshua Wuyts e66e2e2b8f
link to our contribution guidelines
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Pascal Hertleif 56538ebd91 Improve verbose errors for socket addresses
Moves the point of adding error context to the net::addr module so that
we have access to the raw address input and can include it in the error
message.
5 years ago
Pascal Hertleif aa7d1c27a4
Verbose errors: Apply suggestions
Co-Authored-By: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
5 years ago
Yoshua Wuyts 850b8ae9d0
Merge pull request #543 from k-nasa/stream_unzip
Add stream unzip
5 years ago
Yoshua Wuyts ac7a796f82
Merge pull request #537 from k-nasa/ci_master
Enable CI on master branch
5 years ago
Miguel Pérez García c1f7be5d42 Adding timeout extension method to Future trait 5 years ago
Yoshua Wuyts 50cefce803
Merge pull request #561 from async-rs/1.1.0
1.1.0
5 years ago
Yoshua Wuyts 3780ff7b44
1.1.0
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

changelog

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts c9a2e74789
Merge pull request #523 from async-rs/update-lib-example
polish lib.rs examples
5 years ago
Yoshua Wuyts cffacf7fa3
feedback from review
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 02e1d7e5ea
Merge pull request #574 from stjepang/ignore-unread-errors
Ignore seek errors in poll_unread
5 years ago
laizy ec5415358f simplify AllFuture and AnyFuture (#572) 5 years ago
Alejandro Martinez Ruiz ba1ee2d204 Fix a-chat tutorial issues (#573)
* tutorial/receiving_messages: fix future output type bound

* tutorial/receiving_messages: remove unneeded message trimming

Trimming was done twice on messages, so one of the two instances can
be removed. I personally think removing the first instance, in which
we are splitting names from messages makes the code more readable
than removing the second instance, but other examples further in
the tutorial show the second instance removed.

* tutorial/receiving_messages: declare use of TcpStream and io::BufReader

Readers couldn't see the `use` lines corresponding to these two
structures.

* tutorial/connecting_readers_and_writers: typos and grammar fixes

* tutorial/all_together: remove unneeded use async_std::io

* tutorial: use SinkExt consistently from futures::sink::SinkExt

* tutorial/handling_disconnection: hide mpsc use clause and remove empty lines

The empty lines translate to the output making it look weird.

* tutorial/handling_disconnection: fix typos

* tutorial/handling_disconnection: use ? in broker_handle.await

We were happy to return an Err variant from the broker_handle before
and nothing has changed in this regard, so bubbling it up to run().
5 years ago
Stjepan Glavina 16edec3464 Ignore seek errors in poll_unread 5 years ago
Pascal Hertleif e01f07d72a Add context to more errors
cc #569
5 years ago
Yoshua Wuyts b3d30de4a1 mark windows fs APIs as "unstable" (#567)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 6f19165e0e
Merge pull request #568 from stjepang/fix-random
Fix rng use in Stream::merge
5 years ago
nasa d146d95a39
Update src/stream/stream/mod.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
Stjepan Glavina 5fba3a0928 Fix rng use in Stream::merge 5 years ago
Yoshua Wuyts 2ca03cabe6
Merge pull request #552 from hhggit/win_symlink
add os::windows::symlink_{dir,file}
5 years ago
hhggit 72ed4eb4fd
Update mod.rs 5 years ago
Yoshua Wuyts 77800ab3f9
Merge pull request #526 from yjhmelody/refactor-dir
refactor io dir to be same with std and export IntoInnerError
5 years ago
Yoshua Wuyts 8ea920c9f0
Merge pull request #546 from k-nasa/fix_clippy
Fix clippy warn
5 years ago
Yoshua Wuyts d1189f9974
Merge pull request #548 from yjhmelody/fix-stream-code-style
fix stream code style
5 years ago
Yoshua Wuyts 3f8ec5a007
Merge pull request #551 from killercup/feature/verbose-errors
verbose errors feature
5 years ago
nasa 3bc4d293dd
Merge pull request #503 from Razican/random_merge
Randomize Stream::merge to improve the throughput.
5 years ago
Yoshua Wuyts f24b3a4520
Merge pull request #559 from k-nasa/fix_max_by_key
Fix stream max_by_key and min_by_key
5 years ago
razican 72ca2c1a24
Improved the code with some minor changes 5 years ago
k-nasa b5e66c4f93 refactor: Refactoring option type handling 5 years ago
k-nasa 080875edc9 update min_by_key doc 5 years ago
k-nasa ca71ad073b fix stream min_by_key mistake 5 years ago
k-nasa 667bbc1019 doc: update doc test 5 years ago
k-nasa 64b2e10b93 fix max_by_key mistake 5 years ago
k-nasa 314a75da28 fix typo 5 years ago
Pascal Hertleif c704643296 Remove verbose-errors cargo feature 5 years ago
Yoshua Wuyts c6622475b2
Merge pull request #555 from stjepang/optimize-cargo-check
Macro optimization to reduce compilation times
5 years ago
Stjepan Glavina 65afd41a33
Once doesn't need Unpin bound (#554) 5 years ago
Stjepan Glavina d3e7f32a30 Macro optimization to reduce compilation times 5 years ago
Razican f6829859fe
Fixed deduplication of code 5 years ago
hhggit 2c9b558d14 add os::windows::symlink_{dir,file} 5 years ago
Pascal Hertleif 99ddfb3f93 Wrap code more clearly in cfg blocks 5 years ago
Pascal Hertleif 8ce3e78952 verbose errors feature
This adds a new "verbose-errors" feature flag to async-std that enables
wrapping certain errors in structures with more context. As an example,
we use it in `fs::File::{open,create}` to add the given path to the
error message (something that is lacking in std to annoyance of many).
5 years ago
sclaire-1 b2aaa8b825
Edit tutorial: implementing_a_client.md
Edited to improve reading flow
5 years ago
yjhmelody 223fcc30ee fix code style for stream 5 years ago
k-nasa 76975a4441 Merge branch 'master' into fix_clippy 5 years ago
Yoshua Wuyts 355e2eded8
Merge pull request #547 from async-rs/unpin-successors-test
remove pin_mut from successors test
5 years ago
Yoshua Wuyts 6cc9e4dd2b
Merge pull request #544 from async-rs/update-futures-timer
update futures-timer & other deps
5 years ago
Yoshua Wuyts ee23ba6e94
Merge pull request #545 from yjhmelody/stream-partition-patch
use `as_mut` for stream-partition
5 years ago
Yoshua Wuyts d68dc659b2
remove pin_mut from successors test
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts b5c3fb8bb5
Merge pull request #363 from felipesere/async-successors
Async successors
5 years ago
k-nasa 7d616c695d refactor: change to as_mut 5 years ago
yjhmelody a69b3a8a9e use `as_mut` for stream-partition 5 years ago
k-nasa a05b6a3810 fix: mutable ref 5 years ago
k-nasa 6cbf48f12d fix clippy warn 5 years ago
k-nasa 91ee4c7b9f doc: Add stream unzip doc 5 years ago
k-nasa 603b3c5085 add: Add stream unzip 5 years ago
Yoshua Wuyts 693a7257b8
Merge pull request #538 from k-nasa/stream_by_ref
Add stream by_ref
5 years ago
Yoshua Wuyts 8779c04dc7
upgrade all deps
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 3564be9c0c
update futures-timer dep
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
k-nasa df92c63337 fix: Add unstable features 5 years ago
k-nasa 31cf932d80 wip: Add stream unzip 5 years ago
Yoshua Wuyts 3c6d41ccb4
Merge pull request #541 from yjhmelody/stream-partition
add stream-partition
5 years ago
Yoshua Wuyts 837604b833
Merge pull request #542 from yjhmelody/update-doc
update doc url
5 years ago
yjh 74caed2d4b
Update src/io/seek/mod.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
yjhmelody 76ec9c4563 update doc url 5 years ago
yjhmelody d76b32e6d4 make it unstable and fix trait bound 5 years ago
yjhmelody 11268a80fb add stream-partition 5 years ago
Yoshua Wuyts c4ba11ff95
Merge pull request #535 from async-rs/docs-sender-recv
backlink channel types
5 years ago
k-nasa de67bf0fd4 feat: Add stream by_ref 5 years ago
k-nasa 4ef55d4d7b Enable CI on master branch 5 years ago
nasa 77a0419a3e
Merge pull request #536 from async-rs/count-unstable
mark Stream::count as unstable
5 years ago
Yoshua Wuyts ce98834039
Merge pull request #531 from sclaire-1/master
Edit tutorial index.md
5 years ago
Yoshua Wuyts 30ff7b09b6
mark Stream::count as unstable
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts c58747b5fc
Merge pull request #368 from starsheriff/stream_count
add stream::count
5 years ago
Yoshua Wuyts 31f129ebe7
backlink channel types
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts f49d7cbbb8
Merge pull request #533 from async-rs/remove-throttle-example
remove standalone throttle example
5 years ago
Felipe Sere 64216b8e6b Take a normal closure, not an async one 5 years ago
Felipe Sere 786a52a09d Slight miss-merge 5 years ago
Felipe Sere f14b37ff17 Remoe the T: Copy bound on the item 5 years ago
Felipe Sere 7677e9a3df Make the closure take a borrow to the value 5 years ago
Felipe Sere bfb42b432e Rearrange docs to match 'repeat' 5 years ago
Felipe Sere 4c09cdbeac Mark successors as unstable 5 years ago
Felipe Sere 243cdd7ff1 Slight miss-merge 5 years ago
Felipe Sere a257b7018c Rename some variables to match iter 5 years ago
Felipe Sere af928163e4 Got further! Thx Josh! 5 years ago
Felipe Sere 8d97e0f974 Only produes empty value if next is ever a 'None' 5 years ago
Felipe Sere 266754897e Rename the module to 'successors' 5 years ago
Felipe Sere 554d5cfbc1 Slight renamings 5 years ago
Felipe Sere 8b662b659d Run rustfmt 5 years ago
Felipe Sere 95a3e53fcd Only use the Option of the future to decide to construct a new one 5 years ago
Felipe Sere 02b261de10 It compiles! Store the future and poll it instead of creating multiple new ones 5 years ago
Felipe Sere fe3c9ef626 First attempt at successor 5 years ago
Yoshua Wuyts 4e1d79adb1
Merge pull request #524 from yjhmelody/stream-max
Add Stream max
5 years ago
Yoshua Wuyts 1546448800
remove throttle example
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 338273eb18
Merge pull request #356 from Wassasin/342-stream-throttle
Implemented StreamExt::throttle
5 years ago
Wouter Geraedts dda65cbff0 Start throttle measurement before initialisation 5 years ago
Johannes Weissmann 9ebe41f2d6
Update src/stream/stream/mod.rs
Co-Authored-By: nasa <htilcs1115@gmail.com>
5 years ago
Wouter Geraedts 90c67c223a Decreased throttle test time to original values; only test lower bound 5 years ago
sclaire-1 8473b738d0
Edit tutorial index.md
Edited the structure of sentences to make it easier to read
5 years ago
Stjepan Glavina 0c2282ffdc
Optimization: a slot for the next task to run (#529)
* Optimization: a slot for the next task to run

* Only notify workers when a task is pushed into a queue
5 years ago
Florian Gilcher d546ee3d92
Merge pull request #528 from skade/remove-nightly-note
Update version requirements in the tutorial
5 years ago
Florian Gilcher 6338341369
Merge pull request #520 from gierlachg/stream_pinning
Cleaning up stream pinning.
5 years ago
Florian Gilcher 6f4bea07a1
Update version requirements in the tutorial 5 years ago
yjhmelody 5adb112a00 export IntoInnerError for io 5 years ago
yjhmelody 9d634cb2a7 refactor io dir to be same with std 5 years ago
yjhmelody 879af6dc85 Add Stream max 5 years ago
Yoshua Wuyts 79962e20a5
enable attributes feature
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 1431ee0422
polish README.md examples
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 2dfdc1c482
polish lib.rs examples
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Grzegorz Gierlach e442eba625 Cleaning up stream pinning. 5 years ago
Grzegorz Gierlach f0875d2dca Cleaning up stream pinning. 5 years ago
Devashish Dixit f611ceccc8 Run cargo fmt for doc comments (#515) 5 years ago
Yoshua Wuyts 74a7d93611 upgrade async-macros to 2.0.0 (#519)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Wouter Geraedts c5b3a98e5b Increased throttle test to 10x time 5 years ago
Yoshua Wuyts 3151a70b77
Merge pull request #517 from Alexendoo/surf
Enable surf example
5 years ago
Wouter Geraedts 4ab7b213de Updated example to be consistent; added timing measurements to throttle 5 years ago
Wouter Geraedts 6990c1403f Reimplemented throttle to never drop Delay, added boolean flag 5 years ago
Wouter Geraedts 77a1849303 Merge branch '342-stream-throttle' of github.com:Wassasin/async-std into 342-stream-throttle 5 years ago
Wouter Geraedts a722de1a10 Merge remote-tracking branch 'upstream/master' into 342-stream-throttle 5 years ago
Wouter Geraedts 88cbf2c119 Change throttle test to run in milliseconds 5 years ago
Wouter Geraedts 6f6d5e9d20
Updated throttle fn comments.
Co-Authored-By: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
5 years ago
Wouter Geraedts 7c7386735e
Wrap around throttle comment
Co-Authored-By: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
5 years ago
Alex Macleod 1b7d5bea6b Enable surf example
1.0.3 has been released with the required change
5 years ago
Yoshua Wuyts 46c58b214c
Merge pull request #514 from async-rs/stabilize-yield-now
stabilize task::yield_now
5 years ago
Yoshua Wuyts 0d5c7a217f
stabilize task::yield_now
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 5017117326
Merge pull request #513 from async-rs/fix-changelog
fix changelog
5 years ago
Yoshua Wuyts 9d7b2d6696
fix changelog
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 643b678ea5
Merge pull request #511 from async-rs/1.0.1
1.0.1
5 years ago
Yoshua Wuyts b5b2b5a0a3
1.0.1
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Florian Gilcher 54371c21c1
Merge pull request #510 from stjepang/fix-spawn-blocking
Improve thread startup/shutdown algorithm in spawn_blocking
5 years ago
Stjepan Glavina 1a50ffd144 Delete unused import 5 years ago
Stjepan Glavina 21c5c48cb6 Lower the timeout to 1 second 5 years ago
Stjepan Glavina 6677d52c2d Improve thread creating algorithm in spawn_blocking 5 years ago
Johannes Weissmann 37922408e5 use pin_project 5 years ago
Johannes Weissmann 7d2282dbd2 fix merge conflict 5 years ago
Johannes Weissmann 60f822bee5 Merge branch 'master' into stream_count 5 years ago
CosciaDiPollo 9ad0cf9f80 Correct a typo on the async-std version (#508)
Correct a typo on the async-std version in the Cargo.toml file of the documentation.
5 years ago
Yoshua Wuyts 980c30e90f
Merge pull request #496 from async-rs/1.0.0
1.0.0
5 years ago
Yoshua Wuyts 4aa9928ece
v1.0.0
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts eea7af24db
fix bugs in changelog
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 76c5ffe9ab
Merge pull request #506 from stjepang/cleanup-stream
Cleanup stream module
5 years ago
Stjepan Glavina 5438258cee Remove unused import 5 years ago
Wouter Geraedts ef958f0408 Use pin_project_lite instead for throttle 5 years ago
Stjepan Glavina dc5d143c16 Merge branch 'master' into cleanup-stream 5 years ago
Stjepan Glavina c2f750d288 Cleanup stream module 5 years ago
Wouter Geraedts 139a34b685 Make throttle an unstable feature 5 years ago
Wouter Geraedts b591fc68bd Changed semantics of throttle to non-dropping variant with backpressure 5 years ago
razican 5d558ca213
Fixed test, order is no longer guaranteed 5 years ago
razican e48e463736
Duplicating code due to strange Rust error. 5 years ago
razican 0c37d4af10
Anonymous function to avoid type issues 5 years ago
Stjepan Glavina 352f18bc2a
Use async_std::sync::Arc in examples (#501) 5 years ago
razican 79bbf4938d
Randomize Stream::merge to improve the throughput. Implements #490. 5 years ago
Wouter Geraedts 14d7d3bf9c Merge remote-tracking branch 'upstream/master' into 342-stream-throttle 5 years ago
Stjepan Glavina 417b548692
Cleanup path module (#497)
* Cleanup path module

* Derive clone for PathBuf and remove unused import

* impl AsRef<Path> for std::path::PathBuf

* Fix a doc comment
5 years ago
Stjepan Glavina 122e87364b Remove cache padding in channels 5 years ago
Yoshua Wuyts 925b42bc89
Merge pull request #493 from stjepang/cleanup-future
Cleanup future module
5 years ago
Stjepan Glavina d4f38e783f Cleanup future module 5 years ago
Yoshua Wuyts 96d3560742 remove future::*join macros (#492)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts ac1042a9ca note on Stream::merge ordering (#491)
* note on Stream::merge ordering

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* Update src/stream/stream/mod.rs
5 years ago
Stjepan Glavina 9e185f1c3e
Unstable feature: copy takes arguments by value (#471)
* Unstable feature: copy takes arguments by value

* Fix feature flags
5 years ago
Yoshua Wuyts 89d611628a
Merge pull request #483 from ryan-scott-dev/rscott/pathbuf_fromiter
Add FromIterator and Extend trait implementations for PathBuf
5 years ago
Yoshua Wuyts e9c0f8f6b5
Merge pull request #481 from async-rs/fix-proc-macro-render
fix attributes feature
5 years ago
Yoshua Wuyts 16565ccfbc
Merge pull request #489 from jaysonsantos/pathbuf-fromstr
Implement FromStr for PathBuf
5 years ago
Yoshua Wuyts 74882c119d
check attributes
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Jayson Reis d8e52c1002
Implement FromStr for PathBuf
This makes PathBuf compatible with std version as you can simply call
let path: PathBuf = FromStr::from_str(s).unwrap()
5 years ago
Yoshua Wuyts 037119c0c0
Merge pull request #478 from portgasd666/master
Add Future::join and Future::try_join
5 years ago
Stjepan Glavina 548733e5d5
Cleanup stream traits (#487)
* Cleanup stream traits

* Fix docs
5 years ago
Abhishek C. Sharma f04b6f6fe9 Change module level docs for future to refer to join and try_join functions instead of macros 5 years ago
Friedel Ziegelmayer 4a78f731b7 fix: stream::take_while (#485)
When the predicate is false, the stream should be ended.
5 years ago
nasa d2d63348c7 Stable and beta add to CI (#482)
* Add stable and beta

* Add benches
5 years ago
Ryan Scott 8f3366072f Add FromIterator and Extend trait implementations for PathBuf 5 years ago
Yoshua Wuyts e74e246bbb
fix attributes feature
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
laizy fb19ebde17 add `Sync` constraint for RwLock to prevent memory unsafety (#479) 5 years ago
Abhishek C. Sharma b14282457c Add Future::join and Future::try_join 5 years ago
Stjepan Glavina ab2f64cd84 Mark extend() as unstable 5 years ago
Yoshua Wuyts fd088fea38 0.99.12 (#469)
* 0.99.12

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* Update changelog with latest changes
5 years ago
Yoshua Wuyts 335bd34470 Add "std" feature flag (#476)
* core feature

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* introduce std + default features

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* test std features on ci

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* finish up all features

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* Fix task_local macro

* Remove crossbeam-channel and futures-timer from std

* Move future::timeout() behind cfg_default
5 years ago
Stjepan Glavina f588ba6bdd
Spawn more than one blocking thread (#475)
* Spawn more than 1 blocking thread

* Fix a bug

* Fix check when the thread is last sleeping
5 years ago
Yoshua Wuyts 84880c4d8b re-export async-attributes (#238)
* re-export async-attributes

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* doc order

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* rebase + rename feature to "attributes"

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* only expose test and main

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* async-attributes 1.1.0

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Stjepan Glavina bc24503382
Fix deadlock when all receivers are dropped (#474)
* Fix deadlock when all receivers are dropped

* Add a comment to explain the behavior of try_send

* Disable clippy
5 years ago
Yoshua Wuyts 266e6326eb document path submodule (#467)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Stjepan Glavina f8e82564d9
Rename stream_extend to extend (#464)
* Rename stream_extend to extend

* Remove Extend from prelude

* Add stream::extend()
5 years ago
Abhishek C Sharma eb1ef3f4e4 Minor documentation fix for race and try_race (#473) 5 years ago
Yoshua Wuyts d0f1996759
Merge pull request #388 from felipesere/cycle
Implement stream::cycle(..)
5 years ago
Yoshua Wuyts 8a0e29473a
Merge pull request #446 from yjhmelody/stream-cloned
Add Stream cloned
5 years ago
Yoshua Wuyts 2cb887e154
Merge pull request #465 from async-rs/non-pub-flatten
hide future::Flatten::new
5 years ago
Yoshua Wuyts 929027796e
hide future::Flatten
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 9a8805678e
Merge pull request #443 from portgasd666/master
Added Future::flatten
5 years ago
Yoshua Wuyts a064a5b13e
Merge pull request #459 from stjepang/expose-ext-traits
Expose extension traits in preludes
5 years ago
Stjepan Glavina c34e0f8a35
Update futures to 0.3 (#463)
* Update futures to 0.3

* Fix a search-and-replace error

* Fix imports in tests

* Fix an import
5 years ago
Stjepan Glavina 93b01e36ed
Clippy fixes (#462) 5 years ago
Gabriel Majeri d502453057 Remove doc `Stream` impl for `VecDeque` (#461) 5 years ago
Yoshua Wuyts 3144e217ae
Merge pull request #458 from async-rs/rework-intro
rework lib.rs docs
5 years ago
Stjepan Glavina c3254d78d9 Fix a re-rexport 5 years ago
Yoshua Wuyts f4fb8a3534
change one line
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 1c87e97e9c
Apply suggestions from code review
Co-Authored-By: Stjepan Glavina <stjepang@gmail.com>
5 years ago
Stjepan Glavina a757cc02dc Expose extension traits in preludes 5 years ago
Yoshua Wuyts ae8b051892
rework lib.rs docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Stjepan Glavina 1707638ebb
Update mod.rs 5 years ago
Yoshua Wuyts 84fa4ca068
Merge pull request #456 from stjepang/doc-fixes-links
Fix some links in docs
5 years ago
Stjepan Glavina 43bb59cd02 Fix some links in docs 5 years ago
yjh 5179f30d2d
use async_std::stream 5 years ago
yjh a35602f375
Update mod.rs 5 years ago
Yoshua Wuyts e14cc2a30d
Merge pull request #452 from stjepang/fix-deadlocks
Fix a deadlock in channel
5 years ago
Stjepan Glavina 6d421de992 Fix another clippy warning 5 years ago
Stjepan Glavina 5874392397 Fix a clippy warning 5 years ago
Stjepan Glavina e9edadffc7 Fix a deadlock in channel 5 years ago
Yoshua Wuyts 282ae064fe
Merge pull request #449 from async-rs/strip-vecdeque
remove remaining instances of VecDeque stream
5 years ago
yjh e85bbe68e6
Merge branch 'master' into stream-cloned 5 years ago
Abhishek C. Sharma d7afcada76 Fixed ambiguous associated types 5 years ago
Abhishek C. Sharma e36172e808 Merge remote-tracking branch 'upstream/master' 5 years ago
Abhishek C. Sharma a3e68704bc Wrap state enum in public struct 5 years ago
yjh 8bef812e78
Update src/stream/stream/cloned.rs
Co-Authored-By: nasa <htilcs1115@gmail.com>
5 years ago
yjh bf0cd5987a
Update src/stream/stream/cloned.rs
Co-Authored-By: nasa <htilcs1115@gmail.com>
5 years ago
Stjepan Glavina 20cdf73bb0
Simplify RwLock using WakerSet (#440) 5 years ago
Yoshua Wuyts ed1cb49807
remove remaining instances of VecDeque stream
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Stjepan Glavina 78614c6c1d
Clarify blocking in channel docs (#448) 5 years ago
nasa ddbbbfc32a Replace `VecDeque` with `stream::from_iter` in examples (#447) 5 years ago
yjhmelody 4942dc7f9f Add Stream cloned 5 years ago
Abhishek C. Sharma e0910be8fb Added Future::flatten 5 years ago
Felipe Sere 57a6516e63 Make bounds on Stream impl simpler 5 years ago
Felipe Sere fbd5bd867d Revert "Only one generic type needed"
This reverts commit e9b9284863a614b852c22d58205cb983fc26682a.
5 years ago
Felipe Sere 9ee804f9ed Only one generic type needed 5 years ago
Felipe Seré eaa56580e3 Update src/stream/stream/mod.rs
Co-Authored-By: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
5 years ago
Felipe Sere 0186124aef Simpler impl 5 years ago
Felipe Sere 197253aa73 Run fmt 5 years ago
Felipe Sere 19381fa590 One clippy warning 5 years ago
Felipe Sere ed5b095c73 Run fmt 5 years ago
Felipe Sere 5aadc5e4e9 Make cycle a function on the stream type 5 years ago
Felipe Sere b979773505 Follow clippys advice 5 years ago
Felipe Sere fd09e2f248 Run fmt 5 years ago
Felipe Sere 171cc82aed Replace copy with clone bound 5 years ago
Felipe Sere 83ff11ff4c Switch cycle to stream 5 years ago
Felipe Sere e1ba87e7c1 Add slightly better docs 5 years ago
Felipe Sere 8126bb1882 use the module operator to calculate next index 5 years ago
Felipe Sere 486f9a964c Cycle over a known set of values. 5 years ago
Felipe Sere a096d5ec2d stub out an example 5 years ago
Felipe Sere dea1b67670 Skeleton cycle 5 years ago
Aleksey Kladov fa91d7f856 Stream::merge does not end prematurely if one stream is delayed (#437)
* Stream::merge does not end prematurely if one stream is delayed

* `cargo test` without features works

* Stream::merge works correctly for unfused streams
5 years ago
Yoshua Wuyts 9a4f4c591c
Merge pull request #441 from async-rs/stdio-lock-unstable
mark stdio-lock structs as unstable
5 years ago
Yoshua Wuyts 6f9436e575
mark stdio-lock structs as unstable
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 735fa6954e Replace select!/try_select! with Future::{race,try_race} (#405)
* init Future::select

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* implement Future::select

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* try_select

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* fixes

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* works

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* pass clippy

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* please clippy

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* implement feedback from stjepan

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* rename select to race

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* fmt

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
yjh 3a2e6d5b92 add max_by_key (#408)
* add max_by_key

* fix conflict

* fmt code
5 years ago
Zhang Guyu 5fb9d3e980 add Stream::copied (#442) 5 years ago
Yoshua Wuyts 4c63392a85
Merge pull request #334 from k-nasa/add_stdin_lock
Locking for stdin
5 years ago
k-nasa 3dcad984b4 fix: To unstable feature 5 years ago
Yoshua Wuyts c413e717da
Merge pull request #429 from markhildreth/tcp_smoke_tests
Added TCP smoke tests against std Listener and Stream
5 years ago
Yoshua Wuyts 911ebada0b
Merge pull request #434 from paulocsanz/master
Put everything behind a 'stable' feature to avoid future breaking changes
5 years ago
Aleksey Kladov ec1a6ea3e8 Fix typo (#439) 5 years ago
Tyler Neely 5adc608791 Spawn several threads when we fail to enqueue work in the blocki… (#181)
* Rebase onto master

* Switch to unbounded channels
5 years ago
Sheyne Anderson 1a51ca424a Fix typo in tutorial in book (#412) 5 years ago
k-nasa 81873ae5f3 fix 5 years ago
Florian Gilcher d5fd035956 Small example for a TCP server that both handles IP v4 and v6 (#418)
* Add a small example for listening to both ipv4 and ipv6

Presenting stream merge on Incoming.

* Change stable checks workflow to not cover examples, but tests
5 years ago
Yoshua Wuyts e17a6703c8
Merge pull request #415 from k-nasa/stream_from_iter
Add stream::from_iter
5 years ago
Paulo 8e991bcd3a Fix typo 5 years ago
Paulo 2e66c38453 Simplify default feature 5 years ago
k-nasa 0661f774c2 Merge branch 'master' into add_stdin_lock 5 years ago
k-nasa 2f3c867d44 Merge branch 'master' into stream_from_iter 5 years ago
k-nasa 063798ce49 Add doc 5 years ago
Yoshua Wuyts a3b742188d fix doc tests (#431)
* fix doc tests

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* cargo fmt

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Florian Gilcher 57670dd9d7
Merge pull request #433 from JohnTitor/remove-deprecated-action
Remove deprecated action
5 years ago
Paulo dcd7c55cef Put everything behind a 'stable' feature 5 years ago
Yuki Okushi 277fd521bc Remove deprecated action 5 years ago
Stjepan Glavina 87de4e1598
Add utility type WakerSet to the sync module (#390)
* Add utility type Registry to the sync module

* Remove unused import

* Split unregister into complete and cancel

* Refactoring and renaming

* Split remove() into complete() and cancel()

* Rename to WakerSet

* Ignore clippy warning

* Ignore another clippy warning

* Use stronger SeqCst ordering
5 years ago
Stjepan Glavina 3dd59d7056
Refactor the task module (#421)
* Refactor the task module

* Fix clippy warning

* Simplify task-local entries

* Reduce the amount of future wrapping

* Cleanup

* Simplify stealing
5 years ago
k-nasa caa23381f0 fix clippy warning 5 years ago
k-nasa eeb44c86e9 fix 5 years ago
k-nasa f8b8c9debe Merge branch 'master' into add_stdin_lock 5 years ago
Yoshua Wuyts c1e8517959
Merge pull request #414 from k-nasa/fix_github_actions
Add only rustfmt on Checking fmt and docs actions
5 years ago
Yoshua Wuyts cc75b65b8c
Merge pull request #409 from yjhmelody/stream-min
Add Stream min
5 years ago
Yoshua Wuyts f102588df5
Merge pull request #428 from zhangguyu6/stream-position
Add stream position
5 years ago
Yoshua Wuyts 3e0fe742f6
Merge pull request #427 from yjhmelody/stream-ne
Add stream ne
5 years ago
Yoshua Wuyts 65dcaf4464
Merge pull request #426 from yjhmelody/stream-eq
Add stream eq
5 years ago
zhangguyu 07d21e5eb3 change trait bounds 5 years ago
Mark Hildreth c6c2bfa456 Added TCP smoke tests against std Listener and Stream 5 years ago
zhangguyu 48c82a9668 Add stream position 5 years ago
yjhmelody 1ab3d901e4 fmt code 5 years ago
yjhmelody 204da33391 fmt code 5 years ago
yjhmelody 17db7ffcd3 Add stream ne 5 years ago
yjhmelody f5efaaa7ba Add stream eq 5 years ago
Yoshua Wuyts cc949f48ea
Merge pull request #420 from JayatiGoyal/master
correction of a typo
5 years ago
JayatiGoyal 5fee91c050
corrected a typo 5 years ago
Wu Yu Wei ff6a44fcd5 Use once_cell instead of lazy_static (#416)
`once_cell` provides a neat way of initializing lazy singletons without
macro. This PR use `sync::Lazy` to streamline same pattern proposed in
related rust RFC.

Resolve #406
5 years ago
k-nasa 40c4e1a29d feat: Add stream::from_iter 5 years ago
k-nasa 3620b2b6ab fix: Add only rustfmt on Checking fmt and docs actions 5 years ago
k-nasa 2c91b30ee8 feat: Add Read and Write trait to Lock struct 5 years ago
yjhmelody 021862dcc8 fix min 5 years ago
yjhmelody b942d0a405 add stream-min 5 years ago
Yoshua Wuyts da795dec7b
Merge pull request #399 from async-rs/release-0.99.11
v0.99.11
5 years ago
Yoshua Wuyts 2adaaa9d3f
more updates
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts b10930207c
more
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts b3d1fa9c98
v0.99.11
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 2b1c6f04ea
Merge pull request #384 from yjhmelody/stream-max_by
add stream::max_by method
5 years ago
Yoshua Wuyts 5ff4ef8dd4
Merge pull request #385 from yjhmelody/stream-min_by_key
add stream::min_by_key method
5 years ago
Yoshua Wuyts f311e3de9f
Merge pull request #397 from async-rs/sync-docs
add mod level docs for sync
5 years ago
Yoshua Wuyts 3a06a1211b
Add feedback from review
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 526c4da21a
Merge pull request #395 from async-rs/stream-docs
add stream mod docs
5 years ago
Yoshua Wuyts 997e811c58
Merge pull request #402 from async-rs/fuse-docs
update Stream::fuse docs
5 years ago
Yoshua Wuyts 11d0577407
Merge pull request #396 from async-rs/net-docs
standardize net docs
5 years ago
Yoshua Wuyts eb081b1948
Apply suggestions from code review
Co-Authored-By: Florian Gilcher <florian.gilcher@ferrous-systems.com>
5 years ago
k-nasa 35cb11e398 Merge branch 'master' into add_stdin_lock 5 years ago
Yoshua Wuyts 1175a37c47
Merge pull request #367 from k-nasa/add_stream_flatten
Add Stream::flatten and Stream::flat_map
5 years ago
Yoshua Wuyts 206bedfd12
Merge pull request #349 from k-nasa/add_future_delay
Add future::delay
5 years ago
k-nasa 1554b04407 $cargo fmt 5 years ago
k-nasa 1545d24e50 Merge branch 'master' into add_future_delay 5 years ago
k-nasa ae7adf2c36 fix: Remove unused import 5 years ago
k-nasa 040227f38a Merge branch 'master' into add_stream_flatten 5 years ago
k-nasa 688976203e fix: Split FlattenCompat logic to Flatten and FlatMap 5 years ago
k-nasa c7dc147f73 fix indent 5 years ago
Yoshua Wuyts b3ae6f2b03
update Stream::fuse docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 4ecf49fe95
Merge pull request #401 from async-rs/fix-recursion-limit
fix doc recursion limit
5 years ago
Yoshua Wuyts 4346386610
fix doc recursion limit
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts ca4856a0e8
Merge pull request #377 from ktomsic/sum-and-product-impls
Add `Stream::sum()` and `Stream::product()` implementations
5 years ago
Yoshua Wuyts e5675151b9
Merge pull request #364 from stjepang/optimize-flushing
Don't flush files if they weren't written to
5 years ago
Yoshua Wuyts fd940b8c6a
Merge pull request #348 from k-nasa/add_stream_timeout
Add stream timeout
5 years ago
Yoshua Wuyts 1baee98ead
Merge pull request #375 from sunjay/fromstream-pathbuf
Added Extend + FromStream for PathBuf
5 years ago
k-nasa 613895d6be doc: fix documantation text 5 years ago
Florian Gilcher f262fd8a40
Merge pull request #392 from taiki-e/clippy
Remove usage of actions-rs/clippy-check
5 years ago
Florian Gilcher c2a084ed4a
Merge pull request #393 from k-nasa/fix_clippy
Fix clippy warnings
5 years ago
Florian Gilcher ae41d45da6
Merge pull request #376 from AZanellato/typo-fixes
Typos and sentence structure fixes
5 years ago
Yoshua Wuyts 5f8e2cbd4a
add mod level docs for sync
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 20abd5cebf
standardize net docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 4c4604d63e
add stream mod docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 4cab868899
Merge pull request #394 from async-rs/link-types
backreference links for structs
5 years ago
Yoshua Wuyts 4475a229d6
backlink io docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts a3a740c14a
backlink all docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
k-nasa 59615a655b feat: Add StderrLock and StdoutLock struct 5 years ago
k-nasa fe49f2618f fix clippy::redundant_clone 5 years ago
k-nasa 7fe2a1bbce fix clippy::cognitive_complexity 5 years ago
k-nasa 7c293d37f7 fix clippy::comparison_chain 5 years ago
k-nasa c9d958d309 $cargo fix -Z unstable-options --clippy --features unstable 5 years ago
nasa a42ae2f3d9
Narrow the disclosure range of FlattenCompat::new
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
nasa 37f14b0195
Narrow the disclosure range of Flatten::new
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
nasa 13a08b0d54
Narrow the disclosure range of FlatMap::new
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
Johannes Weissmann 75546ef831 Merge branch 'master' into stream_count 5 years ago
Johannes Weissmann 6608d39c59 remove Stream trait bound 5 years ago
Taiki Endo 6549b66ad2 run clippy check on beta & address clippy warnings 5 years ago
Taiki Endo 610c66e774 Remove usage of actions-rs/clippy-check 5 years ago
yjhmelody 7cfec4e8ce use take and remove Copy 5 years ago
yjh fb78ed1812
Update src/stream/stream/min_by_key.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
yjh 5a4fdeb1cd
Update src/stream/stream/min_by_key.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
yjh b57849e1cb
Update src/stream/stream/max_by.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
yjh a8d3d1483f
Update src/stream/stream/max_by.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
yjh 006fc7e9de
Update src/stream/stream/max_by.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
yjhmelody c9e6d3a84c use pin_project_lite 5 years ago
yjhmelody 37a7eadf17 use pin_project_lite 5 years ago
yjhmelody d0c3c9172b Merge branch 'master' of git://github.com/async-std/async-std into stream-max_by 5 years ago
nasa 81e3cab00d Change homepage link (#389) 5 years ago
k-nasa 61b7a09c70 Fix type declaration 5 years ago
nasa 8932cecec7
Update src/stream/stream/flatten.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
nasa bf3508ffb2
Update src/stream/stream/flatten.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
nasa 6168952d6f
Update src/stream/stream/flatten.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
nasa b7b5df13aa
Update src/stream/stream/flatten.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
nasa 7ce721f562
Update src/lib.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
5 years ago
k-nasa b66ffa670e update recursion_limit 5 years ago
k-nasa 0c5abee284 to unstable stream::flat_map, stream::flatten 5 years ago
k-nasa 001368d3df $cargo fmt 5 years ago
k-nasa 00e7e58bf3 fix type def 5 years ago
k-nasa 271b6f4a1c fix: Using pin_project! 5 years ago
k-nasa 3297a0f327 Merge branch 'master' into add_stream_flatten 5 years ago
k-nasa 48b255897e Merge branch 'master' into add_stdin_lock 5 years ago
k-nasa feeb3c10df fix: Remove Pin API related unsafe code 5 years ago
k-nasa b17af61367 Merge branch 'master' into add_stream_timeout 5 years ago
k-nasa d97b3dfdf3 fix: Remove Pin API related unsafe code 5 years ago
k-nasa 5c9cfb4fe8 Merge branch 'master' into add_future_delay 5 years ago
Wouter Geraedts 1fd05a157f Reset delay to prevent poll after ready 5 years ago
Wouter Geraedts 1c843a8124 Re-implemented Throttle to keep last value in memory 5 years ago
Stjepan Glavina b2fe91385b
Add channel behind unstable feature flag (#380)
* Add channel behind unstable feature flag

* Don't check tests without unstable feature flag

* Fix typos

* Remove useless attribute
5 years ago
Taiki Endo 2abf5ca891
Deny warnings on CI (#378)
* Deny warnings on CI

* Fix some clippy warnings
5 years ago
yjhmelody f5a0a0ba86 fmt 5 years ago
yjhmelody d6f940110b update doc 5 years ago
yjhmelody 020eb85093 add stream::min_by_key method 5 years ago
Taiki Endo 944e43d4bf Remove Pin API related unsafe code by using pin-project-lite cra… (#381) 5 years ago
yjhmelody 4e5828e646 add stream::max_by method 5 years ago
Kyle Tomsic e26eb7a719 Add `Stream::sum()` and `Stream::product()` implementations
These are the stream equivalents to `std::iter::Iterator::sum()` and
`std::iter::Iterator::product()`.

Note that this changeset tweaks the `Stream::Sum` and `Stream::Product`
traits a little: rather than returning a generic future `F`, they return
a pinned, boxed, `Future` trait object now. This is in line with other
traits that return a future, e.g. `FromStream`.
5 years ago
Andre Zanellato faad4c8c26 Sentence structure on notice 5 years ago
Andre Zanellato 88558eae6e Typos and sentence structure fixes 5 years ago
Sunjay Varma 0d4a907335 Added Extend + FromStream for PathBuf 5 years ago
Johannes Weissmann 97094b2a1c remove Sized constraint 5 years ago
Wouter Geraedts ced5281b73 Merge remote-tracking branch 'upstream/master' into 342-stream-throttle 5 years ago
Johannes Weissmann a9a7bdc290 add stream::count 5 years ago
k-nasa 410d16eaf6 Add docs + To unstable feature 5 years ago
k-nasa 1c1e2230f3 Merge branch 'master' into add_stream_flatten 5 years ago
k-nasa 176359afae Add Stream::flatten 5 years ago
k-nasa 8138afbfad feat: Add Stream trait for Flatten 5 years ago
k-nasa cd862083a5 Add Flatten struct 5 years ago
k-nasa 2187a2a31d feat: Add Stream::flat_map 5 years ago
k-nasa 2dee289750 Add FlatMap struct 5 years ago
k-nasa bb1416420d feat: Add Stream trait for FlattenCompat 5 years ago
Stjepan Glavina 8bef2e9e95 Don't flush files if they weren't written to 5 years ago
Stjepan Glavina ec23632f3e
Cleanup: replace cfg-if with our macros (#361)
* Cleanup: replace cfg-if with our macros

* Prefix macros with cfg_

* Remove #[macro_export] from internal macros
5 years ago
k-nasa ec98b41c85 feat: Add FlattenCompat struct 5 years ago
Stjepan Glavina 46f0fb1c64
Make sure each invocation of block_on uses its own Parker (#358) 5 years ago
k-nasa f2bf01223c $cargo fmt 5 years ago
k-nasa 70e8476264 fix StdinLock doc test 5 years ago
k-nasa a5a00d7b14 feat: Add StdinLock struct 5 years ago
Taiki Endo e405544ea0
Enable tests on CI (#357)
* Enable tests on CI

* Fix failed test
5 years ago
Wouter Geraedts a2393501c5 Implemented StreamExt::throttle 5 years ago
k-nasa b58bd8d725 Merge branch 'add_stream_timeout' of https://github.com/k-nasa/async-std into add_stream_timeout 5 years ago
k-nasa 0a4073449b doc: Add Stream::Timeout doc 5 years ago
k-nasa c3f6f969c5 fix: Rename TimeoutStream to Timeout 5 years ago
k-nasa 53fa132d13 fix type Declaration 5 years ago
k-nasa 9d55fff81d fix export FutureExt 5 years ago
Yoshua Wuyts ca80ca981e
Merge pull request #338 from async-rs/draft-0.99.10
init 0.99.10 release
5 years ago
Yoshua Wuyts 802d4dfc3b
finalize changelog
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
nasa f1ed034600
Update src/stream/stream/mod.rs
Co-Authored-By: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
5 years ago
Yoshua Wuyts 9ff0750d4d
Merge pull request #353 from async-rs/fix-printing
fix print macros
5 years ago
Yoshua Wuyts 6eb3ea2b21
Merge pull request #279 from montekki/fs-stream-repeat-with
Adds stream::repeat_with
5 years ago
Yoshua Wuyts 4d34a15363
fix macros, take II
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 822e4bc220
Merge branch 'master' into fs-stream-repeat-with 5 years ago
Yoshua Wuyts 6e0905d3ca correctly mark stream::Merge as unstable (#352)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
k-nasa 10f32ca817 Fix TimeoutError 5 years ago
Johannes Weissmann aaa1b6ca39 add Stream::last (#347)
* add stream::LastFuture (not compiling)

Struggling with the associated type, pinning and how to move/copy
LastFuture.last.

* fix type signature -> still cannot assign

still problems assigning the new value to self.last

* remove unused bound

* add doctest

* unpin LastFuture.last

* RustFmt

* add static lifetime

* remove redundant lifetime
5 years ago
k-nasa 358d2bc038 Add import crate 5 years ago
Stjepan Glavina add6863185
Fix typos 5 years ago
k-nasa b251fc999a Move delay method to FutureExt::delay 5 years ago
Yoshua Wuyts faff1f7370 task docs (#346)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
k-nasa 054f4fac74 feat: Add future::delay 5 years ago
k-nasa 7a87dea085 feat: Add Stream::timeout 5 years ago
k-nasa f00d32ee7d Add TimeoutStream struct 5 years ago
Yoshua Wuyts e986e7ba66
Merge pull request #345 from async-rs/io-docs
Io docs
5 years ago
Wouter Geraedts 6b00e5e66c Implemented StreamExt::try_fold (#344) 5 years ago
assemblaj 4b96ea1273 Adds Stream::cmp (#273)
* Adds cmp

* Fixes formatting

* cleans up examples

* attempts to fix rustdoc issue

* formats with cargo fmt

* Adds proper trait bounds for cmp
5 years ago
Yoshua Wuyts d250eee556
port the std::io docs to async_std::io
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 9f8fa45dc7
io docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 2bd82ac249
updates
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
assemblaj a7041be6f2 Adds Stream:ge (#285)
* Adds partial_cmp.rs file and partial_cmp signature to mod.rs

* adds tests that compare streams of same length

* Adds Stream::ge

* cargo fmt

* fixes rustdoc error
5 years ago
assemblaj 5f7238eec6 [Draft PR] Adds Stream::gt (#304)
* [Draft PR] Adds Stream::gt

* Applies cargo format and fixes incorrect comment

* cargo fmt

* fixes rustdoc related issues
5 years ago
assemblaj f0f279ec04 Adds Stream::le (#336) 5 years ago
assemblaj a8dc2c6f9b Adds Stream::lt (#337) 5 years ago
Yoshua Wuyts 24cdb2d489 add stream::{Sum,Product} (#343)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 609a5780a2
0.99.10
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 4911f4599b
init changelog
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 00d936488b stabilize future::timeout (#335)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 49faea2023 init FutureExt (#308)
* init FutureExt

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* prelude

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* Refactor extension_trait

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* Fix rustdoc

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts d46364c834
Merge pull request #299 from async-rs/blocking-updates
Blocking updates
5 years ago
Yoshua Wuyts 237cfa0315 add IntoFuture (#259)
* add IntoFuture

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* blanket impl for IntoFuture

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* cargo fmt

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* example

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* mark as unstable

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 33806ad44c
fix warning
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 12fdc1232d
rename task::blocking to task::spawn_blocking
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts b4c1c63fd2
task::blocking async closure -> FnOnce
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 1a3429655c
init blocking-updates
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Fedor Sakharov 23beab4125 Adds a from_fn stream implementation (#277)
* Adds a from_fn stream implementation

* Update src/stream/from_fn.rs

Co-Authored-By: Yoshua Wuyts <yoshuawuyts+github@gmail.com>

* Fix review nits

* Use async_std Mutex
5 years ago
Yoshua Wuyts e938527f66 add stream::interval (#298)
* add stream::interval

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* fix tests

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* cargo fmt

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* cross-docs

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* update deps

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 35fc85a157 clean readme (#331)
* clean readme

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* add back features

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* Update README.md

Co-Authored-By: Stjepan Glavina <stjepang@gmail.com>
5 years ago
Yoshua Wuyts aed9e2efdf removes Travis CI (#333)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
k-nasa 94ef3dc2b2 feat: Add Stdout::lock 5 years ago
k-nasa 9b09806593 feat: Add Stdin::lock 5 years ago
k-nasa f9741e7488 feat: Add Stderr::lock 5 years ago
Wouter Geraedts c7f6543502 Inline TryFutureExt logic for src/io/timeout.rs (#317) 5 years ago
Yoshua Wuyts 1819408b46 add stream::ExactSizeStream as unstable (#330)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Johannes Weissmann 6be8467cdc impl Stream::take_while adapter (#332)
* impl take_while stream adapter

* fmt

* add comment

* unindent where clauses
5 years ago
Yoshua Wuyts 529a58a066
Merge pull request #327 from assemblaj/assemblaj-partial_cmp_final
Adds Stream::partial_cmp
5 years ago
Yoshua Wuyts 00a8433338
Merge pull request #320 from Wassasin/183-async-path
Implement async Path & PathBuf
5 years ago
Stjepan Glavina aa13ba758b Refactor 5 years ago
Stjepan Glavina 5c1e0522b7 Fix failing tests 5 years ago
Stjepan Glavina 504f8cb137 Use crate::path everywhere 5 years ago
Stjepan Glavina f9cfee9e2c Formatting 5 years ago
Stjepan Glavina 0adcb50f58 Add ToOwned and Borrow impls 5 years ago
Wouter Geraedts ba87048db5 Implemented our own Path::ancestors iterator 5 years ago
assemblaj 80bee9a215 Adds Stream::partial_cmp 5 years ago
Yoshua Wuyts 612a94b31e Add process submodule as unstable (#310)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts e1deaa58d8 Add BufRead::split (#312)
* add BufRead::split

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* fix docs

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

* Update src/io/buf_read/mod.rs

Co-Authored-By: Stjepan Glavina <stjepang@gmail.com>
5 years ago
Yoshua Wuyts 5f52efe465
Merge pull request #324 from async-rs/stabilize-future-join
stabilize future::{join,try_join}
5 years ago
Yoshua Wuyts a9950c5c9f stabilize task::ready! (#325)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts fe88da4e64 make all print macros unstable (#322)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 9b0e02dbb7
Merge pull request #326 from async-rs/fused-stream
add stream::FusedStream as "unstable"
5 years ago
Yoshua Wuyts d6aa1fb501 Add task::yield_now as "unstable" (#300)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 3ac4575d94
add stream::FusedStream
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 05ba07daf8
stabilize future::{join,try_join}
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 454018ef42
Merge pull request #321 from async-rs/stream_merge
rename stream::join to Stream::merge
5 years ago
Yoshua Wuyts 04342c7b5d
docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts b601bcfcb8
polish
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 84a148ddae
rename stream::join to Stream::merge
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Wouter Geraedts 8df55dd015 Implemented PathBuf::set_file_name 5 years ago
Wouter Geraedts 54c94b717c Implemented PathBuf::set_extension 5 years ago
Wouter Geraedts cc417cc001 Implemented PathBuf::push 5 years ago
Wouter Geraedts 07f9e48579 Implemented PathBuf::pop 5 years ago
Wouter Geraedts 71125d5c3b Implemented PathBuf::new 5 years ago
Wouter Geraedts 47ef222dab Implemented PathBuf::into_os_string 5 years ago
Yoshua Wuyts a2baa1d8e0
rename stream::join to stream::merge
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Wouter Geraedts 80eaa28552 Implemented PathBuf::into_boxed_path 5 years ago
Yoshua Wuyts b9bddbb7a0
Merge pull request #319 from async-rs/print
Add print, println, eprint, eprintln
5 years ago
Wouter Geraedts 1bd17f11f2 Implemented PathBuf::as_path 5 years ago
Wouter Geraedts 409a10a8b5 Implemented Path::with_file_name 5 years ago
Wouter Geraedts 3c24b1891b Implemented Path::with_extension 5 years ago
Wouter Geraedts a17b017e01 Implemented Path::to_string_lossy 5 years ago
Wouter Geraedts ea43d7fd29 Implemented Path::to_str 5 years ago
Wouter Geraedts df53a07fc5 Implemented Path::strip_prefix 5 years ago
Wouter Geraedts 942403c52c Implemented Path::starts_with 5 years ago
Wouter Geraedts d349333a43 Implemented Path::read_link 5 years ago
Wouter Geraedts 89f73d3eda Implemented Path::read_dir 5 years ago
Yoshua Wuyts fef2e32a3c
cargo fmt
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 467b64b6e7
doc fmt
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 296d0d9d31
add print macros
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 04479b13c3
add io::stdio
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 33da049717
Merge pull request #311 from async-rs/missing-write-methods
Add Write::write_fmt
5 years ago
Wouter Geraedts 141954d205 Implemented Path::parent 5 years ago
Wouter Geraedts cc57db02a3 Implemented Path::join 5 years ago
Wouter Geraedts 0c03b92373 Implemented Path::iter 5 years ago
Wouter Geraedts 5d87006006 Implemented Path::is_relative 5 years ago
Wouter Geraedts df9a01f534 Implemented Path::is_file 5 years ago
Wouter Geraedts 20f58ea1c1 Implemented Path::is_absolute 5 years ago
Wouter Geraedts 3a9597cd32 Implemented Path::has_root 5 years ago
Wouter Geraedts 28e936f6fe Implemented Path::file_stem 5 years ago
Wouter Geraedts a6e1abecfc Implemented Path::file_name 5 years ago
Wouter Geraedts a7eaae91ae Implemented Path::extension 5 years ago
Wouter Geraedts 4070833482 Implemented Path::ends_with 5 years ago
Wouter Geraedts 5235cd58be Implemented Path::display 5 years ago
Wouter Geraedts 759e357bea Implemented Path::ancestors 5 years ago
Wouter Geraedts a57ba7ece0 Implemented Path::into_path_buf 5 years ago
Wouter Geraedts 6c6106a292 Implemented Path::{metadata, symlink_metadata} 5 years ago
Wouter Geraedts 6bbfd039b1 Fixed various tests 5 years ago
Wouter Geraedts e690b55b18 Implemented fs::metadata and Path::exists 5 years ago
Wouter Geraedts 930b81868d Use std variants of Path and PathBuf internally 5 years ago
Wouter Geraedts 3bd6a9df6d Implemented components 5 years ago
Yoshua Wuyts 28b0ebe83a
Merge pull request #315 from k-nasa/add_flush_to_into_inner
Add BufWriter::into_inner flush
5 years ago
Wouter Geraedts e27b578c27 WIP init Path and PathBuf async stubs 5 years ago
Yoshua Wuyts e3e9d65bae
Merge pull request #316 from k-nasa/remove_needles_main_fn
Remove needless main fn
5 years ago
k-nasa 9d9543c46b refactor: Remove needless main fn 5 years ago
k-nasa 13ff627b09 $cargo fmt 5 years ago
k-nasa ad156b1fce feat: Add BufWriter::into_inner flush 5 years ago
Yoshua Wuyts b62e4a1e48
update desc
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts a1cd76e244
cargo fmt
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts f3eba1fb48
comments
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 570dedd712
cleanup
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 58c3a06a14
init write_fmt
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 483ded0e1c
fix example
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Yoshua Wuyts 064fdf020f
Stream::delay
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
5 years ago
Fedor Sakharov 49d123c7f9
Fix review nits 5 years ago
Fedor Sakharov 2384df11ed
Apply suggestions from code review
Co-Authored-By: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
5 years ago
Fedor Sakharov 735d604cd1
Adds stream::repeat_with 5 years ago

@ -0,0 +1,3 @@
Our contribution policy can be found at [async.rs/contribute][policy].
[policy]: https://async.rs/contribute/

@ -4,9 +4,13 @@ on:
pull_request: pull_request:
push: push:
branches: branches:
- master
- staging - staging
- trying - trying
env:
RUSTFLAGS: -Dwarnings
jobs: jobs:
build_and_test: build_and_test:
name: Build and test name: Build and test
@ -14,7 +18,7 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
rust: [nightly] rust: [nightly, beta, stable]
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
@ -25,39 +29,143 @@ jobs:
toolchain: ${{ matrix.rust }} toolchain: ${{ matrix.rust }}
override: true override: true
- name: Cache cargo registry
uses: actions/cache@v2
with:
path: ~/.cargo/registry
key: ${{ matrix.os }}-${{ matrix.rust }}-cargo-registry-${{ hashFiles('**/Cargo.toml') }}
- name: Cache cargo index
uses: actions/cache@v2
with:
path: ~/.cargo/git
key: ${{ matrix.os }}-${{ matrix.rust }}-cargo-index-${{ hashFiles('**/Cargo.toml') }}
- name: Cache cargo build
uses: actions/cache@v2
with:
path: target
key: ${{ matrix.os }}-${{ matrix.rust }}-cargo-build-target-${{ hashFiles('**/Cargo.toml') }}
- name: check - name: check
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: check command: check
args: --all --benches --bins --examples --tests args: --all --bins --tests
- name: check unstable - name: check unstable
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: check command: check
args: --features unstable --all --benches --bins --examples --tests args: --features unstable --all --bins --examples --tests
- name: check wasm
uses: actions-rs/cargo@v1
with:
command: check
target: wasm32-unknown-unknown
override: true
args: --features unstable --all --bins --tests
- name: check bench
uses: actions-rs/cargo@v1
if: matrix.rust == 'nightly'
with:
command: check
args: --benches
- name: check std only
uses: actions-rs/cargo@v1
with:
command: check
args: --no-default-features --features std
- name: check attributes
uses: actions-rs/cargo@v1
with:
command: check
args: --features attributes
- name: tests - name: tests
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --all --doc --features unstable args: --all --features "unstable attributes"
check_fmt_and_docs: build__with_no_std:
name: Checking fmt and docs name: Build with no-std
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: setup
run: |
rustup default nightly
rustup target add thumbv7m-none-eabi
- name: check no_std
uses: actions-rs/cargo@v1
with:
command: check
args: --no-default-features --features alloc --target thumbv7m-none-eabi -Z avoid-dev-deps
check_tokio_02_feature:
name: Check tokio02 feature
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: check tokio02
uses: actions-rs/cargo@v1
with:
command: check
args: --all --features tokio02
cross:
name: Cross compile
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
target:
- i686-unknown-linux-gnu
- powerpc-unknown-linux-gnu
- powerpc64-unknown-linux-gnu
- mips-unknown-linux-gnu
- arm-linux-androideabi
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- id: component - name: Install nightly
uses: actions-rs/components-nightly@v1 uses: actions-rs/toolchain@v1
with: with:
component: rustfmt toolchain: nightly
override: true
- name: Install cross
run: cargo install cross
- name: check
run: cross check --all --target ${{ matrix.target }}
- name: check unstable
run: cross check --all --features unstable --target ${{ matrix.target }}
- name: test
run: cross test --all --features unstable --target ${{ matrix.target }}
check_fmt_and_docs:
name: Checking fmt and docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: ${{ steps.component.outputs.toolchain }} profile: minimal
toolchain: nightly
override: true override: true
components: rustfmt
- name: setup - name: setup
run: | run: |
@ -73,21 +181,3 @@ jobs:
- name: Docs - name: Docs
run: cargo doc --features docs run: cargo doc --features docs
clippy_check:
name: Clippy check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- id: component
uses: actions-rs/components-nightly@v1
with:
component: clippy
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ steps.component.outputs.toolchain }}
override: true
- run: rustup component add clippy
- uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}

@ -1,68 +0,0 @@
language: rust
env:
- RUSTFLAGS="-D warnings"
# Cache the whole `~/.cargo` directory to keep `~/cargo/.crates.toml`.
cache:
directories:
- /home/travis/.cargo
# Don't cache the cargo registry because it's too big.
before_cache:
- rm -rf /home/travis/.cargo/registry
branches:
only:
- master
- staging
- trying
matrix:
fast_finish: true
include:
- rust: nightly
os: linux
- rust: nightly
os: osx
osx_image: xcode9.2
- rust: nightly-x86_64-pc-windows-msvc
os: windows
- name: fmt
rust: nightly
os: linux
before_script: |
if ! rustup component add rustfmt; then
target=`curl https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/rustfmt`;
echo "'rustfmt' is unavailable on the toolchain 'nightly', use the toolchain 'nightly-$target' instead";
rustup toolchain install nightly-$target;
rustup default nightly-$target;
rustup component add rustfmt;
fi
script:
- cargo fmt --all -- --check
- name: docs
rust: nightly
os: linux
script:
- cargo doc --features docs
- name: book
rust: nightly
os: linux
before_script:
- test -x $HOME/.cargo/bin/mdbook || ./ci/install-mdbook.sh
- cargo build # to find 'extern crate async_std' by `mdbook test`
script:
- mdbook build docs
- mdbook test -L ./target/debug/deps docs
script:
- cargo check --all --benches --bins --examples --tests
- cargo check --features unstable --all --benches --bins --examples --tests
- cargo test --all --doc --features unstable

@ -7,6 +7,569 @@ and this project adheres to [Semantic Versioning](https://book.async.rs/overview
## [Unreleased] ## [Unreleased]
# [1.6.2] - 2020-06-19
## Added
- Add `UdpSocket::peer_addr` ([#816](https://github.com/async-rs/async-std/pull/816))
## Changed
## Fixed
- Ensure the reactor is running for sockets and timers ([#819](https://github.com/async-rs/async-std/pull/819)).
- Avoid excessive polling in `flatten` and `flat_map` ([#701](https://github.com/async-rs/async-std/pull/701))
# [1.6.1] - 2020-06-11
## Added
- Added `tokio02` feature flag, to allow compatability usage with tokio@0.2 ([#804](https://github.com/async-rs/async-std/pull/804)).
## Changed
- Removed unstable `stdio` lock methods, due to their unsoundness ([#807](https://github.com/async-rs/async-std/pull/807)).
## Fixed
- Fixed wrong slice index for file reading ([#802](https://github.com/async-rs/async-std/pull/802)).
- Fixed recursive calls to `block_on` ([#799](https://github.com/async-rs/async-std/pull/799)) and ([#809](https://github.com/async-rs/async-std/pull/809)).
- Remove `default` feature requirement for the `unstable` feature ([#806](https://github.com/async-rs/async-std/pull/806)).
# [1.6.0] - 2020-05-22
See `1.6.0-beta.1` and `1.6.0-beta.2`.
# [1.6.0-beta.2] - 2020-05-19
## Added
- Added an environment variable to configure the thread pool size of the runtime. ([#774](https://github.com/async-rs/async-std/pull/774))
- Implement `Clone` for `UnixStream` ([#772](https://github.com/async-rs/async-std/pull/772))
## Changed
- For `wasm`, switched underlying `Timer` implementation to [`futures-timer`](https://github.com/async-rs/futures-timer). ([#776](https://github.com/async-rs/async-std/pull/776))
## Fixed
- Use `smol::block_on` to handle drop of `File`, avoiding nested executor panic. ([#768](https://github.com/async-rs/async-std/pull/768))
# [1.6.0-beta.1] - 2020-05-07
## Added
- Added `task::spawn_local`. ([#757](https://github.com/async-rs/async-std/pull/757))
- Added out of the box support for `wasm`. ([#757](https://github.com/async-rs/async-std/pull/757))
- Added `JoinHandle::cancel` ([#757](https://github.com/async-rs/async-std/pull/757))
- Added `sync::Condvar` ([#369](https://github.com/async-rs/async-std/pull/369))
- Added `sync::Sender::try_send` and `sync::Receiver::try_recv` ([#585](https://github.com/async-rs/async-std/pull/585))
- Added `no_std` support for `task`, `future` and `stream` ([#680](https://github.com/async-rs/async-std/pull/680))
## Changed
- Switched underlying runtime to [`smol`](https://github.com/stjepang/smol/). ([#757](https://github.com/async-rs/async-std/pull/757))
- Switched implementation of `sync::Barrier` to use `sync::Condvar` like `std` does. ([#581](https://github.com/async-rs/async-std/pull/581))
## Fixed
- Allow compilation on 32 bit targets, by using `AtomicUsize` for `TaskId`. ([#756](https://github.com/async-rs/async-std/pull/756))
# [1.5.0] - 2020-02-03
[API Documentation](https://docs.rs/async-std/1.5.0/async-std)
This patch includes various quality of life improvements to async-std.
Including improved performance, stability, and the addition of various
`Clone` impls that replace the use of `Arc` in many cases.
## Added
- Added links to various ecosystem projects from the README ([#660](https://github.com/async-rs/async-std/pull/660))
- Added an example on `FromStream` for `Result<T, E>` ([#643](https://github.com/async-rs/async-std/pull/643))
- Added `stream::pending` as "unstable" ([#615](https://github.com/async-rs/async-std/pull/615))
- Added an example of `stream::timeout` to document the error flow ([#675](https://github.com/async-rs/async-std/pull/675))
- Implement `Clone` for `DirEntry` ([#682](https://github.com/async-rs/async-std/pull/682))
- Implement `Clone` for `TcpStream` ([#689](https://github.com/async-rs/async-std/pull/689))
## Changed
- Removed internal comment on `stream::Interval` ([#645](https://github.com/async-rs/async-std/pull/645))
- The "unstable" feature can now be used without requiring the "default" feature ([#647](https://github.com/async-rs/async-std/pull/647))
- Removed unnecessary trait bound on `stream::FlatMap` ([#651](https://github.com/async-rs/async-std/pull/651))
- Updated the "broadcaster" dependency used by "unstable" to `1.0.0` ([#681](https://github.com/async-rs/async-std/pull/681))
- Updated `async-task` to 1.2.1 ([#676](https://github.com/async-rs/async-std/pull/676))
- `task::block_on` now parks after a single poll, improving performance in many cases ([#684](https://github.com/async-rs/async-std/pull/684))
- Improved reading flow of the "client" part of the async-std tutorial ([#550](https://github.com/async-rs/async-std/pull/550))
- Use `take_while` instead of `scan` in `impl` of `Product`, `Sum` and `FromStream` ([#667](https://github.com/async-rs/async-std/pull/667))
- `TcpStream::connect` no longer uses a thread from the threadpool, improving performance ([#687](https://github.com/async-rs/async-std/pull/687))
## Fixed
- Fixed crate documentation typo ([#655](https://github.com/async-rs/async-std/pull/655))
- Fixed documentation for `UdpSocket::recv` ([#648](https://github.com/async-rs/async-std/pull/648))
- Fixed documentation for `UdpSocket::send` ([#671](https://github.com/async-rs/async-std/pull/671))
- Fixed typo in stream documentation ([#650](https://github.com/async-rs/async-std/pull/650))
- Fixed typo on `sync::JoinHandle` documentation ([#659](https://github.com/async-rs/async-std/pull/659))
- Removed use of `std::error::Error::description` which failed CI ([#661](https://github.com/async-rs/async-std/pull/662))
- Removed the use of rustfmt's unstable `format_code_in_doc_comments` option which failed CI ([#685](https://github.com/async-rs/async-std/pull/685))
- Fixed a code typo in the `task::sleep` example ([#688](https://github.com/async-rs/async-std/pull/688))
# [1.4.0] - 2019-12-20
[API Documentation](https://docs.rs/async-std/1.4.0/async-std)
This patch adds `Future::timeout`, providing a method counterpart to the
`future::timeout` free function. And includes several bug fixes around missing
APIs. Notably we're not shipping our new executor yet, first announced [on our
blog](https://async.rs/blog/stop-worrying-about-blocking-the-new-async-std-runtime/).
## Examples
```rust
use async_std::prelude::*;
use async_std::future;
use std::time::Duration;
let fut = future::pending::<()>(); // This future will never resolve.
let res = fut.timeout(Duration::from_millis(100)).await;
assert!(res.is_err()); // The future timed out, returning an err.
```
## Added
- Added `Future::timeout` as "unstable" [(#600)](https://github.com/async-rs/async-std/pull/600)
## Fixes
- Fixed a doc test and enabled it on CI [(#597)](https://github.com/async-rs/async-std/pull/597)
- Fixed a rendering issue with the `stream` submodule documentation [(#621)](https://github.com/async-rs/async-std/pull/621)
- `Write::write_fmt`'s future is now correctly marked as `#[must_use]` [(#628)](https://github.com/async-rs/async-std/pull/628)
- Fixed the missing `io::Bytes` export [(#633)](https://github.com/async-rs/async-std/pull/633)
- Fixed the missing `io::Chain` export [(#633)](https://github.com/async-rs/async-std/pull/633)
- Fixed the missing `io::Take` export [(#633)](https://github.com/async-rs/async-std/pull/633)
# [1.3.0] - 2019-12-12
[API Documentation](https://docs.rs/async-std/1.3.0/async-std)
This patch introduces `Stream::delay`, more methods on `DoubleEndedStream`,
and improves compile times. `Stream::delay` is a new API that's similar to
[`task::sleep`](https://docs.rs/async-std/1.2.0/async_std/task/fn.sleep.html),
but can be passed as part of as stream, rather than as a separate block. This is
useful for examples, or when manually debugging race conditions.
## Examples
```rust
let start = Instant::now();
let mut s = stream::from_iter(vec![0u8, 1]).delay(Duration::from_millis(200));
// The first time will take more than 200ms due to delay.
s.next().await;
assert!(start.elapsed().as_millis() >= 200);
// There will be no delay after the first time.
s.next().await;
assert!(start.elapsed().as_millis() <= 210);
```
## Added
- Added `Stream::delay` as "unstable" [(#309)](https://github.com/async-rs/async-std/pull/309)
- Added `DoubleEndedStream::next_back` as "unstable" [(#562)](https://github.com/async-rs/async-std/pull/562)
- Added `DoubleEndedStream::nth_back` as "unstable" [(#562)](https://github.com/async-rs/async-std/pull/562)
- Added `DoubleEndedStream::rfind` as "unstable" [(#562)](https://github.com/async-rs/async-std/pull/562)
- Added `DoubleEndedStream::rfold` as "unstable" [(#562)](https://github.com/async-rs/async-std/pull/562)
- Added `DoubleEndedStream::try_rfold` as "unstable" [(#562)](https://github.com/async-rs/async-std/pull/562)
- `stream::Once` now implements `DoubleEndedStream` [(#562)](https://github.com/async-rs/async-std/pull/562)
- `stream::FromIter` now implements `DoubleEndedStream` [(#562)](https://github.com/async-rs/async-std/pull/562)
## Changed
- Removed our dependency on `async-macros`, speeding up compilation [(#610)](https://github.com/async-rs/async-std/pull/610)
## Fixes
- Fixed a link in the task docs [(#598)](https://github.com/async-rs/async-std/pull/598)
- Fixed the `UdpSocket::recv` example [(#603)](https://github.com/async-rs/async-std/pull/603)
- Fixed a link to `task::block_on` [(#608)](https://github.com/async-rs/async-std/pull/608)
- Fixed an incorrect API mention in `task::Builder` [(#612)](https://github.com/async-rs/async-std/pull/612)
- Fixed leftover mentions of `futures-preview` [(#595)](https://github.com/async-rs/async-std/pull/595)
- Fixed a typo in the tutorial [(#614)](https://github.com/async-rs/async-std/pull/614)
- `<TcpStream as Write>::poll_close` now closes the write half of the stream [(#618)](https://github.com/async-rs/async-std/pull/618)
# [1.2.0] - 2019-11-27
[API Documentation](https://docs.rs/async-std/1.2.0/async-std)
This patch includes some minor quality-of-life improvements, introduces a
new `Stream::unzip` API, and adds verbose errors to our networking types.
This means if you can't connect to a socket, you'll never have to wonder again
*which* address it was you couldn't connect to, instead of having to go through
the motions to debug what the address was.
## Example
Unzip a stream of tuples into two collections:
```rust
use async_std::prelude::*;
use async_std::stream;
let s = stream::from_iter(vec![(1,2), (3,4)]);
let (left, right): (Vec<_>, Vec<_>) = s.unzip().await;
assert_eq!(left, [1, 3]);
assert_eq!(right, [2, 4]);
```
## Added
- Added `Stream::unzip` as "unstable".
- Added verbose errors to the networking types.
## Changed
- Enabled CI on master branch.
- `Future::join` and `Future::try_join` can now join futures with different
output types.
## Fixed
- Fixed the docs and `Debug` output of `BufWriter`.
- Fixed a bug in `Stream::throttle` that made it consume too much CPU.
# [1.1.0] - 2019-11-21
[API Documentation](https://docs.rs/async-std/1.1.0/async-std)
This patch introduces a faster scheduler algorithm, `Stream::throttle`, and
stabilizes `task::yield_now`. Additionally we're introducing several more stream
APIs, bringing us to almost complete parity with the standard library.
Furthermore our `path` submodule now returns more context in errors. So if
opening a file fails, async-std will tell you *which* file was failed to open,
making it easier to write and debug programs.
## Examples
```rust
let start = Instant::now();
let mut s = stream::interval(Duration::from_millis(5))
.throttle(Duration::from_millis(10))
.take(2);
s.next().await;
assert!(start.elapsed().as_millis() >= 5);
s.next().await;
assert!(start.elapsed().as_millis() >= 15);
s.next().await;
assert!(start.elapsed().as_millis() >= 25);
```
## Added
- Added `Stream::throttle` as "unstable".
- Added `Stream::count` as "unstable".
- Added `Stream::max` as "unstable".
- Added `Stream::successors` as "unstable".
- Added `Stream::by_ref` as "unstable".
- Added `Stream::partition` as "unstable".
- Added contextual errors to the `path` submodule.
- Added `os::windows::symlink_dir` as "unstable".
- Added `os::windows::symlink_file` as "unstable".
- Stabilized `task::yield_now`.
## Fixes
- We now ignore seek errors when rolling back failed `read` calls on `File`.
- Fixed a bug where `Stream::max_by_key` was returning the wrong result.
- Fixed a bug where `Stream::min_by_key` was returning the wrong result.
## Changed
- Applied various fixes to the tutorial.
- Fixed an issue with Clippy.
- Optimized an internal code generation macro, improving compilation speeds.
- Removed an `Unpin` bound from `stream::Once`.
- Removed various extra internal uses of `pin_mut!`.
- Simplified `Stream::any` and `Stream::all`'s internals.
- The `surf` example is now enabled again.
- Tweaked some streams internals.
- Updated `futures-timer` to 2.0.0, improving compilation speed.
- Upgraded `async-macros` to 2.0.0.
- `Stream::merge` now uses randomized ordering to reduce overall latency.
- The scheduler is now more efficient by keeping a slot for the next task to
run. This is similar to Go's scheduler, and Tokio's scheduler.
- Fixed the documentation of the `channel` types to link back to the `channel`
function.
# [1.0.1] - 2019-11-12
[API Documentation](https://docs.rs/async-std/1.0.1/async-std)
We were seeing a regression in our fs performance, caused by too many
long-running tasks. This patch fixes that regression by being more proactive
about closing down idle threads.
## Changes
- Improved thread startup/shutdown algorithm in `task::spawn_blocking`.
- Fixed a typo in the tutorial.
# [1.0.0] - 2019-11-11
[API Documentation](https://docs.rs/async-std/1.0.0/async-std)
This release marks the `1.0.0` release of async-std; a major milestone for our
development. This release itself mostly includes quality of life improvements
for all of modules, including more consistent API bounds for a lot of our
submodules.
The biggest change is that we're now using the full semver range,
`major.minor.patch`, and any breaking changes to our "stable" APIs will require
an update of the `major` number.
We're excited we've hit this milestone together with you all. Thank you!
## Added
- Added `Future::join` as "unstable", replacing `future::join!`.
- Added `Future::try_join` as "unstable", replacing `future::try_join!`.
- Enabled `stable` and `beta` channel testing on CI.
- Implemented `FromIterator` and `Extend` for `PathBuf`.
- Implemented `FromStream` for `PathBuf`.
- Loosened the trait bounds of `io::copy` on "unstable".
## Changed
- Added a `Sync` bound to `RwLock`, resolving a memory safety issue.
- Fixed a bug in `Stream::take_while` where it could continue after it should've
ended.
- Fixed a bug where our `attributes` Cargo feature wasn't working as intended.
- Improved documentation of `Stream::merge`, documenting ordering guarantees.
- Update doc imports in examples to prefer async-std's types.
- Various quality of life improvements to the `future` submodule.
- Various quality of life improvements to the `path` submodule.
- Various quality of life improvements to the `stream` submodule.
## Removed
- Removed `future::join!` in favor of `Future::join`.
- Removed `future::try_join!` in favor of `Future::try_join`.
# [0.99.12] - 2019-11-07
[API Documentation](https://docs.rs/async-std/0.99.12/async-std)
This patch upgrades us to `futures` 0.3, support for `async/await` on Rust
Stable, performance improvements, and brand new module-level documentation.
## Added
- Added `Future::flatten` as "unstable".
- Added `Future::race` as "unstable" (replaces `future::select!`).
- Added `Future::try_race` as "unstable" (replaces `future::try_select!`).
- Added `Stderr::lock` as "unstable".
- Added `Stdin::lock` as "unstable".
- Added `Stdout::lock` as "unstable".
- Added `Stream::copied` as "unstable".
- Added `Stream::eq` as "unstable".
- Added `Stream::max_by_key` as "unstable".
- Added `Stream::min` as "unstable".
- Added `Stream::ne` as "unstable".
- Added `Stream::position` as "unstable".
- Added `StreamExt` and `FutureExt` as enumerable in the `prelude`.
- Added `TcpListener` and `TcpStream` integration tests.
- Added `stream::from_iter`.
- Added `sync::WakerSet` for internal use.
- Added an example to handle both `IP v4` and `IP v6` connections.
- Added the `default` Cargo feature.
- Added the `attributes` Cargo feature.
- Added the `std` Cargo feature.
## Changed
- Fixed a bug in the blocking threadpool where it didn't spawn more than one thread.
- Fixed a bug with `Stream::merge` where sometimes it ended too soon.
- Fixed a bug with our GitHub actions setup.
- Fixed an issue where our channels could spuriously deadlock.
- Refactored the `task` module.
- Removed a deprecated GitHub action.
- Replaced `futures-preview` with `futures`.
- Replaced `lazy_static` with `once_cell`.
- Replaced all uses of `VecDequeue` in the examples with `stream::from_iter`.
- Simplified `sync::RwLock` using the internal `sync::WakerSet` type.
- Updated the `path` submodule documentation to match std.
- Updated the mod-level documentation to match std.
## Removed
- Removed `future::select!` (replaced by `Future::race`).
- Removed `future::try_select!` (replaced by `Future::try_race`).
# [0.99.11] - 2019-10-29
This patch introduces `async_std::sync::channel`, a novel asynchronous port of
the ultra-fast Crossbeam channels. This has been one of the most anticipated
features for async-std, and we're excited to be providing a first version of
this!
In addition to channels, this patch has the regular list of new methods, types,
and doc fixes.
## Examples
__Send and receive items from a channel__
```rust
// Create a bounded channel with a max-size of 1
let (s, r) = channel(1);
// This call returns immediately because there is enough space in the channel.
s.send(1).await;
task::spawn(async move {
// This call blocks the current task because the channel is full.
// It will be able to complete only after the first message is received.
s.send(2).await;
});
// Receive items from the channel
task::sleep(Duration::from_secs(1)).await;
assert_eq!(r.recv().await, Some(1));
assert_eq!(r.recv().await, Some(2));
```
## Added
- Added `Future::delay` as "unstable"
- Added `Stream::flat_map` as "unstable"
- Added `Stream::flatten` as "unstable"
- Added `Stream::product` as "unstable"
- Added `Stream::sum` as "unstable"
- Added `Stream::min_by_key`
- Added `Stream::max_by`
- Added `Stream::timeout` as "unstable"
- Added `sync::channel` as "unstable".
- Added doc links from instantiated structs to the methods that create them.
- Implemented `Extend` + `FromStream` for `PathBuf`.
## Changed
- Fixed an issue with `block_on` so it works even when nested.
- Fixed issues with our Clippy check on CI.
- Replaced our uses of `cfg_if` with our own macros, simplifying the codebase.
- Updated the homepage link in `Cargo.toml` to point to [async.rs](https://async.rs).
- Updated the module-level documentation for `stream` and `sync`.
- Various typos and grammar fixes.
- Removed redundant file flushes, improving the performance of `File` operations
## Removed
Nothing was removed in this release.
# [0.99.10] - 2019-10-16
This patch stabilizes several core concurrency macros, introduces async versions
of `Path` and `PathBuf`, and adds almost 100 other commits.
## Examples
__Asynchronously read directories from the filesystem__
```rust
use async_std::fs;
use async_std::path::Path;
use async_std::prelude::*;
let path = Path::new("/laputa");
let mut dir = fs::read_dir(&path).await.unwrap();
while let Some(entry) = dir.next().await {
if let Ok(entry) = entry {
println!("{:?}", entry.path());
}
}
```
__Cooperatively reschedule the current task on the executor__
```rust
use async_std::prelude::*;
use async_std::task;
task::spawn(async {
let x = fibonnacci(1000); // Do expensive work
task::yield_now().await; // Allow other tasks to run
x + fibonnacci(100) // Do more work
})
```
__Create an interval stream__
```rust
use async_std::prelude::*;
use async_std::stream;
use std::time::Duration;
let mut interval = stream::interval(Duration::from_secs(4));
while let Some(_) = interval.next().await {
println!("prints every four seconds");
}
```
## Added
- Added `FutureExt` to the `prelude`, allowing us to extend `Future`
- Added `Stream::cmp`
- Added `Stream::ge`
- Added `Stream::last`
- Added `Stream::le`
- Added `Stream::lt`
- Added `Stream::merge` as "unstable", replacing `stream::join!`
- Added `Stream::partial_cmp`
- Added `Stream::take_while`
- Added `Stream::try_fold`
- Added `future::IntoFuture` as "unstable"
- Added `io::BufRead::split`
- Added `io::Write::write_fmt`
- Added `print!`, `println!`, `eprint!`, `eprintln!` macros as "unstable"
- Added `process` as "unstable", re-exporting std types only for now
- Added `std::net` re-exports to the `net` submodule
- Added `std::path::PathBuf` with all associated methods
- Added `std::path::Path` with all associated methods
- Added `stream::ExactSizeStream` as "unstable"
- Added `stream::FusedStream` as "unstable"
- Added `stream::Product`
- Added `stream::Sum`
- Added `stream::from_fn`
- Added `stream::interval` as "unstable"
- Added `stream::repeat_with`
- Added `task::spawn_blocking` as "unstable", replacing `task::blocking`
- Added `task::yield_now`
- Added `write!` and `writeln!` macros as "unstable"
- Stabilized `future::join!` and `future::try_join!`
- Stabilized `future::timeout`
- Stabilized `path`
- Stabilized `task::ready!`
## Changed
- Fixed `BufWriter::into_inner` so it calls `flush` before yielding
- Refactored `io::BufWriter` internals
- Refactored `net::ToSocketAddrs` internals
- Removed Travis CI entirely
- Rewrote the README.md
- Stabilized `io::Cursor`
- Switched bors over to use GitHub actions
- Updated the `io` documentation to match std's `io` docs
- Updated the `task` documentation to match std's `thread` docs
## Removed
- Removed the "unstable" `stream::join!` in favor of `Stream::merge`
- Removed the "unstable" `task::blocking` in favor of `task::spawn_blocking`
# [0.99.9] - 2019-10-08 # [0.99.9] - 2019-10-08
This patch upgrades our `futures-rs` version, allowing us to build on the 1.39 This patch upgrades our `futures-rs` version, allowing us to build on the 1.39
@ -183,7 +746,22 @@ task::blocking(async {
- Initial beta release - Initial beta release
[Unreleased]: https://github.com/async-rs/async-std/compare/v0.99.9...HEAD [Unreleased]: https://github.com/async-rs/async-std/compare/v1.6.2...HEAD
[1.6.2]: https://github.com/async-rs/async-std/compare/v1.6.1...v1.6.2
[1.6.1]: https://github.com/async-rs/async-std/compare/v1.6.0...v1.6.1
[1.6.0]: https://github.com/async-rs/async-std/compare/v1.5.0...v1.6.0
[1.6.0-beta.2]: https://github.com/async-rs/async-std/compare/v1.6.0-beta.1...v1.6.0-beta.2
[1.6.0-beta.1]: https://github.com/async-rs/async-std/compare/v1.5.0...v1.6.0-beta.1
[1.5.0]: https://github.com/async-rs/async-std/compare/v1.4.0...v1.5.0
[1.4.0]: https://github.com/async-rs/async-std/compare/v1.3.0...v1.4.0
[1.3.0]: https://github.com/async-rs/async-std/compare/v1.2.0...v1.3.0
[1.2.0]: https://github.com/async-rs/async-std/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/async-rs/async-std/compare/v1.0.1...v1.1.0
[1.0.1]: https://github.com/async-rs/async-std/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/async-rs/async-std/compare/v0.99.12...v1.0.0
[0.99.12]: https://github.com/async-rs/async-std/compare/v0.99.11...v0.99.12
[0.99.11]: https://github.com/async-rs/async-std/compare/v0.99.10...v0.99.11
[0.99.10]: https://github.com/async-rs/async-std/compare/v0.99.9...v0.99.10
[0.99.9]: https://github.com/async-rs/async-std/compare/v0.99.8...v0.99.9 [0.99.9]: https://github.com/async-rs/async-std/compare/v0.99.8...v0.99.9
[0.99.8]: https://github.com/async-rs/async-std/compare/v0.99.7...v0.99.8 [0.99.8]: https://github.com/async-rs/async-std/compare/v0.99.7...v0.99.8
[0.99.7]: https://github.com/async-rs/async-std/compare/v0.99.6...v0.99.7 [0.99.7]: https://github.com/async-rs/async-std/compare/v0.99.6...v0.99.7

@ -1,15 +1,16 @@
[package] [package]
name = "async-std" name = "async-std"
version = "0.99.9" version = "1.6.2"
authors = [ authors = [
"Stjepan Glavina <stjepang@gmail.com>", "Stjepan Glavina <stjepang@gmail.com>",
"Yoshua Wuyts <yoshuawuyts@gmail.com>", "Yoshua Wuyts <yoshuawuyts@gmail.com>",
"Friedel Ziegelmayer <me@dignifiedquire.com>",
"Contributors to async-std", "Contributors to async-std",
] ]
edition = "2018" edition = "2018"
license = "Apache-2.0/MIT" license = "Apache-2.0/MIT"
repository = "https://github.com/async-rs/async-std" repository = "https://github.com/async-rs/async-std"
homepage = "https://github.com/async-rs/async-std" homepage = "https://async.rs"
documentation = "https://docs.rs/async-std" documentation = "https://docs.rs/async-std"
description = "Async version of the Rust standard library" description = "Async version of the Rust standard library"
keywords = ["async", "await", "future", "std", "task"] keywords = ["async", "await", "future", "std", "task"]
@ -21,35 +22,86 @@ features = ["docs"]
rustdoc-args = ["--cfg", "feature=\"docs\""] rustdoc-args = ["--cfg", "feature=\"docs\""]
[features] [features]
docs = ["broadcaster"] default = [
unstable = ["broadcaster"] "std",
"async-task",
"kv-log-macro",
"log",
"num_cpus",
"pin-project-lite",
"smol",
]
docs = ["attributes", "unstable", "default"]
unstable = [
"std",
"futures-timer",
]
attributes = ["async-attributes"]
std = [
"alloc",
"crossbeam-utils",
"futures-core/std",
"futures-io",
"memchr",
"once_cell",
"pin-utils",
"slab",
"wasm-bindgen-futures",
"futures-channel",
"async-mutex",
]
alloc = [
"futures-core/alloc",
"pin-project-lite",
]
tokio02 = ["smol/tokio02"]
[dependencies] [dependencies]
async-macros = "1.0.0" async-attributes = { version = "1.1.1", optional = true }
async-task = "1.0.0" async-task = { version = "3.0.0", optional = true }
cfg-if = "0.1.9" async-mutex = { version = "1.1.3", optional = true }
crossbeam-channel = "0.3.9" crossbeam-utils = { version = "0.7.2", optional = true }
crossbeam-deque = "0.7.1" futures-core = { version = "0.3.4", optional = true, default-features = false }
futures-core-preview = "=0.3.0-alpha.19" futures-io = { version = "0.3.4", optional = true }
futures-io-preview = "=0.3.0-alpha.19" kv-log-macro = { version = "1.0.6", optional = true }
futures-timer = "0.4.0" log = { version = "0.4.8", features = ["kv_unstable"], optional = true }
lazy_static = "1.4.0" memchr = { version = "2.3.3", optional = true }
log = { version = "0.4.8", features = ["kv_unstable"] } num_cpus = { version = "1.12.0", optional = true }
memchr = "2.2.1" once_cell = { version = "1.3.1", optional = true }
mio = "0.6.19" pin-project-lite = { version = "0.1.4", optional = true }
mio-uds = "0.6.7" pin-utils = { version = "0.1.0-alpha.4", optional = true }
num_cpus = "1.10.1" slab = { version = "0.4.2", optional = true }
pin-utils = "0.1.0-alpha.4" futures-timer = { version = "3.0.2", optional = true }
slab = "0.4.2"
kv-log-macro = "1.0.4" # Devdepencency, but they are not allowed to be optional :/
broadcaster = { version = "0.2.6", optional = true, default-features = false, features = ["default-channels"] } surf = { version = "1.0.3", optional = true }
[target.'cfg(not(target_os = "unknown"))'.dependencies]
smol = { version = "0.1.17", optional = true }
[target.'cfg(target_arch = "wasm32")'.dependencies]
futures-timer = { version = "3.0.2", optional = true, features = ["wasm-bindgen"] }
wasm-bindgen-futures = { version = "0.4.10", optional = true }
futures-channel = { version = "0.3.4", optional = true }
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "0.3.10"
[dev-dependencies] [dev-dependencies]
femme = "1.2.0" femme = "1.3.0"
# surf = "1.0.2" rand = "0.7.3"
tempdir = "0.3.7" tempdir = "0.3.7"
futures-preview = { version = "=0.3.0-alpha.19", features = ["async-await"] } futures = "0.3.4"
rand_xorshift = "0.2.0"
[[test]]
name = "stream"
required-features = ["unstable"]
[[example]]
name = "tcp-ipv4-and-6-echo"
required-features = ["unstable"]
# These are used by the book for examples [[example]]
futures-channel-preview = "=0.3.0-alpha.19" name = "surf-web"
futures-util-preview = "=0.3.0-alpha.19" required-features = ["surf"]

@ -1,142 +1,159 @@
# Async version of the Rust standard library <h1 align="center">async-std</h1>
<div align="center">
[![Build Status](https://travis-ci.com/async-rs/async-std.svg?branch=master)](https://travis-ci.com/async-rs/async-std) <strong>
[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](https://github.com/async-rs/async-std) Async version of the Rust standard library
[![Cargo](https://img.shields.io/crates/v/async-std.svg)](https://crates.io/crates/async-std) </strong>
[![Documentation](https://docs.rs/async-std/badge.svg)](https://docs.rs/async-std) </div>
[![chat](https://img.shields.io/discord/598880689856970762.svg?logo=discord)](https://discord.gg/JvZeVNe)
<br />
This crate provides an async version of [`std`]. It provides all the interfaces you
are used to, but in an async version and ready for Rust's `async`/`await` syntax. <div align="center">
<!-- CI status -->
<a href="https://github.com/async-rs/async-std/actions">
<img src="https://github.com/async-rs/async-std/workflows/CI/badge.svg"
alt="CI Status" />
</a>
<!-- Crates version -->
<a href="https://crates.io/crates/async-std">
<img src="https://img.shields.io/crates/v/async-std.svg?style=flat-square"
alt="Crates.io version" />
</a>
<!-- Downloads -->
<a href="https://crates.io/crates/async-std">
<img src="https://img.shields.io/crates/d/async-std.svg?style=flat-square"
alt="Download" />
</a>
<!-- docs.rs docs -->
<a href="https://docs.rs/async-std">
<img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square"
alt="docs.rs docs" />
</a>
<a href="https://discord.gg/JvZeVNe">
<img src="https://img.shields.io/discord/598880689856970762.svg?logo=discord&style=flat-square"
alt="chat" />
</a>
</div>
<div align="center">
<h3>
<a href="https://docs.rs/async-std">
API Docs
</a>
<span> | </span>
<a href="https://book.async.rs">
Book
</a>
<span> | </span>
<a href="https://github.com/async-rs/async-std/releases">
Releases
</a>
<span> | </span>
<a href="https://async.rs/contribute">
Contributing
</a>
</h3>
</div>
<br/>
This crate provides an async version of [`std`]. It provides all the interfaces
you are used to, but in an async version and ready for Rust's `async`/`await`
syntax.
[`std`]: https://doc.rust-lang.org/std/index.html [`std`]: https://doc.rust-lang.org/std/index.html
## Documentation ## Features
`async-std` comes with [extensive API documentation][docs] and a [book][book]. - __Modern:__ Built from the ground up for `std::future` and `async/await` with
blazing fast compilation time.
- __Fast:__ Our robust allocator and threadpool designs provide ultra-high
throughput with predictably low latency.
- __Intuitive:__ Complete parity with the stdlib means you only need to learn
APIs once.
- __Clear:__ [Detailed documentation][docs] and [accessible guides][book] mean
using async Rust was never easier.
[docs]: https://docs.rs/async-std [docs]: https://docs.rs/async-std
[book]: https://book.async.rs [book]: https://book.async.rs
## Quickstart ## Examples
Add the following lines to your `Cargo.toml`:
```toml
[dependencies]
async-std = "0.99"
```
Or use [cargo add][cargo-add] if you have it installed:
```sh
$ cargo add async-std
```
[cargo-add]: https://github.com/killercup/cargo-edit
## Hello world
```rust ```rust
use async_std::task; use async_std::task;
fn main() { async fn say_hello() {
task::block_on(async {
println!("Hello, world!"); println!("Hello, world!");
})
}
```
## Low-Friction Sockets with Built-In Timeouts
```rust
use std::time::Duration;
use async_std::{
prelude::*,
task,
io,
net::TcpStream,
};
async fn get() -> io::Result<Vec<u8>> {
let mut stream = TcpStream::connect("example.com:80").await?;
stream.write_all(b"GET /index.html HTTP/1.0\r\n\r\n").await?;
let mut buf = vec![];
io::timeout(Duration::from_secs(5), async {
stream.read_to_end(&mut buf).await?;
Ok(buf)
}).await
} }
fn main() { fn main() {
task::block_on(async { task::block_on(say_hello())
let raw_response = get().await.expect("request");
let response = String::from_utf8(raw_response)
.expect("utf8 conversion");
println!("received: {}", response);
});
} }
``` ```
## Features More examples, including networking and file access, can be found in our
[`examples`] directory and in our [documentation].
`async-std` is strongly commited to following semver. This means your code won't [`examples`]: https://github.com/async-rs/async-std/tree/master/examples
break unless _you_ decide to upgrade. [documentation]: https://docs.rs/async-std#examples
[`task::block_on`]: https://docs.rs/async-std/*/async_std/task/fn.block_on.html
[`"attributes"` feature]: https://docs.rs/async-std/#features
However every now and then we come up with something that we think will work ## Philosophy
_great_ for `async-std`, and we want to provide a sneak-peek so you can try it
out. This is what we call _"unstable"_ features. You can try out the unstable
features by enabling the `unstable` feature in your `Cargo.toml` file:
```toml We believe Async Rust should be as easy to pick up as Sync Rust. We also believe
[dependencies.async-std] that the best API is the one you already know. And finally, we believe that
version = "0.99" providing an asynchronous counterpart to the standard library is the best way
features = ["unstable"] stdlib provides a reliable basis for both performance and productivity.
```
Just be careful when using these features, as they may change between Async-std is the embodiment of that vision. It combines single-allocation task
versions. creation, with an adaptive lock-free executor, threadpool and network driver to
create a smooth system that processes work at a high pace with low latency,
using Rust's familiar stdlib API.
## Take a look around ## Installation
Clone the repo: With [cargo add][cargo-add] installed run:
``` ```sh
git clone git@github.com:async-rs/async-std.git && cd async-std $ cargo add async-std
``` ```
Generate docs: We also provide a set of "unstable" features with async-std. See the [features
documentation] on how to enable them.
``` [cargo-add]: https://github.com/killercup/cargo-edit
cargo +nightly doc --features docs --open [features documentation]: https://docs.rs/async-std/#features
```
Check out the [examples](examples). To run an example: ## Ecosystem
``` * [async-tls](https://crates.io/crates/async-tls) — Async TLS/SSL streams using **Rustls**.
cargo +nightly run --example hello-world
```
## Contributing * [async-native-tls](https://crates.io/crates/async-native-tls) — **Native TLS** for Async. Native TLS for futures and async-std.
See [our contribution document][contribution]. * [async-tungstenite](https://crates.io/crates/async-tungstenite) — Asynchronous **WebSockets** for async-std, tokio, gio and any std Futures runtime.
[contribution]: https://async.rs/contribute * [Tide](https://crates.io/crates/tide) — Serve the web. A modular **web framework** built around async/await.
## License * [SQLx](https://crates.io/crates/sqlx) — The Rust **SQL** Toolkit. SQLx is a 100% safe Rust library for Postgres and MySQL with compile-time checked queries.
* [Surf](https://crates.io/crates/surf) — Surf the web. Surf is a friendly **HTTP client** built for casual Rustaceans and veterans alike.
Licensed under either of * [Xactor](https://crates.io/crates/xactor) — Xactor is a rust actors framework based on async-std.
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * [async-graphql](https://crates.io/crates/async-graphql) — A GraphQL server library implemented in rust, with full support for async/await.
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
## License
at your option. <sup>
Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
</sup>
#### Contribution <br/>
<sub>
Unless you explicitly state otherwise, any contribution intentionally submitted 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 for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
dual licensed as above, without any additional terms or conditions. be dual licensed as above, without any additional terms or conditions.
</sub>

@ -0,0 +1,40 @@
#![feature(test)]
extern crate test;
use async_std::sync::{Arc, Mutex};
use async_std::task;
use test::Bencher;
#[bench]
fn create(b: &mut Bencher) {
b.iter(|| Mutex::new(()));
}
#[bench]
fn contention(b: &mut Bencher) {
b.iter(|| task::block_on(run(10, 1000)));
}
#[bench]
fn no_contention(b: &mut Bencher) {
b.iter(|| task::block_on(run(1, 10000)));
}
async fn run(task: usize, iter: usize) {
let m = Arc::new(Mutex::new(()));
let mut tasks = Vec::new();
for _ in 0..task {
let m = m.clone();
tasks.push(task::spawn(async move {
for _ in 0..iter {
let _ = m.lock().await;
}
}));
}
for t in tasks {
t.await;
}
}

@ -0,0 +1,11 @@
#![feature(test)]
extern crate test;
use async_std::task;
use test::Bencher;
#[bench]
fn block_on(b: &mut Bencher) {
b.iter(|| task::block_on(async {}));
}

@ -19,8 +19,9 @@
- [Clean Shutdown](./tutorial/clean_shutdown.md) - [Clean Shutdown](./tutorial/clean_shutdown.md)
- [Handling Disconnection](./tutorial/handling_disconnection.md) - [Handling Disconnection](./tutorial/handling_disconnection.md)
- [Implementing a Client](./tutorial/implementing_a_client.md) - [Implementing a Client](./tutorial/implementing_a_client.md)
- [TODO: Async Patterns](./patterns.md) - [Async Patterns](./patterns.md)
- [TODO: Collected Small Patterns](./patterns/small-patterns.md) - [TODO: Collected Small Patterns](./patterns/small-patterns.md)
- [Production-Ready Accept Loop](./patterns/accept-loop.md)
- [Security practices](./security/index.md) - [Security practices](./security/index.md)
- [Security Disclosures and Policy](./security/policy.md) - [Security Disclosures and Policy](./security/policy.md)
- [Glossary](./glossary.md) - [Glossary](./glossary.md)

@ -24,11 +24,7 @@ To sum up: Rust gives us the ability to safely abstract over important propertie
## An easy view of computation ## An easy view of computation
While computation is a subject to write a whole [book](https://computationbook.com/) about, a very simplified view suffices for us: While computation is a subject to write a whole [book](https://computationbook.com/) about, a very simplified view suffices for us: A sequence of composable operations which can branch based on a decision, run to succession and yield a result or yield an error
- computation is a sequence of composable operations
- they can branch based on a decision
- they either run to succession and yield a result, or they can yield an error
## Deferring computation ## Deferring computation
@ -136,11 +132,11 @@ When executing 2 or more of these functions at the same time, our runtime system
## Conclusion ## Conclusion
Working from values, we searched for something that expresses *working towards a value available sometime later*. From there, we talked about the concept of polling. Working from values, we searched for something that expresses *working towards a value available later*. From there, we talked about the concept of polling.
A `Future` is any data type that does not represent a value, but the ability to *produce a value at some point in the future*. Implementations of this are very varied and detailed depending on use-case, but the interface is simple. A `Future` is any data type that does not represent a value, but the ability to *produce a value at some point in the future*. Implementations of this are very varied and detailed depending on use-case, but the interface is simple.
Next, we will introduce you to `tasks`, which we need to actually *run* Futures. Next, we will introduce you to `tasks`, which we will use to actually *run* Futures.
[^1]: Two parties reading while it is guaranteed that no one is writing is always safe. [^1]: Two parties reading while it is guaranteed that no one is writing is always safe.

@ -80,7 +80,7 @@ Tasks in `async_std` are one of the core abstractions. Much like Rust's `thread`
## Blocking ## Blocking
`Task`s are assumed to run _concurrently_, potentially by sharing a thread of execution. This means that operations blocking an _operating system thread_, such as `std::thread::sleep` or io function from Rust's `std` library will _stop execution of all tasks sharing this thread_. Other libraries (such as database drivers) have similar behaviour. Note that _blocking the current thread_ is not in and by itself bad behaviour, just something that does not mix well with the concurrent execution model of `async-std`. Essentially, never do this: `Task`s are assumed to run _concurrently_, potentially by sharing a thread of execution. This means that operations blocking an _operating system thread_, such as `std::thread::sleep` or io function from Rust's `std` library will _stop execution of all tasks sharing this thread_. Other libraries (such as database drivers) have similar behaviour. Note that _blocking the current thread_ is not in and of itself bad behaviour, just something that does not mix well with the concurrent execution model of `async-std`. Essentially, never do this:
```rust,edition2018 ```rust,edition2018
# extern crate async_std; # extern crate async_std;

@ -4,4 +4,4 @@
`async-std` provides an interface to all important primitives: filesystem operations, network operations and concurrency basics like timers. It also exposes a `task` in a model similar to the `thread` module found in the Rust standard lib. But it does not only include I/O primitives, but also `async/await` compatible versions of primitives like `Mutex`. `async-std` provides an interface to all important primitives: filesystem operations, network operations and concurrency basics like timers. It also exposes a `task` in a model similar to the `thread` module found in the Rust standard lib. But it does not only include I/O primitives, but also `async/await` compatible versions of primitives like `Mutex`.
[organization]: https://github.com/async-rs/async-std [organization]: https://github.com/async-rs

@ -31,7 +31,7 @@ In general, this crate will be conservative with respect to the minimum supporte
## Security fixes ## Security fixes
Security fixes will be applied to _all_ minor branches of this library in all _supported_ major revisions. This policy might change in the future, in which case we give at least _3 month_ of ahead notice. Security fixes will be applied to _all_ minor branches of this library in all _supported_ major revisions. This policy might change in the future, in which case we give a notice at least _3 months_ ahead.
## Credits ## Credits

@ -4,13 +4,13 @@ Rust has two kinds of types commonly referred to as `Future`:
- the first is `std::future::Future` from Rusts [standard library](https://doc.rust-lang.org/std/future/trait.Future.html). - the first is `std::future::Future` from Rusts [standard library](https://doc.rust-lang.org/std/future/trait.Future.html).
- the second is `futures::future::Future` from the [futures-rs crate](https://docs.rs/futures-preview/0.3.0-alpha.17/futures/prelude/trait.Future.html), currently released as `futures-preview`. - the second is `futures::future::Future` from the [futures-rs crate](https://docs.rs/futures/0.3/futures/prelude/trait.Future.html).
The future defined in the [futures-rs](https://docs.rs/futures-preview/0.3.0-alpha.17/futures/prelude/trait.Future.html) crate was the original implementation of the type. To enable the `async/await` syntax, the core Future trait was moved into Rusts standard library and became `std::future::Future`. In some sense, the `std::future::Future` can be seen as a minimal subset of `futures::future::Future`. The future defined in the [futures-rs](https://docs.rs/futures/0.3/futures/prelude/trait.Future.html) crate was the original implementation of the type. To enable the `async/await` syntax, the core Future trait was moved into Rusts standard library and became `std::future::Future`. In some sense, the `std::future::Future` can be seen as a minimal subset of `futures::future::Future`.
It is critical to understand the difference between `std::future::Future` and `futures::future::Future`, and the approach that `async-std` takes towards them. In itself, `std::future::Future` is not something you want to interact with as a user—except by calling `.await` on it. The inner workings of `std::future::Future` are mostly of interest to people implementing `Future`. Make no mistake—this is very useful! Most of the functionality that used to be defined on `Future` itself has been moved to an extension trait called [`FuturesExt`](https://docs.rs/futures-preview/0.3.0-alpha.17/futures/future/trait.FutureExt.html). From this information, you might be able to infer that the `futures` library serves as an extension to the core Rust async features. It is critical to understand the difference between `std::future::Future` and `futures::future::Future`, and the approach that `async-std` takes towards them. In itself, `std::future::Future` is not something you want to interact with as a user—except by calling `.await` on it. The inner workings of `std::future::Future` are mostly of interest to people implementing `Future`. Make no mistake—this is very useful! Most of the functionality that used to be defined on `Future` itself has been moved to an extension trait called [`FuturesExt`](https://docs.rs/futures/0.3/futures/future/trait.FutureExt.html). From this information, you might be able to infer that the `futures` library serves as an extension to the core Rust async features.
In the same tradition as `futures`, `async-std` re-exports the core `std::future::Future` type. You can actively opt into the extensions provided by the `futures-preview` crate by adding it to your `Cargo.toml` and importing `FuturesExt`. In the same tradition as `futures`, `async-std` re-exports the core `std::future::Future` type. You can actively opt into the extensions provided by the `futures` crate by adding it to your `Cargo.toml` and importing `FuturesExt`.
## Interfaces and Stability ## Interfaces and Stability

@ -0,0 +1,266 @@
# Production-Ready Accept Loop
A production-ready accept loop needs the following things:
1. Handling errors
2. Limiting the number of simultanteous connections to avoid deny-of-service
(DoS) attacks
## Handling errors
There are two kinds of errors in an accept loop:
1. Per-connection errors. The system uses them to notify that there was a
connection in the queue and it's dropped by the peer. Subsequent connections
can be already queued so next connection must be accepted immediately.
2. Resource shortages. When these are encountered it doesn't make sense to
accept the next socket immediately. But the listener stays active, so you server
should try to accept socket later.
Here is the example of a per-connection error (printed in normal and debug mode):
```
Error: Connection reset by peer (os error 104)
Error: Os { code: 104, kind: ConnectionReset, message: "Connection reset by peer" }
```
And the following is the most common example of a resource shortage error:
```
Error: Too many open files (os error 24)
Error: Os { code: 24, kind: Other, message: "Too many open files" }
```
### Testing Application
To test your application for these errors try the following (this works
on unixes only).
Lower limits and start the application:
```
$ ulimit -n 100
$ cargo run --example your_app
Compiling your_app v0.1.0 (/work)
Finished dev [unoptimized + debuginfo] target(s) in 5.47s
Running `target/debug/examples/your_app`
Server is listening on: http://127.0.0.1:1234
```
Then in another console run the [`wrk`] benchmark tool:
```
$ wrk -c 1000 http://127.0.0.1:1234
Running 10s test @ http://localhost:8080/
2 threads and 1000 connections
$ telnet localhost 1234
Trying ::1...
Connected to localhost.
```
Important is to check the following things:
1. The application doesn't crash on error (but may log errors, see below)
2. It's possible to connect to the application again once load is stopped
(few seconds after `wrk`). This is what `telnet` does in example above,
make sure it prints `Connected to <hostname>`.
3. The `Too many open files` error is logged in the appropriate log. This
requires to set "maximum number of simultaneous connections" parameter (see
below) of your application to a value greater then `100` for this example.
4. Check CPU usage of the app while doing a test. It should not occupy 100%
of a single CPU core (it's unlikely that you can exhaust CPU by 1000
connections in Rust, so this means error handling is not right).
#### Testing non-HTTP applications
If it's possible, use the appropriate benchmark tool and set the appropriate
number of connections. For example `redis-benchmark` has a `-c` parameter for
that, if you implement redis protocol.
Alternatively, can still use `wrk`, just make sure that connection is not
immediately closed. If it is, put a temporary timeout before handing
the connection to the protocol handler, like this:
```rust,edition2018
# extern crate async_std;
# use std::time::Duration;
# use async_std::{
# net::{TcpListener, ToSocketAddrs},
# prelude::*,
# };
#
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
#
#async fn accept_loop(addr: impl ToSocketAddrs) -> Result<()> {
# let listener = TcpListener::bind(addr).await?;
# let mut incoming = listener.incoming();
while let Some(stream) = incoming.next().await {
task::spawn(async {
task::sleep(Duration::from_secs(10)).await; // 1
connection_loop(stream).await;
});
}
# Ok(())
# }
```
1. Make sure the sleep coroutine is inside the spawned task, not in the loop.
[`wrk`]: https://github.com/wg/wrk
### Handling Errors Manually
Here is how basic accept loop could look like:
```rust,edition2018
# extern crate async_std;
# use std::time::Duration;
# use async_std::{
# net::{TcpListener, ToSocketAddrs},
# prelude::*,
# };
#
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
#
async fn accept_loop(addr: impl ToSocketAddrs) -> Result<()> {
let listener = TcpListener::bind(addr).await?;
let mut incoming = listener.incoming();
while let Some(result) = incoming.next().await {
let stream = match stream {
Err(ref e) if is_connection_error(e) => continue, // 1
Err(e) => {
eprintln!("Error: {}. Pausing for 500ms."); // 3
task::sleep(Duration::from_millis(500)).await; // 2
continue;
}
Ok(s) => s,
};
// body
}
Ok(())
}
```
1. Ignore per-connection errors.
2. Sleep and continue on resource shortage.
3. It's important to log the message, because these errors commonly mean the
misconfiguration of the system and are helpful for operations people running
the application.
Be sure to [test your application](#testing-application).
### External Crates
The crate [`async-listen`] has a helper to achieve this task:
```rust,edition2018
# extern crate async_std;
# extern crate async_listen;
# use std::time::Duration;
# use async_std::{
# net::{TcpListener, ToSocketAddrs},
# prelude::*,
# };
#
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
#
use async_listen::{ListenExt, error_hint};
async fn accept_loop(addr: impl ToSocketAddrs) -> Result<()> {
let listener = TcpListener::bind(addr).await?;
let mut incoming = listener
.incoming()
.log_warnings(log_accept_error) // 1
.handle_errors(Duration::from_millis(500));
while let Some(socket) = incoming.next().await { // 2
// body
}
Ok(())
}
fn log_accept_error(e: &io::Error) {
eprintln!("Error: {}. Listener paused for 0.5s. {}", e, error_hint(e)) // 3
}
```
1. Logs resource shortages (`async-listen` calls them warnings). If you use
`log` crate or any other in your app this should go to the log.
2. Stream yields sockets without `Result` wrapper after `handle_errors` because
all errors are already handled.
3. Together with the error we print a hint, which explains some errors for end
users. For example, it recommends increasing open file limit and gives
a link.
[`async-listen`]: https://crates.io/crates/async-listen/
Be sure to [test your application](#testing-application).
## Connections Limit
Even if you've applied everything described in
[Handling Errors](#handling-errors) section, there is still a problem.
Let's imagine you have a server that needs to open a file to process
client request. At some point, you might encounter the following situation:
1. There are as many client connection as max file descriptors allowed for
the application.
2. Listener gets `Too many open files` error so it sleeps.
3. Some client sends a request via the previously open connection.
4. Opening a file to serve request fails, because of the same
`Too many open files` error, until some other client drops a connection.
There are many more possible situations, this is just a small illustation that
limiting number of connections is very useful. Generally, it's one of the ways
to control resources used by a server and avoiding some kinds of deny of
service (DoS) attacks.
### `async-listen` crate
Limiting maximum number of simultaneous connections with [`async-listen`]
looks like the following:
```rust,edition2018
# extern crate async_std;
# extern crate async_listen;
# use std::time::Duration;
# use async_std::{
# net::{TcpListener, TcpStream, ToSocketAddrs},
# prelude::*,
# };
#
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
#
use async_listen::{ListenExt, Token, error_hint};
async fn accept_loop(addr: impl ToSocketAddrs) -> Result<()> {
let listener = TcpListener::bind(addr).await?;
let mut incoming = listener
.incoming()
.log_warnings(log_accept_error)
.handle_errors(Duration::from_millis(500)) // 1
.backpressure(100);
while let Some((token, socket)) = incoming.next().await { // 2
task::spawn(async move {
connection_loop(&token, stream).await; // 3
});
}
Ok(())
}
async fn connection_loop(_token: &Token, stream: TcpStream) { // 4
// ...
}
# fn log_accept_error(e: &io::Error) {
# eprintln!("Error: {}. Listener paused for 0.5s. {}", e, error_hint(e));
# }
```
1. We need to handle errors first, because [`backpressure`] helper expects
stream of `TcpStream` rather than `Result`.
2. The token yielded by a new stream is what is counted by backpressure helper.
I.e. if you drop a token, new connection can be established.
3. We give the connection loop a reference to token to bind token's lifetime to
the lifetime of the connection.
4. The token itsellf in the function can be ignored, hence `_token`
[`backpressure`]: https://docs.rs/async-listen/0.1.2/async_listen/trait.ListenExt.html#method.backpressure
Be sure to [test this behavior](#testing-application).

@ -4,16 +4,15 @@ At this point, we only need to start the broker to get a fully-functioning (in t
```rust,edition2018 ```rust,edition2018
# extern crate async_std; # extern crate async_std;
# extern crate futures_channel; # extern crate futures;
# extern crate futures_util;
use async_std::{ use async_std::{
io::{self, BufReader}, io::BufReader,
net::{TcpListener, TcpStream, ToSocketAddrs}, net::{TcpListener, TcpStream, ToSocketAddrs},
prelude::*, prelude::*,
task, task,
}; };
use futures_channel::mpsc; use futures::channel::mpsc;
use futures_util::SinkExt; use futures::sink::SinkExt;
use std::{ use std::{
collections::hash_map::{HashMap, Entry}, collections::hash_map::{HashMap, Entry},
sync::Arc, sync::Arc,

@ -22,16 +22,15 @@ Let's add waiting to the server:
```rust,edition2018 ```rust,edition2018
# extern crate async_std; # extern crate async_std;
# extern crate futures_channel; # extern crate futures;
# extern crate futures_util;
# use async_std::{ # use async_std::{
# io::{self, BufReader}, # io::{self, BufReader},
# net::{TcpListener, TcpStream, ToSocketAddrs}, # net::{TcpListener, TcpStream, ToSocketAddrs},
# prelude::*, # prelude::*,
# task, # task,
# }; # };
# use futures_channel::mpsc; # use futures::channel::mpsc;
# use futures_util::SinkExt; # use futures::sink::SinkExt;
# use std::{ # use std::{
# collections::hash_map::{HashMap, Entry}, # collections::hash_map::{HashMap, Entry},
# sync::Arc, # sync::Arc,
@ -156,16 +155,15 @@ And to the broker:
```rust,edition2018 ```rust,edition2018
# extern crate async_std; # extern crate async_std;
# extern crate futures_channel; # extern crate futures;
# extern crate futures_util;
# use async_std::{ # use async_std::{
# io::{self, BufReader}, # io::{self, BufReader},
# net::{TcpListener, TcpStream, ToSocketAddrs}, # net::{TcpListener, TcpStream, ToSocketAddrs},
# prelude::*, # prelude::*,
# task, # task,
# }; # };
# use futures_channel::mpsc; # use futures::channel::mpsc;
# use futures_util::SinkExt; # use futures::sink::SinkExt;
# use std::{ # use std::{
# collections::hash_map::{HashMap, Entry}, # collections::hash_map::{HashMap, Entry},
# sync::Arc, # sync::Arc,

@ -2,25 +2,24 @@
## Connecting Readers and Writers ## Connecting Readers and Writers
So how do we make sure that messages read in `connection_loop` flow into the relevant `connection_writer_loop`? So how do we make sure that messages read in `connection_loop` flow into the relevant `connection_writer_loop`?
We should somehow maintain an `peers: HashMap<String, Sender<String>>` map which allows a client to find destination channels. We should somehow maintain a `peers: HashMap<String, Sender<String>>` map which allows a client to find destination channels.
However, this map would be a bit of shared mutable state, so we'll have to wrap an `RwLock` over it and answer tough questions of what should happen if the client joins at the same moment as it receives a message. However, this map would be a bit of shared mutable state, so we'll have to wrap an `RwLock` over it and answer tough questions of what should happen if the client joins at the same moment as it receives a message.
One trick to make reasoning about state simpler comes from the actor model. One trick to make reasoning about state simpler comes from the actor model.
We can create a dedicated broker tasks which owns the `peers` map and communicates with other tasks by channels. We can create a dedicated broker task which owns the `peers` map and communicates with other tasks using channels.
By hiding `peers` inside such an "actor" task, we remove the need for mutxes and also make serialization point explicit. By hiding `peers` inside such an "actor" task, we remove the need for mutexes and also make the serialization point explicit.
The order of events "Bob sends message to Alice" and "Alice joins" is determined by the order of the corresponding events in the broker's event queue. The order of events "Bob sends message to Alice" and "Alice joins" is determined by the order of the corresponding events in the broker's event queue.
```rust,edition2018 ```rust,edition2018
# extern crate async_std; # extern crate async_std;
# extern crate futures_channel; # extern crate futures;
# extern crate futures_util;
# use async_std::{ # use async_std::{
# net::TcpStream, # net::TcpStream,
# prelude::*, # prelude::*,
# task, # task,
# }; # };
# use futures_channel::mpsc; # use futures::channel::mpsc;
# use futures_util::sink::SinkExt; # use futures::sink::SinkExt;
# use std::sync::Arc; # use std::sync::Arc;
# #
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; # type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
@ -93,9 +92,9 @@ async fn broker_loop(mut events: Receiver<Event>) -> Result<()> {
} }
``` ```
1. Broker should handle two types of events: a message or an arrival of a new peer. 1. The broker task should handle two types of events: a message or an arrival of a new peer.
2. Internal state of the broker is a `HashMap`. 2. The internal state of the broker is a `HashMap`.
Note how we don't need a `Mutex` here and can confidently say, at each iteration of the broker's loop, what is the current set of peers Note how we don't need a `Mutex` here and can confidently say, at each iteration of the broker's loop, what is the current set of peers
3. To handle a message, we send it over a channel to each destination 3. To handle a message, we send it over a channel to each destination
4. To handle new peer, we first register it in the peer's map ... 4. To handle a new peer, we first register it in the peer's map ...
5. ... and then spawn a dedicated task to actually write the messages to the socket. 5. ... and then spawn a dedicated task to actually write the messages to the socket.

@ -19,11 +19,10 @@ First, let's add a shutdown channel to the `connection_loop`:
```rust,edition2018 ```rust,edition2018
# extern crate async_std; # extern crate async_std;
# extern crate futures_channel; # extern crate futures;
# extern crate futures_util;
# use async_std::net::TcpStream; # use async_std::net::TcpStream;
# use futures_channel::mpsc; # use futures::channel::mpsc;
# use futures_util::SinkExt; # use futures::sink::SinkExt;
# use std::sync::Arc; # use std::sync::Arc;
# #
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; # type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
@ -61,8 +60,8 @@ async fn connection_loop(mut broker: Sender<Event>, stream: Arc<TcpStream>) -> R
} }
``` ```
1. To enforce that no messages are send along the shutdown channel, we use an uninhabited type. 1. To enforce that no messages are sent along the shutdown channel, we use an uninhabited type.
2. We pass the shutdown channel to the writer task 2. We pass the shutdown channel to the writer task.
3. In the reader, we create a `_shutdown_sender` whose only purpose is to get dropped. 3. In the reader, we create a `_shutdown_sender` whose only purpose is to get dropped.
In the `connection_writer_loop`, we now need to choose between shutdown and message channels. In the `connection_writer_loop`, we now need to choose between shutdown and message channels.
@ -70,17 +69,14 @@ We use the `select` macro for this purpose:
```rust,edition2018 ```rust,edition2018
# extern crate async_std; # extern crate async_std;
# extern crate futures_channel; # extern crate futures;
# extern crate futures_util;
# use async_std::{net::TcpStream, prelude::*}; # use async_std::{net::TcpStream, prelude::*};
use futures_channel::mpsc; # use futures::channel::mpsc;
use futures_util::{select, FutureExt}; use futures::{select, FutureExt};
# use std::sync::Arc; # use std::sync::Arc;
# type Receiver<T> = mpsc::UnboundedReceiver<T>; # type Receiver<T> = mpsc::UnboundedReceiver<T>;
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; # type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
# type Sender<T> = mpsc::UnboundedSender<T>; # type Sender<T> = mpsc::UnboundedSender<T>;
# #[derive(Debug)] # #[derive(Debug)]
# enum Void {} // 1 # enum Void {} // 1
@ -114,7 +110,7 @@ async fn connection_writer_loop(
Another problem is that between the moment we detect disconnection in `connection_writer_loop` and the moment when we actually remove the peer from the `peers` map, new messages might be pushed into the peer's channel. Another problem is that between the moment we detect disconnection in `connection_writer_loop` and the moment when we actually remove the peer from the `peers` map, new messages might be pushed into the peer's channel.
To not lose these messages completely, we'll return the messages channel back to the broker. To not lose these messages completely, we'll return the messages channel back to the broker.
This also allows us to establish a useful invariant that the message channel strictly outlives the peer in the `peers` map, and makes the broker itself infailable. This also allows us to establish a useful invariant that the message channel strictly outlives the peer in the `peers` map, and makes the broker itself infallible.
## Final Code ## Final Code
@ -122,16 +118,16 @@ The final code looks like this:
```rust,edition2018 ```rust,edition2018
# extern crate async_std; # extern crate async_std;
# extern crate futures_channel; # extern crate futures;
# extern crate futures_util;
use async_std::{ use async_std::{
io::BufReader, io::BufReader,
net::{TcpListener, TcpStream, ToSocketAddrs}, net::{TcpListener, TcpStream, ToSocketAddrs},
prelude::*, prelude::*,
task, task,
}; };
use futures_channel::mpsc; use futures::channel::mpsc;
use futures_util::{select, FutureExt, SinkExt}; use futures::sink::SinkExt;
use futures::{select, FutureExt};
use std::{ use std::{
collections::hash_map::{Entry, HashMap}, collections::hash_map::{Entry, HashMap},
future::Future, future::Future,

@ -1,29 +1,27 @@
## Implementing a client ## Implementing a client
Let's now implement the client for the chat. Since the protocol is line-based, implementing a client for the chat is straightforward:
Because the protocol is line-based, the implementation is pretty straightforward:
* Lines read from stdin should be sent over the socket. * Lines read from stdin should be sent over the socket.
* Lines read from the socket should be echoed to stdout. * Lines read from the socket should be echoed to stdout.
Unlike the server, the client needs only limited concurrency, as it interacts with only a single user. Although async does not significantly affect client performance (as unlike the server, the client interacts solely with one user and only needs limited concurrency), async is still useful for managing concurrency!
For this reason, async doesn't bring a lot of performance benefits in this case.
The client has to read from stdin and the socket *simultaneously*.
Programming this with threads is cumbersome, especially when implementing a clean shutdown.
With async, the `select!` macro is all that is needed.
However, async is still useful for managing concurrency!
Specifically, the client should *simultaneously* read from stdin and from the socket.
Programming this with threads is cumbersome, especially when implementing clean shutdown.
With async, we can just use the `select!` macro.
```rust,edition2018 ```rust,edition2018
# extern crate async_std; # extern crate async_std;
# extern crate futures_util; # extern crate futures;
use async_std::{ use async_std::{
io::{stdin, BufReader}, io::{stdin, BufReader},
net::{TcpStream, ToSocketAddrs}, net::{TcpStream, ToSocketAddrs},
prelude::*, prelude::*,
task, task,
}; };
use futures_util::{select, FutureExt}; use futures::{select, FutureExt};
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;

@ -1,11 +1,14 @@
# Tutorial: Writing a chat # Tutorial: Writing a chat
Nothing is as simple as a chat server, right? Not quite, chat servers Nothing is simpler than creating a chat server, right?
already expose you to all the fun of asynchronous programming: how Not quite, chat servers expose you to all the fun of asynchronous programming:
do you handle clients connecting concurrently. How do you handle them disconnecting?
How do you distribute the messages? How will the server handle clients connecting concurrently?
In this tutorial, we will show you how to write one in `async-std`. How will it handle them disconnecting?
How will it distribute the messages?
This tutorial explains how to write a chat server in `async-std`.
You can also find the tutorial in [our repository](https://github.com/async-rs/async-std/blob/master/examples/a-chat). You can also find the tutorial in [our repository](https://github.com/async-rs/async-std/blob/master/examples/a-chat).

@ -10,14 +10,18 @@ We need to:
```rust,edition2018 ```rust,edition2018
# extern crate async_std; # extern crate async_std;
# use async_std::{ # use async_std::{
# io::BufReader, # net::{TcpListener, ToSocketAddrs},
# net::{TcpListener, TcpStream, ToSocketAddrs},
# prelude::*, # prelude::*,
# task, # task,
# }; # };
# #
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; # type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
# #
use async_std::{
io::BufReader,
net::TcpStream,
};
async fn accept_loop(addr: impl ToSocketAddrs) -> Result<()> { async fn accept_loop(addr: impl ToSocketAddrs) -> Result<()> {
let listener = TcpListener::bind(addr).await?; let listener = TcpListener::bind(addr).await?;
let mut incoming = listener.incoming(); let mut incoming = listener.incoming();
@ -46,7 +50,7 @@ async fn connection_loop(stream: TcpStream) -> Result<()> {
Some(idx) => (&line[..idx], line[idx + 1 ..].trim()), Some(idx) => (&line[..idx], line[idx + 1 ..].trim()),
}; };
let dest: Vec<String> = dest.split(',').map(|name| name.trim().to_string()).collect(); let dest: Vec<String> = dest.split(',').map(|name| name.trim().to_string()).collect();
let msg: String = msg.trim().to_string(); let msg: String = msg.to_string();
} }
Ok(()) Ok(())
} }
@ -107,7 +111,7 @@ We can "fix" it by waiting for the task to be joined, like this:
# #
# async move |stream| { # async move |stream| {
let handle = task::spawn(connection_loop(stream)); let handle = task::spawn(connection_loop(stream));
handle.await handle.await?
# }; # };
``` ```
@ -130,7 +134,7 @@ So let's use a helper function for this:
# }; # };
fn spawn_and_log_error<F>(fut: F) -> task::JoinHandle<()> fn spawn_and_log_error<F>(fut: F) -> task::JoinHandle<()>
where where
F: Future<Output = io::Result<()>> + Send + 'static, F: Future<Output = Result<()>> + Send + 'static,
{ {
task::spawn(async move { task::spawn(async move {
if let Err(e) = fut.await { if let Err(e) = fut.await {

@ -13,14 +13,13 @@ if Alice and Charley send two messages to Bob at the same time, Bob will see the
```rust,edition2018 ```rust,edition2018
# extern crate async_std; # extern crate async_std;
# extern crate futures_channel; # extern crate futures;
# extern crate futures_util;
# use async_std::{ # use async_std::{
# net::TcpStream, # net::TcpStream,
# prelude::*, # prelude::*,
# }; # };
use futures_channel::mpsc; // 1 use futures::channel::mpsc; // 1
use futures_util::sink::SinkExt; use futures::sink::SinkExt;
use std::sync::Arc; use std::sync::Arc;
# type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; # type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;

@ -12,7 +12,7 @@ After that, the client can send messages to other clients using the following sy
login1, login2, ... loginN: message login1, login2, ... loginN: message
``` ```
Each of the specified clients than receives a `from login: message` message. Each of the specified clients then receives a `from login: message` message.
A possible session might look like this A possible session might look like this
@ -38,18 +38,10 @@ $ cargo new a-chat
$ cd a-chat $ cd a-chat
``` ```
At the moment `async-std` requires Rust nightly, so let's add a rustup override for convenience:
```bash
$ rustup override add nightly
$ rustc --version
rustc 1.38.0-nightly (c4715198b 2019-08-05)
```
Add the following lines to `Cargo.toml`: Add the following lines to `Cargo.toml`:
```toml ```toml
[dependencies] [dependencies]
futures-preview = { version = "0.3.0-alpha.19", features = [ "async-await" ] } futures = "0.3.0"
async-std = "0.99" async-std = "1"
``` ```

@ -8,6 +8,6 @@ fn main() -> Result<()> {
match (args.nth(1).as_ref().map(String::as_str), args.next()) { match (args.nth(1).as_ref().map(String::as_str), args.next()) {
(Some("client"), None) => client::main(), (Some("client"), None) => client::main(),
(Some("server"), None) => server::main(), (Some("server"), None) => server::main(),
_ => Err("Usage: a-chat [client|server]")?, _ => Err("Usage: a-chat [client|server]".into()),
} }
} }

@ -45,7 +45,7 @@ async fn connection_loop(mut broker: Sender<Event>, stream: TcpStream) -> Result
let mut lines = reader.lines(); let mut lines = reader.lines();
let name = match lines.next().await { let name = match lines.next().await {
None => Err("peer disconnected immediately")?, None => return Err("peer disconnected immediately".into()),
Some(line) => line?, Some(line) => line?,
}; };
let (_shutdown_sender, shutdown_receiver) = mpsc::unbounded::<Void>(); let (_shutdown_sender, shutdown_receiver) = mpsc::unbounded::<Void>();

@ -1,6 +1,3 @@
/* TODO: Once the next version of surf released, re-enable this example.
//! Sends an HTTP request to the Rust website.
use async_std::task; use async_std::task;
fn main() -> Result<(), surf::Exception> { fn main() -> Result<(), surf::Exception> {
@ -18,6 +15,3 @@ fn main() -> Result<(), surf::Exception> {
Ok(()) Ok(())
}) })
} }
*/
fn main() {}

@ -14,8 +14,9 @@ use async_std::task;
async fn process(stream: TcpStream) -> io::Result<()> { async fn process(stream: TcpStream) -> io::Result<()> {
println!("Accepted from: {}", stream.peer_addr()?); println!("Accepted from: {}", stream.peer_addr()?);
let (reader, writer) = &mut (&stream, &stream); let mut reader = stream.clone();
io::copy(reader, writer).await?; let mut writer = stream;
io::copy(&mut reader, &mut writer).await?;
Ok(()) Ok(())
} }

@ -0,0 +1,45 @@
//! TCP echo server, accepting connections both on both ipv4 and ipv6 sockets.
//!
//! To send messages, do:
//!
//! ```sh
//! $ nc 127.0.0.1 8080
//! $ nc ::1 8080
//! ```
use async_std::io;
use async_std::net::{TcpListener, TcpStream};
use async_std::prelude::*;
use async_std::task;
async fn process(stream: TcpStream) -> io::Result<()> {
println!("Accepted from: {}", stream.peer_addr()?);
let mut reader = stream.clone();
let mut writer = stream;
io::copy(&mut reader, &mut writer).await?;
Ok(())
}
fn main() -> io::Result<()> {
task::block_on(async {
let ipv4_listener = TcpListener::bind("127.0.0.1:8080").await?;
println!("Listening on {}", ipv4_listener.local_addr()?);
let ipv6_listener = TcpListener::bind("[::1]:8080").await?;
println!("Listening on {}", ipv6_listener.local_addr()?);
let ipv4_incoming = ipv4_listener.incoming();
let ipv6_incoming = ipv6_listener.incoming();
let mut incoming = ipv4_incoming.merge(ipv6_incoming);
while let Some(stream) = incoming.next().await {
let stream = stream?;
task::spawn(async {
process(stream).await.unwrap();
});
}
Ok(())
})
}

@ -2,13 +2,16 @@ use std::collections::BinaryHeap;
use std::pin::Pin; use std::pin::Pin;
use crate::prelude::*; use crate::prelude::*;
use crate::stream::{Extend, IntoStream}; use crate::stream::{self, IntoStream};
impl<T: Ord> Extend<T> for BinaryHeap<T> { impl<T: Ord + Send> stream::Extend<T> for BinaryHeap<T> {
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>( fn extend<'a, S: IntoStream<Item = T> + 'a>(
&'a mut self, &'a mut self,
stream: S, stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> { ) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
let stream = stream.into_stream(); let stream = stream.into_stream();
self.reserve(stream.size_hint().0); self.reserve(stream.size_hint().0);

@ -1,23 +1,22 @@
use std::collections::BinaryHeap; use std::collections::BinaryHeap;
use std::pin::Pin; use std::pin::Pin;
use crate::stream::{Extend, FromStream, IntoStream}; use crate::prelude::*;
use crate::stream::{self, FromStream, IntoStream};
impl<T: Ord> FromStream<T> for BinaryHeap<T> { impl<T: Ord + Send> FromStream<T> for BinaryHeap<T> {
#[inline] #[inline]
fn from_stream<'a, S: IntoStream<Item = T>>( fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
stream: S, stream: S,
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>> ) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where where
<S as IntoStream>::IntoStream: 'a, <S as IntoStream>::IntoStream: Send,
{ {
let stream = stream.into_stream(); let stream = stream.into_stream();
Box::pin(async move { Box::pin(async move {
pin_utils::pin_mut!(stream);
let mut out = BinaryHeap::new(); let mut out = BinaryHeap::new();
out.stream_extend(stream).await; stream::extend(&mut out, stream).await;
out out
}) })
} }

@ -2,13 +2,16 @@ use std::collections::BTreeMap;
use std::pin::Pin; use std::pin::Pin;
use crate::prelude::*; use crate::prelude::*;
use crate::stream::{Extend, IntoStream}; use crate::stream::{self, IntoStream};
impl<K: Ord, V> Extend<(K, V)> for BTreeMap<K, V> { impl<K: Ord + Send, V: Send> stream::Extend<(K, V)> for BTreeMap<K, V> {
fn stream_extend<'a, S: IntoStream<Item = (K, V)> + 'a>( fn extend<'a, S: IntoStream<Item = (K, V)> + 'a>(
&'a mut self, &'a mut self,
stream: S, stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> { ) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
Box::pin(stream.into_stream().for_each(move |(k, v)| { Box::pin(stream.into_stream().for_each(move |(k, v)| {
self.insert(k, v); self.insert(k, v);
})) }))

@ -1,23 +1,22 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::pin::Pin; use std::pin::Pin;
use crate::stream::{Extend, FromStream, IntoStream}; use crate::prelude::*;
use crate::stream::{self, FromStream, IntoStream};
impl<K: Ord, V> FromStream<(K, V)> for BTreeMap<K, V> { impl<K: Ord + Send, V: Send> FromStream<(K, V)> for BTreeMap<K, V> {
#[inline] #[inline]
fn from_stream<'a, S: IntoStream<Item = (K, V)>>( fn from_stream<'a, S: IntoStream<Item = (K, V)> + 'a>(
stream: S, stream: S,
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>> ) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where where
<S as IntoStream>::IntoStream: 'a, <S as IntoStream>::IntoStream: Send,
{ {
let stream = stream.into_stream(); let stream = stream.into_stream();
Box::pin(async move { Box::pin(async move {
pin_utils::pin_mut!(stream);
let mut out = BTreeMap::new(); let mut out = BTreeMap::new();
out.stream_extend(stream).await; stream::extend(&mut out, stream).await;
out out
}) })
} }

@ -2,13 +2,16 @@ use std::collections::BTreeSet;
use std::pin::Pin; use std::pin::Pin;
use crate::prelude::*; use crate::prelude::*;
use crate::stream::{Extend, IntoStream}; use crate::stream::{self, IntoStream};
impl<T: Ord> Extend<T> for BTreeSet<T> { impl<T: Ord + Send> stream::Extend<T> for BTreeSet<T> {
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>( fn extend<'a, S: IntoStream<Item = T> + 'a>(
&'a mut self, &'a mut self,
stream: S, stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> { ) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
Box::pin(stream.into_stream().for_each(move |item| { Box::pin(stream.into_stream().for_each(move |item| {
self.insert(item); self.insert(item);
})) }))

@ -1,23 +1,22 @@
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::pin::Pin; use std::pin::Pin;
use crate::stream::{Extend, FromStream, IntoStream}; use crate::prelude::*;
use crate::stream::{self, FromStream, IntoStream};
impl<T: Ord> FromStream<T> for BTreeSet<T> { impl<T: Ord + Send> FromStream<T> for BTreeSet<T> {
#[inline] #[inline]
fn from_stream<'a, S: IntoStream<Item = T>>( fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
stream: S, stream: S,
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>> ) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where where
<S as IntoStream>::IntoStream: 'a, <S as IntoStream>::IntoStream: Send,
{ {
let stream = stream.into_stream(); let stream = stream.into_stream();
Box::pin(async move { Box::pin(async move {
pin_utils::pin_mut!(stream);
let mut out = BTreeSet::new(); let mut out = BTreeSet::new();
out.stream_extend(stream).await; stream::extend(&mut out, stream).await;
out out
}) })
} }

@ -3,17 +3,21 @@ use std::hash::{BuildHasher, Hash};
use std::pin::Pin; use std::pin::Pin;
use crate::prelude::*; use crate::prelude::*;
use crate::stream::{Extend, IntoStream}; use crate::stream::{self, IntoStream};
impl<K, V, H> Extend<(K, V)> for HashMap<K, V, H> impl<K, V, H> stream::Extend<(K, V)> for HashMap<K, V, H>
where where
K: Eq + Hash, K: Eq + Hash + Send,
H: BuildHasher + Default, V: Send,
H: BuildHasher + Default + Send,
{ {
fn stream_extend<'a, S: IntoStream<Item = (K, V)> + 'a>( fn extend<'a, S: IntoStream<Item = (K, V)> + 'a>(
&'a mut self, &'a mut self,
stream: S, stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> { ) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
let stream = stream.into_stream(); let stream = stream.into_stream();
// The following is adapted from the hashbrown source code: // The following is adapted from the hashbrown source code:

@ -2,27 +2,27 @@ use std::collections::HashMap;
use std::hash::{BuildHasher, Hash}; use std::hash::{BuildHasher, Hash};
use std::pin::Pin; use std::pin::Pin;
use crate::stream::{Extend, FromStream, IntoStream}; use crate::prelude::*;
use crate::stream::{self, FromStream, IntoStream};
impl<K, V, H> FromStream<(K, V)> for HashMap<K, V, H> impl<K, V, H> FromStream<(K, V)> for HashMap<K, V, H>
where where
K: Eq + Hash, K: Eq + Hash + Send,
H: BuildHasher + Default, H: BuildHasher + Default + Send,
V: Send,
{ {
#[inline] #[inline]
fn from_stream<'a, S: IntoStream<Item = (K, V)>>( fn from_stream<'a, S: IntoStream<Item = (K, V)> + 'a>(
stream: S, stream: S,
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>> ) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where where
<S as IntoStream>::IntoStream: 'a, <S as IntoStream>::IntoStream: Send,
{ {
let stream = stream.into_stream(); let stream = stream.into_stream();
Box::pin(async move { Box::pin(async move {
pin_utils::pin_mut!(stream);
let mut out = HashMap::with_hasher(Default::default()); let mut out = HashMap::with_hasher(Default::default());
out.stream_extend(stream).await; stream::extend(&mut out, stream).await;
out out
}) })
} }

@ -3,17 +3,20 @@ use std::hash::{BuildHasher, Hash};
use std::pin::Pin; use std::pin::Pin;
use crate::prelude::*; use crate::prelude::*;
use crate::stream::{Extend, IntoStream}; use crate::stream::{self, IntoStream};
impl<T, H> Extend<T> for HashSet<T, H> impl<T, H> stream::Extend<T> for HashSet<T, H>
where where
T: Eq + Hash, T: Eq + Hash + Send,
H: BuildHasher + Default, H: BuildHasher + Default + Send,
{ {
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>( fn extend<'a, S: IntoStream<Item = T> + 'a>(
&'a mut self, &'a mut self,
stream: S, stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> { ) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
// The Extend impl for HashSet in the standard library delegates to the internal HashMap. // The Extend impl for HashSet in the standard library delegates to the internal HashMap.
// Thus, this impl is just a copy of the async Extend impl for HashMap in this crate. // Thus, this impl is just a copy of the async Extend impl for HashMap in this crate.

@ -2,27 +2,26 @@ use std::collections::HashSet;
use std::hash::{BuildHasher, Hash}; use std::hash::{BuildHasher, Hash};
use std::pin::Pin; use std::pin::Pin;
use crate::stream::{Extend, FromStream, IntoStream}; use crate::prelude::*;
use crate::stream::{self, FromStream, IntoStream};
impl<T, H> FromStream<T> for HashSet<T, H> impl<T, H> FromStream<T> for HashSet<T, H>
where where
T: Eq + Hash, T: Eq + Hash + Send,
H: BuildHasher + Default, H: BuildHasher + Default + Send,
{ {
#[inline] #[inline]
fn from_stream<'a, S: IntoStream<Item = T>>( fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
stream: S, stream: S,
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>> ) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where where
<S as IntoStream>::IntoStream: 'a, <S as IntoStream>::IntoStream: Send,
{ {
let stream = stream.into_stream(); let stream = stream.into_stream();
Box::pin(async move { Box::pin(async move {
pin_utils::pin_mut!(stream);
let mut out = HashSet::with_hasher(Default::default()); let mut out = HashSet::with_hasher(Default::default());
out.stream_extend(stream).await; stream::extend(&mut out, stream).await;
out out
}) })
} }

@ -2,13 +2,16 @@ use std::collections::LinkedList;
use std::pin::Pin; use std::pin::Pin;
use crate::prelude::*; use crate::prelude::*;
use crate::stream::{Extend, IntoStream}; use crate::stream::{self, IntoStream};
impl<T> Extend<T> for LinkedList<T> { impl<T: Send> stream::Extend<T> for LinkedList<T> {
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>( fn extend<'a, S: IntoStream<Item = T> + 'a>(
&'a mut self, &'a mut self,
stream: S, stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> { ) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
let stream = stream.into_stream(); let stream = stream.into_stream();
Box::pin(stream.for_each(move |item| self.push_back(item))) Box::pin(stream.for_each(move |item| self.push_back(item)))
} }

@ -1,23 +1,22 @@
use std::collections::LinkedList; use std::collections::LinkedList;
use std::pin::Pin; use std::pin::Pin;
use crate::stream::{Extend, FromStream, IntoStream}; use crate::prelude::*;
use crate::stream::{self, FromStream, IntoStream};
impl<T> FromStream<T> for LinkedList<T> { impl<T: Send> FromStream<T> for LinkedList<T> {
#[inline] #[inline]
fn from_stream<'a, S: IntoStream<Item = T>>( fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
stream: S, stream: S,
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>> ) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where where
<S as IntoStream>::IntoStream: 'a, <S as IntoStream>::IntoStream: Send,
{ {
let stream = stream.into_stream(); let stream = stream.into_stream();
Box::pin(async move { Box::pin(async move {
pin_utils::pin_mut!(stream);
let mut out = LinkedList::new(); let mut out = LinkedList::new();
out.stream_extend(stream).await; stream::extend(&mut out, stream).await;
out out
}) })
} }

@ -2,13 +2,16 @@ use std::collections::VecDeque;
use std::pin::Pin; use std::pin::Pin;
use crate::prelude::*; use crate::prelude::*;
use crate::stream::{Extend, IntoStream}; use crate::stream::{self, IntoStream};
impl<T> Extend<T> for VecDeque<T> { impl<T: Send> stream::Extend<T> for VecDeque<T> {
fn stream_extend<'a, S: IntoStream<Item = T> + 'a>( fn extend<'a, S: IntoStream<Item = T> + 'a>(
&'a mut self, &'a mut self,
stream: S, stream: S,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> { ) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
where
<S as IntoStream>::IntoStream: Send,
{
let stream = stream.into_stream(); let stream = stream.into_stream();
self.reserve(stream.size_hint().0); self.reserve(stream.size_hint().0);

@ -1,23 +1,22 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::pin::Pin; use std::pin::Pin;
use crate::stream::{Extend, FromStream, IntoStream}; use crate::prelude::*;
use crate::stream::{self, FromStream, IntoStream};
impl<T> FromStream<T> for VecDeque<T> { impl<T: Send> FromStream<T> for VecDeque<T> {
#[inline] #[inline]
fn from_stream<'a, S: IntoStream<Item = T>>( fn from_stream<'a, S: IntoStream<Item = T> + 'a>(
stream: S, stream: S,
) -> Pin<Box<dyn core::future::Future<Output = Self> + 'a>> ) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
where where
<S as IntoStream>::IntoStream: 'a, <S as IntoStream>::IntoStream: Send,
{ {
let stream = stream.into_stream(); let stream = stream.into_stream();
Box::pin(async move { Box::pin(async move {
pin_utils::pin_mut!(stream);
let mut out = VecDeque::new(); let mut out = VecDeque::new();
out.stream_extend(stream).await; stream::extend(&mut out, stream).await;
out out
}) })
} }

@ -1,7 +1,7 @@
use std::path::{Path, PathBuf};
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::{Path, PathBuf};
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Returns the canonical form of a path. /// Returns the canonical form of a path.
/// ///
@ -33,5 +33,10 @@ use crate::task::blocking;
/// ``` /// ```
pub async fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { pub async fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::canonicalize(path) }).await spawn_blocking(move || {
std::fs::canonicalize(&path)
.map(Into::into)
.context(|| format!("could not canonicalize `{}`", path.display()))
})
.await
} }

@ -1,7 +1,7 @@
use std::path::Path;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Copies the contents and permissions of a file to a new location. /// Copies the contents and permissions of a file to a new location.
/// ///
@ -42,5 +42,9 @@ use crate::task::blocking;
pub async fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> { 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 from = from.as_ref().to_owned();
let to = to.as_ref().to_owned(); let to = to.as_ref().to_owned();
blocking::spawn(async move { std::fs::copy(&from, &to) }).await spawn_blocking(move || {
std::fs::copy(&from, &to)
.context(|| format!("could not copy `{}` to `{}`", from.display(), to.display()))
})
.await
} }

@ -1,7 +1,7 @@
use std::path::Path;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Creates a new directory. /// Creates a new directory.
/// ///
@ -35,5 +35,9 @@ use crate::task::blocking;
/// ``` /// ```
pub async fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { pub async fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::create_dir(path) }).await spawn_blocking(move || {
std::fs::create_dir(&path)
.context(|| format!("could not create directory `{}`", path.display()))
})
.await
} }

@ -1,7 +1,7 @@
use std::path::Path;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Creates a new directory and all of its parents if they are missing. /// Creates a new directory and all of its parents if they are missing.
/// ///
@ -30,5 +30,9 @@ use crate::task::blocking;
/// ``` /// ```
pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::create_dir_all(path) }).await spawn_blocking(move || {
std::fs::create_dir_all(&path)
.context(|| format!("could not create directory path `{}`", path.display()))
})
.await
} }

@ -1,10 +1,8 @@
use std::path::Path; use std::future::Future;
use cfg_if::cfg_if;
use crate::future::Future;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
/// A builder for creating directories with configurable options. /// A builder for creating directories with configurable options.
/// ///
@ -109,21 +107,13 @@ impl DirBuilder {
} }
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
async move { blocking::spawn(async move { builder.create(path) }).await } async move { spawn_blocking(move || builder.create(path)).await }
} }
} }
cfg_if! { cfg_unix! {
if #[cfg(feature = "docs")] {
use crate::os::unix::fs::DirBuilderExt; use crate::os::unix::fs::DirBuilderExt;
} else if #[cfg(unix)] {
use std::os::unix::fs::DirBuilderExt;
}
}
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs"))] {
impl DirBuilderExt for DirBuilder { impl DirBuilderExt for DirBuilder {
fn mode(&mut self, mode: u32) -> &mut Self { fn mode(&mut self, mode: u32) -> &mut Self {
self.mode = Some(mode); self.mode = Some(mode);
@ -131,4 +121,3 @@ cfg_if! {
} }
} }
} }
}

@ -1,13 +1,11 @@
use std::ffi::OsString; use std::ffi::OsString;
use std::fmt; use std::fmt;
use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use cfg_if::cfg_if;
use crate::fs::{FileType, Metadata}; use crate::fs::{FileType, Metadata};
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::PathBuf;
use crate::task::spawn_blocking;
/// An entry in a directory. /// An entry in a directory.
/// ///
@ -50,7 +48,7 @@ impl DirEntry {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn path(&self) -> PathBuf { pub fn path(&self) -> PathBuf {
self.0.path() self.0.path().into()
} }
/// Reads the metadata for this entry. /// Reads the metadata for this entry.
@ -89,7 +87,7 @@ impl DirEntry {
/// ``` /// ```
pub async fn metadata(&self) -> io::Result<Metadata> { pub async fn metadata(&self) -> io::Result<Metadata> {
let inner = self.0.clone(); let inner = self.0.clone();
blocking::spawn(async move { inner.metadata() }).await spawn_blocking(move || inner.metadata()).await
} }
/// Reads the file type for this entry. /// Reads the file type for this entry.
@ -127,7 +125,7 @@ impl DirEntry {
/// ``` /// ```
pub async fn file_type(&self) -> io::Result<FileType> { pub async fn file_type(&self) -> io::Result<FileType> {
let inner = self.0.clone(); let inner = self.0.clone();
blocking::spawn(async move { inner.file_type() }).await spawn_blocking(move || inner.file_type()).await
} }
/// Returns the bare name of this entry without the leading path. /// Returns the bare name of this entry without the leading path.
@ -160,21 +158,18 @@ impl fmt::Debug for DirEntry {
} }
} }
cfg_if! { impl Clone for DirEntry {
if #[cfg(feature = "docs")] { fn clone(&self) -> Self {
use crate::os::unix::fs::DirEntryExt; DirEntry(self.0.clone())
} else if #[cfg(unix)] {
use std::os::unix::fs::DirEntryExt;
} }
} }
#[cfg_attr(feature = "docs", doc(cfg(unix)))] cfg_unix! {
cfg_if! { use crate::os::unix::fs::DirEntryExt;
if #[cfg(any(unix, feature = "docs"))] {
impl DirEntryExt for DirEntry { impl DirEntryExt for DirEntry {
fn ino(&self) -> u64 { fn ino(&self) -> u64 {
self.0.ino() self.0.ino()
} }
} }
} }
}

@ -3,18 +3,17 @@ use std::cmp;
use std::fmt; use std::fmt;
use std::io::{Read as _, Seek as _, Write as _}; use std::io::{Read as _, Seek as _, Write as _};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::path::Path;
use std::pin::Pin; use std::pin::Pin;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use cfg_if::cfg_if;
use crate::fs::{Metadata, Permissions}; use crate::fs::{Metadata, Permissions};
use crate::future; use crate::future;
use crate::io::{self, Read, Seek, SeekFrom, Write}; use crate::io::{self, Read, Seek, SeekFrom, Write};
use crate::path::Path;
use crate::prelude::*; use crate::prelude::*;
use crate::task::{self, blocking, Context, Poll, Waker}; use crate::task::{spawn_blocking, Context, Poll, Waker};
use crate::utils::Context as _;
/// An open file on the filesystem. /// An open file on the filesystem.
/// ///
@ -68,6 +67,23 @@ pub struct File {
} }
impl File { impl File {
/// Creates an async file handle.
pub(crate) fn new(file: std::fs::File, is_flushed: bool) -> File {
let file = Arc::new(file);
File {
file: file.clone(),
lock: Lock::new(State {
file,
mode: Mode::Idle,
cache: Vec::new(),
is_flushed,
last_read_err: None,
last_write_err: None,
}),
}
}
/// Opens a file in read-only mode. /// Opens a file in read-only mode.
/// ///
/// See the [`OpenOptions::open`] function for more options. /// See the [`OpenOptions::open`] function for more options.
@ -97,8 +113,11 @@ impl File {
/// ``` /// ```
pub async fn open<P: AsRef<Path>>(path: P) -> io::Result<File> { pub async fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
let file = blocking::spawn(async move { std::fs::File::open(&path) }).await?; let file = spawn_blocking(move || {
Ok(file.into()) std::fs::File::open(&path).context(|| format!("could not open `{}`", path.display()))
})
.await?;
Ok(File::new(file, true))
} }
/// Opens a file in write-only mode. /// Opens a file in write-only mode.
@ -132,8 +151,12 @@ impl File {
/// ``` /// ```
pub async fn create<P: AsRef<Path>>(path: P) -> io::Result<File> { pub async fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
let file = blocking::spawn(async move { std::fs::File::create(&path) }).await?; let file = spawn_blocking(move || {
Ok(file.into()) std::fs::File::create(&path)
.context(|| format!("could not create `{}`", path.display()))
})
.await?;
Ok(File::new(file, true))
} }
/// Synchronizes OS-internal buffered contents and metadata to disk. /// Synchronizes OS-internal buffered contents and metadata to disk.
@ -165,7 +188,7 @@ impl File {
}) })
.await?; .await?;
blocking::spawn(async move { state.file.sync_all() }).await spawn_blocking(move || state.file.sync_all()).await
} }
/// Synchronizes OS-internal buffered contents to disk. /// Synchronizes OS-internal buffered contents to disk.
@ -201,7 +224,7 @@ impl File {
}) })
.await?; .await?;
blocking::spawn(async move { state.file.sync_data() }).await spawn_blocking(move || state.file.sync_data()).await
} }
/// Truncates or extends the file. /// Truncates or extends the file.
@ -234,7 +257,7 @@ impl File {
}) })
.await?; .await?;
blocking::spawn(async move { state.file.set_len(size) }).await spawn_blocking(move || state.file.set_len(size)).await
} }
/// Reads the file's metadata. /// Reads the file's metadata.
@ -253,7 +276,7 @@ impl File {
/// ``` /// ```
pub async fn metadata(&self) -> io::Result<Metadata> { pub async fn metadata(&self) -> io::Result<Metadata> {
let file = self.file.clone(); let file = self.file.clone();
blocking::spawn(async move { file.metadata() }).await spawn_blocking(move || file.metadata()).await
} }
/// Changes the permissions on the file. /// Changes the permissions on the file.
@ -282,7 +305,7 @@ impl File {
/// ``` /// ```
pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> { pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
let file = self.file.clone(); let file = self.file.clone();
blocking::spawn(async move { file.set_permissions(perm) }).await spawn_blocking(move || file.set_permissions(perm)).await
} }
} }
@ -292,7 +315,7 @@ impl Drop for File {
// non-blocking fashion, but our only other option here is losing data remaining in the // non-blocking fashion, but our only other option here is losing data remaining in the
// write cache. Good task schedulers should be resilient to occasional blocking hiccups in // write cache. Good task schedulers should be resilient to occasional blocking hiccups in
// file destructors so we don't expect this to be a common problem in practice. // file destructors so we don't expect this to be a common problem in practice.
let _ = task::block_on(self.flush()); let _ = smol::block_on(self.flush());
} }
} }
@ -385,36 +408,13 @@ impl Seek for &File {
impl From<std::fs::File> for File { impl From<std::fs::File> for File {
fn from(file: std::fs::File) -> File { fn from(file: std::fs::File) -> File {
let file = Arc::new(file); File::new(file, false)
File {
file: file.clone(),
lock: Lock::new(State {
file,
mode: Mode::Idle,
cache: Vec::new(),
is_flushed: false,
last_read_err: None,
last_write_err: None,
}),
}
} }
} }
cfg_if! { cfg_unix! {
if #[cfg(feature = "docs")] {
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; 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 File { impl AsRawFd for File {
fn as_raw_fd(&self) -> RawFd { fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd() self.file.as_raw_fd()
@ -437,11 +437,10 @@ cfg_if! {
} }
} }
} }
}
#[cfg_attr(feature = "docs", doc(cfg(windows)))] cfg_windows! {
cfg_if! { use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
if #[cfg(any(windows, feature = "docs"))] {
impl AsRawHandle for File { impl AsRawHandle for File {
fn as_raw_handle(&self) -> RawHandle { fn as_raw_handle(&self) -> RawHandle {
self.file.as_raw_handle() self.file.as_raw_handle()
@ -464,7 +463,6 @@ cfg_if! {
} }
} }
} }
}
/// An async mutex with non-borrowing lock guards. /// An async mutex with non-borrowing lock guards.
struct Lock<T>(Arc<LockState<T>>); struct Lock<T>(Arc<LockState<T>>);
@ -675,7 +673,7 @@ impl LockGuard<State> {
if available > 0 || self.cache.is_empty() { if available > 0 || self.cache.is_empty() {
// Copy data from the cache into the buffer. // Copy data from the cache into the buffer.
let n = cmp::min(available, buf.len()); let n = cmp::min(available, buf.len());
buf[..n].copy_from_slice(&self.cache[start..n]); buf[..n].copy_from_slice(&self.cache[start..(start + n)]);
// Move the read cursor forward. // Move the read cursor forward.
self.mode = Mode::Reading(start + n); self.mode = Mode::Reading(start + n);
@ -702,7 +700,7 @@ impl LockGuard<State> {
self.register(cx); self.register(cx);
// Start a read operation asynchronously. // Start a read operation asynchronously.
blocking::spawn(async move { spawn_blocking(move || {
// Read some data from the file into the cache. // Read some data from the file into the cache.
let res = { let res = {
let State { file, cache, .. } = &mut *self; let State { file, cache, .. } = &mut *self;
@ -743,7 +741,10 @@ impl LockGuard<State> {
if n > 0 { if n > 0 {
// Seek `n` bytes backwards. This call should not block because it only changes // Seek `n` bytes backwards. This call should not block because it only changes
// the internal offset into the file and doesn't touch the actual file on disk. // the internal offset into the file and doesn't touch the actual file on disk.
(&*self.file).seek(SeekFrom::Current(-(n as i64)))?; //
// We ignore errors here because special files like `/dev/random` are not
// seekable.
let _ = (&*self.file).seek(SeekFrom::Current(-(n as i64)));
} }
// Switch to idle mode. // Switch to idle mode.
@ -811,7 +812,7 @@ impl LockGuard<State> {
self.register(cx); self.register(cx);
// Start a write operation asynchronously. // Start a write operation asynchronously.
blocking::spawn(async move { spawn_blocking(move || {
match (&*self.file).write_all(&self.cache) { match (&*self.file).write_all(&self.cache) {
Ok(_) => { Ok(_) => {
// Switch to idle mode. // Switch to idle mode.
@ -844,7 +845,7 @@ impl LockGuard<State> {
self.register(cx); self.register(cx);
// Start a flush operation asynchronously. // Start a flush operation asynchronously.
blocking::spawn(async move { spawn_blocking(move || {
match (&*self.file).flush() { match (&*self.file).flush() {
Ok(()) => { Ok(()) => {
// Mark the file as flushed. // Mark the file as flushed.
@ -866,3 +867,15 @@ impl LockGuard<State> {
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn async_file_drop() {
crate::task::block_on(async move {
File::open(file!()).await.unwrap();
});
}
}

@ -1,7 +1,8 @@
use cfg_if::cfg_if; cfg_not_docs! {
pub use std::fs::FileType;
}
cfg_if! { cfg_docs! {
if #[cfg(feature = "docs")] {
/// The type of a file or directory. /// The type of a file or directory.
/// ///
/// A file type is returned by [`Metadata::file_type`]. /// A file type is returned by [`Metadata::file_type`].
@ -39,7 +40,7 @@ cfg_if! {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn is_dir(&self) -> bool { pub fn is_dir(&self) -> bool {
unimplemented!() unreachable!("this impl only appears in the rendered docs")
} }
/// Returns `true` if this file type represents a regular file. /// Returns `true` if this file type represents a regular file.
@ -59,7 +60,7 @@ cfg_if! {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn is_file(&self) -> bool { pub fn is_file(&self) -> bool {
unimplemented!() unreachable!("this impl only appears in the rendered docs")
} }
/// Returns `true` if this file type represents a symbolic link. /// Returns `true` if this file type represents a symbolic link.
@ -77,10 +78,7 @@ cfg_if! {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn is_symlink(&self) -> bool { pub fn is_symlink(&self) -> bool {
unimplemented!() unreachable!("this impl only appears in the rendered docs")
} }
} }
} else {
pub use std::fs::FileType;
}
} }

@ -1,7 +1,7 @@
use std::path::Path;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Creates a hard link on the filesystem. /// Creates a hard link on the filesystem.
/// ///
@ -33,5 +33,14 @@ use crate::task::blocking;
pub async fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> { 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 from = from.as_ref().to_owned();
let to = to.as_ref().to_owned(); let to = to.as_ref().to_owned();
blocking::spawn(async move { std::fs::hard_link(&from, &to) }).await spawn_blocking(move || {
std::fs::hard_link(&from, &to).context(|| {
format!(
"could not create a hard link from `{}` to `{}`",
from.display(),
to.display()
)
})
})
.await
} }

@ -1,9 +1,6 @@
use std::path::Path;
use cfg_if::cfg_if;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
/// Reads metadata for a path. /// Reads metadata for a path.
/// ///
@ -37,11 +34,14 @@ use crate::task::blocking;
/// ``` /// ```
pub async fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> { pub async fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::metadata(path) }).await spawn_blocking(move || std::fs::metadata(path)).await
} }
cfg_if! { cfg_not_docs! {
if #[cfg(feature = "docs")] { pub use std::fs::Metadata;
}
cfg_docs! {
use std::time::SystemTime; use std::time::SystemTime;
use crate::fs::{FileType, Permissions}; use crate::fs::{FileType, Permissions};
@ -78,7 +78,7 @@ cfg_if! {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn file_type(&self) -> FileType { pub fn file_type(&self) -> FileType {
unimplemented!() unreachable!("this impl only appears in the rendered docs")
} }
/// Returns `true` if this metadata is for a regular directory. /// Returns `true` if this metadata is for a regular directory.
@ -98,7 +98,7 @@ cfg_if! {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn is_dir(&self) -> bool { pub fn is_dir(&self) -> bool {
unimplemented!() unreachable!("this impl only appears in the rendered docs")
} }
/// Returns `true` if this metadata is for a regular file. /// Returns `true` if this metadata is for a regular file.
@ -118,7 +118,7 @@ cfg_if! {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn is_file(&self) -> bool { pub fn is_file(&self) -> bool {
unimplemented!() unreachable!("this impl only appears in the rendered docs")
} }
/// Returns the file size in bytes. /// Returns the file size in bytes.
@ -136,7 +136,7 @@ cfg_if! {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn len(&self) -> u64 { pub fn len(&self) -> u64 {
unimplemented!() unreachable!("this impl only appears in the rendered docs")
} }
/// Returns the permissions from this metadata. /// Returns the permissions from this metadata.
@ -154,7 +154,7 @@ cfg_if! {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn permissions(&self) -> Permissions { pub fn permissions(&self) -> Permissions {
unimplemented!() unreachable!("this impl only appears in the rendered docs")
} }
/// Returns the last modification time. /// Returns the last modification time.
@ -177,7 +177,7 @@ cfg_if! {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn modified(&self) -> io::Result<SystemTime> { pub fn modified(&self) -> io::Result<SystemTime> {
unimplemented!() unreachable!("this impl only appears in the rendered docs")
} }
/// Returns the last access time. /// Returns the last access time.
@ -200,7 +200,7 @@ cfg_if! {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn accessed(&self) -> io::Result<SystemTime> { pub fn accessed(&self) -> io::Result<SystemTime> {
unimplemented!() unreachable!("this impl only appears in the rendered docs")
} }
/// Returns the creation time. /// Returns the creation time.
@ -223,10 +223,7 @@ cfg_if! {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn created(&self) -> io::Result<SystemTime> { pub fn created(&self) -> io::Result<SystemTime> {
unimplemented!() unreachable!("this impl only appears in the rendered docs")
}
} }
} else {
pub use std::fs::Metadata;
} }
} }

@ -3,11 +3,13 @@
//! This module is an async version of [`std::fs`]. //! This module is an async version of [`std::fs`].
//! //!
//! [`os::unix::fs`]: ../os/unix/fs/index.html //! [`os::unix::fs`]: ../os/unix/fs/index.html
//! [`os::windows::fs`]: ../os/windows/fs/index.html
//! [`std::fs`]: https://doc.rust-lang.org/std/fs/index.html //! [`std::fs`]: https://doc.rust-lang.org/std/fs/index.html
//! //!
//! # Platform-specific extensions //! # Platform-specific extensions
//! //!
//! * Unix: use the [`os::unix::fs`] module. //! * Unix: use the [`os::unix::fs`] module.
//! * Windows: use the [`os::windows::fs`] module.
//! //!
//! # Examples //! # Examples
//! //!

@ -1,11 +1,9 @@
use std::path::Path; use std::future::Future;
use cfg_if::cfg_if;
use crate::fs::File; use crate::fs::File;
use crate::future::Future;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
/// A builder for opening files with configurable options. /// A builder for opening files with configurable options.
/// ///
@ -286,7 +284,10 @@ impl OpenOptions {
pub fn open<P: AsRef<Path>>(&self, path: P) -> impl Future<Output = io::Result<File>> { pub fn open<P: AsRef<Path>>(&self, path: P) -> impl Future<Output = io::Result<File>> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
let options = self.0.clone(); let options = self.0.clone();
async move { blocking::spawn(async move { options.open(path).map(|f| f.into()) }).await } async move {
let file = spawn_blocking(move || options.open(path)).await?;
Ok(File::new(file, true))
}
} }
} }
@ -296,17 +297,9 @@ impl Default for OpenOptions {
} }
} }
cfg_if! { cfg_unix! {
if #[cfg(feature = "docs")] {
use crate::os::unix::fs::OpenOptionsExt; use crate::os::unix::fs::OpenOptionsExt;
} else if #[cfg(unix)] {
use std::os::unix::fs::OpenOptionsExt;
}
}
#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
if #[cfg(any(unix, feature = "docs"))] {
impl OpenOptionsExt for OpenOptions { impl OpenOptionsExt for OpenOptions {
fn mode(&mut self, mode: u32) -> &mut Self { fn mode(&mut self, mode: u32) -> &mut Self {
self.0.mode(mode); self.0.mode(mode);
@ -319,4 +312,3 @@ cfg_if! {
} }
} }
} }
}

@ -1,7 +1,8 @@
use cfg_if::cfg_if; cfg_not_docs! {
pub use std::fs::Permissions;
}
cfg_if! { cfg_docs! {
if #[cfg(feature = "docs")] {
/// A set of permissions on a file or directory. /// A set of permissions on a file or directory.
/// ///
/// This type is a re-export of [`std::fs::Permissions`]. /// This type is a re-export of [`std::fs::Permissions`].
@ -28,7 +29,7 @@ cfg_if! {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn readonly(&self) -> bool { pub fn readonly(&self) -> bool {
unimplemented!() unreachable!("this impl only appears in the rendered docs")
} }
/// Configures the read-only flag. /// Configures the read-only flag.
@ -49,10 +50,7 @@ cfg_if! {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn set_readonly(&mut self, readonly: bool) { pub fn set_readonly(&mut self, readonly: bool) {
unimplemented!() unreachable!("this impl only appears in the rendered docs")
} }
} }
} else {
pub use std::fs::Permissions;
}
} }

@ -1,7 +1,7 @@
use std::path::Path;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Reads the entire contents of a file as raw bytes. /// Reads the entire contents of a file as raw bytes.
/// ///
@ -37,5 +37,8 @@ use crate::task::blocking;
/// ``` /// ```
pub async fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> { pub async fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::read(path) }).await spawn_blocking(move || {
std::fs::read(&path).context(|| format!("could not read file `{}`", path.display()))
})
.await
} }

@ -1,11 +1,12 @@
use std::path::Path; use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use crate::fs::DirEntry; use crate::fs::DirEntry;
use crate::future::Future;
use crate::io; use crate::io;
use crate::path::Path;
use crate::stream::Stream; use crate::stream::Stream;
use crate::task::{blocking, Context, JoinHandle, Poll}; use crate::task::{spawn_blocking, Context, JoinHandle, Poll};
use crate::utils::Context as _;
/// Returns a stream of entries in a directory. /// Returns a stream of entries in a directory.
/// ///
@ -45,7 +46,10 @@ use crate::task::{blocking, Context, JoinHandle, Poll};
/// ``` /// ```
pub async fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> { pub async fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::read_dir(path) }) spawn_blocking(move || {
std::fs::read_dir(&path)
.context(|| format!("could not read directory `{}`", path.display()))
})
.await .await
.map(ReadDir::new) .map(ReadDir::new)
} }
@ -91,7 +95,7 @@ impl Stream for ReadDir {
let mut inner = opt.take().unwrap(); let mut inner = opt.take().unwrap();
// Start the operation asynchronously. // Start the operation asynchronously.
self.0 = State::Busy(blocking::spawn(async move { self.0 = State::Busy(spawn_blocking(move || {
let next = inner.next(); let next = inner.next();
(inner, next) (inner, next)
})); }));

@ -1,7 +1,7 @@
use std::path::{Path, PathBuf};
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::{Path, PathBuf};
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Reads a symbolic link and returns the path it points to. /// Reads a symbolic link and returns the path it points to.
/// ///
@ -29,5 +29,10 @@ use crate::task::blocking;
/// ``` /// ```
pub async fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { pub async fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::read_link(path) }).await spawn_blocking(move || {
std::fs::read_link(&path)
.map(Into::into)
.context(|| format!("could not read link `{}`", path.display()))
})
.await
} }

@ -1,7 +1,7 @@
use std::path::Path;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Reads the entire contents of a file as a string. /// Reads the entire contents of a file as a string.
/// ///
@ -38,5 +38,9 @@ use crate::task::blocking;
/// ``` /// ```
pub async fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> { pub async fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::read_to_string(path) }).await spawn_blocking(move || {
std::fs::read_to_string(&path)
.context(|| format!("could not read file `{}`", path.display()))
})
.await
} }

@ -1,7 +1,7 @@
use std::path::Path;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Removes an empty directory. /// Removes an empty directory.
/// ///
@ -30,5 +30,9 @@ use crate::task::blocking;
/// ``` /// ```
pub async fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { pub async fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::remove_dir(path) }).await spawn_blocking(move || {
std::fs::remove_dir(&path)
.context(|| format!("could not remove directory `{}`", path.display()))
})
.await
} }

@ -1,7 +1,7 @@
use std::path::Path;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Removes a directory and all of its contents. /// Removes a directory and all of its contents.
/// ///
@ -30,5 +30,9 @@ use crate::task::blocking;
/// ``` /// ```
pub async fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { pub async fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::remove_dir_all(path) }).await spawn_blocking(move || {
std::fs::remove_dir_all(&path)
.context(|| format!("could not remove directory `{}`", path.display()))
})
.await
} }

@ -1,7 +1,7 @@
use std::path::Path;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Removes a file. /// Removes a file.
/// ///
@ -30,5 +30,9 @@ use crate::task::blocking;
/// ``` /// ```
pub async fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> { pub async fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::remove_file(path) }).await spawn_blocking(move || {
std::fs::remove_file(&path)
.context(|| format!("could not remove file `{}`", path.display()))
})
.await
} }

@ -1,7 +1,7 @@
use std::path::Path;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Renames a file or directory to a new location. /// Renames a file or directory to a new location.
/// ///
@ -35,5 +35,14 @@ use crate::task::blocking;
pub async fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> { pub async fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
let from = from.as_ref().to_owned(); let from = from.as_ref().to_owned();
let to = to.as_ref().to_owned(); let to = to.as_ref().to_owned();
blocking::spawn(async move { std::fs::rename(&from, &to) }).await spawn_blocking(move || {
std::fs::rename(&from, &to).context(|| {
format!(
"could not rename `{}` to `{}`",
from.display(),
to.display()
)
})
})
.await
} }

@ -1,8 +1,7 @@
use std::path::Path;
use crate::fs::Permissions; use crate::fs::Permissions;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
/// Changes the permissions of a file or directory. /// Changes the permissions of a file or directory.
/// ///
@ -33,5 +32,5 @@ use crate::task::blocking;
/// ``` /// ```
pub async fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> { pub async fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::set_permissions(path, perm) }).await spawn_blocking(move || std::fs::set_permissions(path, perm)).await
} }

@ -1,8 +1,7 @@
use std::path::Path;
use crate::fs::Metadata; use crate::fs::Metadata;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
/// Reads metadata for a path without following symbolic links. /// Reads metadata for a path without following symbolic links.
/// ///
@ -35,5 +34,5 @@ use crate::task::blocking;
/// ``` /// ```
pub async fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> { pub async fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
blocking::spawn(async move { std::fs::symlink_metadata(path) }).await spawn_blocking(move || std::fs::symlink_metadata(path)).await
} }

@ -1,7 +1,7 @@
use std::path::Path;
use crate::io; use crate::io;
use crate::task::blocking; use crate::path::Path;
use crate::task::spawn_blocking;
use crate::utils::Context as _;
/// Writes a slice of bytes as the new contents of a file. /// Writes a slice of bytes as the new contents of a file.
/// ///
@ -34,5 +34,9 @@ use crate::task::blocking;
pub async fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { pub async fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
let contents = contents.as_ref().to_owned(); let contents = contents.as_ref().to_owned();
blocking::spawn(async move { std::fs::write(path, contents) }).await spawn_blocking(move || {
std::fs::write(&path, contents)
.context(|| format!("could not write to file `{}`", path.display()))
})
.await
} }

@ -0,0 +1,43 @@
use std::future::Future;
use std::pin::Pin;
use std::time::Duration;
use pin_project_lite::pin_project;
use crate::task::{Context, Poll};
use crate::utils::{timer_after, Timer};
pin_project! {
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct DelayFuture<F> {
#[pin]
future: F,
#[pin]
delay: Timer,
}
}
impl<F> DelayFuture<F> {
pub fn new(future: F, dur: Duration) -> DelayFuture<F> {
let delay = timer_after(dur);
DelayFuture { future, delay }
}
}
impl<F: Future> Future for DelayFuture<F> {
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
match this.delay.poll(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(_) => match this.future.poll(cx) {
Poll::Ready(v) => Poll::Ready(v),
Poll::Pending => Poll::Pending,
},
}
}
}

@ -0,0 +1,52 @@
use std::future::Future;
use std::pin::Pin;
use crate::future::IntoFuture;
use crate::task::{ready, Context, Poll};
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct FlattenFuture<Fut1, Fut2> {
state: State<Fut1, Fut2>,
}
#[derive(Debug)]
enum State<Fut1, Fut2> {
First(Fut1),
Second(Fut2),
Empty,
}
impl<Fut1, Fut2> FlattenFuture<Fut1, Fut2> {
pub(crate) fn new(future: Fut1) -> FlattenFuture<Fut1, Fut2> {
FlattenFuture {
state: State::First(future),
}
}
}
impl<Fut1> Future for FlattenFuture<Fut1, <Fut1::Output as IntoFuture>::Future>
where
Fut1: Future,
Fut1::Output: IntoFuture,
{
type Output = <Fut1::Output as IntoFuture>::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let Self { state } = unsafe { self.get_unchecked_mut() };
loop {
match state {
State::First(fut1) => {
let fut2 = ready!(unsafe { Pin::new_unchecked(fut1) }.poll(cx)).into_future();
*state = State::Second(fut2);
}
State::Second(fut2) => {
let v = ready!(unsafe { Pin::new_unchecked(fut2) }.poll(cx));
*state = State::Empty;
return Poll::Ready(v);
}
State::Empty => panic!("polled a completed future"),
}
}
}
}

@ -0,0 +1,60 @@
use std::pin::Pin;
use crate::future::MaybeDone;
use pin_project_lite::pin_project;
use crate::task::{Context, Poll};
use std::future::Future;
pin_project! {
#[allow(missing_docs)]
#[allow(missing_debug_implementations)]
pub struct Join<L, R>
where
L: Future,
R: Future,
{
#[pin] left: MaybeDone<L>,
#[pin] right: MaybeDone<R>,
}
}
impl<L, R> Join<L, R>
where
L: Future,
R: Future,
{
pub(crate) fn new(left: L, right: R) -> Self {
Self {
left: MaybeDone::new(left),
right: MaybeDone::new(right),
}
}
}
impl<L, R> Future for Join<L, R>
where
L: Future,
R: Future,
{
type Output = (L::Output, R::Output);
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let mut left = this.left;
let mut right = this.right;
let is_left_ready = Future::poll(Pin::new(&mut left), cx).is_ready();
if is_left_ready && right.as_ref().output().is_some() {
return Poll::Ready((left.take().unwrap(), right.take().unwrap()));
}
let is_right_ready = Future::poll(Pin::new(&mut right), cx).is_ready();
if is_right_ready && left.as_ref().output().is_some() {
return Poll::Ready((left.take().unwrap(), right.take().unwrap()));
}
Poll::Pending
}
}

@ -0,0 +1,432 @@
cfg_unstable! {
mod delay;
mod flatten;
mod race;
mod try_race;
mod join;
mod try_join;
use std::time::Duration;
use delay::DelayFuture;
use flatten::FlattenFuture;
use crate::future::IntoFuture;
use race::Race;
use try_race::TryRace;
use join::Join;
use try_join::TryJoin;
}
cfg_unstable_default! {
use crate::future::timeout::TimeoutFuture;
}
extension_trait! {
use core::pin::Pin;
use core::ops::{Deref, DerefMut};
use crate::task::{Context, Poll};
#[doc = r#"
A future represents an asynchronous computation.
A future is a value that may not have finished computing yet. This kind of
"asynchronous value" makes it possible for a thread to continue doing useful
work while it waits for the value to become available.
The [provided methods] do not really exist in the trait itself, but they become
available when [`FutureExt`] from the [prelude] is imported:
```
# #[allow(unused_imports)]
use async_std::prelude::*;
```
# The `poll` method
The core method of future, `poll`, *attempts* to resolve the future into a
final value. This method does not block if the value is not ready. Instead,
the current task is scheduled to be woken up when it's possible to make
further progress by `poll`ing again. The `context` passed to the `poll`
method can provide a [`Waker`], which is a handle for waking up the current
task.
When using a future, you generally won't call `poll` directly, but instead
`.await` the value.
[`Waker`]: ../task/struct.Waker.html
[provided methods]: #provided-methods
[`FutureExt`]: ../prelude/trait.FutureExt.html
[prelude]: ../prelude/index.html
"#]
pub trait Future {
#[doc = r#"
The type of value produced on completion.
"#]
type Output;
#[doc = r#"
Attempt to resolve the future to a final value, registering
the current task for wakeup if the value is not yet available.
# Return value
This function returns:
- [`Poll::Pending`] if the future is not ready yet
- [`Poll::Ready(val)`] with the result `val` of this future if it
finished successfully.
Once a future has finished, clients should not `poll` it again.
When a future is not ready yet, `poll` returns `Poll::Pending` and
stores a clone of the [`Waker`] copied from the current [`Context`].
This [`Waker`] is then woken once the future can make progress.
For example, a future waiting for a socket to become
readable would call `.clone()` on the [`Waker`] and store it.
When a signal arrives elsewhere indicating that the socket is readable,
[`Waker::wake`] is called and the socket future's task is awoken.
Once a task has been woken up, it should attempt to `poll` the future
again, which may or may not produce a final value.
Note that on multiple calls to `poll`, only the [`Waker`] from the
[`Context`] passed to the most recent call should be scheduled to
receive a wakeup.
# Runtime characteristics
Futures alone are *inert*; they must be *actively* `poll`ed to make
progress, meaning that each time the current task is woken up, it should
actively re-`poll` pending futures that it still has an interest in.
The `poll` function is not called repeatedly in a tight loop -- instead,
it should only be called when the future indicates that it is ready to
make progress (by calling `wake()`). If you're familiar with the
`poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures
typically do *not* suffer the same problems of "all wakeups must poll
all events"; they are more like `epoll(4)`.
An implementation of `poll` should strive to return quickly, and should
not block. Returning quickly prevents unnecessarily clogging up
threads or event loops. If it is known ahead of time that a call to
`poll` may end up taking awhile, the work should be offloaded to a
thread pool (or something similar) to ensure that `poll` can return
quickly.
# Panics
Once a future has completed (returned `Ready` from `poll`), calling its
`poll` method again may panic, block forever, or cause other kinds of
problems; the `Future` trait places no requirements on the effects of
such a call. However, as the `poll` method is not marked `unsafe`,
Rust's usual rules apply: calls must never cause undefined behavior
(memory corruption, incorrect use of `unsafe` functions, or the like),
regardless of the future's state.
[`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending
[`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready
[`Context`]: ../task/struct.Context.html
[`Waker`]: ../task/struct.Waker.html
[`Waker::wake`]: ../task/struct.Waker.html#method.wake
"#]
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output>;
}
#[doc = r#"
Extension methods for [`Future`].
[`Future`]: ../future/trait.Future.html
"#]
pub trait FutureExt: core::future::Future {
/// Returns a Future that delays execution for a specified time.
///
/// # Examples
///
/// ```
/// # async_std::task::block_on(async {
/// use async_std::prelude::*;
/// use async_std::future;
/// use std::time::Duration;
///
/// let a = future::ready(1).delay(Duration::from_millis(2000));
/// dbg!(a.await);
/// # })
/// ```
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
fn delay(self, dur: Duration) -> impl Future<Output = Self::Output> [DelayFuture<Self>]
where
Self: Sized,
{
DelayFuture::new(self, dur)
}
/// Flatten out the execution of this future when the result itself
/// can be converted into another future.
///
/// # Examples
///
/// ```
/// # async_std::task::block_on(async {
/// use async_std::prelude::*;
///
/// let nested_future = async { async { 1 } };
/// let future = nested_future.flatten();
/// assert_eq!(future.await, 1);
/// # })
/// ```
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
fn flatten(
self,
) -> impl Future<Output = <Self::Output as IntoFuture>::Output>
[FlattenFuture<Self, <Self::Output as IntoFuture>::Future>]
where
Self: Sized,
<Self as Future>::Output: IntoFuture,
{
FlattenFuture::new(self)
}
#[doc = r#"
Waits for one of two similarly-typed futures to complete.
Awaits multiple futures simultaneously, returning the output of the
first future that completes.
This function will return a new future which awaits for either one of both
futures to complete. If multiple futures are completed at the same time,
resolution will occur in the order that they have been passed.
Note that this function consumes all futures passed, and once a future is
completed, all other futures are dropped.
# Examples
```
# async_std::task::block_on(async {
use async_std::prelude::*;
use async_std::future;
let a = future::pending();
let b = future::ready(1u8);
let c = future::ready(2u8);
let f = a.race(b).race(c);
assert_eq!(f.await, 1u8);
# });
```
"#]
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
fn race<F>(
self,
other: F,
) -> impl Future<Output = <Self as std::future::Future>::Output> [Race<Self, F>]
where
Self: std::future::Future + Sized,
F: std::future::Future<Output = <Self as std::future::Future>::Output>,
{
Race::new(self, other)
}
#[doc = r#"
Waits for one of two similarly-typed fallible futures to complete.
Awaits multiple futures simultaneously, returning all results once complete.
`try_race` is similar to [`race`], but keeps going if a future
resolved to an error until all futures have been resolved. In which case
an error is returned.
The ordering of which value is yielded when two futures resolve
simultaneously is intentionally left unspecified.
[`race`]: #method.race
# Examples
```
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
#
use async_std::prelude::*;
use async_std::future;
use std::io::{Error, ErrorKind};
let a = future::pending::<Result<_, Error>>();
let b = future::ready(Err(Error::from(ErrorKind::Other)));
let c = future::ready(Ok(1u8));
let f = a.try_race(b).try_race(c);
assert_eq!(f.await?, 1u8);
#
# Ok(()) }) }
```
"#]
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
fn try_race<F, T, E>(
self,
other: F
) -> impl Future<Output = <Self as std::future::Future>::Output> [TryRace<Self, F>]
where
Self: std::future::Future<Output = Result<T, E>> + Sized,
F: std::future::Future<Output = <Self as std::future::Future>::Output>,
{
TryRace::new(self, other)
}
#[doc = r#"
Waits for two similarly-typed futures to complete.
Awaits multiple futures simultaneously, returning the output of the
futures once both complete.
This function returns a new future which polls both futures
concurrently.
# Examples
```
# async_std::task::block_on(async {
use async_std::prelude::*;
use async_std::future;
let a = future::ready(1u8);
let b = future::ready(2u16);
let f = a.join(b);
assert_eq!(f.await, (1u8, 2u16));
# });
```
"#]
#[cfg(any(feature = "unstable", feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
fn join<F>(
self,
other: F
) -> impl Future<Output = (<Self as std::future::Future>::Output, <F as std::future::Future>::Output)> [Join<Self, F>]
where
Self: std::future::Future + Sized,
F: std::future::Future,
{
Join::new(self, other)
}
#[doc = r#"
Waits for two similarly-typed fallible futures to complete.
Awaits multiple futures simultaneously, returning all results once
complete.
`try_join` is similar to [`join`], but returns an error immediately
if a future resolves to an error.
[`join`]: #method.join
# Examples
```
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
#
use async_std::prelude::*;
use async_std::future;
let a = future::ready(Err::<u8, &str>("Error"));
let b = future::ready(Ok(1u8));
let f = a.try_join(b);
assert_eq!(f.await, Err("Error"));
let a = future::ready(Ok::<u8, String>(1u8));
let b = future::ready(Ok::<u16, String>(2u16));
let f = a.try_join(b);
assert_eq!(f.await, Ok((1u8, 2u16)));
#
# Ok(()) }) }
```
"#]
#[cfg(any(feature = "unstable", feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
fn try_join<F, A, B, E>(
self,
other: F
) -> impl Future<Output = Result<(A, B), E>> [TryJoin<Self, F>]
where
Self: std::future::Future<Output = Result<A, E>> + Sized,
F: std::future::Future<Output = Result<B, E>>,
{
TryJoin::new(self, other)
}
#[doc = r#"
Waits for both the future and a timeout, if the timeout completes before
the future, it returns an TimeoutError.
# Example
```
# async_std::task::block_on(async {
#
use std::time::Duration;
use async_std::prelude::*;
use async_std::future;
let fut = future::ready(0);
let dur = Duration::from_millis(100);
let res = fut.timeout(dur).await;
assert!(res.is_ok());
let fut = future::pending::<()>();
let dur = Duration::from_millis(100);
let res = fut.timeout(dur).await;
assert!(res.is_err())
#
# });
```
"#]
#[cfg(any(all(feature = "default", feature = "unstable"), feature = "docs"))]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
fn timeout(self, dur: Duration) -> impl Future<Output = Self::Output> [TimeoutFuture<Self>]
where Self: Sized
{
TimeoutFuture::new(self, dur)
}
}
impl<F: Future + Unpin + ?Sized> Future for Box<F> {
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
unreachable!("this impl only appears in the rendered docs")
}
}
impl<F: Future + Unpin + ?Sized> Future for &mut F {
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
unreachable!("this impl only appears in the rendered docs")
}
}
impl<P> Future for Pin<P>
where
P: DerefMut + Unpin,
<P as Deref>::Target: Future,
{
type Output = <<P as Deref>::Target as Future>::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
unreachable!("this impl only appears in the rendered docs")
}
}
impl<F: Future> Future for std::panic::AssertUnwindSafe<F> {
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
unreachable!("this impl only appears in the rendered docs")
}
}
}

@ -0,0 +1,57 @@
use std::future::Future;
use std::pin::Pin;
use crate::future::MaybeDone;
use pin_project_lite::pin_project;
use crate::task::{Context, Poll};
pin_project! {
#[allow(missing_docs)]
#[allow(missing_debug_implementations)]
pub struct Race<L, R>
where
L: Future,
R: Future<Output = L::Output>
{
#[pin] left: MaybeDone<L>,
#[pin] right: MaybeDone<R>,
}
}
impl<L, R> Race<L, R>
where
L: Future,
R: Future<Output = L::Output>,
{
pub(crate) fn new(left: L, right: R) -> Self {
Self {
left: MaybeDone::new(left),
right: MaybeDone::new(right),
}
}
}
impl<L, R> Future for Race<L, R>
where
L: Future,
R: Future<Output = L::Output>,
{
type Output = L::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let mut left = this.left;
if Future::poll(Pin::new(&mut left), cx).is_ready() {
return Poll::Ready(left.take().unwrap());
}
let mut right = this.right;
if Future::poll(Pin::new(&mut right), cx).is_ready() {
return Poll::Ready(right.take().unwrap());
}
Poll::Pending
}
}

@ -0,0 +1,72 @@
use std::pin::Pin;
use crate::future::MaybeDone;
use pin_project_lite::pin_project;
use crate::task::{Context, Poll};
use std::future::Future;
pin_project! {
#[allow(missing_docs)]
#[allow(missing_debug_implementations)]
pub struct TryJoin<L, R>
where
L: Future,
R: Future,
{
#[pin] left: MaybeDone<L>,
#[pin] right: MaybeDone<R>,
}
}
impl<L, R> TryJoin<L, R>
where
L: Future,
R: Future,
{
pub(crate) fn new(left: L, right: R) -> Self {
Self {
left: MaybeDone::new(left),
right: MaybeDone::new(right),
}
}
}
impl<L, R, A, B, E> Future for TryJoin<L, R>
where
L: Future<Output = Result<A, E>>,
R: Future<Output = Result<B, E>>,
{
type Output = Result<(A, B), E>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let mut left = this.left;
let mut right = this.right;
if Future::poll(Pin::new(&mut left), cx).is_ready() {
if left.as_ref().output().unwrap().is_err() {
return Poll::Ready(Err(left.take().unwrap().err().unwrap()));
} else if right.as_ref().output().is_some() {
return Poll::Ready(Ok((
left.take().unwrap().ok().unwrap(),
right.take().unwrap().ok().unwrap(),
)));
}
}
if Future::poll(Pin::new(&mut right), cx).is_ready() {
if right.as_ref().output().unwrap().is_err() {
return Poll::Ready(Err(right.take().unwrap().err().unwrap()));
} else if left.as_ref().output().is_some() {
return Poll::Ready(Ok((
left.take().unwrap().ok().unwrap(),
right.take().unwrap().ok().unwrap(),
)));
}
}
Poll::Pending
}
}

@ -0,0 +1,66 @@
use std::pin::Pin;
use crate::future::MaybeDone;
use pin_project_lite::pin_project;
use crate::task::{Context, Poll};
use std::future::Future;
pin_project! {
#[allow(missing_docs)]
#[allow(missing_debug_implementations)]
pub struct TryRace<L, R>
where
L: Future,
R: Future<Output = L::Output>
{
#[pin] left: MaybeDone<L>,
#[pin] right: MaybeDone<R>,
}
}
impl<L, R> TryRace<L, R>
where
L: Future,
R: Future<Output = L::Output>,
{
pub(crate) fn new(left: L, right: R) -> Self {
Self {
left: MaybeDone::new(left),
right: MaybeDone::new(right),
}
}
}
impl<L, R, T, E> Future for TryRace<L, R>
where
L: Future<Output = Result<T, E>>,
R: Future<Output = L::Output>,
{
type Output = L::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let mut left_errored = false;
// Check if the left future is ready & successful. Continue if not.
let mut left = this.left;
if Future::poll(Pin::new(&mut left), cx).is_ready() {
if left.as_ref().output().unwrap().is_ok() {
return Poll::Ready(left.take().unwrap());
} else {
left_errored = true;
}
}
// Check if the right future is ready & successful. Return err if left
// future also resolved to err. Continue if not.
let mut right = this.right;
let is_ready = Future::poll(Pin::new(&mut right), cx).is_ready();
if is_ready && (right.as_ref().output().unwrap().is_ok() || left_errored) {
return Poll::Ready(right.take().unwrap());
}
Poll::Pending
}
}

@ -0,0 +1,53 @@
use std::future::Future;
/// Convert a type into a `Future`.
///
/// # Examples
///
/// ```
/// use async_std::future::{Future, IntoFuture};
/// use async_std::io;
/// use async_std::pin::Pin;
///
/// struct Client;
///
/// impl Client {
/// pub async fn send(self) -> io::Result<()> {
/// // Send a request
/// Ok(())
/// }
/// }
///
/// impl IntoFuture for Client {
/// type Output = io::Result<()>;
///
/// type Future = Pin<Box<dyn Future<Output = Self::Output>>>;
///
/// fn into_future(self) -> Self::Future {
/// Box::pin(async {
/// self.send().await
/// })
/// }
/// }
/// ```
#[cfg(feature = "unstable")]
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
pub trait IntoFuture {
/// The type of value produced on completion.
type Output;
/// Which kind of future are we turning this into?
type Future: Future<Output = Self::Output>;
/// Create a future from a value
fn into_future(self) -> Self::Future;
}
impl<T: Future> IntoFuture for T {
type Output = T::Output;
type Future = T;
fn into_future(self) -> Self::Future {
self
}
}

@ -0,0 +1,79 @@
//! A type that wraps a future to keep track of its completion status.
//!
//! This implementation was taken from the original `macro_rules` `join/try_join`
//! macros in the `futures-preview` crate.
use std::future::Future;
use std::mem;
use std::pin::Pin;
use std::task::{Context, Poll};
use futures_core::ready;
/// A future that may have completed.
#[derive(Debug)]
pub(crate) enum MaybeDone<Fut: Future> {
/// A not-yet-completed future
Future(Fut),
/// The output of the completed future
Done(Fut::Output),
/// The empty variant after the result of a [`MaybeDone`] has been
/// taken using the [`take`](MaybeDone::take) method.
Gone,
}
impl<Fut: Future> MaybeDone<Fut> {
/// Create a new instance of `MaybeDone`.
pub(crate) fn new(future: Fut) -> MaybeDone<Fut> {
Self::Future(future)
}
/// Returns an [`Option`] containing a reference to the output of the future.
/// The output of this method will be [`Some`] if and only if the inner
/// future has been completed and [`take`](MaybeDone::take)
/// has not yet been called.
#[inline]
pub(crate) fn output(self: Pin<&Self>) -> Option<&Fut::Output> {
let this = self.get_ref();
match this {
MaybeDone::Done(res) => Some(res),
_ => None,
}
}
/// Attempt to take the output of a `MaybeDone` without driving it
/// towards completion.
#[inline]
pub(crate) fn take(self: Pin<&mut Self>) -> Option<Fut::Output> {
unsafe {
let this = self.get_unchecked_mut();
match this {
MaybeDone::Done(_) => {}
MaybeDone::Future(_) | MaybeDone::Gone => return None,
};
if let MaybeDone::Done(output) = mem::replace(this, MaybeDone::Gone) {
Some(output)
} else {
unreachable!()
}
}
}
}
impl<Fut: Future> Future for MaybeDone<Fut> {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let res = unsafe {
match Pin::as_mut(&mut self).get_unchecked_mut() {
MaybeDone::Future(a) => ready!(Pin::new_unchecked(a).poll(cx)),
MaybeDone::Done(_) => return Poll::Ready(()),
MaybeDone::Gone => panic!("MaybeDone polled after value taken"),
}
};
self.set(MaybeDone::Done(res));
Poll::Ready(())
}
}

@ -4,52 +4,54 @@
//! //!
//! Often it's desireable to await multiple futures as if it was a single //! Often it's desireable to await multiple futures as if it was a single
//! future. The `join` family of operations converts multiple futures into a //! future. The `join` family of operations converts multiple futures into a
//! single future that returns all of their outputs. The `select` family of //! single future that returns all of their outputs. The `race` family of
//! operations converts multiple future into a single future that returns the //! operations converts multiple future into a single future that returns the
//! first output. //! first output.
//! //!
//! For operating on futures the following macros can be used: //! For operating on futures the following functions can be used:
//! //!
//! | Name | Return signature | When does it return? | //! | Name | Return signature | When does it return? |
//! | --- | --- | --- | //! | --- | --- | --- |
//! | `future::join` | `(T1, T2)` | Wait for all to complete //! | [`Future::join`] | `(T1, T2)` | Wait for all to complete
//! | `future::select` | `T` | Return on first value //! | [`Future::race`] | `T` | Return on first value
//! //!
//! ## Fallible Futures Concurrency //! ## Fallible Futures Concurrency
//! //!
//! For operating on futures that return `Result` additional `try_` variants of //! For operating on futures that return `Result` additional `try_` variants of
//! the macros mentioned before can be used. These macros are aware of `Result`, //! the functions mentioned before can be used. These functions are aware of `Result`,
//! and will behave slightly differently from their base variants. //! and will behave slightly differently from their base variants.
//! //!
//! In the case of `try_join`, if any of the futures returns `Err` all //! In the case of `try_join`, if any of the futures returns `Err` all
//! futures are dropped and an error is returned. This is referred to as //! futures are dropped and an error is returned. This is referred to as
//! "short-circuiting". //! "short-circuiting".
//! //!
//! In the case of `try_select`, instead of returning the first future that //! In the case of `try_race`, instead of returning the first future that
//! completes it returns the first future that _successfully_ completes. This //! completes it returns the first future that _successfully_ completes. This
//! means `try_select` will keep going until any one of the futures returns //! means `try_race` will keep going until any one of the futures returns
//! `Ok`, or _all_ futures have returned `Err`. //! `Ok`, or _all_ futures have returned `Err`.
//! //!
//! However sometimes it can be useful to use the base variants of the macros //! However sometimes it can be useful to use the base variants of the functions
//! even on futures that return `Result`. Here is an overview of operations that //! even on futures that return `Result`. Here is an overview of operations that
//! work on `Result`, and their respective semantics: //! work on `Result`, and their respective semantics:
//! //!
//! | Name | Return signature | When does it return? | //! | Name | Return signature | When does it return? |
//! | --- | --- | --- | //! | --- | --- | --- |
//! | `future::join` | `(Result<T, E>, Result<T, E>)` | Wait for all to complete //! | [`Future::join`] | `(Result<T, E>, Result<T, E>)` | Wait for all to complete
//! | `future::try_join` | `Result<(T1, T2), E>` | Return on first `Err`, wait for all to complete //! | [`Future::try_join`] | `Result<(T1, T2), E>` | Return on first `Err`, wait for all to complete
//! | `future::select` | `Result<T, E>` | Return on first value //! | [`Future::race`] | `Result<T, E>` | Return on first value
//! | `future::try_select` | `Result<T, E>` | Return on first `Ok`, reject on last Err //! | [`Future::try_race`] | `Result<T, E>` | Return on first `Ok`, reject on last Err
//!
#[doc(inline)] //! [`Future::join`]: trait.Future.html#method.join
pub use std::future::Future; //! [`Future::try_join`]: trait.Future.html#method.try_join
//! [`Future::race`]: trait.Future.html#method.race
#[doc(inline)] //! [`Future::try_race`]: trait.Future.html#method.try_race
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
pub use async_macros::{join, select, try_join, try_select};
use cfg_if::cfg_if; cfg_alloc! {
pub use future::Future;
pub(crate) mod future;
}
cfg_std! {
pub use pending::pending; pub use pending::pending;
pub use poll_fn::poll_fn; pub use poll_fn::poll_fn;
pub use ready::ready; pub use ready::ready;
@ -57,10 +59,16 @@ pub use ready::ready;
mod pending; mod pending;
mod poll_fn; mod poll_fn;
mod ready; mod ready;
}
cfg_if! { #[cfg(any(feature = "unstable", feature = "default"))]
if #[cfg(any(feature = "unstable", feature = "docs"))] {
mod timeout;
pub use timeout::{timeout, TimeoutError}; pub use timeout::{timeout, TimeoutError};
} #[cfg(any(feature = "unstable", feature = "default"))]
mod timeout;
cfg_unstable! {
pub use into_future::IntoFuture;
pub(crate) use maybe_done::MaybeDone;
mod into_future;
mod maybe_done;
} }

@ -1,7 +1,7 @@
use std::future::Future;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::pin::Pin; use std::pin::Pin;
use crate::future::Future;
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
/// Never resolves to a value. /// Never resolves to a value.
@ -9,7 +9,7 @@ use crate::task::{Context, Poll};
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// # fn main() { async_std::task::block_on(async { /// # async_std::task::block_on(async {
/// # /// #
/// use std::time::Duration; /// use std::time::Duration;
/// ///
@ -22,7 +22,7 @@ use crate::task::{Context, Poll};
/// let res: io::Result<()> = io::timeout(dur, fut).await; /// let res: io::Result<()> = io::timeout(dur, fut).await;
/// assert!(res.is_err()); /// assert!(res.is_err());
/// # /// #
/// # }) } /// # })
/// ``` /// ```
pub async fn pending<T>() -> T { pub async fn pending<T>() -> T {
let fut = Pending { let fut = Pending {

@ -1,6 +1,6 @@
use std::pin::Pin; use std::pin::Pin;
use std::future::Future;
use crate::future::Future;
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
/// Creates a new future wrapping around a function returning [`Poll`]. /// Creates a new future wrapping around a function returning [`Poll`].
@ -10,7 +10,7 @@ use crate::task::{Context, Poll};
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// # fn main() { async_std::task::block_on(async { /// # async_std::task::block_on(async {
/// # /// #
/// use async_std::future; /// use async_std::future;
/// use async_std::task::{Context, Poll}; /// use async_std::task::{Context, Poll};
@ -21,7 +21,7 @@ use crate::task::{Context, Poll};
/// ///
/// assert_eq!(future::poll_fn(poll_greeting).await, "hello world"); /// assert_eq!(future::poll_fn(poll_greeting).await, "hello world");
/// # /// #
/// # }) } /// # })
/// ``` /// ```
pub async fn poll_fn<F, T>(f: F) -> T pub async fn poll_fn<F, T>(f: F) -> T
where where

@ -7,13 +7,13 @@
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// # fn main() { async_std::task::block_on(async { /// # async_std::task::block_on(async {
/// # /// #
/// use async_std::future; /// use async_std::future;
/// ///
/// assert_eq!(future::ready(10).await, 10); /// assert_eq!(future::ready(10).await, 10);
/// # /// #
/// # }) } /// # })
/// ``` /// ```
pub async fn ready<T>(val: T) -> T { pub async fn ready<T>(val: T) -> T {
val val

@ -1,12 +1,13 @@
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::time::Duration; use std::time::Duration;
use futures_timer::Delay; use pin_project_lite::pin_project;
use crate::future::Future;
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
use crate::utils::{timer_after, Timer};
/// Awaits a future or times out after a duration of time. /// Awaits a future or times out after a duration of time.
/// ///
@ -28,39 +29,41 @@ use crate::task::{Context, Poll};
/// # /// #
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[cfg(any(feature = "unstable", feature = "docs"))]
pub async fn timeout<F, T>(dur: Duration, f: F) -> Result<T, TimeoutError> pub async fn timeout<F, T>(dur: Duration, f: F) -> Result<T, TimeoutError>
where where
F: Future<Output = T>, F: Future<Output = T>,
{ {
let f = TimeoutFuture { TimeoutFuture::new(f, dur).await
future: f,
delay: Delay::new(dur),
};
f.await
} }
pin_project! {
/// A future that times out after a duration of time. /// A future that times out after a duration of time.
#[doc(hidden)] pub struct TimeoutFuture<F> {
#[allow(missing_debug_implementations)] #[pin]
struct TimeoutFuture<F> {
future: F, future: F,
delay: Delay, #[pin]
delay: Timer,
}
} }
impl<F> TimeoutFuture<F> { impl<F> TimeoutFuture<F> {
pin_utils::unsafe_pinned!(future: F); #[allow(dead_code)]
pin_utils::unsafe_pinned!(delay: Delay); pub(super) fn new(future: F, dur: Duration) -> TimeoutFuture<F> {
TimeoutFuture {
future,
delay: timer_after(dur),
}
}
} }
impl<F: Future> Future for TimeoutFuture<F> { impl<F: Future> Future for TimeoutFuture<F> {
type Output = Result<F::Output, TimeoutError>; type Output = Result<F::Output, TimeoutError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.as_mut().future().poll(cx) { let this = self.project();
match this.future.poll(cx) {
Poll::Ready(v) => Poll::Ready(Ok(v)), Poll::Ready(v) => Poll::Ready(Ok(v)),
Poll::Pending => match self.delay().poll(cx) { Poll::Pending => match this.delay.poll(cx) {
Poll::Ready(_) => Poll::Ready(Err(TimeoutError { _private: () })), Poll::Ready(_) => Poll::Ready(Err(TimeoutError { _private: () })),
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,
}, },
@ -69,8 +72,6 @@ impl<F: Future> Future for TimeoutFuture<F> {
} }
/// An error returned when a future times out. /// An error returned when a future times out.
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
#[cfg(any(feature = "unstable", feature = "docs"))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct TimeoutError { pub struct TimeoutError {
_private: (), _private: (),

@ -2,11 +2,14 @@ use std::mem;
use std::pin::Pin; use std::pin::Pin;
use std::str; use std::str;
use pin_project_lite::pin_project;
use super::read_until_internal; use super::read_until_internal;
use crate::io::{self, BufRead}; use crate::io::{self, BufRead};
use crate::stream::Stream; use crate::stream::Stream;
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
pin_project! {
/// A stream of lines in a byte stream. /// A stream of lines in a byte stream.
/// ///
/// This stream is created by the [`lines`] method on types that implement [`BufRead`]. /// This stream is created by the [`lines`] method on types that implement [`BufRead`].
@ -18,34 +21,36 @@ use crate::task::{Context, Poll};
/// [`std::io::Lines`]: https://doc.rust-lang.org/std/io/struct.Lines.html /// [`std::io::Lines`]: https://doc.rust-lang.org/std/io/struct.Lines.html
#[derive(Debug)] #[derive(Debug)]
pub struct Lines<R> { pub struct Lines<R> {
#[pin]
pub(crate) reader: R, pub(crate) reader: R,
pub(crate) buf: String, pub(crate) buf: String,
pub(crate) bytes: Vec<u8>, pub(crate) bytes: Vec<u8>,
pub(crate) read: usize, pub(crate) read: usize,
} }
}
impl<R: BufRead> Stream for Lines<R> { impl<R: BufRead> Stream for Lines<R> {
type Item = io::Result<String>; type Item = io::Result<String>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let Self { let this = self.project();
reader, let n = futures_core::ready!(read_line_internal(
buf, this.reader,
bytes, cx,
read, this.buf,
} = unsafe { self.get_unchecked_mut() }; this.bytes,
let reader = unsafe { Pin::new_unchecked(reader) }; this.read
let n = futures_core::ready!(read_line_internal(reader, cx, buf, bytes, read))?; ))?;
if n == 0 && buf.is_empty() { if n == 0 && this.buf.is_empty() {
return Poll::Ready(None); return Poll::Ready(None);
} }
if buf.ends_with('\n') { if this.buf.ends_with('\n') {
buf.pop(); this.buf.pop();
if buf.ends_with('\r') { if this.buf.ends_with('\r') {
buf.pop(); this.buf.pop();
} }
} }
Poll::Ready(Some(Ok(mem::replace(buf, String::new())))) Poll::Ready(Some(Ok(mem::replace(this.buf, String::new()))))
} }
} }

@ -1,27 +1,23 @@
mod lines; mod lines;
mod read_line; mod read_line;
mod read_until; mod read_until;
mod split;
pub use lines::Lines; pub use lines::Lines;
pub use split::Split;
use read_line::ReadLineFuture; use read_line::ReadLineFuture;
use read_until::ReadUntilFuture; use read_until::ReadUntilFuture;
use std::mem; use std::mem;
use std::pin::Pin; use std::pin::Pin;
use cfg_if::cfg_if;
use crate::io; use crate::io;
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
use crate::utils::extension_trait;
cfg_if! { extension_trait! {
if #[cfg(feature = "docs")] {
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
}
}
extension_trait! {
#[doc = r#" #[doc = r#"
Allows reading from a buffered byte stream. Allows reading from a buffered byte stream.
@ -29,19 +25,21 @@ extension_trait! {
[`std::io::BufRead`]. [`std::io::BufRead`].
The [provided methods] do not really exist in the trait itself, but they become The [provided methods] do not really exist in the trait itself, but they become
available when the prelude is imported: available when [`BufReadExt`] from the [prelude] is imported:
``` ```
# #[allow(unused_imports)] # #[allow(unused_imports)]
use async_std::prelude::*; use async_std::io::prelude::*;
``` ```
[`std::io::BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html [`std::io::BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html
[`futures::io::AsyncBufRead`]: [`futures::io::AsyncBufRead`]:
https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncBufRead.html https://docs.rs/futures/0.3/futures/io/trait.AsyncBufRead.html
[provided methods]: #provided-methods [provided methods]: #provided-methods
[`BufReadExt`]: ../io/prelude/trait.BufReadExt.html
[prelude]: ../prelude/index.html
"#] "#]
pub trait BufRead [BufReadExt: futures_io::AsyncBufRead] { pub trait BufRead {
#[doc = r#" #[doc = r#"
Returns the contents of the internal buffer, filling it with more data from the Returns the contents of the internal buffer, filling it with more data from the
inner reader if it is empty. inner reader if it is empty.
@ -64,7 +62,14 @@ extension_trait! {
should no longer be returned in calls to `read`. should no longer be returned in calls to `read`.
"#] "#]
fn consume(self: Pin<&mut Self>, amt: usize); fn consume(self: Pin<&mut Self>, amt: usize);
}
#[doc = r#"
Extension methods for [`BufRead`].
[`BufRead`]: ../trait.BufRead.html
"#]
pub trait BufReadExt: futures_io::AsyncBufRead {
#[doc = r#" #[doc = r#"
Reads all bytes into `buf` until the delimiter `byte` or EOF is reached. Reads all bytes into `buf` until the delimiter `byte` or EOF is reached.
@ -226,6 +231,57 @@ extension_trait! {
read: 0, read: 0,
} }
} }
#[doc = r#"
Returns a stream over the contents of this reader split on the byte `byte`.
The stream returned from this function will return instances of
[`io::Result`]`<`[`Vec<u8>`]`>`. Each vector returned will *not* have
the delimiter byte at the end.
This function will yield errors whenever [`read_until`] would have
also yielded an error.
[`io::Result`]: type.Result.html
[`Vec<u8>`]: ../vec/struct.Vec.html
[`read_until`]: #method.read_until
# Examples
[`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
this example, we use [`Cursor`] to iterate over all hyphen delimited
segments in a byte slice
[`Cursor`]: struct.Cursor.html
```
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
#
use async_std::prelude::*;
use async_std::io;
let cursor = io::Cursor::new(b"lorem-ipsum-dolor");
let mut split_iter = cursor.split(b'-').map(|l| l.unwrap());
assert_eq!(split_iter.next().await, Some(b"lorem".to_vec()));
assert_eq!(split_iter.next().await, Some(b"ipsum".to_vec()));
assert_eq!(split_iter.next().await, Some(b"dolor".to_vec()));
assert_eq!(split_iter.next().await, None);
#
# Ok(()) }) }
```
"#]
fn split(self, byte: u8) -> Split<Self>
where
Self: Sized,
{
Split {
reader: self,
buf: Vec::new(),
delim: byte,
read: 0,
}
}
} }
impl<T: BufRead + Unpin + ?Sized> BufRead for Box<T> { impl<T: BufRead + Unpin + ?Sized> BufRead for Box<T> {

@ -1,9 +1,9 @@
use std::mem; use std::mem;
use std::pin::Pin; use std::pin::Pin;
use std::str; use std::str;
use std::future::Future;
use super::read_until_internal; use super::read_until_internal;
use crate::future::Future;
use crate::io::{self, BufRead}; use crate::io::{self, BufRead};
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
@ -37,8 +37,12 @@ impl<T: BufRead + Unpin + ?Sized> Future for ReadLineFuture<'_, T> {
)) ))
})) }))
} else { } else {
#[allow(clippy::debug_assert_with_mut_call)]
{
debug_assert!(buf.is_empty()); debug_assert!(buf.is_empty());
debug_assert_eq!(*read, 0); debug_assert_eq!(*read, 0);
}
// Safety: `bytes` is a valid UTF-8 because `str::from_utf8` returned `Ok`. // Safety: `bytes` is a valid UTF-8 because `str::from_utf8` returned `Ok`.
mem::swap(unsafe { buf.as_mut_vec() }, bytes); mem::swap(unsafe { buf.as_mut_vec() }, bytes);
Poll::Ready(ret) Poll::Ready(ret)

@ -1,7 +1,7 @@
use std::pin::Pin; use std::pin::Pin;
use std::future::Future;
use super::read_until_internal; use super::read_until_internal;
use crate::future::Future;
use crate::io::{self, BufRead}; use crate::io::{self, BufRead};
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};

@ -0,0 +1,51 @@
use std::mem;
use std::pin::Pin;
use pin_project_lite::pin_project;
use super::read_until_internal;
use crate::io::{self, BufRead};
use crate::stream::Stream;
use crate::task::{Context, Poll};
pin_project! {
/// A stream over the contents of an instance of [`BufRead`] split on a particular byte.
///
/// This stream is created by the [`split`] method on types that implement [`BufRead`].
///
/// This type is an async version of [`std::io::Split`].
///
/// [`split`]: trait.BufRead.html#method.lines
/// [`BufRead`]: trait.BufRead.html
/// [`std::io::Split`]: https://doc.rust-lang.org/std/io/struct.Split.html
#[derive(Debug)]
pub struct Split<R> {
#[pin]
pub(crate) reader: R,
pub(crate) buf: Vec<u8>,
pub(crate) read: usize,
pub(crate) delim: u8,
}
}
impl<R: BufRead> Stream for Split<R> {
type Item = io::Result<Vec<u8>>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.project();
let n = futures_core::ready!(read_until_internal(
this.reader,
cx,
*this.delim,
this.buf,
this.read
))?;
if n == 0 && this.buf.is_empty() {
return Poll::Ready(None);
}
if this.buf[this.buf.len() - 1] == *this.delim {
this.buf.pop();
}
Poll::Ready(Some(Ok(mem::replace(this.buf, vec![]))))
}
}

@ -2,11 +2,12 @@ use std::io::{IoSliceMut, Read as _};
use std::pin::Pin; use std::pin::Pin;
use std::{cmp, fmt}; use std::{cmp, fmt};
use crate::io::{self, BufRead, Read, Seek, SeekFrom}; use pin_project_lite::pin_project;
use crate::task::{Context, Poll};
const DEFAULT_CAPACITY: usize = 8 * 1024; use crate::io::{self, BufRead, Read, Seek, SeekFrom, DEFAULT_BUF_SIZE};
use crate::task::{Context, Poll};
pin_project! {
/// Adds buffering to any reader. /// Adds buffering to any reader.
/// ///
/// It can be excessively inefficient to work directly with a [`Read`] instance. A `BufReader` /// It can be excessively inefficient to work directly with a [`Read`] instance. A `BufReader`
@ -43,11 +44,13 @@ const DEFAULT_CAPACITY: usize = 8 * 1024;
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub struct BufReader<R> { pub struct BufReader<R> {
#[pin]
inner: R, inner: R,
buf: Box<[u8]>, buf: Box<[u8]>,
pos: usize, pos: usize,
cap: usize, cap: usize,
} }
}
impl<R: io::Read> BufReader<R> { impl<R: io::Read> BufReader<R> {
/// Creates a buffered reader with default buffer capacity. /// Creates a buffered reader with default buffer capacity.
@ -67,7 +70,7 @@ impl<R: io::Read> BufReader<R> {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn new(inner: R) -> BufReader<R> { pub fn new(inner: R) -> BufReader<R> {
BufReader::with_capacity(DEFAULT_CAPACITY, inner) BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
} }
/// Creates a new buffered reader with the specified capacity. /// Creates a new buffered reader with the specified capacity.
@ -95,10 +98,6 @@ impl<R: io::Read> BufReader<R> {
} }
impl<R> BufReader<R> { 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. /// Gets a reference to the underlying reader.
/// ///
/// It is inadvisable to directly read from the underlying reader. /// It is inadvisable to directly read from the underlying reader.
@ -141,6 +140,13 @@ impl<R> BufReader<R> {
&mut self.inner &mut self.inner
} }
/// Gets a pinned mutable reference to the underlying reader.
///
/// It is inadvisable to directly read from the underlying reader.
fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut R> {
self.project().inner
}
/// Returns a reference to the internal buffer. /// Returns a reference to the internal buffer.
/// ///
/// This function will not attempt to fill the buffer if it is empty. /// This function will not attempt to fill the buffer if it is empty.
@ -185,9 +191,10 @@ impl<R> BufReader<R> {
/// Invalidates all data in the internal buffer. /// Invalidates all data in the internal buffer.
#[inline] #[inline]
fn discard_buffer(mut self: Pin<&mut Self>) { fn discard_buffer(self: Pin<&mut Self>) {
*self.as_mut().pos() = 0; let this = self.project();
*self.cap() = 0; *this.pos = 0;
*this.cap = 0;
} }
} }
@ -201,7 +208,7 @@ impl<R: Read> Read for BufReader<R> {
// (larger than our internal buffer), bypass our internal buffer // (larger than our internal buffer), bypass our internal buffer
// entirely. // entirely.
if self.pos == self.cap && buf.len() >= self.buf.len() { if self.pos == self.cap && buf.len() >= self.buf.len() {
let res = futures_core::ready!(self.as_mut().inner().poll_read(cx, buf)); let res = futures_core::ready!(self.as_mut().get_pin_mut().poll_read(cx, buf));
self.discard_buffer(); self.discard_buffer();
return Poll::Ready(res); return Poll::Ready(res);
} }
@ -218,7 +225,8 @@ impl<R: Read> Read for BufReader<R> {
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
let total_len = bufs.iter().map(|b| b.len()).sum::<usize>(); let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
if self.pos == self.cap && total_len >= self.buf.len() { if self.pos == self.cap && total_len >= self.buf.len() {
let res = futures_core::ready!(self.as_mut().inner().poll_read_vectored(cx, bufs)); let res =
futures_core::ready!(self.as_mut().get_pin_mut().poll_read_vectored(cx, bufs));
self.discard_buffer(); self.discard_buffer();
return Poll::Ready(res); return Poll::Ready(res);
} }
@ -234,28 +242,23 @@ impl<R: Read> BufRead for BufReader<R> {
self: Pin<&'a mut Self>, self: Pin<&'a mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
) -> Poll<io::Result<&'a [u8]>> { ) -> Poll<io::Result<&'a [u8]>> {
let Self { let mut this = self.project();
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 // If we've reached the end of our internal buffer then we need to fetch
// some more data from the underlying reader. // some more data from the underlying reader.
// Branch using `>=` instead of the more correct `==` // Branch using `>=` instead of the more correct `==`
// to tell the compiler that the pos..cap slice is always valid. // to tell the compiler that the pos..cap slice is always valid.
if *pos >= *cap { if *this.pos >= *this.cap {
debug_assert!(*pos == *cap); debug_assert!(*this.pos == *this.cap);
*cap = futures_core::ready!(inner.as_mut().poll_read(cx, buf))?; *this.cap = futures_core::ready!(this.inner.as_mut().poll_read(cx, this.buf))?;
*pos = 0; *this.pos = 0;
} }
Poll::Ready(Ok(&buf[*pos..*cap])) Poll::Ready(Ok(&this.buf[*this.pos..*this.cap]))
} }
fn consume(mut self: Pin<&mut Self>, amt: usize) { fn consume(self: Pin<&mut Self>, amt: usize) {
*self.as_mut().pos() = cmp::min(self.pos + amt, self.cap); let this = self.project();
*this.pos = cmp::min(*this.pos + amt, *this.cap);
} }
} }
@ -305,24 +308,26 @@ impl<R: Seek> Seek for BufReader<R> {
if let Some(offset) = n.checked_sub(remainder) { if let Some(offset) = n.checked_sub(remainder) {
result = futures_core::ready!( result = futures_core::ready!(
self.as_mut() self.as_mut()
.inner() .get_pin_mut()
.poll_seek(cx, SeekFrom::Current(offset)) .poll_seek(cx, SeekFrom::Current(offset))
)?; )?;
} else { } else {
// seek backwards by our remainder, and then by the offset // seek backwards by our remainder, and then by the offset
futures_core::ready!( futures_core::ready!(
self.as_mut() self.as_mut()
.inner() .get_pin_mut()
.poll_seek(cx, SeekFrom::Current(-remainder)) .poll_seek(cx, SeekFrom::Current(-remainder))
)?; )?;
self.as_mut().discard_buffer(); self.as_mut().discard_buffer();
result = futures_core::ready!( result = futures_core::ready!(
self.as_mut().inner().poll_seek(cx, SeekFrom::Current(n)) self.as_mut()
.get_pin_mut()
.poll_seek(cx, SeekFrom::Current(n))
)?; )?;
} }
} else { } else {
// Seeking with Start/End doesn't care about our buffer length. // Seeking with Start/End doesn't care about our buffer length.
result = futures_core::ready!(self.as_mut().inner().poll_seek(cx, pos))?; result = futures_core::ready!(self.as_mut().get_pin_mut().poll_seek(cx, pos))?;
} }
self.discard_buffer(); self.discard_buffer();
Poll::Ready(Ok(result)) Poll::Ready(Ok(result))

@ -1,13 +1,13 @@
use std::fmt; use std::fmt;
use std::pin::Pin; use std::pin::Pin;
use futures_core::ready; use pin_project_lite::pin_project;
use crate::io::{self, Seek, SeekFrom, Write}; use crate::io::write::WriteExt;
use crate::task::{Context, Poll}; use crate::io::{self, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE};
use crate::task::{Context, Poll, ready};
const DEFAULT_CAPACITY: usize = 8 * 1024;
pin_project! {
/// Wraps a writer and buffers its output. /// Wraps a writer and buffers its output.
/// ///
/// It can be excessively inefficient to work directly with something that /// It can be excessively inefficient to work directly with something that
@ -22,14 +22,14 @@ const DEFAULT_CAPACITY: usize = 8 * 1024;
/// times. It also provides no advantage when writing to a destination that is /// times. It also provides no advantage when writing to a destination that is
/// in memory, like a `Vec<u8>`. /// in memory, like a `Vec<u8>`.
/// ///
/// When the `BufWriter` is dropped, the contents of its buffer will be written /// Unlike the `BufWriter` type in `std`, this type does not write out the
/// out. However, any errors that happen in the process of flushing the buffer /// contents of its buffer when it is dropped. Therefore, it is absolutely
/// when the writer is dropped will be ignored. Code that wishes to handle such /// critical that users explicitly flush the buffer before dropping a
/// errors must manually call [`flush`] before the writer is dropped. /// `BufWriter`.
/// ///
/// This type is an async version of [`std::io::BufReader`]. /// This type is an async version of [`std::io::BufWriter`].
/// ///
/// [`std::io::BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html /// [`std::io::BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html
/// ///
/// # Examples /// # Examples
/// ///
@ -61,10 +61,13 @@ const DEFAULT_CAPACITY: usize = 8 * 1024;
/// use async_std::prelude::*; /// use async_std::prelude::*;
/// ///
/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").await?); /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").await?);
///
/// for i in 0..10 { /// for i in 0..10 {
/// let arr = [i+1]; /// let arr = [i+1];
/// stream.write(&arr).await?; /// stream.write(&arr).await?;
/// }; /// };
///
/// stream.flush().await?;
/// # /// #
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
@ -78,15 +81,41 @@ const DEFAULT_CAPACITY: usize = 8 * 1024;
/// [`TcpStream`]: ../net/struct.TcpStream.html /// [`TcpStream`]: ../net/struct.TcpStream.html
/// [`flush`]: trait.Write.html#tymethod.flush /// [`flush`]: trait.Write.html#tymethod.flush
pub struct BufWriter<W> { pub struct BufWriter<W> {
#[pin]
inner: W, inner: W,
buf: Vec<u8>, buf: Vec<u8>,
written: usize, written: usize,
} }
}
impl<W: Write> BufWriter<W> { /// An error returned by `into_inner` which combines an error that
pin_utils::unsafe_pinned!(inner: W); /// happened while writing out the buffer, and the buffered writer object
pin_utils::unsafe_unpinned!(buf: Vec<u8>); /// which may be used to recover from the condition.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::io::BufWriter;
/// use async_std::net::TcpStream;
///
/// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34251").await?);
///
/// // unwrap the TcpStream and flush the buffer
/// let stream = match buf_writer.into_inner().await {
/// Ok(s) => s,
/// Err(e) => {
/// // Here, e is an IntoInnerError
/// panic!("An error occurred");
/// }
/// };
/// #
/// # Ok(()) }) }
///```
#[derive(Debug)]
pub struct IntoInnerError<W>(W, crate::io::Error);
impl<W: Write> BufWriter<W> {
/// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB, /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB,
/// but may change in the future. /// but may change in the future.
/// ///
@ -103,7 +132,7 @@ impl<W: Write> BufWriter<W> {
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
pub fn new(inner: W) -> BufWriter<W> { pub fn new(inner: W) -> BufWriter<W> {
BufWriter::with_capacity(DEFAULT_CAPACITY, inner) BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
} }
/// Creates a new `BufWriter` with the specified buffer capacity. /// Creates a new `BufWriter` with the specified buffer capacity.
@ -174,14 +203,41 @@ impl<W: Write> BufWriter<W> {
&mut self.inner &mut self.inner
} }
/// Gets a pinned mutable reference to the underlying writer.
///
/// It is inadvisable to directly write to the underlying writer.
fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut W> {
self.project().inner
}
/// Consumes BufWriter, returning the underlying writer /// Consumes BufWriter, returning the underlying writer
/// ///
/// This method will not write leftover data, it will be lost. /// This method will not write leftover data, it will be lost.
/// For method that will attempt to write before returning the writer see [`poll_into_inner`] /// For method that will attempt to write before returning the writer see [`poll_into_inner`]
/// ///
/// [`poll_into_inner`]: #method.poll_into_inner /// [`poll_into_inner`]: #method.poll_into_inner
pub fn into_inner(self) -> W { /// # Examples
self.inner ///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::io::BufWriter;
/// use async_std::net::TcpStream;
///
/// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34251").await?);
///
/// // unwrap the TcpStream and flush the buffer
/// let stream = buf_writer.into_inner().await.unwrap();
/// #
/// # Ok(()) }) }
/// ```
pub async fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>>
where
Self: Unpin,
{
match self.flush().await {
Err(e) => Err(IntoInnerError(self, e)),
Ok(()) => Ok(self.inner),
}
} }
/// Returns a reference to the internally buffered data. /// Returns a reference to the internally buffered data.
@ -210,16 +266,15 @@ impl<W: Write> BufWriter<W> {
/// ///
/// [`LineWriter`]: struct.LineWriter.html /// [`LineWriter`]: struct.LineWriter.html
fn poll_flush_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { fn poll_flush_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
let Self { let mut this = self.project();
inner, let len = this.buf.len();
buf,
written,
} = unsafe { Pin::get_unchecked_mut(self) };
let mut inner = unsafe { Pin::new_unchecked(inner) };
let len = buf.len();
let mut ret = Ok(()); let mut ret = Ok(());
while *written < len { while *this.written < len {
match inner.as_mut().poll_write(cx, &buf[*written..]) { match this
.inner
.as_mut()
.poll_write(cx, &this.buf[*this.written..])
{
Poll::Ready(Ok(0)) => { Poll::Ready(Ok(0)) => {
ret = Err(io::Error::new( ret = Err(io::Error::new(
io::ErrorKind::WriteZero, io::ErrorKind::WriteZero,
@ -227,7 +282,7 @@ impl<W: Write> BufWriter<W> {
)); ));
break; break;
} }
Poll::Ready(Ok(n)) => *written += n, Poll::Ready(Ok(n)) => *this.written += n,
Poll::Ready(Err(ref e)) if e.kind() == io::ErrorKind::Interrupted => {} Poll::Ready(Err(ref e)) if e.kind() == io::ErrorKind::Interrupted => {}
Poll::Ready(Err(e)) => { Poll::Ready(Err(e)) => {
ret = Err(e); ret = Err(e);
@ -236,10 +291,10 @@ impl<W: Write> BufWriter<W> {
Poll::Pending => return Poll::Pending, Poll::Pending => return Poll::Pending,
} }
} }
if *written > 0 { if *this.written > 0 {
buf.drain(..*written); this.buf.drain(..*this.written);
} }
*written = 0; *this.written = 0;
Poll::Ready(ret) Poll::Ready(ret)
} }
} }
@ -254,26 +309,26 @@ impl<W: Write> Write for BufWriter<W> {
ready!(self.as_mut().poll_flush_buf(cx))?; ready!(self.as_mut().poll_flush_buf(cx))?;
} }
if buf.len() >= self.buf.capacity() { if buf.len() >= self.buf.capacity() {
self.inner().poll_write(cx, buf) self.get_pin_mut().poll_write(cx, buf)
} else { } else {
Pin::new(&mut *self.buf()).poll_write(cx, buf) Pin::new(&mut *self.project().buf).poll_write(cx, buf)
} }
} }
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
ready!(self.as_mut().poll_flush_buf(cx))?; ready!(self.as_mut().poll_flush_buf(cx))?;
self.inner().poll_flush(cx) self.get_pin_mut().poll_flush(cx)
} }
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
ready!(self.as_mut().poll_flush_buf(cx))?; ready!(self.as_mut().poll_flush_buf(cx))?;
self.inner().poll_close(cx) self.get_pin_mut().poll_close(cx)
} }
} }
impl<W: Write + fmt::Debug> fmt::Debug for BufWriter<W> { impl<W: Write + fmt::Debug> fmt::Debug for BufWriter<W> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BufReader") f.debug_struct("BufWriter")
.field("writer", &self.inner) .field("writer", &self.inner)
.field("buf", &self.buf) .field("buf", &self.buf)
.finish() .finish()
@ -290,6 +345,6 @@ impl<W: Write + Seek> Seek for BufWriter<W> {
pos: SeekFrom, pos: SeekFrom,
) -> Poll<io::Result<u64>> { ) -> Poll<io::Result<u64>> {
ready!(self.as_mut().poll_flush_buf(cx))?; ready!(self.as_mut().poll_flush_buf(cx))?;
self.inner().poll_seek(cx, pos) self.get_pin_mut().poll_seek(cx, pos)
} }
} }

@ -1,8 +1,11 @@
use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use crate::future::Future; use pin_project_lite::pin_project;
use crate::io::{self, BufRead, BufReader, Read, Write}; use crate::io::{self, BufRead, BufReader, Read, Write};
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
use crate::utils::Context as _;
/// Copies the entire contents of a reader into a writer. /// Copies the entire contents of a reader into a writer.
/// ///
@ -41,52 +44,131 @@ use crate::task::{Context, Poll};
/// # /// #
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` /// ```
#[cfg(any(feature = "docs", not(feature = "unstable")))]
pub async fn copy<R, W>(reader: &mut R, writer: &mut W) -> io::Result<u64> pub async fn copy<R, W>(reader: &mut R, writer: &mut W) -> io::Result<u64>
where where
R: Read + Unpin + ?Sized, R: Read + Unpin + ?Sized,
W: Write + Unpin + ?Sized, W: Write + Unpin + ?Sized,
{ {
pub struct CopyFuture<'a, R, W: ?Sized> { pin_project! {
struct CopyFuture<R, W> {
#[pin]
reader: R, reader: R,
writer: &'a mut W, #[pin]
writer: W,
amt: u64, amt: u64,
} }
}
impl<R, W: Unpin + ?Sized> CopyFuture<'_, R, W> { impl<R, W> Future for CopyFuture<R, W>
fn project(self: Pin<&mut Self>) -> (Pin<&mut R>, Pin<&mut W>, &mut u64) { where
unsafe { R: BufRead,
let this = self.get_unchecked_mut(); W: Write + Unpin,
( {
Pin::new_unchecked(&mut this.reader), type Output = io::Result<u64>;
Pin::new(&mut *this.writer),
&mut this.amt, fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
) let mut this = self.project();
loop {
let buffer = futures_core::ready!(this.reader.as_mut().poll_fill_buf(cx))?;
if buffer.is_empty() {
futures_core::ready!(this.writer.as_mut().poll_flush(cx))?;
return Poll::Ready(Ok(*this.amt));
}
let i = futures_core::ready!(this.writer.as_mut().poll_write(cx, buffer))?;
if i == 0 {
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
}
*this.amt += i as u64;
this.reader.as_mut().consume(i);
} }
} }
} }
impl<R, W> Future for CopyFuture<'_, R, W> let future = CopyFuture {
reader: BufReader::new(reader),
writer,
amt: 0,
};
future.await.context(|| String::from("io::copy failed"))
}
/// Copies the entire contents of a reader into a writer.
///
/// This function will continuously read data from `reader` and then
/// write it into `writer` in a streaming fashion until `reader`
/// returns EOF.
///
/// On success, the total number of bytes that were copied from
/// `reader` to `writer` is returned.
///
/// If youre wanting to copy the contents of one file to another and youre
/// working with filesystem paths, see the [`fs::copy`] function.
///
/// This function is an async version of [`std::io::copy`].
///
/// [`std::io::copy`]: https://doc.rust-lang.org/std/io/fn.copy.html
/// [`fs::copy`]: ../fs/fn.copy.html
///
/// # Errors
///
/// This function will return an error immediately if any call to `read` or
/// `write` returns an error. All instances of `ErrorKind::Interrupted` are
/// handled by this function and the underlying operation is retried.
///
/// # Examples
///
/// ```
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::io;
///
/// let mut reader: &[u8] = b"hello";
/// let mut writer = io::stdout();
///
/// io::copy(&mut reader, &mut writer).await?;
/// #
/// # Ok(()) }) }
/// ```
#[cfg(all(feature = "unstable", not(feature = "docs")))]
pub async fn copy<R, W>(reader: R, writer: W) -> io::Result<u64>
where
R: Read + Unpin,
W: Write + Unpin,
{
pin_project! {
struct CopyFuture<R, W> {
#[pin]
reader: R,
#[pin]
writer: W,
amt: u64,
}
}
impl<R, W> Future for CopyFuture<R, W>
where where
R: BufRead, R: BufRead,
W: Write + Unpin + ?Sized, W: Write + Unpin,
{ {
type Output = io::Result<u64>; type Output = io::Result<u64>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let (mut reader, mut writer, amt) = self.project(); let mut this = self.project();
loop { loop {
let buffer = futures_core::ready!(reader.as_mut().poll_fill_buf(cx))?; let buffer = futures_core::ready!(this.reader.as_mut().poll_fill_buf(cx))?;
if buffer.is_empty() { if buffer.is_empty() {
futures_core::ready!(writer.as_mut().poll_flush(cx))?; futures_core::ready!(this.writer.as_mut().poll_flush(cx))?;
return Poll::Ready(Ok(*amt)); return Poll::Ready(Ok(*this.amt));
} }
let i = futures_core::ready!(writer.as_mut().poll_write(cx, buffer))?; let i = futures_core::ready!(this.writer.as_mut().poll_write(cx, buffer))?;
if i == 0 { if i == 0 {
return Poll::Ready(Err(io::ErrorKind::WriteZero.into())); return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
} }
*amt += i as u64; *this.amt += i as u64;
reader.as_mut().consume(i); this.reader.as_mut().consume(i);
} }
} }
} }
@ -96,5 +178,5 @@ where
writer, writer,
amt: 0, amt: 0,
}; };
future.await future.await.context(|| String::from("io::copy failed"))
} }

@ -28,9 +28,10 @@ pub fn empty() -> Empty {
/// A reader that contains no data. /// A reader that contains no data.
/// ///
/// This reader is constructed by the [`sink`] function. /// This reader is created by the [`empty`] function. See its
/// documentation for more.
/// ///
/// [`sink`]: fn.sink.html /// [`empty`]: fn.empty.html
pub struct Empty { pub struct Empty {
_private: (), _private: (),
} }

@ -1,42 +1,290 @@
//! Basic input and output. //! Traits, helpers, and type definitions for core I/O functionality.
//!
//! The `async_std::io` module contains a number of common things you'll need
//! when doing input and output. The most core part of this module is
//! the [`Read`] and [`Write`] traits, which provide the
//! most general interface for reading and writing input and output.
//! //!
//! This module is an async version of [`std::io`]. //! This module is an async version of [`std::io`].
//! //!
//! [`std::io`]: https://doc.rust-lang.org/std/io/index.html //! [`std::io`]: https://doc.rust-lang.org/std/io/index.html
//! //!
//! # Examples //! # Read and Write
//!
//! Because they are traits, [`Read`] and [`Write`] are implemented by a number
//! of other types, and you can implement them for your types too. As such,
//! you'll see a few different types of I/O throughout the documentation in
//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on
//! [`File`]s:
//!
//! ```no_run
//! use async_std::fs::File;
//! use async_std::prelude::*;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! let mut f = File::open("foo.txt").await?;
//! let mut buffer = [0; 10];
//!
//! // read up to 10 bytes
//! let n = f.read(&mut buffer).await?;
//!
//! println!("The bytes: {:?}", &buffer[..n]);
//! #
//! # Ok(()) }) }
//! ```
//!
//! [`Read`] and [`Write`] are so important, implementors of the two traits have a
//! nickname: readers and writers. So you'll sometimes see 'a reader' instead
//! of 'a type that implements the [`Read`] trait'. Much easier!
//!
//! ## Seek and BufRead
//!
//! Beyond that, there are two important traits that are provided: [`Seek`]
//! and [`BufRead`]. Both of these build on top of a reader to control
//! how the reading happens. [`Seek`] lets you control where the next byte is
//! coming from:
//!
//! ```no_run
//! use async_std::fs::File;
//! use async_std::io::SeekFrom;
//! use async_std::prelude::*;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! let mut f = File::open("foo.txt").await?;
//! let mut buffer = [0; 10];
//!
//! // skip to the last 10 bytes of the file
//! f.seek(SeekFrom::End(-10)).await?;
//!
//! // read up to 10 bytes
//! let n = f.read(&mut buffer).await?;
//!
//! println!("The bytes: {:?}", &buffer[..n]);
//! #
//! # Ok(()) }) }
//! ```
//!
//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but
//! to show it off, we'll need to talk about buffers in general. Keep reading!
//!
//! ## BufReader and BufWriter
//!
//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be
//! making near-constant calls to the operating system. To help with this,
//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap
//! readers and writers. The wrapper uses a buffer, reducing the number of
//! calls and providing nicer methods for accessing exactly what you want.
//!
//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra
//! methods to any reader:
//!
//! ```no_run
//! use async_std::fs::File;
//! use async_std::io::BufReader;
//! use async_std::prelude::*;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! let f = File::open("foo.txt").await?;
//! let mut reader = BufReader::new(f);
//! let mut buffer = String::new();
//!
//! // read a line into buffer
//! reader.read_line(&mut buffer).await?;
//!
//! println!("{}", buffer);
//! #
//! # Ok(()) }) }
//! ```
//!
//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
//! to [`write`][`Write::write`]:
//!
//! ```no_run
//! use async_std::fs::File;
//! use async_std::io::prelude::*;
//! use async_std::io::BufWriter;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! let f = File::create("foo.txt").await?;
//! {
//! let mut writer = BufWriter::new(f);
//!
//! // write a byte to the buffer
//! writer.write(&[42]).await?;
//! } // the buffer is flushed once writer goes out of scope
//! //
//! #
//! # Ok(()) }) }
//! ```
//!
//! ## Standard input and output
//!
//! A very common source of input is standard input:
//!
//! ```no_run
//! use async_std::io;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! let mut input = String::new();
//!
//! io::stdin().read_line(&mut input).await?;
//!
//! println!("You typed: {}", input.trim());
//! #
//! # Ok(()) }) }
//! ```
//!
//! Note that you cannot use the [`?` operator] in functions that do not return
//! a [`Result<T, E>`][`Result`]. Instead, you can call [`.unwrap()`]
//! or `match` on the return value to catch any possible errors:
//!
//! ```no_run
//! use async_std::io;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! let mut input = String::new();
//!
//! io::stdin().read_line(&mut input).await.unwrap();
//! #
//! # Ok(()) }) }
//! ```
//!
//! And a very common source of output is standard output:
//!
//! ```no_run
//! use async_std::io;
//! use async_std::io::prelude::*;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! io::stdout().write(&[42]).await?;
//! #
//! # Ok(()) }) }
//! ```
//!
//! Of course, using [`io::stdout`] directly is less common than something like
//! [`println!`].
//! //!
//! Read a line from the standard input: //! ## Iterator types
//!
//! A large number of the structures provided by `std::io` are for various
//! ways of iterating over I/O. For example, [`Lines`] is used to split over
//! lines:
//! //!
//! ```no_run //! ```no_run
//! use async_std::fs::File;
//! use async_std::io::BufReader;
//! use async_std::prelude::*;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async { //! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! # //! #
//! let f = File::open("foo.txt").await?;
//! let reader = BufReader::new(f);
//!
//! let mut lines = reader.lines();
//! while let Some(line) = lines.next().await {
//! println!("{}", line?);
//! }
//! #
//! # Ok(()) }) }
//! ```
//!
//! ## Functions
//!
//! There are a number of [functions][functions-list] that offer access to various
//! features. For example, we can use three of these functions to copy everything
//! from standard input to standard output:
//!
//! ```no_run
//! use async_std::io; //! use async_std::io;
//! //!
//! let stdin = io::stdin(); //! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! let mut line = String::new(); //! #
//! stdin.read_line(&mut line).await?; //! io::copy(&mut io::stdin(), &mut io::stdout()).await?;
//! # //! #
//! # Ok(()) }) } //! # Ok(()) }) }
//! ``` //! ```
//!
//! [functions-list]: #functions-1
//!
//! ## io::Result
//!
//! Last, but certainly not least, is [`io::Result`]. This type is used
//! as the return type of many `std::io` functions that can cause an error, and
//! can be returned from your own functions as well. Many of the examples in this
//! module use the [`?` operator]:
//!
//! ```
//! #![allow(dead_code)]
//! use async_std::io;
//!
//! async fn read_input() -> io::Result<()> {
//! let mut input = String::new();
//!
//! io::stdin().read_line(&mut input).await?;
//!
//! println!("You typed: {}", input.trim());
//!
//! Ok(())
//! }
//! ```
//!
//! The return type of `read_input`, [`io::Result<()>`][`io::Result`], is a very
//! common type for functions which don't have a 'real' return value, but do want to
//! return errors if they happen. In this case, the only purpose of this function is
//! to read the line and print it, so we use `()`.
//!
//! ## Platform-specific behavior
//!
//! Many I/O functions throughout the standard library are documented to indicate
//! what various library or syscalls they are delegated to. This is done to help
//! applications both understand what's happening under the hood as well as investigate
//! any possibly unclear semantics. Note, however, that this is informative, not a binding
//! contract. The implementation of many of these functions are subject to change over
//! time and may call fewer or more syscalls/library functions.
//!
//! [`Read`]: trait.Read.html
//! [`Write`]: trait.Write.html
//! [`Seek`]: trait.Seek.html
//! [`BufRead`]: trait.BufRead.html
//! [`File`]: ../fs/struct.File.html
//! [`TcpStream`]: ../net/struct.TcpStream.html
//! [`Vec<T>`]: ../vec/struct.Vec.html
//! [`BufReader`]: struct.BufReader.html
//! [`BufWriter`]: struct.BufWriter.html
//! [`Write::write`]: trait.Write.html#tymethod.write
//! [`io::stdout`]: fn.stdout.html
//! [`println!`]: ../macro.println.html
//! [`Lines`]: struct.Lines.html
//! [`io::Result`]: type.Result.html
//! [`?` operator]: https://doc.rust-lang.org/stable/book/appendix-02-operators.html
//! [`Read::read`]: trait.Read.html#tymethod.read
//! [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
//! [`.unwrap()`]: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap
const DEFAULT_BUF_SIZE: usize = 8 * 1024;
cfg_std! {
#[doc(inline)] #[doc(inline)]
pub use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result, SeekFrom}; pub use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result, SeekFrom};
pub use buf_read::{BufRead, Lines}; pub use buf_read::{BufRead, Lines, Split};
pub use buf_reader::BufReader; pub use buf_reader::BufReader;
pub use buf_writer::BufWriter; pub use buf_writer::{BufWriter, IntoInnerError};
pub use copy::copy; pub use copy::copy;
pub use cursor::Cursor; pub use cursor::Cursor;
pub use empty::{empty, Empty}; pub use empty::{empty, Empty};
pub use read::Read; pub use read::*;
pub use repeat::{repeat, Repeat}; pub use repeat::{repeat, Repeat};
pub use seek::Seek; pub use seek::Seek;
pub use sink::{sink, Sink}; pub use sink::{sink, Sink};
pub use stderr::{stderr, Stderr};
pub use stdin::{stdin, Stdin};
pub use stdout::{stdout, Stdout};
pub use timeout::timeout;
pub use write::Write; pub use write::Write;
pub mod prelude; pub mod prelude;
@ -45,6 +293,7 @@ pub(crate) mod buf_read;
pub(crate) mod read; pub(crate) mod read;
pub(crate) mod seek; pub(crate) mod seek;
pub(crate) mod write; pub(crate) mod write;
pub(crate) mod utils;
mod buf_reader; mod buf_reader;
mod buf_writer; mod buf_writer;
@ -53,7 +302,29 @@ mod cursor;
mod empty; mod empty;
mod repeat; mod repeat;
mod sink; mod sink;
}
cfg_default! {
// For use in the print macros.
#[doc(hidden)]
#[cfg(not(target_os = "unknown"))]
pub use stdio::{_eprint, _print};
#[cfg(not(target_os = "unknown"))]
pub use stderr::{stderr, Stderr};
#[cfg(not(target_os = "unknown"))]
pub use stdin::{stdin, Stdin};
#[cfg(not(target_os = "unknown"))]
pub use stdout::{stdout, Stdout};
pub use timeout::timeout;
mod timeout;
#[cfg(not(target_os = "unknown"))]
mod stderr; mod stderr;
#[cfg(not(target_os = "unknown"))]
mod stdin; mod stdin;
#[cfg(not(target_os = "unknown"))]
mod stdio;
#[cfg(not(target_os = "unknown"))]
mod stdout; mod stdout;
mod timeout; }

@ -1,4 +1,4 @@
//! The async I/O Prelude //! The async I/O prelude.
//! //!
//! The purpose of this module is to alleviate imports of many common I/O traits //! The purpose of this module is to alleviate imports of many common I/O traits
//! by adding a glob import to the top of I/O heavy modules: //! by adding a glob import to the top of I/O heavy modules:
@ -17,11 +17,11 @@ pub use crate::io::Seek;
#[doc(no_inline)] #[doc(no_inline)]
pub use crate::io::Write; pub use crate::io::Write;
#[doc(hidden)] #[doc(inline)]
pub use crate::io::buf_read::BufReadExt as _; pub use crate::io::buf_read::BufReadExt;
#[doc(hidden)] #[doc(inline)]
pub use crate::io::read::ReadExt as _; pub use crate::io::read::ReadExt;
#[doc(hidden)] #[doc(inline)]
pub use crate::io::seek::SeekExt as _; pub use crate::io::seek::SeekExt;
#[doc(hidden)] #[doc(inline)]
pub use crate::io::write::WriteExt as _; pub use crate::io::write::WriteExt;

@ -32,7 +32,7 @@ impl<T: Read + Unpin> Stream for Bytes<T> {
} }
} }
#[cfg(test)] #[cfg(all(test, default))]
mod tests { mod tests {
use crate::io; use crate::io;
use crate::prelude::*; use crate::prelude::*;

@ -1,10 +1,12 @@
use crate::io::IoSliceMut;
use std::fmt; use std::fmt;
use std::pin::Pin; use std::pin::Pin;
use crate::io::{self, BufRead, Read}; use pin_project_lite::pin_project;
use crate::io::{self, BufRead, IoSliceMut, Read};
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
pin_project! {
/// Adaptor to chain together two readers. /// Adaptor to chain together two readers.
/// ///
/// This struct is generally created by calling [`chain`] on a reader. /// This struct is generally created by calling [`chain`] on a reader.
@ -12,10 +14,13 @@ use crate::task::{Context, Poll};
/// ///
/// [`chain`]: trait.Read.html#method.chain /// [`chain`]: trait.Read.html#method.chain
pub struct Chain<T, U> { pub struct Chain<T, U> {
#[pin]
pub(crate) first: T, pub(crate) first: T,
#[pin]
pub(crate) second: U, pub(crate) second: U,
pub(crate) done_first: bool, pub(crate) done_first: bool,
} }
}
impl<T, U> Chain<T, U> { impl<T, U> Chain<T, U> {
/// Consumes the `Chain`, returning the wrapped readers. /// Consumes the `Chain`, returning the wrapped readers.
@ -98,81 +103,69 @@ impl<T: fmt::Debug, U: fmt::Debug> fmt::Debug for Chain<T, U> {
} }
} }
impl<T: Read + Unpin, U: Read + Unpin> Read for Chain<T, U> { impl<T: Read, U: Read> Read for Chain<T, U> {
fn poll_read( fn poll_read(
mut self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &mut [u8], buf: &mut [u8],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
if !self.done_first { let this = self.project();
let rd = Pin::new(&mut self.first); if !*this.done_first {
match futures_core::ready!(this.first.poll_read(cx, buf)) {
match futures_core::ready!(rd.poll_read(cx, buf)) { Ok(0) if !buf.is_empty() => *this.done_first = true,
Ok(0) if !buf.is_empty() => self.done_first = true,
Ok(n) => return Poll::Ready(Ok(n)), Ok(n) => return Poll::Ready(Ok(n)),
Err(err) => return Poll::Ready(Err(err)), Err(err) => return Poll::Ready(Err(err)),
} }
} }
let rd = Pin::new(&mut self.second); this.second.poll_read(cx, buf)
rd.poll_read(cx, buf)
} }
fn poll_read_vectored( fn poll_read_vectored(
mut self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
bufs: &mut [IoSliceMut<'_>], bufs: &mut [IoSliceMut<'_>],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
if !self.done_first { let this = self.project();
let rd = Pin::new(&mut self.first); if !*this.done_first {
match futures_core::ready!(this.first.poll_read_vectored(cx, bufs)) {
match futures_core::ready!(rd.poll_read_vectored(cx, bufs)) { Ok(0) if !bufs.is_empty() => *this.done_first = true,
Ok(0) if !bufs.is_empty() => self.done_first = true,
Ok(n) => return Poll::Ready(Ok(n)), Ok(n) => return Poll::Ready(Ok(n)),
Err(err) => return Poll::Ready(Err(err)), Err(err) => return Poll::Ready(Err(err)),
} }
} }
let rd = Pin::new(&mut self.second); this.second.poll_read_vectored(cx, bufs)
rd.poll_read_vectored(cx, bufs)
} }
} }
impl<T: BufRead + Unpin, U: BufRead + Unpin> BufRead for Chain<T, U> { impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> { fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
let Self { let this = self.project();
first, if !*this.done_first {
second, match futures_core::ready!(this.first.poll_fill_buf(cx)) {
done_first,
} = unsafe { self.get_unchecked_mut() };
if !*done_first {
let first = unsafe { Pin::new_unchecked(first) };
match futures_core::ready!(first.poll_fill_buf(cx)) {
Ok(buf) if buf.is_empty() => { Ok(buf) if buf.is_empty() => {
*done_first = true; *this.done_first = true;
} }
Ok(buf) => return Poll::Ready(Ok(buf)), Ok(buf) => return Poll::Ready(Ok(buf)),
Err(err) => return Poll::Ready(Err(err)), Err(err) => return Poll::Ready(Err(err)),
} }
} }
let second = unsafe { Pin::new_unchecked(second) }; this.second.poll_fill_buf(cx)
second.poll_fill_buf(cx)
} }
fn consume(mut self: Pin<&mut Self>, amt: usize) { fn consume(self: Pin<&mut Self>, amt: usize) {
if !self.done_first { let this = self.project();
let rd = Pin::new(&mut self.first); if !*this.done_first {
rd.consume(amt) this.first.consume(amt)
} else { } else {
let rd = Pin::new(&mut self.second); this.second.consume(amt)
rd.consume(amt)
} }
} }
} }
#[cfg(test)] #[cfg(all(test, default))]
mod tests { mod tests {
use crate::io; use crate::io;
use crate::prelude::*; use crate::prelude::*;

@ -13,23 +13,21 @@ use read_to_end::{read_to_end_internal, ReadToEndFuture};
use read_to_string::ReadToStringFuture; use read_to_string::ReadToStringFuture;
use read_vectored::ReadVectoredFuture; use read_vectored::ReadVectoredFuture;
use cfg_if::cfg_if;
use std::mem; use std::mem;
use crate::io::IoSliceMut; use crate::io::IoSliceMut;
use crate::utils::extension_trait;
cfg_if! { pub use bytes::Bytes;
if #[cfg(feature = "docs")] { pub use chain::Chain;
pub use take::Take;
extension_trait! {
use std::pin::Pin; use std::pin::Pin;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use crate::io; use crate::io;
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
}
}
extension_trait! {
#[doc = r#" #[doc = r#"
Allows reading from a byte stream. Allows reading from a byte stream.
@ -37,7 +35,7 @@ extension_trait! {
[`std::io::Read`]. [`std::io::Read`].
Methods other than [`poll_read`] and [`poll_read_vectored`] do not really exist in the Methods other than [`poll_read`] and [`poll_read_vectored`] do not really exist in the
trait itself, but they become available when the prelude is imported: trait itself, but they become available when [`ReadExt`] from the [prelude] is imported:
``` ```
# #[allow(unused_imports)] # #[allow(unused_imports)]
@ -46,11 +44,13 @@ extension_trait! {
[`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html [`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
[`futures::io::AsyncRead`]: [`futures::io::AsyncRead`]:
https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncRead.html https://docs.rs/futures/0.3/futures/io/trait.AsyncRead.html
[`poll_read`]: #tymethod.poll_read [`poll_read`]: #tymethod.poll_read
[`poll_read_vectored`]: #method.poll_read_vectored [`poll_read_vectored`]: #method.poll_read_vectored
[`ReadExt`]: ../io/prelude/trait.ReadExt.html
[prelude]: ../prelude/index.html
"#] "#]
pub trait Read [ReadExt: futures_io::AsyncRead] { pub trait Read {
#[doc = r#" #[doc = r#"
Attempt to read from the `AsyncRead` into `buf`. Attempt to read from the `AsyncRead` into `buf`.
"#] "#]
@ -70,7 +70,14 @@ extension_trait! {
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
unreachable!("this impl only appears in the rendered docs") unreachable!("this impl only appears in the rendered docs")
} }
}
#[doc = r#"
Extension methods for [`Read`].
[`Read`]: ../trait.Read.html
"#]
pub trait ReadExt: futures_io::AsyncRead {
#[doc = r#" #[doc = r#"
Reads some bytes from the byte stream. Reads some bytes from the byte stream.
@ -271,7 +278,7 @@ extension_trait! {
This function returns a new instance of `Read` which will read at most This function returns a new instance of `Read` which will read at most
`limit` bytes, after which it will always return EOF ([`Ok(0)`]). Any `limit` bytes, after which it will always return EOF ([`Ok(0)`]). Any
read errors will not count towards the number of bytes read and future read errors will not count towards the number of bytes read and future
calls to [`read()`] may succeed. calls to [`read`] may succeed.
# Examples # Examples
@ -279,7 +286,7 @@ extension_trait! {
[`File`]: ../fs/struct.File.html [`File`]: ../fs/struct.File.html
[`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok
[`read()`]: tymethod.read [`read`]: tymethod.read
```no_run ```no_run
# fn main() -> std::io::Result<()> { async_std::task::block_on(async { # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
@ -298,11 +305,11 @@ extension_trait! {
# Ok(()) }) } # Ok(()) }) }
``` ```
"#] "#]
fn take(self, limit: u64) -> take::Take<Self> fn take(self, limit: u64) -> Take<Self>
where where
Self: Sized, Self: Sized,
{ {
take::Take { inner: self, limit } Take { inner: self, limit }
} }
#[doc = r#" #[doc = r#"
@ -374,8 +381,8 @@ extension_trait! {
# Ok(()) }) } # Ok(()) }) }
``` ```
"#] "#]
fn bytes(self) -> bytes::Bytes<Self> where Self: Sized { fn bytes(self) -> Bytes<Self> where Self: Sized {
bytes::Bytes { inner: self } Bytes { inner: self }
} }
#[doc = r#" #[doc = r#"
@ -410,8 +417,8 @@ extension_trait! {
# Ok(()) }) } # Ok(()) }) }
``` ```
"#] "#]
fn chain<R: Read>(self, next: R) -> chain::Chain<Self, R> where Self: Sized { fn chain<R: Read>(self, next: R) -> Chain<Self, R> where Self: Sized {
chain::Chain { first: self, second: next, done_first: false } Chain { first: self, second: next, done_first: false }
} }
} }
@ -470,13 +477,13 @@ unsafe fn initialize<R: futures_io::AsyncRead>(_reader: &R, buf: &mut [u8]) {
std::ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) std::ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len())
} }
#[cfg(test)] #[cfg(all(test, not(target_os = "unknown")))]
mod tests { mod tests {
use crate::io; use crate::io;
use crate::prelude::*; use crate::prelude::*;
#[test] #[test]
fn test_read_by_ref() -> io::Result<()> { fn test_read_by_ref() {
crate::task::block_on(async { crate::task::block_on(async {
let mut f = io::Cursor::new(vec![0u8, 1, 2, 3, 4, 5, 6, 7, 8]); let mut f = io::Cursor::new(vec![0u8, 1, 2, 3, 4, 5, 6, 7, 8]);
let mut buffer = Vec::new(); let mut buffer = Vec::new();
@ -486,14 +493,13 @@ mod tests {
let reference = f.by_ref(); let reference = f.by_ref();
// read at most 5 bytes // read at most 5 bytes
assert_eq!(reference.take(5).read_to_end(&mut buffer).await?, 5); assert_eq!(reference.take(5).read_to_end(&mut buffer).await.unwrap(), 5);
assert_eq!(&buffer, &[0, 1, 2, 3, 4]) assert_eq!(&buffer, &[0, 1, 2, 3, 4])
} // drop our &mut reference so we can use f again } // drop our &mut reference so we can use f again
// original file still usable, read the rest // original file still usable, read the rest
assert_eq!(f.read_to_end(&mut other_buffer).await?, 4); assert_eq!(f.read_to_end(&mut other_buffer).await.unwrap(), 4);
assert_eq!(&other_buffer, &[5, 6, 7, 8]); assert_eq!(&other_buffer, &[5, 6, 7, 8]);
Ok(()) });
})
} }
} }

@ -1,6 +1,6 @@
use std::pin::Pin; use std::pin::Pin;
use std::future::Future;
use crate::future::Future;
use crate::io::{self, Read}; use crate::io::{self, Read};
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};

@ -1,7 +1,7 @@
use std::mem; use std::mem;
use std::pin::Pin; use std::pin::Pin;
use std::future::Future;
use crate::future::Future;
use crate::io::{self, Read}; use crate::io::{self, Read};
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};

@ -1,6 +1,6 @@
use std::pin::Pin; use std::pin::Pin;
use std::future::Future;
use crate::future::Future;
use crate::io::{self, Read}; use crate::io::{self, Read};
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};

@ -1,9 +1,9 @@
use std::mem; use std::mem;
use std::pin::Pin; use std::pin::Pin;
use std::str; use std::str;
use std::future::Future;
use super::read_to_end_internal; use super::read_to_end_internal;
use crate::future::Future;
use crate::io::{self, Read}; use crate::io::{self, Read};
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
@ -37,7 +37,11 @@ impl<T: Read + Unpin + ?Sized> Future for ReadToStringFuture<'_, T> {
)) ))
})) }))
} else { } else {
#[allow(clippy::debug_assert_with_mut_call)]
{
debug_assert!(buf.is_empty()); debug_assert!(buf.is_empty());
}
// Safety: `bytes` is a valid UTF-8 because `str::from_utf8` returned `Ok`. // Safety: `bytes` is a valid UTF-8 because `str::from_utf8` returned `Ok`.
mem::swap(unsafe { buf.as_mut_vec() }, bytes); mem::swap(unsafe { buf.as_mut_vec() }, bytes);
Poll::Ready(ret) Poll::Ready(ret)

@ -1,6 +1,6 @@
use std::pin::Pin; use std::pin::Pin;
use std::future::Future;
use crate::future::Future;
use crate::io::{self, IoSliceMut, Read}; use crate::io::{self, IoSliceMut, Read};
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};

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

Loading…
Cancel
Save