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
2020-07-14 10:40:40 +02:00
Jonathas-Conceicao
cd7fb9dec2 channel doc: Fix misleading reference to None return on Receiver
Signed-off-by: Jonathas-Conceicao <jonathas.conceicao@ossystems.com.br>
2020-07-13 10:52:44 -03:00
Yoshua Wuyts
c82b1efb69
fix(stream): add send guards on collect
Closes #639 

Co-authored-by: dignifiedquire <me@dignifiedquire.com>
2020-06-27 16:46:14 +02:00
Friedel Ziegelmayer
8c4b425136
Merge pull request #826 from thibault-martinez/kv-log-macro-1.0.6
Update kv-log-macro to 1.0.6
2020-06-27 15:25:26 +02:00
Thibault Martinez
2ab08ebbbc Update kv-log-macro to 1.0.6 2020-06-27 14:23:54 +02:00
Friedel Ziegelmayer
0e7650a421
Merge pull request #822 from async-rs/async-extern-1 2020-06-26 16:43:49 +02:00
dignifiedquire
8f17e9275b test: try to stabilize CI 2020-06-26 12:48:23 +02:00
dignifiedquire
18dffe8b43 refactor: switch to async-mutex for Mutex implementation 2020-06-26 10:30:58 +02:00
Friedel Ziegelmayer
43de93312c
Merge pull request #825 from nbdd0121/master
Fix unused_mut warning in nightly
2020-06-25 19:02:28 +02:00
Gary Guo
2e7e804736 Fix unused_mut warning in nightly 2020-06-25 17:44:39 +01:00
Friedel Ziegelmayer
17ab958ac2
Merge pull request #820 from zhaxzhax/docs-#815 2020-06-21 21:36:09 +02:00
Friedel Ziegelmayer
caa76af745
Merge pull request #821 from async-rs/1-6-2
chore: release v1.6.2
2020-06-19 12:52:36 +02:00
dignifiedquire
e495ba46b3 chore: release v1.6.2 2020-06-19 12:15:42 +02:00
Afirez
0c2ce52ac4 fix doc missing in #815 2020-06-18 20:30:11 +08:00
Friedel Ziegelmayer
5f418f07ac
Merge pull request #819 from async-rs/fix-sockets 2020-06-18 13:58:18 +02:00
dignifiedquire
06a2fb8c4f fix export 2020-06-18 13:10:37 +02:00
dignifiedquire
1c1c168e1b fix(timer): ensure the runtime is working for timers 2020-06-18 12:37:14 +02:00
Friedel Ziegelmayer
5d55fa7a47
Merge pull request #701 from olegnn/flat_map_fixed 2020-06-18 12:18:47 +02:00
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
2020-06-18 12:11:37 +02:00
Oleg Nosov
42425f6c1a
Another hotfix 2020-06-14 18:42:18 +03:00
Yoshua Wuyts
a602a91d83
Merge pull request #816 from zhaxzhax/add-udpscket-peeraddr
Add UdpSocket::PeerAddr #307
2020-06-14 15:26:48 +02:00
Afirez
9fa3ce3fd6 Add UdpSocket::PeerAddr #307 2020-06-14 18:45:27 +08:00
Oleg Nosov
df22d87d09
Removed unnecessary links + hotfix 2020-06-12 18:21:16 +03:00
Oleg Nosov
924e5a3f41
Merge remote-tracking branch 'origin/master' into flat_map_fixed 2020-06-12 18:13:01 +03:00
Oleg Nosov
2323ac9a8e
Apply suggestions from code review
Co-authored-by: nasa <htilcs1115@gmail.com>
2020-06-12 18:03:07 +03:00
Friedel Ziegelmayer
5c2a3de9e7
Merge pull request #814 from async-rs/1-6-1
chore: release v1.6.1
2020-06-11 19:44:40 +02:00
dignifiedquire
e9c6ea873c chore: release v1.6.1 2020-06-11 13:17:31 +02:00
Friedel Ziegelmayer
0d98aac8f7
Merge pull request #812 from thibault-martinez/gh-actions-cache-v2 2020-06-09 12:55:06 +02:00
Thibault Martinez
4555f193a5 ci: update actions/cache to v2 2020-06-07 18:15:43 +02:00
Yoshua Wuyts
61fc2bae72
Merge pull request #809 from async-rs/fix/recursive-block-2
fix(rt): use task::block_on on spawned threads
2020-06-07 10:37:28 +02:00
dignifiedquire
5a1a681d68 fix(rt): use task::block_on on spawned threads
This makes sure to capture threads into the recursive block_on detection.
2020-06-04 18:25:07 +02:00
Friedel Ziegelmayer
e12cf80ab0
fix: allow for recursive block-on calls
Fixes #798,#795,#760
2020-06-04 13:19:03 +02:00
Friedel Ziegelmayer
631105b650
Merge pull request #806 from async-rs/fix-feature-unstable 2020-06-04 12:23:32 +02:00
Friedel Ziegelmayer
0897b9184a
Merge pull request #804 from async-rs/tokio02-feature 2020-06-04 12:23:12 +02:00
Friedel Ziegelmayer
6ca7b0977c
Merge pull request #807 from xfix/remove-stdio-lock-methods
Remove stdio lock methods
2020-06-04 12:22:23 +02:00
Konrad Borowski
721760a7a6 Remove stdio lock methods
Fixes #805.
2020-06-04 09:05:14 +02:00
dignifiedquire
8389041414 fix 2020-06-03 18:50:12 +02:00
dignifiedquire
8943ba82dd fix nostd 2020-06-03 18:43:19 +02:00
dignifiedquire
52c72426c1 fix: do not require the runtime to use unstable features 2020-06-03 18:38:20 +02:00
Yoshua Wuyts
0df3c02b81 check tokio02 features 2020-06-03 12:40:02 +02:00
Yoshua Wuyts
166c469d1c Add the tokio02 feature flag 2020-06-03 12:09:33 +02:00
Friedel Ziegelmayer
0ec027dbff
Merge pull request #802 from jerry73204/fix-reading-buf-bug 2020-05-29 13:32:48 +02:00
jerry73204
d60e7cc27d Fix wrong slice index when reading a file 2020-05-29 19:18:06 +08:00
Friedel Ziegelmayer
6d2a43e336
Merge pull request #794 from async-rs/1-6-0 2020-05-22 23:19:41 +02:00
dignifiedquire
e1c8638173 chore: release v1.6.0 2020-05-22 23:08:42 +02:00
dignifiedquire
06eea4225b feat: add PartialEq and Eq for channel Errors
Closes #792
2020-05-22 22:08:23 +02:00
Friedel Ziegelmayer
252140839b
Merge pull request #791 from Licenser/patch-1 2020-05-22 16:46:32 +02:00
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`
2020-05-20 14:24:06 +02:00
Friedel Ziegelmayer
955befd746
Merge pull request #790 from async-rs/1-6-0-beta-2 2020-05-20 11:18:38 +02:00
nasa
70dac51938
Merge pull request #729 from k-nasa/fix_doc_test
Fix doc test
2020-05-20 15:33:29 +09:00
k-nasa
d30603affe Merge branch 'master' into fix_doc_test 2020-05-20 13:50:39 +09:00
dignifiedquire
c9ecb5bbbd prepare v1.6.0-beta.2 2020-05-19 11:29:36 +02:00
Jacob Rothstein
9e6a76af04
feat: add env vars to configure the runtime threadpool size and name 2020-05-19 11:16:01 +02:00
Friedel Ziegelmayer
2b6c7fedff
Merge pull request #772 from jbr/unixstream-clone 2020-05-13 18:03:47 +02:00
Friedel Ziegelmayer
b3277954c7
Merge pull request #776 from azriel91/bugfix/775/wasm-timer-delay 2020-05-13 18:03:04 +02:00
Azriel Hoh
baead51a28 Reduces duration in timeout test.
Tries to get CI to pass.
2020-05-13 10:38:40 +12:00
Azriel Hoh
e9621af345 Updates CHANGELOG.md. 2020-05-13 10:37:19 +12:00
Azriel Hoh
d3e59370e7 Switches wasm-timer for futures-timer. 2020-05-13 10:14:05 +12:00
Jacob Rothstein
cd5e17fe87
make UnixStream Clone 2020-05-10 18:21:45 -07:00
Friedel Ziegelmayer
e20b0f0d75
Merge pull request #768 from async-rs/fix/file-block
fix(fs): use smol::block_on for drop handling of File
2020-05-09 16:28:10 +02:00
dignifiedquire
19170aead4 use local file 2020-05-09 11:44:16 +02:00
dignifiedquire
2762ec5800 fix(fs): use smol::block_on for drop handling of File
Ref #766
2020-05-09 11:36:13 +02:00
dignifiedquire
247c94ca06 docs(changelog): add missing link 2020-05-07 23:34:49 +02:00
Friedel Ziegelmayer
e404dcdd03
Merge pull request #765 from async-rs/feat/1-6-0 2020-05-07 23:32:47 +02:00
dignifiedquire
bd6a7e200b prepare v1.6.0-beta.1 2020-05-07 23:20:56 +02:00
Friedel Ziegelmayer
e4c4c93d29
Test and fix 32 bit targets 2020-05-07 23:20:44 +02:00
Thayne McCombs
6f6fced103
feat: implement Barrier using Condvar 2020-05-07 22:26:46 +02:00
Friedel Ziegelmayer
10f7abb3b6
Merge pull request #757 from dignifiedquire/feat/smol 2020-05-07 21:21:11 +02:00
dignifiedquire
27c605b4c9 cr: bring back trace call 2020-05-07 20:56:52 +02:00
dignifiedquire
faea222b9c fix: use run instead of block_on 2020-05-02 20:27:50 +02:00
dignifiedquire
1214bc2dee increase timeouts 2020-05-02 20:27:50 +02:00
dignifiedquire
26f62aafd9 make wasm deps part of std 2020-05-02 20:27:50 +02:00
dignifiedquire
e0928463b1 fix windows traits 2020-05-02 20:27:50 +02:00
dignifiedquire
92532612b7 mark spawn_local unstable 2020-05-02 20:27:50 +02:00
dignifiedquire
1a6d4f6a2f fix windows trait declarations for rawsocket 2020-05-02 20:27:50 +02:00
dignifiedquire
7a9afbd81c update smol 2020-05-02 20:27:50 +02:00
dignifiedquire
280b1a4344 remove invalid doc comment 2020-05-02 20:27:50 +02:00
dignifiedquire
48dd683535 fix feature settings 2020-05-02 20:27:50 +02:00
dignifiedquire
804a52b7fd use published smol 2020-05-02 20:27:50 +02:00
dignifiedquire
e4df1405c1 feat: add basic wasm support 2020-05-02 20:27:50 +02:00
dignifiedquire
2cd2ba3530 remove unused dependencies 2020-05-02 20:27:50 +02:00
dignifiedquire
3161a4e449 add some missing windows imports 2020-05-02 20:27:50 +02:00
dignifiedquire
228cc59b3b feat: add spawn_local 2020-05-02 20:27:50 +02:00
dignifiedquire
0a7a52aed5 update to work on smol/master 2020-05-02 20:27:50 +02:00
dignifiedquire
10c8b9a6d8 silence must use 2020-05-02 20:27:50 +02:00
dignifiedquire
fd6ae40817 add timeout stress test 2020-05-02 20:27:50 +02:00
dignifiedquire
ab9d6554aa switch to smol::Timer 2020-05-02 20:27:50 +02:00
dignifiedquire
f5fa0d7e4e avoid boxing futures 2020-05-02 20:27:50 +02:00
dignifiedquire
b96afc41dc implement task locals 2020-05-02 20:27:50 +02:00
dignifiedquire
75ab7219df bring back random 2020-05-02 20:27:50 +02:00
dignifiedquire
e082634b5e fix spawning 2020-05-02 20:27:50 +02:00
dignifiedquire
fc9ee0dfdd keep std::sync::Arc 2020-05-02 20:27:50 +02:00
dignifiedquire
1308fbdf55 switch to smol instead of an internal runtime 2020-05-02 20:27:50 +02:00
dignifiedquire
690ab16587 add dependency 2020-05-02 20:27:50 +02:00
Florian Gilcher
370642ef3e
Merge pull request #734 from sunli829/master
Add async-graphql to the ecosystems inside the readme
2020-04-28 13:17:52 +02:00
Sunli
100c3423c1
Apply suggestions from code review
Thank you.😁

Co-Authored-By: Friedel Ziegelmayer <me@dignifiedquire.com>
2020-04-27 13:49:53 +08:00
nasa
7999e6bf4b
ci: speed up github actions 2020-04-26 18:23:09 +02:00
Fangdun Cai
e707ea96e0
docs(readme): add ci status badge 2020-04-26 18:18:21 +02:00
Friedel Ziegelmayer
b446cd0230
Merge pull request #748 from async-rs/fix/scheduler-2
fix(rt): bring back dynamic machines
2020-04-12 15:22:51 +02:00
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
2020-04-12 13:35:18 +02:00
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
2020-04-10 02:22:03 +02:00
Yoshua Wuyts
aebba2bd95
Merge pull request #747 from async-rs/fix/scheduler-perf
Fix new scheduler loop
2020-04-09 17:26:46 +02:00
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
2020-04-09 17:02:27 +02:00
Friedel Ziegelmayer
fc4e472599
Merge pull request #733 from k-nasa/new-scheduler
New scheduler
2020-04-07 22:50:04 +02:00
nasa
6674dc0edf
Merge pull request #739 from devashishdxt/futures-timer-update
Update futures-timer to 3.0.2
2020-04-03 13:41:12 +09:00
k-nasa
088aa5662c refactor: Remove wrapping cell 2020-04-03 13:38:07 +09:00
Devashish Dixit
68fa054517 Update futures-timer to 3.0.2 2020-03-30 19:30:00 +08:00
k-nasa
b88138b5d7 kick ci 2020-03-27 17:03:16 +09:00
k-nasa
11ee2a8985 fix 2020-03-22 19:25:40 +09:00
k-nasa
322911142c lock processor and remove unsafe Send, Sync 2020-03-22 19:20:01 +09:00
k-nasa
cfaec2aa95 re add spin_lock 2020-03-22 19:19:17 +09:00
sunli
57c648cf01 Add async-graphql to the ecosystems inside the readme 2020-03-21 15:49:15 +08:00
k-nasa
6d3ca5a06f remove poll function 2020-03-21 14:19:38 +09:00
k-nasa
f960776846 fix 2020-03-21 13:40:59 +09:00
k-nasa
5c6741724f Merge branch 'master' into new-scheduler 2020-03-20 23:17:12 +09:00
k-nasa
24c5dbf949 Remove scheduler state 2020-03-20 23:13:20 +09:00
nasa
2dbebe54ed
Merge pull request #721 from k-nasa/update_dep_crate
update dependence crates
2020-03-20 12:33:56 +09:00
k-nasa
d7ee29a03f fix test code 2020-03-19 19:16:12 +09:00
k-nasa
2b44c1be2e refactor: swap to swap_and_compare 2020-03-19 18:41:00 +09:00
k-nasa
b1ec1ea930 Move Spinlock to sync module 2020-03-19 18:39:01 +09:00
k-nasa
2ab075d027 refactor 2020-03-19 11:50:19 +09:00
k-nasa
c0f18600cf run ignored test 2020-03-18 23:07:07 +09:00
k-nasa
6c8237276b fix doc test 2020-03-18 23:02:59 +09:00
k-nasa
98cbf7f8eb Restore task::spawn_blocking 2020-03-17 20:54:16 +09:00
k-nasa
84e5c5f351 Merge branch 'master' into new-scheduler 2020-03-17 20:38:19 +09:00
Yoshua Wuyts
3ff9e98f20
Merge pull request #585 from async-rs/try_channels
expose try_recv and try_send on channels
2020-03-16 02:38:00 +01:00
Yoshua Wuyts
b7c7efc797 Update try_channel doctests 2020-03-16 00:05:39 +01:00
Yoshua Wuyts
19fd7a4084 fix channel tests
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2020-03-15 23:53:03 +01:00
Yoshua Wuyts
7885c245c5 recverror
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2020-03-15 23:53:03 +01:00
Yoshua Wuyts
7b7b959a6e mark channel errs as unstable
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2020-03-15 23:53:03 +01:00
Yoshua Wuyts
32dce319d3 expose try_recv and try_send on channels
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2020-03-15 23:53:03 +01:00
Yoshua Wuyts
49dd02b4de Make the split struct public 2020-03-15 23:51:19 +01:00
Yoshua Wuyts
bb11c676a1 doctests pass 2020-03-15 23:46:36 +01:00
Yoshua Wuyts
e026b7579a
Merge pull request #703 from spacekookie/recv-docs
channel/recv: improving function docs and code example
2020-03-15 14:41:07 +01:00
Yoshua Wuyts
51dd7ceb72
Merge pull request #727 from async-rs/revert-719-remove_re_export
Revert "Stabilize most stream method and remove unnecessary macros"
2020-03-15 13:27:39 +01:00
k-nasa
8931d1464e fix ci 2020-03-14 22:46:22 +09:00
nasa
cc19592f80
Revert "Stabilize most stream method and remove unnecessary macros" 2020-03-12 18:34:09 +09:00
nasa
f69887a50d
Update Cargo.toml 2020-03-09 09:09:17 +09:00
k-nasa
0b0531057d feat: update dependence crates 2020-03-08 20:46:26 +09:00
Yoshua Wuyts
61f9483cc5
Merge pull request #719 from k-nasa/remove_re_export
Stabilize most stream method and remove unnecessary macros
2020-03-06 14:31:06 +01:00
k-nasa
f33d7f40ab fix test 2020-03-06 09:53:28 +09:00
k-nasa
e3bf89fc05 $cargo fmt 2020-03-05 18:49:58 +09:00
k-nasa
ec4b09ecd0 fix test code 2020-03-05 18:47:53 +09:00
k-nasa
b95bd6c1fe fix: Remove unnecessary io modules 2020-03-05 10:34:41 +09:00
k-nasa
1e18839f1f fix warning 2020-03-04 08:55:37 +09:00
k-nasa
f31878655e fix: Stabilize stream method 2020-03-04 08:30:45 +09:00
k-nasa
9a62df143f add whitespace 2020-03-03 23:14:25 +09:00
k-nasa
75223905bd fix: Stabilize stream most method 2020-03-03 23:12:09 +09:00
k-nasa
be60dd9fe7 fix: Remove unnecessary re-export and macros 2020-03-03 22:50:26 +09:00
k-nasa
23b7c174f3 feat: Stabilize io::Std*Lock 2020-03-03 22:46:18 +09:00
Yoshua Wuyts
9167d42f4b
Merge pull request #708 from sunli829/master
Add Xactor to the ecosystems inside the readme
2020-03-02 13:20:14 +01:00
Yoshua Wuyts
4034d58709
Merge pull request #714 from abhijeetbhagat/patch-1
Add missing ? operator after handle.await
2020-03-02 13:11:15 +01:00
abhi
4742f461fe
Add missing ? operator after handle.await
According to line#118, there should be a `?` operator after `await`.
2020-02-22 15:17:06 +05:30
nasa
efab39eeaf
Merge pull request #710 from k-nasa/fix_ci_failed
Fixed ci failing
2020-02-20 09:33:44 +09:00
k-nasa
bd60cd9f81 run cargo fmt 2020-02-20 09:03:36 +09:00
sunli
b9e4b6da3e Add Xactor to the ecosystems inside the readme 2020-02-19 14:36:07 +08:00
Yoshua Wuyts
eb03f37e43
Merge pull request #697 from async-rs/core-docs
Document the core feature
2020-02-17 13:38:39 +01:00
Yoshua Wuyts
d87e283215
Update src/lib.rs 2020-02-17 13:38:24 +01:00
Yoshua Wuyts
283a54a155
Update src/lib.rs 2020-02-17 13:36:59 +01:00
Yoshua Wuyts
3719484eba
Update src/lib.rs
Co-Authored-By: nasa <htilcs1115@gmail.com>
2020-02-17 13:36:23 +01:00
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).
2020-02-12 01:38:20 +01:00
Oleg Nosov
68063adddf
Add link to tests 2020-02-08 16:22:11 +03:00
Oleg Nosov
d7cab38b67
core => std 2020-02-08 15:49:01 +03:00
Oleg Nosov
32068942a6
Fixed flatten 2020-02-08 15:44:25 +03:00
Oleg Nosov
85c32ef9d2
Use assert without if-clause 2020-02-07 22:45:15 +03:00
Oleg Nosov
b68be72763
Use assert instead of panic 2020-02-07 22:42:59 +03:00
Oleg Nosov
c80915e216
Dont spawn thread in tests 2020-02-07 22:22:38 +03:00
Oleg Nosov
303ac90b7c
Fixed flat_map 2020-02-07 22:12:42 +03:00
Yoshua Wuyts
d026c44ea3 Document the core feature
Follow-up to https://github.com/async-rs/async-std/pull/680
2020-02-04 11:07:50 +01:00
Yoshua Wuyts
125fa5b0a0
Merge pull request #680 from k-nasa/no_std
Some modules support no_std
2020-02-04 11:02:19 +01:00
Yoshua Wuyts
39f2c6da78
V1.5.0 (#694)
* Update CHANGELOG.md

* v1.5.0

* Update CHANGELOG.md
2020-02-03 16:45:00 +01:00
k-nasa
3e24e0ba4e ci: fix no-std check 2020-02-01 16:45:59 +09:00
k-nasa
0d90cb07b9 fix: Move extern crate alloc to lib.rs 2020-02-01 09:49:54 +09:00
k-nasa
f789f9d4f6 Select future-core featue according to feature 2020-02-01 09:47:33 +09:00
k-nasa
ef985bc72e ci: fix no_std ci 2020-02-01 09:45:41 +09:00
Stjepan Glavina
1d875836a2
Implement Clone for TcpStream (#689)
* Implement Clone for TcpStream

* Update examples

* Remove accidentally added examples
2020-01-28 18:14:16 +01:00
k-nasa
7efe7caf66 fix: Change feature name no-std to alloc 2020-01-28 15:58:46 +09:00
k-nasa
22d929d481 fix import Future 2020-01-28 15:58:46 +09:00
k-nasa
d622ec5d35 feat: Make the stream module no_std 2020-01-28 15:58:46 +09:00
k-nasa
880b7ee987 remove crate::prelude import 2020-01-28 15:58:46 +09:00
k-nasa
1762de285b feat: Make the future module no_std 2020-01-28 15:58:46 +09:00
k-nasa
6aa55fde59 feat: Make the task module no_std 2020-01-28 15:58:46 +09:00
k-nasa
41f114d9fe ci: Add no-std check 2020-01-28 15:58:46 +09:00
k-nasa
3d32fd81f4 feat: Make the utils module no_std 2020-01-28 15:58:46 +09:00
k-nasa
51b84a7620 feat: Add no_std attribute when not std feature 2020-01-28 15:58:46 +09:00
k-nasa
4996f29778 feat: Add no-std feature 2020-01-28 15:58:46 +09:00
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.
2020-01-27 23:13:13 +01:00
Yoshua Wuyts
57f9fb7e93
Merge pull request #682 from k-nasa/impl_clone_for_dir_entry
Implement Clone trait for DirEntry
2020-01-27 13:10:20 +01:00
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`
2020-01-27 11:54:20 +01:00
Yoshua Wuyts
beb8d240c2
Merge pull request #688 from ninj/patch-1
fix syntax problem for task::sleep
2020-01-25 23:40:43 +01:00
ninj
b258215952
fix syntax problem for task::sleep 2020-01-25 22:13:26 +00:00
Florian Gilcher
1ababac97f
Merge branch 'accept_loop_pattern' 2020-01-22 12:47:41 +01:00
Florian Gilcher
f9fe5c90cf
Fix some typos in accept-loop pattern chapter 2020-01-22 12:47:18 +01:00
Florian Gilcher
84fe94444b
Merge pull request #675 from k-nasa/add_timeout_example
Add stream::timeout example when timeout error
2020-01-21 16:02:28 +01:00
Florian Gilcher
cad2880eb8
Merge pull request #550 from sclaire-1/master
Edit tutorial: implementing_a_client.md
2020-01-21 15:44:44 +01:00
Taiki Endo
6b860c370a Remove usage of unstable format_code_in_doc_comments option (#685) 2020-01-20 21:41:48 +01:00
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.
2020-01-20 20:40:01 +01:00
k-nasa
2221441a4c feat: Implement Clone trait for DirEntry 2020-01-18 08:36:54 +09:00
Oleg Nosov
ed7ddacb28
Rewrote Results implementation using take_while and filter_map 2020-01-17 17:19:51 +03:00
nasa
d283352a9a update broadcastor to 1.0.0 (#681) 2020-01-16 13:07:11 -05:00
Oleg Nosov
ed248017b4
Use internal scan state in Results implementation 2020-01-15 12:06:50 +03:00
Yoshua Wuyts
0eb5ca14ac
Merge pull request #676 from k-nasa/async_task_bump_to1.2.1
update async-task to 1.2.1
2020-01-15 08:09:19 +01:00
Oleg Nosov
38de0bfd22
Use std::convert::identity 2020-01-15 09:43:01 +03:00
Oleg Nosov
134089af2c
Use filter_map(identity) + other fixes 2020-01-15 08:57:43 +03:00
k-nasa
b72dd83726 update async-task to 1.2.1 2020-01-15 11:00:03 +09:00
k-nasa
ee102dfc9e docs: Add stream::timeout example when timeout error 2020-01-15 10:41:39 +09:00
nasa
1071e82132
Merge pull request #671 from Noah-Kennedy/udp-socket-send-doc
Fix docs for UdpSocket::send
2020-01-15 10:41:04 +09:00
noah
0a52864764 Revert "Fixes https://github.com/async-rs/async-std/issues/652"
This reverts commit a4f68066
2020-01-14 10:59:17 -06:00
noah
76993dd755 Revert "Fixes https://github.com/async-rs/async-std/issues/652"
This reverts commit a4f68066
2020-01-14 10:55:10 -06:00
Yoshua Wuyts
133e30e6f6
Merge pull request #615 from lqf96/pending-stream
Add an implementation of pending stream
2020-01-14 15:58:27 +01:00
nasa
76ed174fd5 Version up of dependent crate (#672) 2020-01-14 15:26:22 +01:00
k-nasa
f53fcbb706 test,docs: Add stream::pending example code 2020-01-14 10:18:14 +09:00
k-nasa
e9357c0307 style: Run cargo fmt 2020-01-14 09:49:34 +09:00
Qifan Lu
879e14c6ab Remove size_hint from Stream impl 2020-01-14 09:41:43 +09:00
Qifan Lu
f8dd3d9816 Add stream::pending::{pending, Pending} 2020-01-14 09:41:43 +09:00
noah
a4f6806605 Fixes https://github.com/async-rs/async-std/issues/652 2020-01-13 17:47:51 -06:00
Yoshua Wuyts
5d5064b871 add FromStream Result example (#643)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2020-01-13 21:42:31 +01:00
nasa
0ed0d63094 Remove unnecessary trait bound on FlatMap (#651)
* Remove unnecessary trait bound on FlatMap

* test: upgrade test code
2020-01-13 19:49:52 +01:00
Paul Colomiets
0029037883 async-listen crate: Add error_hint() invocation 2020-01-13 08:46:32 +02:00
Oleg Nosov
fb567a3a09
Recovered comments 2020-01-12 17:53:16 +03:00
Oleg Nosov
83afbab2ef
Use take_while instead of scan for Option 2020-01-12 17:35:57 +03:00
Paul Colomiets
c8c075615c book: Add Production-ready Accept Loop section
Part of the #658 work
2020-01-12 03:47:37 +02:00
Yoshua Wuyts
98d45f4be1
Merge pull request #647 from dignifiedquire/feat/unstable-without-default
feat: do not require default feature for unstable
2020-01-11 12:24:00 +01:00
dignifiedquire
9c6ab5e7c3 fix 2020-01-11 11:57:42 +01:00
dignifiedquire
9c9ab90da3 feature gate random 2020-01-11 11:49:52 +01:00
dignifiedquire
5bf3d95313 feat: do not require default feature for unstable 2020-01-11 11:44:51 +01:00
Yoshua Wuyts
1f78efec64
Merge pull request #660 from mehcode/mehcode-ecosystem
Showcase the ecosystem
2020-01-10 13:20:30 +01:00
Yoshua Wuyts
383057b8ea
Merge pull request #659 from alfiedotwtf/master
Tiny grammar fix
2020-01-07 17:09:49 +01:00
Yoshua Wuyts
763862acc7
Merge pull request #661 from async-rs/fix-ci
remove usage of deprecated Error method to fix CI
2020-01-07 17:09:03 +01:00
Yoshua Wuyts
e2bb79c207
Merge pull request #648 from spacekookie/master
Fixing inaccurate function description in udp::recv
2020-01-07 14:23:14 +01:00
Yoshua Wuyts
57a62797f2
Merge pull request #655 from u32i64/patch-1
Fix crate documentation typo
2020-01-07 14:22:52 +01:00
Yoshua Wuyts
dfb0c8124c
remove usage of deprecated method
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2020-01-07 14:21:17 +01:00
Ryan Leckey
d806a09599 Add a section on the async ecosystem to showcase crates that use async-std 2020-01-06 23:17:13 -08:00
Alfie John
af2d46d9b9 Tiny grammar fix 2020-01-07 13:29:30 +11:00
Artem Varaksa
65d7950df1
Fix crate documentation typo 2020-01-01 15:36:47 +03:00
nasa
6d69a3e368
Merge pull request #650 from senden9/patch-1
Fix typo in stream documentation
2019-12-29 14:41:56 +09:00
Stefano Probst
c3d5dba1b5
Fix typo in stream documentation 2019-12-28 17:27:37 +01:00
Katharina Fey
081166f204
Fixing inaccurate function description in udp::recv 2019-12-27 03:06:41 +01:00
Yoshua Wuyts
fee3b6f603
Merge pull request #645 from async-rs/remove-tokio-mention
update stream::Interval internal comments left over from migration
2019-12-24 15:05:39 +01:00
Yoshua Wuyts
b3942ecfa8
remove tokio mention
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-12-24 14:39:55 +01:00
Yoshua Wuyts
86d3d74180
Merge pull request #637 from async-rs/v1.4.0
1.4.0
2019-12-20 16:30:45 +01:00
Yoshua Wuyts
3fd6d8b02e
1.4.0
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-12-20 11:58:32 +01:00
nasa
0d4b4cd260
Merge pull request #600 from miker1423/future-timeout
Adding timeout extension method to Future trait
2019-12-20 14:26:52 +09:00
Miguel Pérez García
ef021dcb2b Changing test condition 2019-12-18 07:18:57 -06:00
Miguel Pérez García
eedf1d3367 Fixing docs 2019-12-17 23:17:02 -06:00
Miguel Pérez García
97b4901b75 Fixing tests 2019-12-17 23:12:09 -06:00
Miguel Pérez García
1eeb1019e9 Fixing example 2019-12-17 23:05:06 -06:00
Miguel Pérez García
980a1f7834 Correcting docs on function 2019-12-17 22:46:25 -06:00
nasa
d2c25f483a
Merge pull request #635 from async-rs/revert-629-update-log
Revert "upgrade log, remove kv-log-macro"
2019-12-18 08:30:56 +09:00
nasa
d8befe24e8
Revert "upgrade log, remove kv-log-macro" 2019-12-18 08:01:09 +09:00
Florian Gilcher
c7cf1934db
Merge pull request #629 from async-rs/update-log
upgrade log, remove kv-log-macro
2019-12-17 22:05:51 +01:00
Yoshua Wuyts
37d8a013de
Merge pull request #633 from k-nasa/fix_io_export
fix missing export for the return value
2019-12-17 16:52:59 +01:00
k-nasa
43f4f393af fix missing export for the return value 2019-12-17 22:48:14 +09:00
Stjepan Glavina
ceba324bef Fix feature flags 2019-12-16 15:53:31 +01:00
Stjepan Glavina
36d24cd0e1 New scheduler resilient to blocking 2019-12-16 13:57:27 +01:00
Yoshua Wuyts
61eb52cb36
Merge pull request #625 from nbdd0121/sync_unsized
Use ?Sized in Mutex and RwLock
2019-12-16 12:01:45 +01:00
Yoshua Wuyts
6f4dcad6a0
Merge pull request #630 from async-rs/fix-ci-2
fix ci
2019-12-16 11:41:07 +01:00
Yoshua Wuyts
60de8e1082
up time limits
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-12-16 11:29:21 +01:00
Yoshua Wuyts
cac4e081cc
Merge pull request #628 from fenhl/patch-1
Make WriteFmtFuture must_use
2019-12-16 11:22:30 +01:00
Yoshua Wuyts
8ad1d23116
fix ci
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-12-16 10:43:19 +01:00
Yoshua Wuyts
019aa14898
Merge pull request #621 from async-rs/fix-doc-hiccup
fix stream doc hiccup
2019-12-16 10:38:36 +01:00
Yoshua Wuyts
b7e55762d8
upgrade log, remove kv-log-macro
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-12-16 10:04:39 +01:00
Yoshua Wuyts
c70552ead5
unpub double_ended_stream
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-12-16 09:37:14 +01:00
Fenhl
07eb2c1280
Make WriteFmtFuture must_use
Fixes #627. Thanks to @jebrosen for pointing out the location of the issue.
2019-12-14 17:43:22 +00:00
Gary Guo
732ef10f98 Make code compile 2019-12-14 23:42:14 +08:00
Gary Guo
499a44ab3b Use ?Sized in Mutex and RwLock 2019-12-14 23:34:55 +08:00
Yoshua Wuyts
761029cd08
fix stream doc hiccup
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-12-13 15:28:43 +01:00
Yoshua Wuyts
83a488b290
Merge pull request #597 from k-nasa/fix_doc_test
Fix failed doc test and enable doc test on CI
2019-12-13 15:03:22 +01:00
Yoshua Wuyts
2f0907714d
Merge pull request #617 from async-rs/1.3.0
1.3.0
2019-12-13 09:50:32 +01:00
Yoshua Wuyts
055c64e8a7
1.3.0
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-12-13 09:44:06 +01:00
Yoshua Wuyts
96d6fc43d6
Merge pull request #618 from twittner/poll_close_shutdown
TcpStream: Shutdown write direction in poll_close.
2019-12-13 09:32:48 +01:00
Yoshua Wuyts
3d3bf914ea
Merge pull request #562 from felipesere/double_ended_ext
DoubleEndedStream extension
2019-12-13 09:17:16 +01:00
Miguel Pérez García
84b6d2b276 Removing duplicated tests 2019-12-12 18:34:02 -06:00
Miguel Pérez García
8de9f9b8e1 Merge branch 'future-timeout' of https://github.com/miker1423/async-std into future-timeout 2019-12-12 18:31:45 -06:00
Felipe Sere
182fe6896f No need for a custom impl for FromIter for DoubleEndedStream 2019-12-12 20:52:38 +01:00
Felipe Sere
b0038e11be Only implement the DoubleEndedStream for once when the flag is on 2019-12-12 20:26:38 +01:00
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?
2019-12-12 20:26:38 +01:00
Felipe Sere
41cf0f855b Make Once a DoubleEndedStream 2019-12-12 20:26:38 +01:00
Felipe Sere
f9a4c35fd6 Silence warning about missing docs for the double_ended module 2019-12-12 20:26:38 +01:00
Felipe Sere
6e8236d0e1 Document from_iter for DoubleEndedStream 2019-12-12 20:26:38 +01:00
Felipe Sere
892c6008c2 Replace sample with a hidden from_iter implementation for double-ended-stream 2019-12-12 20:26:38 +01:00
Felipe Sere
abd360893c Disable docs and Debug for unexposed structs 2019-12-12 20:26:38 +01:00
Felipe Sere
94893d2924 Move more of the documentation 2019-12-12 20:26:38 +01:00
Felipe Sere
02aa2f3d2a Fix next_back 2019-12-12 20:26:38 +01:00
Felipe Sere
ee2f52f3ce Add next_back 2019-12-12 20:26:38 +01:00
Felipe Sere
55194edbf7 Add try_rfold 2019-12-12 20:26:38 +01:00
Felipe Sere
c4b9a7f680 Add samples for some of the functions 2019-12-12 20:26:38 +01:00
Felipe Sere
aabfefd015 Add a sample implementation of a double ended stream 2019-12-12 20:26:38 +01:00
Felipe Sere
cc493df433 Sketch out rfold 2019-12-12 20:26:38 +01:00
Felipe Sere
78bafbb88f Sketch outch rfind 2019-12-12 20:26:38 +01:00
Felipe Sere
d0ef48c753 Sketch out nth_back 2019-12-12 20:26:38 +01:00
Felipe Sere
fa288931c6 Skeleton for DoubleEndedStreamExt trait 2019-12-12 20:26:38 +01:00
Toralf Wittner
c90732a805 TcpStream: Shutdown write direction in poll_close.
Fixes #599.
2019-12-12 17:37:38 +01:00
Yoshua Wuyts
63b6a2b961
Merge pull request #614 from killzoner/doc-typo-await
fix: Fix typo in documentation
2019-12-12 12:04:23 +01:00
Yoshua Wuyts
1103c17e16
Merge pull request #613 from k-nasa/fix_readme
Readme example simply compile
2019-12-12 12:03:45 +01:00
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>
2019-12-11 12:49:22 +01:00
Tomasz Miąsko
f06ab9fbc4 Remove mention of task stack size configuration (#612) 2019-12-11 12:36:50 +01:00
svengrim
447c17128f
fix: Fix typo in documentation 2019-12-10 14:37:32 +01:00
k-nasa
a04157850b fix readme 2019-12-08 15:15:29 +09:00
nasa
9311fd7fae
Merge pull request #595 from linkmauve/patch-1
docs: Replace mention of futures-preview crate
2019-12-07 23:22:03 +09:00
nasa
f7b21a3e8d
Merge pull request #608 from dungph/master
fix link to `task/block_on` on README.md
2019-12-07 10:45:44 +09:00
Dung Pham
f0bdcfec25
fix link 2019-12-06 13:06:44 +07:00
Miguel Pérez García
33e7c87dfc Adding example to docs 2019-12-05 21:19:02 -06:00
Miguel Pérez García
cc85533f7c fixing format 2019-12-05 21:15:32 -06:00
Miguel Pérez García
4670388a56 Adding tests 2019-12-05 08:10:06 -06:00
Miguel Pérez García
c14c377974 Changing method signature 2019-12-05 08:09:58 -06:00
Miguel Pérez García
54fa559554 Changing scope of disclosure 2019-12-05 08:09:20 -06:00
Yoshua Wuyts
bce8688763
Merge pull request #603 from bluk/udp-socket-recv-doc
Change recv_from to recv in UdpSocket::recv doc
2019-12-03 06:25:26 +09:00
Bryant Luk
fd86effb63
Change recv_from to recv in UdpSocket::recv doc 2019-12-02 13:04:19 -06:00
nasa
128a6bc6ce
Merge pull request #598 from povilasb/fix/docs
Fix a link in the docs
2019-11-30 12:48:10 +09:00
Yoshua Wuyts
d51a135015
Merge pull request #309 from async-rs/stream-delay
Stream::delay
2019-11-30 11:25:41 +09:00
Miguel Pérez García
1c2055fff0 Merge remote-tracking branch 'original/master' into future-timeout 2019-11-29 18:00:00 -06:00
Povilas Balciunas
81e3c41826 Fix a link in the docs 2019-11-29 11:52:54 +13:00
k-nasa
fb1fb6c903 test: Test the delay time 2019-11-28 22:53:24 +09:00
k-nasa
c85e2496b1 Enable doc test on ci 2019-11-28 20:54:07 +09:00
k-nasa
7d9a063002 fix cargo test arguments on ci 2019-11-28 20:53:47 +09:00
k-nasa
44e38eae59 fix open_file test code 2019-11-28 19:52:46 +09:00
k-nasa
fe04cf26b6 test: fix stream::throttle doc test 2019-11-28 16:16:39 +09:00
k-nasa
556d7992ce test: fix failed doc test 2019-11-28 15:57:22 +09:00
k-nasa
da965e9ba4 fix indent 2019-11-28 15:54:13 +09:00
k-nasa
9f7c1833dc fix module 2019-11-28 10:37:04 +09:00
linkmauve
55560ea9b4
docs: Replace mention of futures-preview crate
It is now stable in 0.3.
2019-11-27 19:35:27 +01:00
Stjepan Glavina
bf9ee88815 Fix a typo 2019-11-27 16:29:29 +01:00
Stjepan Glavina
9627826756 Bump the version to 1.2.0 2019-11-27 16:14:43 +01:00
Stjepan Glavina
4ed15d67c9 Fix links in the changelog 2019-11-27 16:12:31 +01:00
Stjepan Glavina
0165d7f6d1 Add missing items to the changelog 2019-11-27 16:08:57 +01:00
Yoshua Wuyts
dba416608a 1.2.0 (#589)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-27 16:05:15 +01:00
Yoshua Wuyts
68005661d9 fix Stream::throttle hot loop (#584)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-27 15:47:27 +01:00
nasa
794e331761 Refactor join type (#577)
* refactor: update future join type

* test: update future join test

* update future::try_join
2019-11-27 13:38:38 +01:00
Yoshua Wuyts
63f7ea3081
Merge pull request #587 from async-rs/contributing
link to our contribution guidelines
2019-11-27 13:21:40 +01:00
k-nasa
32765ece41 test: Add stream::delay test code 2019-11-27 14:26:25 +09:00
k-nasa
635c592950 feat: Add stream::delay 2019-11-27 14:26:04 +09:00
k-nasa
3b055f364e Merge branch 'master' into stream-delay 2019-11-27 13:50:05 +09:00
Yoshua Wuyts
46cafffc31
Merge pull request #571 from killercup/more-errors
Add context to more errors
2019-11-27 01:54:27 +01:00
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.
2019-11-26 14:23:10 +01:00
Yoshua Wuyts
e66e2e2b8f
link to our contribution guidelines
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-26 11:42:02 +01:00
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.
2019-11-25 23:30:31 +01:00
Pascal Hertleif
aa7d1c27a4
Verbose errors: Apply suggestions
Co-Authored-By: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
2019-11-25 21:18:40 +01:00
Yoshua Wuyts
850b8ae9d0
Merge pull request #543 from k-nasa/stream_unzip
Add stream unzip
2019-11-25 20:25:44 +01:00
Yoshua Wuyts
ac7a796f82
Merge pull request #537 from k-nasa/ci_master
Enable CI on master branch
2019-11-25 12:53:37 +01:00
Miguel Pérez García
c1f7be5d42 Adding timeout extension method to Future trait 2019-11-23 11:40:07 -06:00
Yoshua Wuyts
50cefce803
Merge pull request #561 from async-rs/1.1.0
1.1.0
2019-11-21 22:01:34 +01:00
Yoshua Wuyts
3780ff7b44
1.1.0
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>

changelog

Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-21 21:49:32 +01:00
Yoshua Wuyts
c9a2e74789
Merge pull request #523 from async-rs/update-lib-example
polish lib.rs examples
2019-11-21 21:24:54 +01:00
Yoshua Wuyts
cffacf7fa3
feedback from review
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-21 21:21:19 +01:00
Yoshua Wuyts
02e1d7e5ea
Merge pull request #574 from stjepang/ignore-unread-errors
Ignore seek errors in poll_unread
2019-11-21 18:32:55 +01:00
laizy
ec5415358f simplify AllFuture and AnyFuture (#572) 2019-11-21 18:03:23 +01:00
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().
2019-11-21 18:03:10 +01:00
Stjepan Glavina
16edec3464 Ignore seek errors in poll_unread 2019-11-21 17:50:30 +01:00
Pascal Hertleif
e01f07d72a Add context to more errors
cc #569
2019-11-21 00:27:47 +01:00
Yoshua Wuyts
b3d30de4a1 mark windows fs APIs as "unstable" (#567)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-20 14:58:49 +01:00
Yoshua Wuyts
6f19165e0e
Merge pull request #568 from stjepang/fix-random
Fix rng use in Stream::merge
2019-11-20 14:08:16 +01:00
nasa
d146d95a39
Update src/stream/stream/mod.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-11-20 21:38:42 +09:00
Stjepan Glavina
5fba3a0928 Fix rng use in Stream::merge 2019-11-20 13:24:18 +01:00
Yoshua Wuyts
2ca03cabe6
Merge pull request #552 from hhggit/win_symlink
add os::windows::symlink_{dir,file}
2019-11-20 13:17:39 +01:00
hhggit
72ed4eb4fd
Update mod.rs 2019-11-20 19:51:01 +08:00
Yoshua Wuyts
77800ab3f9
Merge pull request #526 from yjhmelody/refactor-dir
refactor io dir to be same with std and export IntoInnerError
2019-11-20 12:35:04 +01:00
Yoshua Wuyts
8ea920c9f0
Merge pull request #546 from k-nasa/fix_clippy
Fix clippy warn
2019-11-20 12:26:28 +01:00
Yoshua Wuyts
d1189f9974
Merge pull request #548 from yjhmelody/fix-stream-code-style
fix stream code style
2019-11-20 12:25:11 +01:00
Yoshua Wuyts
3f8ec5a007
Merge pull request #551 from killercup/feature/verbose-errors
verbose errors feature
2019-11-20 12:22:58 +01:00
nasa
3bc4d293dd
Merge pull request #503 from Razican/random_merge
Randomize Stream::merge to improve the throughput.
2019-11-20 08:42:50 +09:00
Yoshua Wuyts
f24b3a4520
Merge pull request #559 from k-nasa/fix_max_by_key
Fix stream max_by_key and min_by_key
2019-11-19 23:43:46 +01:00
razican
72ca2c1a24
Improved the code with some minor changes 2019-11-19 21:14:56 +01:00
k-nasa
b5e66c4f93 refactor: Refactoring option type handling 2019-11-20 00:38:51 +09:00
k-nasa
080875edc9 update min_by_key doc 2019-11-20 00:25:48 +09:00
k-nasa
ca71ad073b fix stream min_by_key mistake 2019-11-20 00:25:35 +09:00
k-nasa
667bbc1019 doc: update doc test 2019-11-20 00:18:11 +09:00
k-nasa
64b2e10b93 fix max_by_key mistake 2019-11-20 00:17:29 +09:00
k-nasa
314a75da28 fix typo 2019-11-20 00:00:54 +09:00
Pascal Hertleif
c704643296 Remove verbose-errors cargo feature 2019-11-19 13:15:48 +01:00
Yoshua Wuyts
c6622475b2
Merge pull request #555 from stjepang/optimize-cargo-check
Macro optimization to reduce compilation times
2019-11-19 05:15:58 +01:00
Stjepan Glavina
65afd41a33
Once doesn't need Unpin bound (#554) 2019-11-19 05:04:18 +01:00
Stjepan Glavina
d3e7f32a30 Macro optimization to reduce compilation times 2019-11-18 15:47:45 +00:00
Razican
f6829859fe
Fixed deduplication of code 2019-11-18 16:39:21 +01:00
hhggit
2c9b558d14 add os::windows::symlink_{dir,file} 2019-11-18 10:20:07 +08:00
Pascal Hertleif
99ddfb3f93 Wrap code more clearly in cfg blocks 2019-11-17 23:11:11 +01:00
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).
2019-11-17 21:54:44 +01:00
sclaire-1
b2aaa8b825
Edit tutorial: implementing_a_client.md
Edited to improve reading flow
2019-11-16 13:02:17 -08:00
yjhmelody
223fcc30ee fix code style for stream 2019-11-17 00:35:56 +08:00
k-nasa
76975a4441 Merge branch 'master' into fix_clippy 2019-11-16 02:41:39 +09:00
Yoshua Wuyts
355e2eded8
Merge pull request #547 from async-rs/unpin-successors-test
remove pin_mut from successors test
2019-11-15 18:24:58 +01:00
Yoshua Wuyts
6cc9e4dd2b
Merge pull request #544 from async-rs/update-futures-timer
update futures-timer & other deps
2019-11-15 18:12:03 +01:00
Yoshua Wuyts
ee23ba6e94
Merge pull request #545 from yjhmelody/stream-partition-patch
use `as_mut` for stream-partition
2019-11-15 18:08:51 +01:00
Yoshua Wuyts
d68dc659b2
remove pin_mut from successors test
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-15 18:08:00 +01:00
Yoshua Wuyts
b5c3fb8bb5
Merge pull request #363 from felipesere/async-successors
Async successors
2019-11-15 18:04:10 +01:00
k-nasa
7d616c695d refactor: change to as_mut 2019-11-16 01:58:45 +09:00
yjhmelody
a69b3a8a9e use as_mut for stream-partition 2019-11-16 00:54:50 +08:00
k-nasa
a05b6a3810 fix: mutable ref 2019-11-16 01:36:53 +09:00
k-nasa
6cbf48f12d fix clippy warn 2019-11-16 01:29:16 +09:00
k-nasa
91ee4c7b9f doc: Add stream unzip doc 2019-11-16 01:16:48 +09:00
k-nasa
603b3c5085 add: Add stream unzip 2019-11-16 01:16:35 +09:00
Yoshua Wuyts
693a7257b8
Merge pull request #538 from k-nasa/stream_by_ref
Add stream by_ref
2019-11-15 17:14:17 +01:00
Yoshua Wuyts
8779c04dc7
upgrade all deps
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-15 16:59:58 +01:00
Yoshua Wuyts
3564be9c0c
update futures-timer dep
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-15 16:58:33 +01:00
k-nasa
df92c63337 fix: Add unstable features 2019-11-16 00:29:54 +09:00
k-nasa
31cf932d80 wip: Add stream unzip 2019-11-16 00:24:59 +09:00
Yoshua Wuyts
3c6d41ccb4
Merge pull request #541 from yjhmelody/stream-partition
add stream-partition
2019-11-15 14:27:42 +01:00
Yoshua Wuyts
837604b833
Merge pull request #542 from yjhmelody/update-doc
update doc url
2019-11-15 14:26:36 +01:00
yjh
74caed2d4b
Update src/io/seek/mod.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-11-15 18:22:06 +08:00
yjhmelody
76ec9c4563 update doc url 2019-11-15 14:33:34 +08:00
yjhmelody
d76b32e6d4 make it unstable and fix trait bound 2019-11-15 14:23:34 +08:00
yjhmelody
11268a80fb add stream-partition 2019-11-15 12:28:03 +08:00
Yoshua Wuyts
c4ba11ff95
Merge pull request #535 from async-rs/docs-sender-recv
backlink channel types
2019-11-15 03:35:43 +01:00
k-nasa
de67bf0fd4 feat: Add stream by_ref 2019-11-15 11:17:39 +09:00
k-nasa
4ef55d4d7b Enable CI on master branch 2019-11-15 09:01:41 +09:00
nasa
77a0419a3e
Merge pull request #536 from async-rs/count-unstable
mark Stream::count as unstable
2019-11-15 08:41:29 +09:00
Yoshua Wuyts
ce98834039
Merge pull request #531 from sclaire-1/master
Edit tutorial index.md
2019-11-14 22:56:13 +01:00
Yoshua Wuyts
30ff7b09b6
mark Stream::count as unstable
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-14 22:45:46 +01:00
Yoshua Wuyts
c58747b5fc
Merge pull request #368 from starsheriff/stream_count
add stream::count
2019-11-14 22:40:45 +01:00
Yoshua Wuyts
31f129ebe7
backlink channel types
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-14 22:37:04 +01:00
Yoshua Wuyts
f49d7cbbb8
Merge pull request #533 from async-rs/remove-throttle-example
remove standalone throttle example
2019-11-14 22:30:48 +01:00
Felipe Sere
64216b8e6b Take a normal closure, not an async one 2019-11-14 21:49:24 +01:00
Felipe Sere
786a52a09d Slight miss-merge 2019-11-14 21:37:51 +01:00
Felipe Sere
f14b37ff17 Remoe the T: Copy bound on the item 2019-11-14 21:35:38 +01:00
Felipe Sere
7677e9a3df Make the closure take a borrow to the value 2019-11-14 21:35:38 +01:00
Felipe Sere
bfb42b432e Rearrange docs to match 'repeat' 2019-11-14 21:35:38 +01:00
Felipe Sere
4c09cdbeac Mark successors as unstable 2019-11-14 21:35:38 +01:00
Felipe Sere
243cdd7ff1 Slight miss-merge 2019-11-14 21:35:19 +01:00
Felipe Sere
a257b7018c Rename some variables to match iter 2019-11-14 21:35:19 +01:00
Felipe Sere
af928163e4 Got further! Thx Josh! 2019-11-14 21:35:19 +01:00
Felipe Sere
8d97e0f974 Only produes empty value if next is ever a 'None' 2019-11-14 21:35:19 +01:00
Felipe Sere
266754897e Rename the module to 'successors' 2019-11-14 21:35:19 +01:00
Felipe Sere
554d5cfbc1 Slight renamings 2019-11-14 21:34:57 +01:00
Felipe Sere
8b662b659d Run rustfmt 2019-11-14 21:34:19 +01:00
Felipe Sere
95a3e53fcd Only use the Option of the future to decide to construct a new one 2019-11-14 21:33:45 +01:00
Felipe Sere
02b261de10 It compiles! Store the future and poll it instead of creating multiple new ones 2019-11-14 21:33:45 +01:00
Felipe Sere
fe3c9ef626 First attempt at successor 2019-11-14 21:33:45 +01:00
Yoshua Wuyts
4e1d79adb1
Merge pull request #524 from yjhmelody/stream-max
Add Stream max
2019-11-14 21:28:36 +01:00
Yoshua Wuyts
1546448800
remove throttle example
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-14 21:27:20 +01:00
Yoshua Wuyts
338273eb18
Merge pull request #356 from Wassasin/342-stream-throttle
Implemented StreamExt::throttle
2019-11-14 21:25:34 +01:00
Wouter Geraedts
dda65cbff0 Start throttle measurement before initialisation 2019-11-14 11:29:49 +01:00
Johannes Weissmann
9ebe41f2d6
Update src/stream/stream/mod.rs
Co-Authored-By: nasa <htilcs1115@gmail.com>
2019-11-14 10:34:09 +01:00
Wouter Geraedts
90c67c223a Decreased throttle test time to original values; only test lower bound 2019-11-14 10:26:56 +01:00
sclaire-1
8473b738d0
Edit tutorial index.md
Edited the structure of sentences to make it easier to read
2019-11-13 16:33:44 -08:00
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
2019-11-13 20:32:37 +01:00
Florian Gilcher
d546ee3d92
Merge pull request #528 from skade/remove-nightly-note
Update version requirements in the tutorial
2019-11-13 16:31:42 +01:00
Florian Gilcher
6338341369
Merge pull request #520 from gierlachg/stream_pinning
Cleaning up stream pinning.
2019-11-13 15:56:48 +01:00
Florian Gilcher
6f4bea07a1
Update version requirements in the tutorial 2019-11-13 15:33:52 +01:00
yjhmelody
5adb112a00 export IntoInnerError for io 2019-11-13 13:52:16 +08:00
yjhmelody
9d634cb2a7 refactor io dir to be same with std 2019-11-13 12:42:59 +08:00
yjhmelody
879af6dc85 Add Stream max 2019-11-13 10:50:09 +08:00
Yoshua Wuyts
79962e20a5
enable attributes feature
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-12 23:37:43 +01:00
Yoshua Wuyts
1431ee0422
polish README.md examples
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-12 23:26:15 +01:00
Yoshua Wuyts
2dfdc1c482
polish lib.rs examples
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-12 23:10:23 +01:00
Grzegorz Gierlach
e442eba625 Cleaning up stream pinning. 2019-11-12 19:51:58 +01:00
Grzegorz Gierlach
f0875d2dca Cleaning up stream pinning. 2019-11-12 19:34:08 +01:00
Devashish Dixit
f611ceccc8 Run cargo fmt for doc comments (#515) 2019-11-12 17:47:03 +01:00
Yoshua Wuyts
74a7d93611 upgrade async-macros to 2.0.0 (#519)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-12 17:34:13 +01:00
Wouter Geraedts
c5b3a98e5b Increased throttle test to 10x time 2019-11-12 16:22:25 +01:00
Yoshua Wuyts
3151a70b77
Merge pull request #517 from Alexendoo/surf
Enable surf example
2019-11-12 15:59:00 +01:00
Wouter Geraedts
4ab7b213de Updated example to be consistent; added timing measurements to throttle 2019-11-12 15:38:02 +01:00
Wouter Geraedts
6990c1403f Reimplemented throttle to never drop Delay, added boolean flag 2019-11-12 15:07:20 +01:00
Wouter Geraedts
77a1849303 Merge branch '342-stream-throttle' of github.com:Wassasin/async-std into 342-stream-throttle 2019-11-12 15:03:54 +01:00
Wouter Geraedts
a722de1a10 Merge remote-tracking branch 'upstream/master' into 342-stream-throttle 2019-11-12 14:51:24 +01:00
Wouter Geraedts
88cbf2c119 Change throttle test to run in milliseconds 2019-11-12 14:51:11 +01:00
Wouter Geraedts
6f6d5e9d20
Updated throttle fn comments.
Co-Authored-By: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
2019-11-12 14:35:03 +01:00
Wouter Geraedts
7c7386735e
Wrap around throttle comment
Co-Authored-By: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
2019-11-12 14:34:31 +01:00
Alex Macleod
1b7d5bea6b Enable surf example
1.0.3 has been released with the required change
2019-11-12 12:19:11 +00:00
Yoshua Wuyts
46c58b214c
Merge pull request #514 from async-rs/stabilize-yield-now
stabilize task::yield_now
2019-11-12 02:32:55 +01:00
Yoshua Wuyts
0d5c7a217f
stabilize task::yield_now
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-12 02:10:55 +01:00
Yoshua Wuyts
5017117326
Merge pull request #513 from async-rs/fix-changelog
fix changelog
2019-11-12 01:55:34 +01:00
Yoshua Wuyts
9d7b2d6696
fix changelog
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-12 01:36:03 +01:00
Yoshua Wuyts
643b678ea5
Merge pull request #511 from async-rs/1.0.1
1.0.1
2019-11-12 01:13:23 +01:00
Yoshua Wuyts
b5b2b5a0a3
1.0.1
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-12 00:48:26 +01:00
Florian Gilcher
54371c21c1
Merge pull request #510 from stjepang/fix-spawn-blocking
Improve thread startup/shutdown algorithm in spawn_blocking
2019-11-12 00:39:10 +01:00
Stjepan Glavina
1a50ffd144 Delete unused import 2019-11-12 00:38:22 +01:00
Stjepan Glavina
21c5c48cb6 Lower the timeout to 1 second 2019-11-12 00:37:54 +01:00
Stjepan Glavina
6677d52c2d Improve thread creating algorithm in spawn_blocking 2019-11-12 00:35:29 +01:00
Johannes Weissmann
37922408e5 use pin_project 2019-11-11 22:17:29 +01:00
Johannes Weissmann
7d2282dbd2 fix merge conflict 2019-11-11 22:11:06 +01:00
Johannes Weissmann
60f822bee5 Merge branch 'master' into stream_count 2019-11-11 22:06:09 +01:00
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.
2019-11-11 21:14:55 +01:00
Yoshua Wuyts
980c30e90f
Merge pull request #496 from async-rs/1.0.0
1.0.0
2019-11-11 18:05:53 +01:00
Yoshua Wuyts
4aa9928ece
v1.0.0
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-11 16:13:22 +01:00
Yoshua Wuyts
eea7af24db
fix bugs in changelog
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-11 15:53:13 +01:00
Yoshua Wuyts
76c5ffe9ab
Merge pull request #506 from stjepang/cleanup-stream
Cleanup stream module
2019-11-11 15:46:58 +01:00
Stjepan Glavina
5438258cee Remove unused import 2019-11-11 13:19:59 +01:00
Wouter Geraedts
ef958f0408 Use pin_project_lite instead for throttle 2019-11-11 13:09:41 +01:00
Stjepan Glavina
dc5d143c16 Merge branch 'master' into cleanup-stream 2019-11-11 13:08:38 +01:00
Stjepan Glavina
c2f750d288 Cleanup stream module 2019-11-11 13:07:29 +01:00
Wouter Geraedts
139a34b685 Make throttle an unstable feature 2019-11-11 12:26:32 +01:00
Wouter Geraedts
b591fc68bd Changed semantics of throttle to non-dropping variant with backpressure 2019-11-11 12:17:00 +01:00
razican
5d558ca213
Fixed test, order is no longer guaranteed 2019-11-11 11:39:30 +01:00
razican
e48e463736
Duplicating code due to strange Rust error. 2019-11-11 11:26:40 +01:00
razican
0c37d4af10
Anonymous function to avoid type issues 2019-11-11 11:25:50 +01:00
Stjepan Glavina
352f18bc2a
Use async_std::sync::Arc in examples (#501) 2019-11-11 11:10:36 +01:00
razican
79bbf4938d
Randomize Stream::merge to improve the throughput. Implements #490. 2019-11-11 10:44:12 +01:00
Wouter Geraedts
14d7d3bf9c Merge remote-tracking branch 'upstream/master' into 342-stream-throttle 2019-11-11 10:15:27 +01:00
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
2019-11-11 00:31:33 +01:00
Stjepan Glavina
122e87364b Remove cache padding in channels 2019-11-09 23:08:31 +01:00
Yoshua Wuyts
925b42bc89
Merge pull request #493 from stjepang/cleanup-future
Cleanup future module
2019-11-09 18:19:40 +01:00
Stjepan Glavina
d4f38e783f Cleanup future module 2019-11-09 17:26:19 +01:00
Yoshua Wuyts
96d3560742 remove future::*join macros (#492)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-09 17:02:48 +01:00
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
2019-11-09 17:02:17 +01:00
Stjepan Glavina
9e185f1c3e
Unstable feature: copy takes arguments by value (#471)
* Unstable feature: copy takes arguments by value

* Fix feature flags
2019-11-09 16:59:35 +01:00
Yoshua Wuyts
89d611628a
Merge pull request #483 from ryan-scott-dev/rscott/pathbuf_fromiter
Add FromIterator and Extend trait implementations for PathBuf
2019-11-09 13:03:28 +01:00
Yoshua Wuyts
e9c0f8f6b5
Merge pull request #481 from async-rs/fix-proc-macro-render
fix attributes feature
2019-11-09 12:56:10 +01:00
Yoshua Wuyts
16565ccfbc
Merge pull request #489 from jaysonsantos/pathbuf-fromstr
Implement FromStr for PathBuf
2019-11-09 12:51:42 +01:00
Yoshua Wuyts
74882c119d
check attributes
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-09 12:44:14 +01:00
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()
2019-11-09 12:14:56 +01:00
Yoshua Wuyts
037119c0c0
Merge pull request #478 from portgasd666/master
Add Future::join and Future::try_join
2019-11-09 11:31:47 +01:00
Stjepan Glavina
548733e5d5
Cleanup stream traits (#487)
* Cleanup stream traits

* Fix docs
2019-11-09 11:22:09 +01:00
Abhishek C. Sharma
f04b6f6fe9 Change module level docs for future to refer to join and try_join functions instead of macros 2019-11-09 13:09:47 +05:30
Friedel Ziegelmayer
4a78f731b7 fix: stream::take_while (#485)
When the predicate is false, the stream should be ended.
2019-11-09 00:00:03 +01:00
nasa
d2d63348c7 Stable and beta add to CI (#482)
* Add stable and beta

* Add benches
2019-11-08 14:05:53 +01:00
Ryan Scott
8f3366072f Add FromIterator and Extend trait implementations for PathBuf 2019-11-08 22:10:56 +11:00
Yoshua Wuyts
e74e246bbb
fix attributes feature
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-08 11:15:47 +01:00
laizy
fb19ebde17 add Sync constraint for RwLock to prevent memory unsafety (#479) 2019-11-08 08:56:55 +00:00
Abhishek C. Sharma
b14282457c Add Future::join and Future::try_join 2019-11-08 11:29:39 +05:30
Stjepan Glavina
ab2f64cd84 Mark extend() as unstable 2019-11-08 02:38:49 +01:00
Yoshua Wuyts
fd088fea38 0.99.12 (#469)
* 0.99.12

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

* Update changelog with latest changes
2019-11-08 00:11:35 +00:00
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
2019-11-07 23:56:58 +00:00
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
2019-11-07 23:39:54 +00:00
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>
2019-11-07 22:10:55 +00:00
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
2019-11-07 22:01:36 +00:00
Yoshua Wuyts
266e6326eb document path submodule (#467)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-07 21:48:23 +00:00
Stjepan Glavina
f8e82564d9
Rename stream_extend to extend (#464)
* Rename stream_extend to extend

* Remove Extend from prelude

* Add stream::extend()
2019-11-07 21:46:58 +00:00
Abhishek C Sharma
eb1ef3f4e4 Minor documentation fix for race and try_race (#473) 2019-11-07 19:19:05 +00:00
Yoshua Wuyts
d0f1996759
Merge pull request #388 from felipesere/cycle
Implement stream::cycle(..)
2019-11-07 13:14:43 +01:00
Yoshua Wuyts
8a0e29473a
Merge pull request #446 from yjhmelody/stream-cloned
Add Stream cloned
2019-11-07 13:13:20 +01:00
Yoshua Wuyts
2cb887e154
Merge pull request #465 from async-rs/non-pub-flatten
hide future::Flatten::new
2019-11-07 03:18:43 +01:00
Yoshua Wuyts
929027796e
hide future::Flatten
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-07 03:06:38 +01:00
Yoshua Wuyts
9a8805678e
Merge pull request #443 from portgasd666/master
Added Future::flatten
2019-11-07 03:04:23 +01:00
Yoshua Wuyts
a064a5b13e
Merge pull request #459 from stjepang/expose-ext-traits
Expose extension traits in preludes
2019-11-07 02:48:50 +01:00
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
2019-11-06 20:20:27 +00:00
Stjepan Glavina
93b01e36ed
Clippy fixes (#462) 2019-11-06 19:29:17 +00:00
Gabriel Majeri
d502453057 Remove doc Stream impl for VecDeque (#461) 2019-11-06 08:35:31 +00:00
Yoshua Wuyts
3144e217ae
Merge pull request #458 from async-rs/rework-intro
rework lib.rs docs
2019-11-06 01:19:16 +01:00
Stjepan Glavina
c3254d78d9 Fix a re-rexport 2019-11-06 01:17:35 +01:00
Yoshua Wuyts
f4fb8a3534
change one line
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-06 01:04:46 +01:00
Yoshua Wuyts
1c87e97e9c
Apply suggestions from code review
Co-Authored-By: Stjepan Glavina <stjepang@gmail.com>
2019-11-06 01:02:39 +01:00
Stjepan Glavina
a757cc02dc Expose extension traits in preludes 2019-11-06 00:21:32 +01:00
Yoshua Wuyts
ae8b051892
rework lib.rs docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-05 21:00:12 +01:00
Stjepan Glavina
1707638ebb
Update mod.rs 2019-11-05 17:09:32 +00:00
Yoshua Wuyts
84fa4ca068
Merge pull request #456 from stjepang/doc-fixes-links
Fix some links in docs
2019-11-05 18:06:03 +01:00
Stjepan Glavina
43bb59cd02 Fix some links in docs 2019-11-05 17:49:05 +01:00
yjh
5179f30d2d
use async_std::stream 2019-11-05 21:15:33 +08:00
yjh
a35602f375
Update mod.rs 2019-11-05 21:08:56 +08:00
Yoshua Wuyts
e14cc2a30d
Merge pull request #452 from stjepang/fix-deadlocks
Fix a deadlock in channel
2019-11-05 11:27:00 +01:00
Stjepan Glavina
6d421de992 Fix another clippy warning 2019-11-05 10:16:00 +00:00
Stjepan Glavina
5874392397 Fix a clippy warning 2019-11-04 18:48:49 +01:00
Stjepan Glavina
e9edadffc7 Fix a deadlock in channel 2019-11-04 18:15:12 +01:00
Yoshua Wuyts
282ae064fe
Merge pull request #449 from async-rs/strip-vecdeque
remove remaining instances of VecDeque stream
2019-11-04 17:46:19 +01:00
yjh
e85bbe68e6
Merge branch 'master' into stream-cloned 2019-11-04 22:30:46 +08:00
Abhishek C. Sharma
d7afcada76 Fixed ambiguous associated types 2019-11-04 15:19:47 +05:30
Abhishek C. Sharma
e36172e808 Merge remote-tracking branch 'upstream/master' 2019-11-04 14:03:29 +05:30
Abhishek C. Sharma
a3e68704bc Wrap state enum in public struct 2019-11-04 13:58:14 +05:30
yjh
8bef812e78
Update src/stream/stream/cloned.rs
Co-Authored-By: nasa <htilcs1115@gmail.com>
2019-11-04 11:49:50 +08:00
yjh
bf0cd5987a
Update src/stream/stream/cloned.rs
Co-Authored-By: nasa <htilcs1115@gmail.com>
2019-11-04 11:49:43 +08:00
Stjepan Glavina
20cdf73bb0
Simplify RwLock using WakerSet (#440) 2019-11-04 02:40:55 +01:00
Yoshua Wuyts
ed1cb49807
remove remaining instances of VecDeque stream
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-04 01:57:53 +01:00
Stjepan Glavina
78614c6c1d
Clarify blocking in channel docs (#448) 2019-11-03 22:19:04 +01:00
nasa
ddbbbfc32a Replace VecDeque with stream::from_iter in examples (#447) 2019-11-03 13:40:51 +01:00
yjhmelody
4942dc7f9f Add Stream cloned 2019-11-03 19:19:52 +08:00
Abhishek C. Sharma
e0910be8fb Added Future::flatten 2019-11-03 11:34:49 +05:30
Felipe Sere
57a6516e63 Make bounds on Stream impl simpler 2019-11-02 22:24:12 -05:00
Felipe Sere
fbd5bd867d Revert "Only one generic type needed"
This reverts commit e9b9284863a614b852c22d58205cb983fc26682a.
2019-11-02 22:24:12 -05:00
Felipe Sere
9ee804f9ed Only one generic type needed 2019-11-02 22:24:12 -05:00
Felipe Seré
eaa56580e3 Update src/stream/stream/mod.rs
Co-Authored-By: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
2019-11-02 22:24:12 -05:00
Felipe Sere
0186124aef Simpler impl 2019-11-02 22:24:12 -05:00
Felipe Sere
197253aa73 Run fmt 2019-11-02 22:24:12 -05:00
Felipe Sere
19381fa590 One clippy warning 2019-11-02 22:23:46 -05:00
Felipe Sere
ed5b095c73 Run fmt 2019-11-02 22:23:46 -05:00
Felipe Sere
5aadc5e4e9 Make cycle a function on the stream type 2019-11-02 22:23:46 -05:00
Felipe Sere
b979773505 Follow clippys advice 2019-11-02 22:23:46 -05:00
Felipe Sere
fd09e2f248 Run fmt 2019-11-02 22:23:46 -05:00
Felipe Sere
171cc82aed Replace copy with clone bound 2019-11-02 22:23:46 -05:00
Felipe Sere
83ff11ff4c Switch cycle to stream 2019-11-02 22:23:46 -05:00
Felipe Sere
e1ba87e7c1 Add slightly better docs 2019-11-02 22:23:46 -05:00
Felipe Sere
8126bb1882 use the module operator to calculate next index 2019-11-02 22:23:46 -05:00
Felipe Sere
486f9a964c Cycle over a known set of values. 2019-11-02 22:23:46 -05:00
Felipe Sere
a096d5ec2d stub out an example 2019-11-02 22:23:00 -05:00
Felipe Sere
dea1b67670 Skeleton cycle 2019-11-02 22:23:00 -05:00
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
2019-11-03 00:11:59 +01:00
Yoshua Wuyts
9a4f4c591c
Merge pull request #441 from async-rs/stdio-lock-unstable
mark stdio-lock structs as unstable
2019-11-03 00:05:11 +01:00
Yoshua Wuyts
6f9436e575
mark stdio-lock structs as unstable
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-11-02 23:54:27 +01:00
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>
2019-11-02 23:00:03 +01:00
yjh
3a2e6d5b92 add max_by_key (#408)
* add max_by_key

* fix conflict

* fmt code
2019-11-02 15:59:15 +01:00
Zhang Guyu
5fb9d3e980 add Stream::copied (#442) 2019-11-02 15:58:30 +01:00
Yoshua Wuyts
4c63392a85
Merge pull request #334 from k-nasa/add_stdin_lock
Locking for stdin
2019-11-02 14:18:36 +01:00
k-nasa
3dcad984b4 fix: To unstable feature 2019-11-02 12:34:53 +09:00
Yoshua Wuyts
c413e717da
Merge pull request #429 from markhildreth/tcp_smoke_tests
Added TCP smoke tests against std Listener and Stream
2019-11-02 02:30:42 +01:00
Yoshua Wuyts
911ebada0b
Merge pull request #434 from paulocsanz/master
Put everything behind a 'stable' feature to avoid future breaking changes
2019-11-02 01:33:52 +01:00
Aleksey Kladov
ec1a6ea3e8 Fix typo (#439) 2019-11-01 22:08:19 +01:00
Tyler Neely
5adc608791 Spawn several threads when we fail to enqueue work in the blocki… (#181)
* Rebase onto master

* Switch to unbounded channels
2019-11-01 21:53:13 +01:00
Sheyne Anderson
1a51ca424a Fix typo in tutorial in book (#412) 2019-11-01 20:17:46 +01:00
k-nasa
81873ae5f3 fix 2019-11-02 01:27:27 +09:00
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
2019-11-01 16:10:37 +01:00
Yoshua Wuyts
e17a6703c8
Merge pull request #415 from k-nasa/stream_from_iter
Add stream::from_iter
2019-11-01 16:05:58 +01:00
Paulo
8e991bcd3a Fix typo 2019-11-01 10:59:38 -03:00
Paulo
2e66c38453 Simplify default feature 2019-11-01 10:58:51 -03:00
k-nasa
0661f774c2 Merge branch 'master' into add_stdin_lock 2019-11-01 21:20:38 +09:00
k-nasa
2f3c867d44 Merge branch 'master' into stream_from_iter 2019-11-01 21:19:53 +09:00
k-nasa
063798ce49 Add doc 2019-11-01 21:18:43 +09:00
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>
2019-11-01 12:54:43 +01:00
Florian Gilcher
57670dd9d7
Merge pull request #433 from JohnTitor/remove-deprecated-action
Remove deprecated action
2019-11-01 09:30:25 +01:00
Paulo
dcd7c55cef Put everything behind a 'stable' feature 2019-11-01 00:41:38 -03:00
Yuki Okushi
277fd521bc Remove deprecated action 2019-11-01 11:30:51 +09:00
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
2019-11-01 02:45:50 +01:00
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
2019-11-01 02:45:33 +01:00
k-nasa
caa23381f0 fix clippy warning 2019-11-01 10:41:21 +09:00
k-nasa
eeb44c86e9 fix 2019-11-01 10:34:28 +09:00
k-nasa
f8b8c9debe Merge branch 'master' into add_stdin_lock 2019-11-01 10:10:49 +09:00
Yoshua Wuyts
c1e8517959
Merge pull request #414 from k-nasa/fix_github_actions
Add only rustfmt on Checking fmt and docs actions
2019-11-01 02:06:04 +01:00
Yoshua Wuyts
cc75b65b8c
Merge pull request #409 from yjhmelody/stream-min
Add Stream min
2019-11-01 00:41:54 +01:00
Yoshua Wuyts
f102588df5
Merge pull request #428 from zhangguyu6/stream-position
Add stream position
2019-11-01 00:33:39 +01:00
Yoshua Wuyts
3e0fe742f6
Merge pull request #427 from yjhmelody/stream-ne
Add stream ne
2019-11-01 00:29:21 +01:00
Yoshua Wuyts
65dcaf4464
Merge pull request #426 from yjhmelody/stream-eq
Add stream eq
2019-11-01 00:28:27 +01:00
zhangguyu
07d21e5eb3 change trait bounds 2019-10-31 23:30:11 +08:00
Mark Hildreth
c6c2bfa456 Added TCP smoke tests against std Listener and Stream 2019-10-31 11:24:23 -04:00
zhangguyu
48c82a9668 Add stream position 2019-10-31 22:33:17 +08:00
yjhmelody
1ab3d901e4 fmt code 2019-10-31 21:17:07 +08:00
yjhmelody
204da33391 fmt code 2019-10-31 21:16:13 +08:00
yjhmelody
17db7ffcd3 Add stream ne 2019-10-31 20:18:53 +08:00
yjhmelody
f5efaaa7ba Add stream eq 2019-10-31 14:44:19 +08:00
Yoshua Wuyts
cc949f48ea
Merge pull request #420 from JayatiGoyal/master
correction of a typo
2019-10-31 03:42:27 +01:00
JayatiGoyal
5fee91c050
corrected a typo 2019-10-31 00:36:42 +05:30
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
2019-10-30 11:23:08 +00:00
k-nasa
40c4e1a29d feat: Add stream::from_iter 2019-10-30 10:39:05 +09:00
k-nasa
3620b2b6ab fix: Add only rustfmt on Checking fmt and docs actions 2019-10-30 09:17:12 +09:00
k-nasa
2c91b30ee8 feat: Add Read and Write trait to Lock struct 2019-10-29 23:12:32 +09:00
yjhmelody
021862dcc8 fix min 2019-10-29 21:49:30 +08:00
yjhmelody
b942d0a405 add stream-min 2019-10-29 21:44:56 +08:00
Yoshua Wuyts
da795dec7b
Merge pull request #399 from async-rs/release-0.99.11
v0.99.11
2019-10-29 12:46:07 +01:00
Yoshua Wuyts
2adaaa9d3f
more updates
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-29 12:16:56 +01:00
Yoshua Wuyts
b10930207c
more
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-29 12:14:48 +01:00
Yoshua Wuyts
b3d1fa9c98
v0.99.11
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-29 12:14:48 +01:00
Yoshua Wuyts
2b1c6f04ea
Merge pull request #384 from yjhmelody/stream-max_by
add stream::max_by method
2019-10-29 11:19:50 +01:00
Yoshua Wuyts
5ff4ef8dd4
Merge pull request #385 from yjhmelody/stream-min_by_key
add stream::min_by_key method
2019-10-29 11:18:34 +01:00
Yoshua Wuyts
f311e3de9f
Merge pull request #397 from async-rs/sync-docs
add mod level docs for sync
2019-10-29 11:07:56 +01:00
Yoshua Wuyts
3a06a1211b
Add feedback from review
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-29 10:56:33 +01:00
Yoshua Wuyts
526c4da21a
Merge pull request #395 from async-rs/stream-docs
add stream mod docs
2019-10-29 10:50:26 +01:00
Yoshua Wuyts
997e811c58
Merge pull request #402 from async-rs/fuse-docs
update Stream::fuse docs
2019-10-29 10:49:43 +01:00
Yoshua Wuyts
11d0577407
Merge pull request #396 from async-rs/net-docs
standardize net docs
2019-10-29 10:30:45 +01:00
Yoshua Wuyts
eb081b1948
Apply suggestions from code review
Co-Authored-By: Florian Gilcher <florian.gilcher@ferrous-systems.com>
2019-10-29 10:23:54 +01:00
k-nasa
35cb11e398 Merge branch 'master' into add_stdin_lock 2019-10-29 16:01:58 +09:00
Yoshua Wuyts
1175a37c47
Merge pull request #367 from k-nasa/add_stream_flatten
Add Stream::flatten and Stream::flat_map
2019-10-29 02:22:04 +01:00
Yoshua Wuyts
206bedfd12
Merge pull request #349 from k-nasa/add_future_delay
Add future::delay
2019-10-29 02:20:53 +01:00
k-nasa
1554b04407 $cargo fmt 2019-10-29 10:12:22 +09:00
k-nasa
1545d24e50 Merge branch 'master' into add_future_delay 2019-10-29 10:09:09 +09:00
k-nasa
ae7adf2c36 fix: Remove unused import 2019-10-29 10:01:41 +09:00
k-nasa
040227f38a Merge branch 'master' into add_stream_flatten 2019-10-29 09:58:10 +09:00
k-nasa
688976203e fix: Split FlattenCompat logic to Flatten and FlatMap 2019-10-29 09:52:50 +09:00
k-nasa
c7dc147f73 fix indent 2019-10-29 09:27:35 +09:00
Yoshua Wuyts
b3ae6f2b03
update Stream::fuse docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-28 13:02:13 +01:00
Yoshua Wuyts
4ecf49fe95
Merge pull request #401 from async-rs/fix-recursion-limit
fix doc recursion limit
2019-10-28 12:59:02 +01:00
Yoshua Wuyts
4346386610
fix doc recursion limit
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-28 12:42:23 +01:00
Yoshua Wuyts
ca4856a0e8
Merge pull request #377 from ktomsic/sum-and-product-impls
Add `Stream::sum()` and `Stream::product()` implementations
2019-10-28 12:34:30 +01:00
Yoshua Wuyts
e5675151b9
Merge pull request #364 from stjepang/optimize-flushing
Don't flush files if they weren't written to
2019-10-28 12:19:15 +01:00
Yoshua Wuyts
fd940b8c6a
Merge pull request #348 from k-nasa/add_stream_timeout
Add stream timeout
2019-10-28 12:12:02 +01:00
Yoshua Wuyts
1baee98ead
Merge pull request #375 from sunjay/fromstream-pathbuf
Added Extend + FromStream for PathBuf
2019-10-28 10:34:48 +01:00
k-nasa
613895d6be doc: fix documantation text 2019-10-28 13:58:54 +09:00
Florian Gilcher
f262fd8a40
Merge pull request #392 from taiki-e/clippy
Remove usage of actions-rs/clippy-check
2019-10-27 20:26:43 -07:00
Florian Gilcher
c2a084ed4a
Merge pull request #393 from k-nasa/fix_clippy
Fix clippy warnings
2019-10-27 20:22:35 -07:00
Florian Gilcher
ae41d45da6
Merge pull request #376 from AZanellato/typo-fixes
Typos and sentence structure fixes
2019-10-27 19:23:41 -07:00
Yoshua Wuyts
5f8e2cbd4a
add mod level docs for sync
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-28 00:34:27 +01:00
Yoshua Wuyts
20abd5cebf
standardize net docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-28 00:15:13 +01:00
Yoshua Wuyts
4c4604d63e
add stream mod docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-28 00:08:32 +01:00
Yoshua Wuyts
4cab868899
Merge pull request #394 from async-rs/link-types
backreference links for structs
2019-10-27 23:19:16 +01:00
Yoshua Wuyts
4475a229d6
backlink io docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-27 22:46:18 +01:00
Yoshua Wuyts
a3a740c14a
backlink all docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-27 22:29:20 +01:00
k-nasa
59615a655b feat: Add StderrLock and StdoutLock struct 2019-10-27 22:04:43 +09:00
k-nasa
fe49f2618f fix clippy::redundant_clone 2019-10-27 20:34:44 +09:00
k-nasa
7fe2a1bbce fix clippy::cognitive_complexity 2019-10-27 20:32:22 +09:00
k-nasa
7c293d37f7 fix clippy::comparison_chain 2019-10-27 20:32:22 +09:00
k-nasa
c9d958d309 $cargo fix -Z unstable-options --clippy --features unstable 2019-10-27 20:31:53 +09:00
nasa
a42ae2f3d9
Narrow the disclosure range of FlattenCompat::new
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-10-27 12:35:51 +09:00
nasa
37f14b0195
Narrow the disclosure range of Flatten::new
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-10-27 12:35:32 +09:00
nasa
13a08b0d54
Narrow the disclosure range of FlatMap::new
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-10-27 12:35:14 +09:00
Johannes Weissmann
75546ef831 Merge branch 'master' into stream_count 2019-10-26 23:18:04 +02:00
Johannes Weissmann
6608d39c59 remove Stream trait bound 2019-10-26 21:58:34 +02:00
Taiki Endo
6549b66ad2 run clippy check on beta & address clippy warnings 2019-10-27 03:28:20 +09:00
Taiki Endo
610c66e774 Remove usage of actions-rs/clippy-check 2019-10-27 02:22:26 +09:00
yjhmelody
7cfec4e8ce use take and remove Copy 2019-10-27 00:26:19 +08:00
yjh
fb78ed1812
Update src/stream/stream/min_by_key.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-10-27 00:19:49 +08:00
yjh
5a4fdeb1cd
Update src/stream/stream/min_by_key.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-10-27 00:18:18 +08:00
yjh
b57849e1cb
Update src/stream/stream/max_by.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-10-27 00:18:01 +08:00
yjh
a8d3d1483f
Update src/stream/stream/max_by.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-10-27 00:17:50 +08:00
yjh
006fc7e9de
Update src/stream/stream/max_by.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-10-27 00:17:42 +08:00
yjhmelody
c9e6d3a84c use pin_project_lite 2019-10-26 12:59:43 +08:00
yjhmelody
37a7eadf17 use pin_project_lite 2019-10-26 11:52:41 +08:00
yjhmelody
d0c3c9172b Merge branch 'master' of git://github.com/async-std/async-std into stream-max_by 2019-10-26 11:34:59 +08:00
nasa
81e3cab00d Change homepage link (#389) 2019-10-25 22:14:57 +01:00
k-nasa
61b7a09c70 Fix type declaration 2019-10-26 01:45:12 +09:00
nasa
8932cecec7
Update src/stream/stream/flatten.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-10-26 01:43:14 +09:00
nasa
bf3508ffb2
Update src/stream/stream/flatten.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-10-26 01:43:07 +09:00
nasa
6168952d6f
Update src/stream/stream/flatten.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-10-26 01:42:57 +09:00
nasa
b7b5df13aa
Update src/stream/stream/flatten.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-10-26 01:42:39 +09:00
nasa
7ce721f562
Update src/lib.rs
Co-Authored-By: Taiki Endo <te316e89@gmail.com>
2019-10-26 01:42:19 +09:00
k-nasa
b66ffa670e update recursion_limit 2019-10-26 00:42:27 +09:00
k-nasa
0c5abee284 to unstable stream::flat_map, stream::flatten 2019-10-26 00:36:04 +09:00
k-nasa
001368d3df $cargo fmt 2019-10-26 00:29:10 +09:00
k-nasa
00e7e58bf3 fix type def 2019-10-26 00:26:53 +09:00
k-nasa
271b6f4a1c fix: Using pin_project! 2019-10-25 23:58:08 +09:00
k-nasa
3297a0f327 Merge branch 'master' into add_stream_flatten 2019-10-25 23:34:44 +09:00
k-nasa
48b255897e Merge branch 'master' into add_stdin_lock 2019-10-24 18:34:42 +09:00
k-nasa
feeb3c10df fix: Remove Pin API related unsafe code 2019-10-24 08:41:01 +09:00
k-nasa
b17af61367 Merge branch 'master' into add_stream_timeout 2019-10-24 08:40:43 +09:00
k-nasa
d97b3dfdf3 fix: Remove Pin API related unsafe code 2019-10-24 08:29:05 +09:00
k-nasa
5c9cfb4fe8 Merge branch 'master' into add_future_delay 2019-10-24 08:23:01 +09:00
Wouter Geraedts
1fd05a157f Reset delay to prevent poll after ready 2019-10-23 22:34:39 +02:00
Wouter Geraedts
1c843a8124 Re-implemented Throttle to keep last value in memory 2019-10-23 22:27:51 +02:00
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
2019-10-23 17:02:03 +01:00
Taiki Endo
2abf5ca891
Deny warnings on CI (#378)
* Deny warnings on CI

* Fix some clippy warnings
2019-10-23 20:20:59 +09:00
yjhmelody
f5a0a0ba86 fmt 2019-10-23 19:17:24 +08:00
yjhmelody
d6f940110b update doc 2019-10-23 19:04:04 +08:00
yjhmelody
020eb85093 add stream::min_by_key method 2019-10-23 18:59:06 +08:00
Taiki Endo
944e43d4bf Remove Pin API related unsafe code by using pin-project-lite cra… (#381) 2019-10-23 10:35:02 +01:00
yjhmelody
4e5828e646 add stream::max_by method 2019-10-23 16:46:11 +08:00
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`.
2019-10-22 20:30:27 -04:00
Andre Zanellato
faad4c8c26 Sentence structure on notice 2019-10-21 19:50:57 -03:00
Andre Zanellato
88558eae6e Typos and sentence structure fixes 2019-10-21 19:47:14 -03:00
Sunjay Varma
0d4a907335 Added Extend + FromStream for PathBuf 2019-10-20 19:18:37 -04:00
Johannes Weissmann
97094b2a1c remove Sized constraint 2019-10-20 22:03:51 +02:00
Wouter Geraedts
ced5281b73 Merge remote-tracking branch 'upstream/master' into 342-stream-throttle 2019-10-20 16:50:31 +02:00
Johannes Weissmann
a9a7bdc290 add stream::count 2019-10-18 07:23:52 +02:00
k-nasa
410d16eaf6 Add docs + To unstable feature 2019-10-18 13:20:44 +09:00
k-nasa
1c1e2230f3 Merge branch 'master' into add_stream_flatten 2019-10-18 12:47:48 +09:00
k-nasa
176359afae Add Stream::flatten 2019-10-18 12:20:28 +09:00
k-nasa
8138afbfad feat: Add Stream trait for Flatten 2019-10-18 12:20:02 +09:00
k-nasa
cd862083a5 Add Flatten struct 2019-10-18 12:19:38 +09:00
k-nasa
2187a2a31d feat: Add Stream::flat_map 2019-10-18 10:43:36 +09:00
k-nasa
2dee289750 Add FlatMap struct 2019-10-18 10:43:21 +09:00
k-nasa
bb1416420d feat: Add Stream trait for FlattenCompat 2019-10-18 10:34:53 +09:00
Stjepan Glavina
8bef2e9e95 Don't flush files if they weren't written to 2019-10-17 21:28:38 +02:00
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
2019-10-17 19:17:49 +02:00
k-nasa
ec98b41c85 feat: Add FlattenCompat struct 2019-10-17 23:56:01 +09:00
Stjepan Glavina
46f0fb1c64
Make sure each invocation of block_on uses its own Parker (#358) 2019-10-17 11:52:42 +02:00
k-nasa
f2bf01223c $cargo fmt 2019-10-17 16:34:39 +09:00
k-nasa
70e8476264 fix StdinLock doc test 2019-10-17 16:32:14 +09:00
k-nasa
a5a00d7b14 feat: Add StdinLock struct 2019-10-17 16:29:23 +09:00
Taiki Endo
e405544ea0
Enable tests on CI (#357)
* Enable tests on CI

* Fix failed test
2019-10-17 07:06:29 +09:00
Wouter Geraedts
a2393501c5 Implemented StreamExt::throttle 2019-10-16 18:43:34 +02:00
k-nasa
b58bd8d725 Merge branch 'add_stream_timeout' of https://github.com/k-nasa/async-std into add_stream_timeout 2019-10-16 23:08:23 +09:00
k-nasa
0a4073449b doc: Add Stream::Timeout doc 2019-10-16 22:56:48 +09:00
k-nasa
c3f6f969c5 fix: Rename TimeoutStream to Timeout 2019-10-16 22:56:17 +09:00
k-nasa
53fa132d13 fix type Declaration 2019-10-16 22:45:18 +09:00
k-nasa
9d55fff81d fix export FutureExt 2019-10-16 22:38:28 +09:00
Yoshua Wuyts
ca80ca981e
Merge pull request #338 from async-rs/draft-0.99.10
init 0.99.10 release
2019-10-16 15:32:12 +02:00
Yoshua Wuyts
802d4dfc3b
finalize changelog
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-16 15:24:35 +02:00
nasa
f1ed034600
Update src/stream/stream/mod.rs
Co-Authored-By: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
2019-10-16 22:21:32 +09:00
Yoshua Wuyts
9ff0750d4d
Merge pull request #353 from async-rs/fix-printing
fix print macros
2019-10-16 15:07:33 +02:00
Yoshua Wuyts
6eb3ea2b21
Merge pull request #279 from montekki/fs-stream-repeat-with
Adds stream::repeat_with
2019-10-16 14:35:51 +02:00
Yoshua Wuyts
4d34a15363
fix macros, take II
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-16 14:35:10 +02:00
Yoshua Wuyts
822e4bc220
Merge branch 'master' into fs-stream-repeat-with 2019-10-16 14:26:20 +02:00
Yoshua Wuyts
6e0905d3ca correctly mark stream::Merge as unstable (#352)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-16 14:13:35 +02:00
k-nasa
10f32ca817 Fix TimeoutError 2019-10-16 20:21:45 +09:00
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
2019-10-16 13:14:54 +02:00
k-nasa
358d2bc038 Add import crate 2019-10-16 19:57:03 +09:00
Stjepan Glavina
add6863185
Fix typos 2019-10-16 12:24:18 +02:00
k-nasa
b251fc999a Move delay method to FutureExt::delay 2019-10-16 19:18:05 +09:00
Yoshua Wuyts
faff1f7370 task docs (#346)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-16 10:28:14 +02:00
k-nasa
054f4fac74 feat: Add future::delay 2019-10-16 16:53:43 +09:00
k-nasa
7a87dea085 feat: Add Stream::timeout 2019-10-16 15:31:40 +09:00
k-nasa
f00d32ee7d Add TimeoutStream struct 2019-10-16 15:31:40 +09:00
Yoshua Wuyts
e986e7ba66
Merge pull request #345 from async-rs/io-docs
Io docs
2019-10-16 02:53:38 +02:00
Wouter Geraedts
6b00e5e66c Implemented StreamExt::try_fold (#344) 2019-10-16 02:32:27 +02:00
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
2019-10-16 02:23:41 +02:00
Yoshua Wuyts
d250eee556
port the std::io docs to async_std::io
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-16 02:15:20 +02:00
Yoshua Wuyts
9f8fa45dc7
io docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-16 02:03:26 +02:00
Yoshua Wuyts
2bd82ac249
updates
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-16 01:48:40 +02:00
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
2019-10-16 01:24:27 +02:00
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
2019-10-16 01:11:48 +02:00
assemblaj
f0f279ec04 Adds Stream::le (#336) 2019-10-16 00:46:06 +02:00
assemblaj
a8dc2c6f9b Adds Stream::lt (#337) 2019-10-16 00:32:54 +02:00
Yoshua Wuyts
24cdb2d489 add stream::{Sum,Product} (#343)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-16 00:31:49 +02:00
Yoshua Wuyts
609a5780a2
0.99.10
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-15 17:51:32 +02:00
Yoshua Wuyts
4911f4599b
init changelog
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-15 17:50:24 +02:00
Yoshua Wuyts
00d936488b stabilize future::timeout (#335)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-15 16:33:23 +02:00
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>
2019-10-15 16:27:06 +02:00
Yoshua Wuyts
d46364c834
Merge pull request #299 from async-rs/blocking-updates
Blocking updates
2019-10-15 16:17:07 +02:00
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>
2019-10-15 16:03:49 +02:00
Yoshua Wuyts
33806ad44c
fix warning
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-15 16:01:26 +02:00
Yoshua Wuyts
12fdc1232d
rename task::blocking to task::spawn_blocking
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-15 16:01:26 +02:00
Yoshua Wuyts
b4c1c63fd2
task::blocking async closure -> FnOnce
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-15 16:01:24 +02:00
Yoshua Wuyts
1a3429655c
init blocking-updates
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-15 16:00:15 +02:00
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
2019-10-15 15:50:17 +02:00
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>
2019-10-15 15:30:24 +02:00
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>
2019-10-15 15:27:41 +02:00
Yoshua Wuyts
aed9e2efdf removes Travis CI (#333)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-15 15:27:27 +02:00
k-nasa
94ef3dc2b2 feat: Add Stdout::lock 2019-10-15 21:44:23 +09:00
k-nasa
9b09806593 feat: Add Stdin::lock 2019-10-15 21:44:11 +09:00
k-nasa
f9741e7488 feat: Add Stderr::lock 2019-10-15 21:43:54 +09:00
Wouter Geraedts
c7f6543502 Inline TryFutureExt logic for src/io/timeout.rs (#317) 2019-10-15 09:56:39 +02:00
Yoshua Wuyts
1819408b46 add stream::ExactSizeStream as unstable (#330)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-15 09:51:53 +02:00
Johannes Weissmann
6be8467cdc impl Stream::take_while adapter (#332)
* impl take_while stream adapter

* fmt

* add comment

* unindent where clauses
2019-10-15 09:50:03 +02:00
Yoshua Wuyts
529a58a066
Merge pull request #327 from assemblaj/assemblaj-partial_cmp_final
Adds Stream::partial_cmp
2019-10-15 03:45:21 +02:00
Yoshua Wuyts
00a8433338
Merge pull request #320 from Wassasin/183-async-path
Implement async Path & PathBuf
2019-10-15 02:51:55 +02:00
Stjepan Glavina
aa13ba758b Refactor 2019-10-15 02:05:23 +02:00
Stjepan Glavina
5c1e0522b7 Fix failing tests 2019-10-15 01:33:36 +02:00
Stjepan Glavina
504f8cb137 Use crate::path everywhere 2019-10-15 01:25:20 +02:00
Stjepan Glavina
f9cfee9e2c Formatting 2019-10-15 01:11:32 +02:00
Stjepan Glavina
0adcb50f58 Add ToOwned and Borrow impls 2019-10-15 01:08:12 +02:00
Wouter Geraedts
ba87048db5 Implemented our own Path::ancestors iterator 2019-10-14 22:00:45 +02:00
assemblaj
80bee9a215 Adds Stream::partial_cmp 2019-10-14 11:43:00 -04:00
Yoshua Wuyts
612a94b31e Add process submodule as unstable (#310)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-14 15:51:47 +02:00
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>
2019-10-14 15:49:54 +02:00
Yoshua Wuyts
5f52efe465
Merge pull request #324 from async-rs/stabilize-future-join
stabilize future::{join,try_join}
2019-10-14 15:31:55 +02:00
Yoshua Wuyts
a9950c5c9f stabilize task::ready! (#325)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-14 15:06:24 +02:00
Yoshua Wuyts
fe88da4e64 make all print macros unstable (#322)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-14 14:48:12 +02:00
Yoshua Wuyts
9b0e02dbb7
Merge pull request #326 from async-rs/fused-stream
add stream::FusedStream as "unstable"
2019-10-14 14:22:41 +02:00
Yoshua Wuyts
d6aa1fb501 Add task::yield_now as "unstable" (#300)
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-14 13:58:26 +02:00
Yoshua Wuyts
3ac4575d94
add stream::FusedStream
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-14 02:21:27 +02:00
Yoshua Wuyts
05ba07daf8
stabilize future::{join,try_join}
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-14 01:52:10 +02:00
Yoshua Wuyts
454018ef42
Merge pull request #321 from async-rs/stream_merge
rename stream::join to Stream::merge
2019-10-14 01:46:42 +02:00
Yoshua Wuyts
04342c7b5d
docs
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-13 22:05:11 +02:00
Yoshua Wuyts
b601bcfcb8
polish
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-13 21:55:19 +02:00
Yoshua Wuyts
84a148ddae
rename stream::join to Stream::merge
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-13 21:48:53 +02:00
Wouter Geraedts
8df55dd015 Implemented PathBuf::set_file_name 2019-10-13 21:46:04 +02:00
Wouter Geraedts
54c94b717c Implemented PathBuf::set_extension 2019-10-13 21:41:16 +02:00
Wouter Geraedts
cc417cc001 Implemented PathBuf::push 2019-10-13 21:38:47 +02:00
Wouter Geraedts
07f9e48579 Implemented PathBuf::pop 2019-10-13 21:29:35 +02:00
Wouter Geraedts
71125d5c3b Implemented PathBuf::new 2019-10-13 21:19:23 +02:00
Wouter Geraedts
47ef222dab Implemented PathBuf::into_os_string 2019-10-13 21:13:01 +02:00
Yoshua Wuyts
a2baa1d8e0
rename stream::join to stream::merge
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-13 21:12:05 +02:00
Wouter Geraedts
80eaa28552 Implemented PathBuf::into_boxed_path 2019-10-13 21:11:42 +02:00
Yoshua Wuyts
b9bddbb7a0
Merge pull request #319 from async-rs/print
Add print, println, eprint, eprintln
2019-10-13 21:06:12 +02:00
Wouter Geraedts
1bd17f11f2 Implemented PathBuf::as_path 2019-10-13 21:04:47 +02:00
Wouter Geraedts
409a10a8b5 Implemented Path::with_file_name 2019-10-13 20:55:56 +02:00
Wouter Geraedts
3c24b1891b Implemented Path::with_extension 2019-10-13 20:54:08 +02:00
Wouter Geraedts
a17b017e01 Implemented Path::to_string_lossy 2019-10-13 20:49:57 +02:00
Wouter Geraedts
ea43d7fd29 Implemented Path::to_str 2019-10-13 20:46:51 +02:00
Wouter Geraedts
df53a07fc5 Implemented Path::strip_prefix 2019-10-13 20:45:06 +02:00
Wouter Geraedts
942403c52c Implemented Path::starts_with 2019-10-13 20:14:07 +02:00
Wouter Geraedts
d349333a43 Implemented Path::read_link 2019-10-13 20:12:57 +02:00
Wouter Geraedts
89f73d3eda Implemented Path::read_dir 2019-10-13 19:57:46 +02:00
Yoshua Wuyts
fef2e32a3c
cargo fmt
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-13 19:54:44 +02:00
Yoshua Wuyts
467b64b6e7
doc fmt
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-13 19:54:44 +02:00
Yoshua Wuyts
296d0d9d31
add print macros
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-13 19:54:44 +02:00
Yoshua Wuyts
04479b13c3
add io::stdio
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-13 19:54:44 +02:00
Yoshua Wuyts
33da049717
Merge pull request #311 from async-rs/missing-write-methods
Add Write::write_fmt
2019-10-13 19:53:04 +02:00
Wouter Geraedts
141954d205 Implemented Path::parent 2019-10-13 19:38:33 +02:00
Wouter Geraedts
cc57db02a3 Implemented Path::join 2019-10-13 19:33:55 +02:00
Wouter Geraedts
0c03b92373 Implemented Path::iter 2019-10-13 19:31:17 +02:00
Wouter Geraedts
5d87006006 Implemented Path::is_relative 2019-10-13 19:16:52 +02:00
Wouter Geraedts
df9a01f534 Implemented Path::is_file 2019-10-13 19:15:15 +02:00
Wouter Geraedts
20f58ea1c1 Implemented Path::is_absolute 2019-10-13 19:10:16 +02:00
Wouter Geraedts
3a9597cd32 Implemented Path::has_root 2019-10-13 19:07:12 +02:00
Wouter Geraedts
28e936f6fe Implemented Path::file_stem 2019-10-13 19:05:18 +02:00
Wouter Geraedts
a6e1abecfc Implemented Path::file_name 2019-10-13 19:03:33 +02:00
Wouter Geraedts
a7eaae91ae Implemented Path::extension 2019-10-13 19:00:34 +02:00
Wouter Geraedts
4070833482 Implemented Path::ends_with 2019-10-13 18:58:36 +02:00
Wouter Geraedts
5235cd58be Implemented Path::display 2019-10-13 18:56:26 +02:00
Wouter Geraedts
759e357bea Implemented Path::ancestors 2019-10-13 18:54:36 +02:00
Wouter Geraedts
a57ba7ece0 Implemented Path::into_path_buf 2019-10-13 18:49:57 +02:00
Wouter Geraedts
6c6106a292 Implemented Path::{metadata, symlink_metadata} 2019-10-13 14:17:33 +02:00
Wouter Geraedts
6bbfd039b1 Fixed various tests 2019-10-13 14:11:41 +02:00
Wouter Geraedts
e690b55b18 Implemented fs::metadata and Path::exists 2019-10-13 13:52:58 +02:00
Wouter Geraedts
930b81868d Use std variants of Path and PathBuf internally 2019-10-13 13:46:02 +02:00
Wouter Geraedts
3bd6a9df6d Implemented components 2019-10-13 13:39:12 +02:00
Yoshua Wuyts
28b0ebe83a
Merge pull request #315 from k-nasa/add_flush_to_into_inner
Add BufWriter::into_inner flush
2019-10-13 13:38:22 +02:00
Wouter Geraedts
e27b578c27 WIP init Path and PathBuf async stubs 2019-10-13 13:06:39 +02:00
Yoshua Wuyts
e3e9d65bae
Merge pull request #316 from k-nasa/remove_needles_main_fn
Remove needless main fn
2019-10-13 11:44:15 +02:00
k-nasa
9d9543c46b refactor: Remove needless main fn 2019-10-13 16:33:02 +09:00
k-nasa
13ff627b09 $cargo fmt 2019-10-13 16:02:02 +09:00
k-nasa
ad156b1fce feat: Add BufWriter::into_inner flush 2019-10-13 15:55:32 +09:00
Yoshua Wuyts
b62e4a1e48
update desc
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-13 02:39:14 +02:00
Yoshua Wuyts
a1cd76e244
cargo fmt
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-13 01:36:44 +02:00
Yoshua Wuyts
f3eba1fb48
comments
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-13 01:35:16 +02:00
Yoshua Wuyts
570dedd712
cleanup
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-13 01:31:51 +02:00
Yoshua Wuyts
58c3a06a14
init write_fmt
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-13 01:29:17 +02:00
Yoshua Wuyts
483ded0e1c
fix example
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-12 01:38:53 +02:00
Yoshua Wuyts
064fdf020f
Stream::delay
Signed-off-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2019-10-12 01:35:41 +02:00
Fedor Sakharov
49d123c7f9
Fix review nits 2019-10-06 08:32:44 +03:00
Fedor Sakharov
2384df11ed
Apply suggestions from code review
Co-Authored-By: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
2019-10-06 08:27:44 +03:00
Fedor Sakharov
735d604cd1
Adds stream::repeat_with 2019-10-05 22:17:21 +03:00
282 changed files with 17077 additions and 5029 deletions

3
.github/CONTRIBUTING.md vendored Normal file
View file

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

View file

@ -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,23 +29,130 @@ 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"
build__with_no_std:
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
strategy:
matrix:
target:
- i686-unknown-linux-gnu
- powerpc-unknown-linux-gnu
- powerpc64-unknown-linux-gnu
- mips-unknown-linux-gnu
- arm-linux-androideabi
steps:
- uses: actions/checkout@master
- name: Install nightly
uses: actions-rs/toolchain@v1
with:
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: check_fmt_and_docs:
name: Checking fmt and docs name: Checking fmt and docs
@ -49,15 +160,12 @@ jobs:
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- id: component
uses: actions-rs/components-nightly@v1
with:
component: rustfmt
- 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 }}

View file

@ -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

View file

@ -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

View file

@ -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"
# These are used by the book for examples [[test]]
futures-channel-preview = "=0.3.0-alpha.19" name = "stream"
futures-util-preview = "=0.3.0-alpha.19" required-features = ["unstable"]
[[example]]
name = "tcp-ipv4-and-6-echo"
required-features = ["unstable"]
[[example]]
name = "surf-web"
required-features = ["surf"]

245
README.md
View file

@ -1,142 +1,159 @@
# Async version of the Rust standard library <h1 align="center">async-std</h1>
<div align="center">
<strong>
Async version of the Rust standard library
</strong>
</div>
[![Build Status](https://travis-ci.com/async-rs/async-std.svg?branch=master)](https://travis-ci.com/async-rs/async-std) <br />
[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](https://github.com/async-rs/async-std)
[![Cargo](https://img.shields.io/crates/v/async-std.svg)](https://crates.io/crates/async-std)
[![Documentation](https://docs.rs/async-std/badge.svg)](https://docs.rs/async-std)
[![chat](https://img.shields.io/discord/598880689856970762.svg?logo=discord)](https://discord.gg/JvZeVNe)
This crate provides an async version of [`std`]. It provides all the interfaces you <div align="center">
are used to, but in an async version and ready for Rust's `async`/`await` syntax. <!-- 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`: ```rust
use async_std::task;
```toml async fn say_hello() {
[dependencies] println!("Hello, world!");
async-std = "0.99" }
fn main() {
task::block_on(say_hello())
}
``` ```
Or use [cargo add][cargo-add] if you have it installed: More examples, including networking and file access, can be found in our
[`examples`] directory and in our [documentation].
[`examples`]: https://github.com/async-rs/async-std/tree/master/examples
[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
## Philosophy
We believe Async Rust should be as easy to pick up as Sync Rust. We also believe
that the best API is the one you already know. And finally, we believe that
providing an asynchronous counterpart to the standard library is the best way
stdlib provides a reliable basis for both performance and productivity.
Async-std is the embodiment of that vision. It combines single-allocation task
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.
## Installation
With [cargo add][cargo-add] installed run:
```sh ```sh
$ cargo add async-std $ cargo add async-std
``` ```
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-add]: https://github.com/killercup/cargo-edit
[features documentation]: https://docs.rs/async-std/#features
## Hello world ## Ecosystem
* [async-tls](https://crates.io/crates/async-tls) — Async TLS/SSL streams using **Rustls**.
* [async-native-tls](https://crates.io/crates/async-native-tls) — **Native TLS** for Async. Native TLS for futures and async-std.
* [async-tungstenite](https://crates.io/crates/async-tungstenite) — Asynchronous **WebSockets** for async-std, tokio, gio and any std Futures runtime.
* [Tide](https://crates.io/crates/tide) — Serve the web. A modular **web framework** built around async/await.
```rust * [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.
use async_std::task;
fn main() {
task::block_on(async {
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() {
task::block_on(async {
let raw_response = get().await.expect("request");
let response = String::from_utf8(raw_response)
.expect("utf8 conversion");
println!("received: {}", response);
});
}
```
## Features
`async-std` is strongly commited to following semver. This means your code won't
break unless _you_ decide to upgrade.
However every now and then we come up with something that we think will work
_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
[dependencies.async-std]
version = "0.99"
features = ["unstable"]
```
Just be careful when using these features, as they may change between
versions.
## Take a look around
Clone the repo:
```
git clone git@github.com:async-rs/async-std.git && cd async-std
```
Generate docs:
```
cargo +nightly doc --features docs --open
```
Check out the [examples](examples). To run an example:
```
cargo +nightly run --example hello-world
```
## Contributing
See [our contribution document][contribution].
[contribution]: https://async.rs/contribute
* [Surf](https://crates.io/crates/surf) — Surf the web. Surf is a friendly **HTTP client** built for casual Rustaceans and veterans alike.
* [Xactor](https://crates.io/crates/xactor) — Xactor is a rust actors framework based on async-std.
* [async-graphql](https://crates.io/crates/async-graphql) — A GraphQL server library implemented in rust, with full support for async/await.
## License ## License
Licensed under either of <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>
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) <br/>
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
#### Contribution
<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>

40
benches/mutex.rs Normal file
View file

@ -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;
}
}

11
benches/task.rs Normal file
View file

@ -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 {}));
}

View file

@ -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)

View file

@ -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.

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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).

View file

@ -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,

View file

@ -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,

View file

@ -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.

View file

@ -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,

View file

@ -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>>;

View file

@ -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).

View file

@ -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 {

View file

@ -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>>;

View file

@ -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"
``` ```

View file

@ -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()),
} }
} }

View file

@ -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>();

View file

@ -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() {}

View file

@ -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(())
} }

View file

@ -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(())
})
}

View file

@ -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);

View file

@ -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
}) })
} }

View file

@ -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);
})) }))

View file

@ -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
}) })
} }

View file

@ -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);
})) }))

View file

@ -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
}) })
} }

View file

@ -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:

View file

@ -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
}) })
} }

View file

@ -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.

View file

@ -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
}) })
} }

View file

@ -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)))
} }

View file

@ -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
}) })
} }

View file

@ -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);

View file

@ -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
}) })
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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,26 +107,17 @@ 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)))] impl DirBuilderExt for DirBuilder {
cfg_if! { fn mode(&mut self, mode: u32) -> &mut Self {
if #[cfg(any(unix, feature = "docs"))] { self.mode = Some(mode);
impl DirBuilderExt for DirBuilder { self
fn mode(&mut self, mode: u32) -> &mut Self {
self.mode = Some(mode);
self
}
} }
} }
} }

View file

@ -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()
}
} }
} }
} }

View file

@ -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,83 +408,58 @@ 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 { cfg_unix! {
file: file.clone(), use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
lock: Lock::new(State {
file, impl AsRawFd for File {
mode: Mode::Idle, fn as_raw_fd(&self) -> RawFd {
cache: Vec::new(), self.file.as_raw_fd()
is_flushed: false, }
last_read_err: None, }
last_write_err: None,
}), impl FromRawFd for File {
unsafe fn from_raw_fd(fd: RawFd) -> File {
std::fs::File::from_raw_fd(fd).into()
}
}
impl IntoRawFd for File {
fn into_raw_fd(self) -> RawFd {
let file = self.file.clone();
drop(self);
Arc::try_unwrap(file)
.expect("cannot acquire ownership of the file handle after drop")
.into_raw_fd()
} }
} }
} }
cfg_if! { cfg_windows! {
if #[cfg(feature = "docs")] { use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
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)))] impl AsRawHandle for File {
cfg_if! { fn as_raw_handle(&self) -> RawHandle {
if #[cfg(any(unix, feature = "docs"))] { self.file.as_raw_handle()
impl AsRawFd for File {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}
impl FromRawFd for File {
unsafe fn from_raw_fd(fd: RawFd) -> File {
std::fs::File::from_raw_fd(fd).into()
}
}
impl IntoRawFd for File {
fn into_raw_fd(self) -> RawFd {
let file = self.file.clone();
drop(self);
Arc::try_unwrap(file)
.expect("cannot acquire ownership of the file handle after drop")
.into_raw_fd()
}
} }
} }
}
#[cfg_attr(feature = "docs", doc(cfg(windows)))] impl FromRawHandle for File {
cfg_if! { unsafe fn from_raw_handle(handle: RawHandle) -> File {
if #[cfg(any(windows, feature = "docs"))] { std::fs::File::from_raw_handle(handle).into()
impl AsRawHandle for File {
fn as_raw_handle(&self) -> RawHandle {
self.file.as_raw_handle()
}
} }
}
impl FromRawHandle for File { impl IntoRawHandle for File {
unsafe fn from_raw_handle(handle: RawHandle) -> File { fn into_raw_handle(self) -> RawHandle {
std::fs::File::from_raw_handle(handle).into() let file = self.file.clone();
} drop(self);
} Arc::try_unwrap(file)
.expect("cannot acquire ownership of the file handle after drop")
impl IntoRawHandle for File { .into_raw_handle()
fn into_raw_handle(self) -> RawHandle {
let file = self.file.clone();
drop(self);
Arc::try_unwrap(file)
.expect("cannot acquire ownership of the file handle after drop")
.into_raw_handle()
}
} }
} }
} }
@ -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();
});
}
}

View file

@ -1,86 +1,84 @@
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`].
///
/// Note that file types are mutually exclusive, i.e. at most one of methods [`is_dir`],
/// [`is_file`], and [`is_symlink`] can return `true`.
///
/// This type is a re-export of [`std::fs::FileType`].
///
/// [`Metadata::file_type`]: struct.Metadata.html#method.file_type
/// [`is_dir`]: #method.is_dir
/// [`is_file`]: #method.is_file
/// [`is_symlink`]: #method.is_symlink
/// [`std::fs::FileType`]: https://doc.rust-lang.org/std/fs/struct.FileType.html
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct FileType {
_private: (),
}
impl FileType {
/// Returns `true` if this file type represents a regular directory.
/// ///
/// A file type is returned by [`Metadata::file_type`]. /// If this file type represents a symbolic link, this method returns `false`.
/// ///
/// Note that file types are mutually exclusive, i.e. at most one of methods [`is_dir`], /// # Examples
/// [`is_file`], and [`is_symlink`] can return `true`.
/// ///
/// This type is a re-export of [`std::fs::FileType`]. /// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
/// ///
/// [`Metadata::file_type`]: struct.Metadata.html#method.file_type /// let file_type = fs::metadata(".").await?.file_type();
/// [`is_dir`]: #method.is_dir /// println!("{:?}", file_type.is_dir());
/// [`is_file`]: #method.is_file /// #
/// [`is_symlink`]: #method.is_symlink /// # Ok(()) }) }
/// [`std::fs::FileType`]: https://doc.rust-lang.org/std/fs/struct.FileType.html /// ```
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub fn is_dir(&self) -> bool {
pub struct FileType { unreachable!("this impl only appears in the rendered docs")
_private: (),
} }
impl FileType { /// Returns `true` if this file type represents a regular file.
/// Returns `true` if this file type represents a regular directory. ///
/// /// If this file type represents a symbolic link, this method returns `false`.
/// If this file type represents a symbolic link, this method returns `false`. ///
/// /// # Examples
/// # Examples ///
/// /// ```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 { /// #
/// # /// use async_std::fs;
/// use async_std::fs; ///
/// /// let file_type = fs::metadata("a.txt").await?.file_type();
/// let file_type = fs::metadata(".").await?.file_type(); /// println!("{:?}", file_type.is_file());
/// println!("{:?}", file_type.is_dir()); /// #
/// # /// # Ok(()) }) }
/// # Ok(()) }) } /// ```
/// ``` pub fn is_file(&self) -> bool {
pub fn is_dir(&self) -> bool { unreachable!("this impl only appears in the rendered docs")
unimplemented!() }
}
/// Returns `true` if this file type represents a symbolic link.
/// Returns `true` if this file type represents a regular file. ///
/// /// # Examples
/// If this file type represents a symbolic link, this method returns `false`. ///
/// /// ```no_run
/// # Examples /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// /// #
/// ```no_run /// use async_std::fs;
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ///
/// # /// let file_type = fs::metadata("a.txt").await?.file_type();
/// use async_std::fs; /// println!("{:?}", file_type.is_symlink());
/// /// #
/// let file_type = fs::metadata("a.txt").await?.file_type(); /// # Ok(()) }) }
/// println!("{:?}", file_type.is_file()); /// ```
/// # pub fn is_symlink(&self) -> bool {
/// # Ok(()) }) } unreachable!("this impl only appears in the rendered docs")
/// ```
pub fn is_file(&self) -> bool {
unimplemented!()
}
/// Returns `true` if this file type represents a symbolic link.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let file_type = fs::metadata("a.txt").await?.file_type();
/// println!("{:?}", file_type.is_symlink());
/// #
/// # Ok(()) }) }
/// ```
pub fn is_symlink(&self) -> bool {
unimplemented!()
}
} }
} else {
pub use std::fs::FileType;
} }
} }

View file

@ -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
} }

View file

@ -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,196 +34,196 @@ 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;
use std::time::SystemTime; }
use crate::fs::{FileType, Permissions}; cfg_docs! {
use std::time::SystemTime;
/// Metadata for a file or directory. use crate::fs::{FileType, Permissions};
/// Metadata for a file or directory.
///
/// Metadata is returned by [`metadata`] and [`symlink_metadata`].
///
/// This type is a re-export of [`std::fs::Metadata`].
///
/// [`metadata`]: fn.metadata.html
/// [`symlink_metadata`]: fn.symlink_metadata.html
/// [`is_dir`]: #method.is_dir
/// [`is_file`]: #method.is_file
/// [`std::fs::Metadata`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html
#[derive(Clone, Debug)]
pub struct Metadata {
_private: (),
}
impl Metadata {
/// Returns the file type from this metadata.
/// ///
/// Metadata is returned by [`metadata`] and [`symlink_metadata`]. /// # Examples
/// ///
/// This type is a re-export of [`std::fs::Metadata`]. /// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
/// ///
/// [`metadata`]: fn.metadata.html /// let metadata = fs::metadata("a.txt").await?;
/// [`symlink_metadata`]: fn.symlink_metadata.html /// println!("{:?}", metadata.file_type());
/// [`is_dir`]: #method.is_dir /// #
/// [`is_file`]: #method.is_file /// # Ok(()) }) }
/// [`std::fs::Metadata`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html /// ```
#[derive(Clone, Debug)] pub fn file_type(&self) -> FileType {
pub struct Metadata { unreachable!("this impl only appears in the rendered docs")
_private: (),
} }
impl Metadata { /// Returns `true` if this metadata is for a regular directory.
/// Returns the file type from this metadata. ///
/// /// If this metadata is for a symbolic link, this method returns `false`.
/// # Examples ///
/// /// # Examples
/// ```no_run ///
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// ```no_run
/// # /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::fs; /// #
/// /// use async_std::fs;
/// let metadata = fs::metadata("a.txt").await?; ///
/// println!("{:?}", metadata.file_type()); /// let metadata = fs::metadata(".").await?;
/// # /// println!("{:?}", metadata.is_dir());
/// # Ok(()) }) } /// #
/// ``` /// # Ok(()) }) }
pub fn file_type(&self) -> FileType { /// ```
unimplemented!() pub fn is_dir(&self) -> bool {
} 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 file.
/// If this metadata is for a symbolic link, this method returns `false`. ///
/// /// If this metadata is for a symbolic link, this method returns `false`.
/// # Examples ///
/// /// # Examples
/// ```no_run ///
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// ```no_run
/// # /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::fs; /// #
/// /// use async_std::fs;
/// let metadata = fs::metadata(".").await?; ///
/// println!("{:?}", metadata.is_dir()); /// let metadata = fs::metadata("a.txt").await?;
/// # /// println!("{:?}", metadata.is_file());
/// # Ok(()) }) } /// #
/// ``` /// # Ok(()) }) }
pub fn is_dir(&self) -> bool { /// ```
unimplemented!() pub fn is_file(&self) -> bool {
} unreachable!("this impl only appears in the rendered docs")
}
/// Returns `true` if this metadata is for a regular file.
/// /// Returns the file size in bytes.
/// If this metadata is for a symbolic link, this method returns `false`. ///
/// /// # Examples
/// # Examples ///
/// /// ```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 { /// #
/// # /// use async_std::fs;
/// use async_std::fs; ///
/// /// let metadata = fs::metadata("a.txt").await?;
/// let metadata = fs::metadata("a.txt").await?; /// println!("{}", metadata.len());
/// println!("{:?}", metadata.is_file()); /// #
/// # /// # Ok(()) }) }
/// # Ok(()) }) } /// ```
/// ``` pub fn len(&self) -> u64 {
pub fn is_file(&self) -> bool { unreachable!("this impl only appears in the rendered docs")
unimplemented!() }
}
/// Returns the permissions from this metadata.
/// Returns the file size in bytes. ///
/// /// # Examples
/// # Examples ///
/// /// ```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 { /// #
/// # /// use async_std::fs;
/// use async_std::fs; ///
/// /// let metadata = fs::metadata("a.txt").await?;
/// let metadata = fs::metadata("a.txt").await?; /// println!("{:?}", metadata.permissions());
/// println!("{}", metadata.len()); /// #
/// # /// # Ok(()) }) }
/// # Ok(()) }) } /// ```
/// ``` pub fn permissions(&self) -> Permissions {
pub fn len(&self) -> u64 { unreachable!("this impl only appears in the rendered docs")
unimplemented!() }
}
/// Returns the last modification time.
/// Returns the permissions from this metadata. ///
/// /// # Errors
/// # Examples ///
/// /// This data may not be available on all platforms, in which case an error will be
/// ```no_run /// returned.
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ///
/// # /// # Examples
/// use async_std::fs; ///
/// /// ```no_run
/// let metadata = fs::metadata("a.txt").await?; /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// println!("{:?}", metadata.permissions()); /// #
/// # /// use async_std::fs;
/// # Ok(()) }) } ///
/// ``` /// let metadata = fs::metadata("a.txt").await?;
pub fn permissions(&self) -> Permissions { /// println!("{:?}", metadata.modified());
unimplemented!() /// #
} /// # Ok(()) }) }
/// ```
/// Returns the last modification time. pub fn modified(&self) -> io::Result<SystemTime> {
/// unreachable!("this impl only appears in the rendered docs")
/// # Errors }
///
/// This data may not be available on all platforms, in which case an error will be /// Returns the last access time.
/// returned. ///
/// /// # Errors
/// # Examples ///
/// /// This data may not be available on all platforms, in which case an error will be
/// ```no_run /// returned.
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ///
/// # /// # Examples
/// use async_std::fs; ///
/// /// ```no_run
/// let metadata = fs::metadata("a.txt").await?; /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// println!("{:?}", metadata.modified()); /// #
/// # /// use async_std::fs;
/// # Ok(()) }) } ///
/// ``` /// let metadata = fs::metadata("a.txt").await?;
pub fn modified(&self) -> io::Result<SystemTime> { /// println!("{:?}", metadata.accessed());
unimplemented!() /// #
} /// # Ok(()) }) }
/// ```
/// Returns the last access time. pub fn accessed(&self) -> io::Result<SystemTime> {
/// unreachable!("this impl only appears in the rendered docs")
/// # Errors }
///
/// This data may not be available on all platforms, in which case an error will be /// Returns the creation time.
/// returned. ///
/// /// # Errors
/// # Examples ///
/// /// This data may not be available on all platforms, in which case an error will be
/// ```no_run /// returned.
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ///
/// # /// # Examples
/// use async_std::fs; ///
/// /// ```no_run
/// let metadata = fs::metadata("a.txt").await?; /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// println!("{:?}", metadata.accessed()); /// #
/// # /// use async_std::fs;
/// # Ok(()) }) } ///
/// ``` /// let metadata = fs::metadata("a.txt").await?;
pub fn accessed(&self) -> io::Result<SystemTime> { /// println!("{:?}", metadata.created());
unimplemented!() /// #
} /// # Ok(()) }) }
/// ```
/// Returns the creation time. pub fn created(&self) -> io::Result<SystemTime> {
/// unreachable!("this impl only appears in the rendered docs")
/// # Errors
///
/// This data may not be available on all platforms, in which case an error will be
/// returned.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let metadata = fs::metadata("a.txt").await?;
/// println!("{:?}", metadata.created());
/// #
/// # Ok(()) }) }
/// ```
pub fn created(&self) -> io::Result<SystemTime> {
unimplemented!()
}
} }
} else {
pub use std::fs::Metadata;
} }
} }

View file

@ -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
//! //!

View file

@ -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,27 +297,18 @@ 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)))] impl OpenOptionsExt for OpenOptions {
cfg_if! { fn mode(&mut self, mode: u32) -> &mut Self {
if #[cfg(any(unix, feature = "docs"))] { self.0.mode(mode);
impl OpenOptionsExt for OpenOptions { self
fn mode(&mut self, mode: u32) -> &mut Self { }
self.0.mode(mode);
self
}
fn custom_flags(&mut self, flags: i32) -> &mut Self { fn custom_flags(&mut self, flags: i32) -> &mut Self {
self.0.custom_flags(flags); self.0.custom_flags(flags);
self self
}
} }
} }
} }

View file

@ -1,58 +1,56 @@
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`].
///
/// [`std::fs::Permissions`]: https://doc.rust-lang.org/std/fs/struct.Permissions.html
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Permissions {
_private: (),
}
impl Permissions {
/// Returns the read-only flag.
/// ///
/// This type is a re-export of [`std::fs::Permissions`]. /// # Examples
/// ///
/// [`std::fs::Permissions`]: https://doc.rust-lang.org/std/fs/struct.Permissions.html /// ```no_run
#[derive(Clone, PartialEq, Eq, Debug)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
pub struct Permissions { /// #
_private: (), /// use async_std::fs;
///
/// let perm = fs::metadata("a.txt").await?.permissions();
/// println!("{:?}", perm.readonly());
/// #
/// # Ok(()) }) }
/// ```
pub fn readonly(&self) -> bool {
unreachable!("this impl only appears in the rendered docs")
} }
impl Permissions { /// Configures the read-only flag.
/// Returns the read-only flag. ///
/// /// [`fs::set_permissions`]: fn.set_permissions.html
/// # Examples ///
/// /// # Examples
/// ```no_run ///
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// ```no_run
/// # /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::fs; /// #
/// /// use async_std::fs;
/// let perm = fs::metadata("a.txt").await?.permissions(); ///
/// println!("{:?}", perm.readonly()); /// let mut perm = fs::metadata("a.txt").await?.permissions();
/// # /// perm.set_readonly(true);
/// # Ok(()) }) } /// fs::set_permissions("a.txt", perm).await?;
/// ``` /// #
pub fn readonly(&self) -> bool { /// # Ok(()) }) }
unimplemented!() /// ```
} pub fn set_readonly(&mut self, readonly: bool) {
unreachable!("this impl only appears in the rendered docs")
/// Configures the read-only flag.
///
/// [`fs::set_permissions`]: fn.set_permissions.html
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs;
///
/// let mut perm = fs::metadata("a.txt").await?.permissions();
/// perm.set_readonly(true);
/// fs::set_permissions("a.txt", perm).await?;
/// #
/// # Ok(()) }) }
/// ```
pub fn set_readonly(&mut self, readonly: bool) {
unimplemented!()
}
} }
} else {
pub use std::fs::Permissions;
} }
} }

View file

@ -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
} }

View file

@ -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,9 +46,12 @@ 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 || {
.await std::fs::read_dir(&path)
.map(ReadDir::new) .context(|| format!("could not read directory `{}`", path.display()))
})
.await
.map(ReadDir::new)
} }
/// A stream of entries in a directory. /// A stream of entries in a directory.
@ -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)
})); }));

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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,
},
}
}
}

View file

@ -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"),
}
}
}
}

60
src/future/future/join.rs Normal file
View file

@ -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
}
}

432
src/future/future/mod.rs Normal file
View file

@ -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")
}
}
}

57
src/future/future/race.rs Normal file
View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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
}
}

53
src/future/into_future.rs Normal file
View file

@ -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
}
}

79
src/future/maybe_done.rs Normal file
View file

@ -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(())
}
}

View file

@ -4,63 +4,71 @@
//! //!
//! 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
//!
//! [`Future::join`]: trait.Future.html#method.join
//! [`Future::try_join`]: trait.Future.html#method.try_join
//! [`Future::race`]: trait.Future.html#method.race
//! [`Future::try_race`]: trait.Future.html#method.try_race
#[doc(inline)] cfg_alloc! {
pub use std::future::Future; pub use future::Future;
pub(crate) mod future;
#[doc(inline)] }
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
pub use async_macros::{join, select, try_join, try_select}; cfg_std! {
pub use pending::pending;
use cfg_if::cfg_if; pub use poll_fn::poll_fn;
pub use ready::ready;
pub use pending::pending;
pub use poll_fn::poll_fn; mod pending;
pub use ready::ready; mod poll_fn;
mod ready;
mod pending; }
mod poll_fn;
mod ready; #[cfg(any(feature = "unstable", feature = "default"))]
pub use timeout::{timeout, TimeoutError};
cfg_if! { #[cfg(any(feature = "unstable", feature = "default"))]
if #[cfg(any(feature = "unstable", feature = "docs"))] { mod timeout;
mod timeout;
pub use timeout::{timeout, TimeoutError}; cfg_unstable! {
} pub use into_future::IntoFuture;
pub(crate) use maybe_done::MaybeDone;
mod into_future;
mod maybe_done;
} }

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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
} }
/// A future that times out after a duration of time. pin_project! {
#[doc(hidden)] /// A future that times out after a duration of time.
#[allow(missing_debug_implementations)] pub struct TimeoutFuture<F> {
struct TimeoutFuture<F> { #[pin]
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: (),

View file

@ -2,50 +2,55 @@ 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};
/// A stream of lines in a byte stream. pin_project! {
/// /// 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`].
/// This type is an async version of [`std::io::Lines`]. ///
/// /// This type is an async version of [`std::io::Lines`].
/// [`lines`]: trait.BufRead.html#method.lines ///
/// [`BufRead`]: trait.BufRead.html /// [`lines`]: trait.BufRead.html#method.lines
/// [`std::io::Lines`]: https://doc.rust-lang.org/std/io/struct.Lines.html /// [`BufRead`]: trait.BufRead.html
#[derive(Debug)] /// [`std::io::Lines`]: https://doc.rust-lang.org/std/io/struct.Lines.html
pub struct Lines<R> { #[derive(Debug)]
pub(crate) reader: R, pub struct Lines<R> {
pub(crate) buf: String, #[pin]
pub(crate) bytes: Vec<u8>, pub(crate) reader: R,
pub(crate) read: usize, pub(crate) buf: String,
pub(crate) bytes: Vec<u8>,
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()))))
} }
} }

View file

@ -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! {
if #[cfg(feature = "docs")] {
use std::ops::{Deref, DerefMut};
}
}
extension_trait! { extension_trait! {
use std::ops::{Deref, DerefMut};
#[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> {

View file

@ -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 {
debug_assert!(buf.is_empty()); #[allow(clippy::debug_assert_with_mut_call)]
debug_assert_eq!(*read, 0); {
debug_assert!(buf.is_empty());
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)

View file

@ -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};

51
src/io/buf_read/split.rs Normal file
View file

@ -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![]))))
}
}

View file

@ -2,51 +2,54 @@ 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::io::{self, BufRead, Read, Seek, SeekFrom, DEFAULT_BUF_SIZE};
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
const DEFAULT_CAPACITY: usize = 8 * 1024; 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` /// performs large, infrequent reads on the underlying [`Read`] and maintains an in-memory buffer
/// performs large, infrequent reads on the underlying [`Read`] and maintains an in-memory buffer /// of the incoming byte stream.
/// of the incoming byte stream. ///
/// /// `BufReader` can improve the speed of programs that make *small* and *repeated* read calls to
/// `BufReader` can improve the speed of programs that make *small* and *repeated* read calls to /// the same file or network socket. It does not help when reading very large amounts at once, or
/// the same file or network socket. It does not help when reading very large amounts at once, or /// reading just one or a few times. It also provides no advantage when reading from a source that
/// reading just one or a few times. It also provides no advantage when reading from a source that /// is already in memory, like a `Vec<u8>`.
/// is already in memory, like a `Vec<u8>`. ///
/// /// When the `BufReader` is dropped, the contents of its buffer will be discarded. Creating
/// When the `BufReader` is dropped, the contents of its buffer will be discarded. Creating /// multiple instances of a `BufReader` on the same stream can cause data loss.
/// multiple instances of a `BufReader` on the same stream can cause data loss. ///
/// /// This type is an async version of [`std::io::BufReader`].
/// This type is an async version of [`std::io::BufReader`]. ///
/// /// [`Read`]: trait.Read.html
/// [`Read`]: trait.Read.html /// [`std::io::BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html
/// [`std::io::BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html ///
/// /// # Examples
/// # Examples ///
/// /// ```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 { /// #
/// # /// use async_std::fs::File;
/// use async_std::fs::File; /// use async_std::io::BufReader;
/// use async_std::io::BufReader; /// use async_std::prelude::*;
/// use async_std::prelude::*; ///
/// /// let mut file = BufReader::new(File::open("a.txt").await?);
/// let mut file = BufReader::new(File::open("a.txt").await?); ///
/// /// let mut line = String::new();
/// let mut line = String::new(); /// file.read_line(&mut line).await?;
/// file.read_line(&mut line).await?; /// #
/// # /// # 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> {
@ -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))

View file

@ -1,92 +1,121 @@
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.
///
/// It can be excessively inefficient to work directly with something that
/// implements [`Write`]. For example, every call to
/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A
/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying
/// writer in large, infrequent batches.
///
/// `BufWriter` can improve the speed of programs that make *small* and
/// *repeated* write calls to the same file or network socket. It does not
/// help when writing very large amounts at once, or writing just one or a few
/// times. It also provides no advantage when writing to a destination that is
/// in memory, like a `Vec<u8>`.
///
/// Unlike the `BufWriter` type in `std`, this type does not write out the
/// contents of its buffer when it is dropped. Therefore, it is absolutely
/// critical that users explicitly flush the buffer before dropping a
/// `BufWriter`.
///
/// This type is an async version of [`std::io::BufWriter`].
///
/// [`std::io::BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html
///
/// # Examples
///
/// Let's write the numbers one through ten to a [`TcpStream`]:
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::net::TcpStream;
/// use async_std::prelude::*;
///
/// let mut stream = TcpStream::connect("127.0.0.1:34254").await?;
///
/// for i in 0..10 {
/// let arr = [i+1];
/// stream.write(&arr).await?;
/// }
/// #
/// # Ok(()) }) }
/// ```
///
/// Because we're not buffering, we write each one in turn, incurring the
/// overhead of a system call per byte written. We can fix this with a
/// `BufWriter`:
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::io::BufWriter;
/// use async_std::net::TcpStream;
/// use async_std::prelude::*;
///
/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").await?);
///
/// for i in 0..10 {
/// let arr = [i+1];
/// stream.write(&arr).await?;
/// };
///
/// stream.flush().await?;
/// #
/// # Ok(()) }) }
/// ```
///
/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped
/// together by the buffer, and will all be written out in one system call when
/// the `stream` is dropped.
///
/// [`Write`]: trait.Write.html
/// [`TcpStream::write`]: ../net/struct.TcpStream.html#method.write
/// [`TcpStream`]: ../net/struct.TcpStream.html
/// [`flush`]: trait.Write.html#tymethod.flush
pub struct BufWriter<W> {
#[pin]
inner: W,
buf: Vec<u8>,
written: usize,
}
}
/// Wraps a writer and buffers its output. /// An error returned by `into_inner` which combines an error that
/// /// happened while writing out the buffer, and the buffered writer object
/// It can be excessively inefficient to work directly with something that /// which may be used to recover from the condition.
/// implements [`Write`]. For example, every call to
/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A
/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying
/// writer in large, infrequent batches.
///
/// `BufWriter` can improve the speed of programs that make *small* and
/// *repeated* write calls to the same file or network socket. It does not
/// help when writing very large amounts at once, or writing just one or a few
/// times. It also provides no advantage when writing to a destination that is
/// in memory, like a `Vec<u8>`.
///
/// When the `BufWriter` is dropped, the contents of its buffer will be written
/// out. However, any errors that happen in the process of flushing the buffer
/// when the writer is dropped will be ignored. Code that wishes to handle such
/// errors must manually call [`flush`] before the writer is dropped.
///
/// This type is an async version of [`std::io::BufReader`].
///
/// [`std::io::BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html
/// ///
/// # Examples /// # Examples
/// ///
/// Let's write the numbers one through ten to a [`TcpStream`]:
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::net::TcpStream;
/// use async_std::prelude::*;
///
/// let mut stream = TcpStream::connect("127.0.0.1:34254").await?;
///
/// for i in 0..10 {
/// let arr = [i+1];
/// stream.write(&arr).await?;
/// }
/// #
/// # Ok(()) }) }
/// ```
///
/// Because we're not buffering, we write each one in turn, incurring the
/// overhead of a system call per byte written. We can fix this with a
/// `BufWriter`:
///
/// ```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 {
/// use async_std::io::BufWriter; /// use async_std::io::BufWriter;
/// use async_std::net::TcpStream; /// use async_std::net::TcpStream;
/// use async_std::prelude::*;
/// ///
/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").await?); /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34251").await?);
/// for i in 0..10 { ///
/// let arr = [i+1]; /// // unwrap the TcpStream and flush the buffer
/// stream.write(&arr).await?; /// let stream = match buf_writer.into_inner().await {
/// Ok(s) => s,
/// Err(e) => {
/// // Here, e is an IntoInnerError
/// panic!("An error occurred");
/// }
/// }; /// };
/// # /// #
/// # Ok(()) }) } /// # Ok(()) }) }
/// ``` ///```
/// #[derive(Debug)]
/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped pub struct IntoInnerError<W>(W, crate::io::Error);
/// together by the buffer, and will all be written out in one system call when
/// the `stream` is dropped.
///
/// [`Write`]: trait.Write.html
/// [`TcpStream::write`]: ../net/struct.TcpStream.html#method.write
/// [`TcpStream`]: ../net/struct.TcpStream.html
/// [`flush`]: trait.Write.html#tymethod.flush
pub struct BufWriter<W> {
inner: W,
buf: Vec<u8>,
written: usize,
}
impl<W: Write> BufWriter<W> { impl<W: Write> BufWriter<W> {
pin_utils::unsafe_pinned!(inner: W);
pin_utils::unsafe_unpinned!(buf: Vec<u8>);
/// 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)
} }
} }

View file

@ -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,44 @@ 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! {
reader: R, struct CopyFuture<R, W> {
writer: &'a mut W, #[pin]
amt: u64, reader: R,
} #[pin]
writer: W,
impl<R, W: Unpin + ?Sized> CopyFuture<'_, R, W> { amt: u64,
fn project(self: Pin<&mut Self>) -> (Pin<&mut R>, Pin<&mut W>, &mut u64) {
unsafe {
let this = self.get_unchecked_mut();
(
Pin::new_unchecked(&mut this.reader),
Pin::new(&mut *this.writer),
&mut this.amt,
)
}
} }
} }
impl<R, W> Future for CopyFuture<'_, R, W> 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 +91,92 @@ where
writer, writer,
amt: 0, amt: 0,
}; };
future.await 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
R: BufRead,
W: Write + Unpin,
{
type Output = io::Result<u64>;
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);
}
}
}
let future = CopyFuture {
reader: BufReader::new(reader),
writer,
amt: 0,
};
future.await.context(|| String::from("io::copy failed"))
} }

View file

@ -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: (),
} }

View file

@ -1,59 +1,330 @@
//! 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
//! //!
//! Read a line from the standard input: //! 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 //! ```no_run
//! use async_std::fs::File;
//! 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 {
//! # //! #
//! use async_std::io; //! let mut f = File::open("foo.txt").await?;
//! let mut buffer = [0; 10];
//! //!
//! let stdin = io::stdin(); //! // read up to 10 bytes
//! let mut line = String::new(); //! let n = f.read(&mut buffer).await?;
//! stdin.read_line(&mut line).await?; //!
//! println!("The bytes: {:?}", &buffer[..n]);
//! # //! #
//! # Ok(()) }) } //! # 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!`].
//!
//! ## 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
//! 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 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;
//!
//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
//! #
//! io::copy(&mut io::stdin(), &mut io::stdout()).await?;
//! #
//! # 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
#[doc(inline)] const DEFAULT_BUF_SIZE: usize = 8 * 1024;
pub use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result, SeekFrom};
pub use buf_read::{BufRead, Lines}; cfg_std! {
pub use buf_reader::BufReader; #[doc(inline)]
pub use buf_writer::BufWriter; pub use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result, SeekFrom};
pub use copy::copy;
pub use cursor::Cursor;
pub use empty::{empty, Empty};
pub use read::Read;
pub use repeat::{repeat, Repeat};
pub use seek::Seek;
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 mod prelude; pub use buf_read::{BufRead, Lines, Split};
pub use buf_reader::BufReader;
pub use buf_writer::{BufWriter, IntoInnerError};
pub use copy::copy;
pub use cursor::Cursor;
pub use empty::{empty, Empty};
pub use read::*;
pub use repeat::{repeat, Repeat};
pub use seek::Seek;
pub use sink::{sink, Sink};
pub use write::Write;
pub(crate) mod buf_read; pub mod prelude;
pub(crate) mod read;
pub(crate) mod seek;
pub(crate) mod write;
mod buf_reader; pub(crate) mod buf_read;
mod buf_writer; pub(crate) mod read;
mod copy; pub(crate) mod seek;
mod cursor; pub(crate) mod write;
mod empty; pub(crate) mod utils;
mod repeat;
mod sink; mod buf_reader;
mod stderr; mod buf_writer;
mod stdin; mod copy;
mod stdout; mod cursor;
mod timeout; mod empty;
mod repeat;
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;
#[cfg(not(target_os = "unknown"))]
mod stdin;
#[cfg(not(target_os = "unknown"))]
mod stdio;
#[cfg(not(target_os = "unknown"))]
mod stdout;
}

View file

@ -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;

View file

@ -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::*;

View file

@ -1,20 +1,25 @@
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};
/// Adaptor to chain together two readers. pin_project! {
/// /// Adaptor to chain together two readers.
/// This struct is generally created by calling [`chain`] on a reader. ///
/// Please see the documentation of [`chain`] for more details. /// This struct is generally created by calling [`chain`] on a reader.
/// /// Please see the documentation of [`chain`] for more details.
/// [`chain`]: trait.Read.html#method.chain ///
pub struct Chain<T, U> { /// [`chain`]: trait.Read.html#method.chain
pub(crate) first: T, pub struct Chain<T, U> {
pub(crate) second: U, #[pin]
pub(crate) done_first: bool, pub(crate) first: T,
#[pin]
pub(crate) second: U,
pub(crate) done_first: bool,
}
} }
impl<T, U> Chain<T, U> { impl<T, U> Chain<T, U> {
@ -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::*;

View file

@ -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;
use std::pin::Pin; pub use take::Take;
use std::ops::{Deref, DerefMut};
use crate::io;
use crate::task::{Context, Poll};
}
}
extension_trait! { extension_trait! {
use std::pin::Pin;
use std::ops::{Deref, DerefMut};
use crate::io;
use crate::task::{Context, Poll};
#[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,43 +305,43 @@ 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#"
Creates a "by reference" adaptor for this instance of `Read`. Creates a "by reference" adaptor for this instance of `Read`.
The returned adaptor also implements `Read` and will simply borrow this The returned adaptor also implements `Read` and will simply borrow this
current reader. current reader.
# Examples # Examples
[`File`][file]s implement `Read`: [`File`][file]s implement `Read`:
[file]: ../fs/struct.File.html [file]: ../fs/struct.File.html
```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 {
# #
use async_std::prelude::*; use async_std::prelude::*;
use async_std::fs::File; use async_std::fs::File;
let mut f = File::open("foo.txt").await?; let mut f = File::open("foo.txt").await?;
let mut buffer = Vec::new(); let mut buffer = Vec::new();
let mut other_buffer = Vec::new(); let mut other_buffer = Vec::new();
{ {
let reference = f.by_ref(); let reference = f.by_ref();
// read at most 5 bytes // read at most 5 bytes
reference.take(5).read_to_end(&mut buffer).await?; reference.take(5).read_to_end(&mut buffer).await?;
} // 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
f.read_to_end(&mut other_buffer).await?; f.read_to_end(&mut other_buffer).await?;
# #
@ -346,27 +353,27 @@ extension_trait! {
#[doc = r#" #[doc = r#"
Transforms this `Read` instance to a `Stream` over its bytes. Transforms this `Read` instance to a `Stream` over its bytes.
The returned type implements `Stream` where the `Item` is The returned type implements `Stream` where the `Item` is
`Result<u8, io::Error>`. `Result<u8, io::Error>`.
The yielded item is `Ok` if a byte was successfully read and `Err` The yielded item is `Ok` if a byte was successfully read and `Err`
otherwise. EOF is mapped to returning `None` from this iterator. otherwise. EOF is mapped to returning `None` from this iterator.
# Examples # Examples
[`File`][file]s implement `Read`: [`File`][file]s implement `Read`:
[file]: ../fs/struct.File.html [file]: ../fs/struct.File.html
```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 {
# #
use async_std::prelude::*; use async_std::prelude::*;
use async_std::fs::File; use async_std::fs::File;
let f = File::open("foo.txt").await?; let f = File::open("foo.txt").await?;
let mut s = f.bytes(); let mut s = f.bytes();
while let Some(byte) = s.next().await { while let Some(byte) = s.next().await {
println!("{}", byte.unwrap()); println!("{}", byte.unwrap());
} }
@ -374,35 +381,35 @@ 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#"
Creates an adaptor which will chain this stream with another. Creates an adaptor which will chain this stream with another.
The returned `Read` instance will first read all bytes from this object The returned `Read` instance will first read all bytes from this object
until EOF is encountered. Afterwards the output is equivalent to the until EOF is encountered. Afterwards the output is equivalent to the
output of `next`. output of `next`.
# Examples # Examples
[`File`][file]s implement `Read`: [`File`][file]s implement `Read`:
[file]: ../fs/struct.File.html [file]: ../fs/struct.File.html
```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 {
# #
use async_std::prelude::*; use async_std::prelude::*;
use async_std::fs::File; use async_std::fs::File;
let f1 = File::open("foo.txt").await?; let f1 = File::open("foo.txt").await?;
let f2 = File::open("bar.txt").await?; let f2 = File::open("bar.txt").await?;
let mut handle = f1.chain(f2); let mut handle = f1.chain(f2);
let mut buffer = String::new(); let mut buffer = String::new();
// read the value into a String. We could use any Read method here, // read the value into a String. We could use any Read method here,
// this is just one example. // this is just one example.
handle.read_to_string(&mut buffer).await?; handle.read_to_string(&mut buffer).await?;
@ -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(()) });
})
} }
} }

View file

@ -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};

View file

@ -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};

View file

@ -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};

View file

@ -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 {
debug_assert!(buf.is_empty()); #[allow(clippy::debug_assert_with_mut_call)]
{
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)

View file

@ -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