diff --git a/listings/ch17-async-await/listing-17-34/Cargo.lock b/listings/ch17-async-await/listing-17-26/Cargo.lock similarity index 96% rename from listings/ch17-async-await/listing-17-34/Cargo.lock rename to listings/ch17-async-await/listing-17-26/Cargo.lock index c0e8bb2b3f..2e0f3ebedb 100644 --- a/listings/ch17-async-await/listing-17-34/Cargo.lock +++ b/listings/ch17-async-await/listing-17-26/Cargo.lock @@ -265,12 +265,24 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "trpl" version = "0.1.0" dependencies = [ "futures", "tokio", + "tokio-stream", ] [[package]] diff --git a/listings/ch17-async-await/listing-17-32/Cargo.toml b/listings/ch17-async-await/listing-17-26/Cargo.toml similarity index 100% rename from listings/ch17-async-await/listing-17-32/Cargo.toml rename to listings/ch17-async-await/listing-17-26/Cargo.toml diff --git a/listings/ch17-async-await/listing-17-32/src/main.rs b/listings/ch17-async-await/listing-17-26/src/main.rs similarity index 75% rename from listings/ch17-async-await/listing-17-32/src/main.rs rename to listings/ch17-async-await/listing-17-26/src/main.rs index 5e702a2edc..4727e58c48 100644 --- a/listings/ch17-async-await/listing-17-32/src/main.rs +++ b/listings/ch17-async-await/listing-17-26/src/main.rs @@ -4,11 +4,11 @@ fn main() { trpl::block_on(async { // ANCHOR: here let slow = async { - trpl::sleep(Duration::from_secs(5)).await; + trpl::sleep(Duration::from_millis(100)).await; "I finished!" }; - match trpl::timeout(Duration::from_secs(2), slow).await { + match timeout(slow, Duration::from_millis(10)).await { Ok(message) => println!("Succeeded with '{message}'"), Err(duration) => { println!("Failed after {} seconds", duration.as_secs()) diff --git a/listings/ch17-async-await/listing-17-33/Cargo.lock b/listings/ch17-async-await/listing-17-27/Cargo.lock similarity index 96% rename from listings/ch17-async-await/listing-17-33/Cargo.lock rename to listings/ch17-async-await/listing-17-27/Cargo.lock index c0e8bb2b3f..2e0f3ebedb 100644 --- a/listings/ch17-async-await/listing-17-33/Cargo.lock +++ b/listings/ch17-async-await/listing-17-27/Cargo.lock @@ -265,12 +265,24 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "trpl" version = "0.1.0" dependencies = [ "futures", "tokio", + "tokio-stream", ] [[package]] diff --git a/listings/ch17-async-await/listing-17-33/Cargo.toml b/listings/ch17-async-await/listing-17-27/Cargo.toml similarity index 100% rename from listings/ch17-async-await/listing-17-33/Cargo.toml rename to listings/ch17-async-await/listing-17-27/Cargo.toml diff --git a/listings/ch17-async-await/listing-17-33/src/main.rs b/listings/ch17-async-await/listing-17-27/src/main.rs similarity index 51% rename from listings/ch17-async-await/listing-17-33/src/main.rs rename to listings/ch17-async-await/listing-17-27/src/main.rs index 17d2f985f1..a53169bfb2 100644 --- a/listings/ch17-async-await/listing-17-33/src/main.rs +++ b/listings/ch17-async-await/listing-17-27/src/main.rs @@ -7,15 +7,20 @@ fn main() { "Finally finished" }; - // Here we will actually use the new `timeout` with `slow`. + match timeout(slow, Duration::from_millis(10)).await { + Ok(message) => println!("Succeeded with '{message}'"), + Err(duration) => { + println!("Failed after {} seconds", duration.as_secs()) + } + } }); } // ANCHOR: declaration async fn timeout( - max_time: Duration, future: F, + max_time: Duration, ) -> Result { - // ANCHOR_END: declaration - unimplemented!() + // Here is where our implementation will go! } +// ANCHOR_END: declaration diff --git a/listings/ch17-async-await/listing-17-35/Cargo.lock b/listings/ch17-async-await/listing-17-28/Cargo.lock similarity index 96% rename from listings/ch17-async-await/listing-17-35/Cargo.lock rename to listings/ch17-async-await/listing-17-28/Cargo.lock index c0e8bb2b3f..2e0f3ebedb 100644 --- a/listings/ch17-async-await/listing-17-35/Cargo.lock +++ b/listings/ch17-async-await/listing-17-28/Cargo.lock @@ -265,12 +265,24 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "trpl" version = "0.1.0" dependencies = [ "futures", "tokio", + "tokio-stream", ] [[package]] diff --git a/listings/ch17-async-await/listing-17-34/Cargo.toml b/listings/ch17-async-await/listing-17-28/Cargo.toml similarity index 100% rename from listings/ch17-async-await/listing-17-34/Cargo.toml rename to listings/ch17-async-await/listing-17-28/Cargo.toml diff --git a/listings/ch17-async-await/listing-17-35/src/main.rs b/listings/ch17-async-await/listing-17-28/src/main.rs similarity index 92% rename from listings/ch17-async-await/listing-17-35/src/main.rs rename to listings/ch17-async-await/listing-17-28/src/main.rs index 2e389a6509..639d9c8978 100644 --- a/listings/ch17-async-await/listing-17-35/src/main.rs +++ b/listings/ch17-async-await/listing-17-28/src/main.rs @@ -9,9 +9,7 @@ fn main() { "Finally finished" }; - // ANCHOR: main match timeout(Duration::from_secs(2), slow).await { - // ANCHOR_END: main Ok(message) => println!("Succeeded with '{message}'"), Err(duration) => { println!("Failed after {} seconds", duration.as_secs()) @@ -24,8 +22,10 @@ async fn timeout( max_time: Duration, future: F, ) -> Result { + // ANCHOR: implementation match trpl::race(future, trpl::sleep(max_time)).await { Either::Left(output) => Ok(output), Either::Right(_) => Err(max_time), } + // ANCHOR_END: implementation } diff --git a/listings/ch17-async-await/listing-17-32/Cargo.lock b/listings/ch17-async-await/listing-17-32/Cargo.lock deleted file mode 100644 index 3be4eaaa53..0000000000 --- a/listings/ch17-async-await/listing-17-32/Cargo.lock +++ /dev/null @@ -1,540 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "async_await" -version = "0.1.0" -dependencies = [ - "trpl", -] - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "backtrace" -version = "0.3.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "bytes" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" - -[[package]] -name = "cc" -version = "1.0.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "libc" -version = "0.2.154" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "parking_lot" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.5", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "proc-macro2" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" -dependencies = [ - "bitflags", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "syn" -version = "2.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tokio" -version = "1.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-macros" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "trpl" -version = "0.1.0" -dependencies = [ - "futures", - "tokio", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.5", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" -dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/listings/ch17-async-await/listing-17-34/src/main.rs b/listings/ch17-async-await/listing-17-34/src/main.rs deleted file mode 100644 index 7ff4a59390..0000000000 --- a/listings/ch17-async-await/listing-17-34/src/main.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::{future::Future, time::Duration}; - -// ANCHOR: timeout -use trpl::Either; -// ANCHOR_END: timeout - -fn main() { - trpl::block_on(async { - let slow = async { - trpl::sleep(Duration::from_secs(5)).await; - "Finally finished" - }; - - // Here we will actually use the new `timeout` with `slow`. - }); -} - -// Note for maintainers: the extra space after the `ANCHOR` is intentional: it -// makes this render more nicely! -// ANCHOR: timeout - -async fn timeout( - max_time: Duration, - future: F, -) -> Result { - match trpl::race(future, trpl::sleep(max_time)).await { - Either::Left(output) => Ok(output), - Either::Right(_) => Err(max_time), - } -} -// ANCHOR_END: timeout diff --git a/listings/ch17-async-await/listing-17-35/Cargo.toml b/listings/ch17-async-await/listing-17-35/Cargo.toml deleted file mode 100644 index 349041d3eb..0000000000 --- a/listings/ch17-async-await/listing-17-35/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "async_await" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -trpl = { path = "../../../packages/trpl" } diff --git a/packages/trpl/src/lib.rs b/packages/trpl/src/lib.rs index c661ffd459..e95cce16d1 100644 --- a/packages/trpl/src/lib.rs +++ b/packages/trpl/src/lib.rs @@ -13,8 +13,7 @@ //! release at some point. // For direct use within the `trpl` crate, *not* re-exported. -use std::{future::Future, pin::pin, time::Duration}; -use tokio::time; +use std::{future::Future, pin::pin}; // Re-exports, to be used like `trpl::join`. pub use futures::{ @@ -65,22 +64,6 @@ pub fn block_on(future: F) -> F::Output { rt.block_on(future) } -/// Race a future against a specified timeout duration. -/// -/// Under the hood, this uses `tokio::time::timeout`, but instead of returning -/// Tokio's internal error type in the case of a failure, this simply returns -/// the duration which had elapsed. (It actually provides strictly *more* info -/// than Tokio's error does, though it does not `impl Error`.) -pub async fn timeout( - duration: Duration, - future: F, -) -> Result -where - F: Future, -{ - time::timeout(duration, future).await.map_err(|_| duration) -} - /// Run two futures, taking whichever finishes first and canceling the other. /// /// Notice that this is built on [`futures::future::select`], which has the @@ -91,6 +74,13 @@ where /// We use the `race` semantics, where the slower future is simply dropped, for /// the sake of simplicity in the examples: no need to deal with the tuple and /// intentionally ignore the second future this way! +/// +/// Note that this only works as “simply” as it does because: +/// +/// - It takes ownership of the futures. +/// - It internally *pins* the futures. +/// - It throws away (rather than returning) the unused future (which is why it +/// can get away with pinning them). pub async fn race(f1: F1, f2: F2) -> Either where F1: Future, diff --git a/packages/trpl/tests/integration/main.rs b/packages/trpl/tests/integration/main.rs index a46533534a..639c460eb6 100644 --- a/packages/trpl/tests/integration/main.rs +++ b/packages/trpl/tests/integration/main.rs @@ -94,10 +94,10 @@ mod re_exported_join_apis_work { let result = trpl::block_on(async { let a = async { format!("{}", 1) }; - let b = async { format!("Hello") }; + let b = async { "Hello".to_string() }; let outer = String::from("World"); - let c = async move { format!("{outer}") }; + let c = async move { outer.to_string() }; let futures: Vec>>> = vec![Box::pin(a), Box::pin(b), Box::pin(c)]; @@ -131,29 +131,6 @@ mod re_exported_join_apis_work { } } -#[test] -fn re_exported_timeout_works() { - let val = trpl::block_on(async { - let winner = async { - trpl::sleep(Duration::from_millis(1)).await; - String::from("Hello") - }; - trpl::timeout(Duration::from_millis(2), winner).await - }); - - assert_eq!(val, Ok(String::from("Hello"))); - - let val = trpl::block_on(async { - let loser = async { - trpl::sleep(Duration::from_millis(2)).await; - String::from("Hello") - }; - trpl::timeout(Duration::from_millis(1), loser).await - }); - - assert!(val.is_err()); -} - #[test] fn race() { #[derive(Debug, PartialEq)] diff --git a/src/ch17-04-more-ways-of-combining-futures.md b/src/ch17-04-more-ways-of-combining-futures.md index 49e3190237..060cd569f5 100644 --- a/src/ch17-04-more-ways-of-combining-futures.md +++ b/src/ch17-04-more-ways-of-combining-futures.md @@ -73,9 +73,11 @@ a pair of futures. To begin, each future only hands control back to the runtime If you run this, you will see this output: - + ```text 'a' started. @@ -114,9 +116,11 @@ as a starting point? In Listing 17-23, we add `trpl::sleep` calls with await points between each call to `slow`. Now the two futures’ work is interleaved: - + ```text 'a' started. @@ -175,13 +179,13 @@ Listings 17-23 and 17-24. Then we run for 1,000 iterations and see how long The version with `yield_now` is *way* faster! -> Note: This means that async can be a useful tool even for CPU-bound tasks, -> depending on what else your program is doing, because it provides a useful -> tool for structuring the relationships between different parts of the program. -> This is a form of *cooperative multitasking*, where each future has both the -> power to determine when it hands over control via await points and therefore -> also the *responsibility* to avoid blocking for too long. This is how some -> Rust-based embedded operating systems work! +This means that async can be useful even for CPU-bound tasks, depending on what +else your program is doing, because it provides a useful tool for structuring +the relationships between different parts of the program. This is a form of +*cooperative multitasking*, where each future has both the power to determine +when it hands over control via await points. Each future therefore also has the +*responsibility* to avoid blocking for too long. In some Rust-based embedded +operating systems, this is the *only* kind of multitasking! In real-world code, you will not usually be alternating function calls with await points on every single line, of course. The underlying dynamic is an @@ -189,55 +193,57 @@ important one to keep in mind, though! ### Building Our Own Async Abstractions -Many of these patterns are common enough to warrant abstracting over. For -example, the `trpl::timeout` function takes a `Duration` for the maximum time to -run, but also takes a future to run, and produces a new future you can await, -whose `Output` type is a `Result`. Listing 17-32 shows how we can use it. If -the passed-in future finishes first, the output result will be `Ok`, with the -result of that passed-in future. If the duration elapses before the passed-in -future finishes, the result will be `Err` with the duration that elapsed. +We can also compose futures together to create new patterns. For example, we can +build a `timeout` function with async building blocks we already have. When we +are done, the result will be another building block we could use to build up yet +further async abstractions. -+Listing 17-26 shows how we would expect this `timeout` to work with a slow +future. -```rust -{{#rustdoc_include ../listings/ch17-async-await/listing-17-32/src/main.rs:here}} ++ +```rust,ignore +{{#rustdoc_include ../listings/ch17-async-await/listing-17-26/src/main.rs:here}} ``` -Here we were using the `timeout` supplied by `trpl`, but we do not have to. We -can implement it ourselves using `race` and `sleep`! To begin, let’s think about -the API of `timeout`: +Let’s implement this! To begin, let’s think about the API for `timeout`: -- Its first parameter is a `std::time::Duration` which specifies the maximum - time to wait. -- Its second parameter is the future to run. -- It returns a `Result`. If the future completes successfully, the `Result` will - be `Ok` with the value produced by the future. If the timeout happens, the - `Result` will be `Err` with the duration that the timeout waited for. +- It needs to be an async function itself so we can await it. +- Its first parameter should be a future to run. We can make it generic to allow + it to work with any future. +- Its second parameter will be the maximum time to wait. If we use a `Duration`, + that will make it easy to pass along to `trpl::sleep`. +- It should return a `Result`. If the future completes successfully, the + `Result` will be `Ok` with the value produced by the future. If the timeout + elapses first, the `Result` will be `Err` with the duration that the timeout + waited for. -We can write the same signature ourselves, as in Listing 17-33. +Listing 17-27 shows this declaration. -+ ```rust -{{#rustdoc_include ../listings/ch17-async-await/listing-17-33/src/main.rs:declaration}} +{{#rustdoc_include ../listings/ch17-async-await/listing-17-27/src/main.rs:declaration}} ``` -Then, in the body of the function, we can `race` whatever future the caller -passes with a `sleep` future. +The types line up now, so let’s think about the *behavior* we need. We want to +race the future passed in against the duration. We can use `trpl::sleep` to make +a timer future from the duration, and use `trpl::race` to run the future and the +timer against each other. -When we saw `race` earlier in Listing 17-20, we ignored its return type, -because we were just interested in seeing the behavior of `fast` and `slow` when -we ran the program. Here, though, its return value tells us whether the future -or the sleep finished first. With `race`, both futures passed as arguments can +When we saw `race` earlier in Listing 17-20, we ignored its return type, because +we were just interested in seeing the behavior of `fast` and `slow` when we ran +the program. Here, though, its return value tells us whether the future or the +sleep finished first. With `race`, both futures passed as arguments can legitimately “win,” so it does not make sense to use a `Result` to represent the -return type. Instead, it returns a similar type called `Either`. Like `Result`, -`Either` can be one of two types, but unlike `Result`, there is no notion of -success or failure baked into the type. Instead, it uses `Left` and `Right` to -indicate “one or the other”. Its implementation looks like this: +return type. Instead, it returns a similar type called `Either`. Unlike +`Result`, there is no notion of success or failure baked into `Either`. Instead, +it uses `Left` and `Right` to indicate “one or the other”: ```rust enum Either { @@ -246,54 +252,39 @@ enum Either { } ``` -In the case of `race` specifically, it returns `Left` if the first argument -finishes first, with that future’s output, and `Right` with the second future -argument’s output if *that* one finishes first. - -```rust,ignore -match trpl::race(future_a, future_b).await { - Either::Left(output_from_future_a) => /* ... */, - Either::Right(output_from_future_b) => /* ... */, -} -``` +The `race` function returns `Left` if the first argument finishes first, with +that future’s output, and `Right` with the second future argument’s output if +*that* one finishes first. We also know that `race` is not fair, and polls +arguments in the order they are passed. For `timeout`, we pass the future to +`race` first so it gets a chance to complete even if `max_time` is a very short +duration. If `future` finishes first, `race` will return `Left` with the output +from `future`. If `timer` finishes first, `race` will return `Right` with the +timer’s output of `()`. -That gives us enough to be able to implement `timeout` ourselves using `race` -and `sleep`. +In Listing 17-28, we match on the result of awaiting `trpl::race`. If the +future succeeded and we get a `Left(output)`, we return `Ok(output)`. If the +sleep timer elapsed instead and we get a `Right(())`, we ignore the `()` with +`_` and return `Err(duration)` instead. -+ ```rust -{{#rustdoc_include ../listings/ch17-async-await/listing-17-34/src/main.rs:timeout}} +{{#rustdoc_include ../listings/ch17-async-await/listing-17-28/src/main.rs:implementation}} ``` -Let’s walk through the details. Since we know from earlier that `race` is not -fair, and will prefer the first argument to the second, we pass it the future -first so it gets a chance to complete even if the caller passes in a very short -value for `max_time`. Then we match on the result of awaiting the `race`. If the -future passed in by the caller finished first, we will have `Left(output)`, -which we can return as a success with `Ok`. If the sleep finished first, we will -have `Right(())` instead, since `timeout` returns the unit type `()` if it -succeeds. We can ignore that `()` by using `_` and return `Err` with the -duration the user passed in instead. And that’s it! +With that, we have a working `timeout`, built out of two other async helpers. If +we run our code, it will print the failure mode after the timeout: -Back in `main`, we can call this new `timeout` function exactly like we called -`trpl::timeout` before, but without the `trpl::` namespace: - -- -```rust -{{#rustdoc_include ../listings/ch17-async-await/listing-17-35/src/main.rs:main}} +```text +Failed after 2 seconds ``` - - -This pattern is quite common and useful. Futures compose with other futures, so -you can build really powerful tools using smaller async building blocks. For -example, you can use this same approach to combine timeouts with retries, and -in turn use those with things like network calls—the exact example we started -out with at the beginning of the chapter! +Because futures compose with other futures, you can build really powerful tools +using smaller async building blocks. For example, you can use this same approach +to combine timeouts with retries, and in turn use those with things like network +calls—one of the examples from the beginning of the chapter! Over the last two sections, we have seen how to work with multiple futures at the same time. Up next, let’s look at how we can work with multiple futures in a