1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//! Extension trait for `Future` to handle `.block()`

use crate::async_impl::AsyncRuntime;
use std::future::Future;

/// Blocks on a `Future` using the hreq configured [`AsyncRuntime`].
///
/// hreq is an async lib but every call can be turned sync by
/// using `.block()` in the same positions you would use `.await`.
/// Depending on the runtime, this might use the blocked thread
/// to drive the entire async operation.
///
/// This feature needs support by the current [`AsyncRuntime`].
/// The only runtime where this *doesn't* work is [`TokioShared`]
/// (see technical notes below).
///
/// # Single thread default
///
/// We want hreq to use a minimal amount of resources. By default
/// hreq uses a tokio runtime using the `rt-core` feature
/// which is a single threaded executor. The user can configure
/// hreq into a runtime with thread pools and work stealing.
///
/// The default runtime configuration is [`TokioSingle`] which
/// supports `.block()`.
///
/// # Usage
///
/// To synchronously make a request put `.block()` where `.await`
/// usually goes.
///
/// ```
/// use hreq::prelude::*;
///
/// let res = Request::get("https://www.google.com")
///     .call().block();
/// ```
///
/// Another way is to group a series of async actions with
/// `.await` and then run the entire thing with one `.block()`.
///
/// ```
/// use hreq::prelude::*;
///
/// let body_str = async {
///     let res = Request::get("https://www.google.com")
///         .call().await?;
///
///     let mut body = res.into_body();
///     body.read_to_string().await
/// }.block().unwrap();
///
/// assert_eq!(&body_str.as_bytes()[0..15], b"<!doctype html>");
/// ```
///
/// # Technical note
///
/// For tokio we need a direct reference to the [`Runtime`] to
/// reach the `block_on` function, something we don't get when
/// talking to a shared runtime via a [`Handle`].
///
/// This is not a problem with async-std where there is only one
/// shared runtime and we can always use the [`block_on`] function.
///
/// [`AsyncRuntime`]: enum.AsyncRuntime.html
/// [`TokioSingle`]: enum.AsyncRuntime.html#variant.TokioSingle
/// [`TokioShared`]: enum.AsyncRuntime.html#variant.TokioShared
/// [`Runtime`]: https://docs.rs/tokio/latest/tokio/runtime/struct.Runtime.html
/// [`Handle`]: https://docs.rs/tokio/latest/tokio/runtime/struct.Handle.html
/// [`block_on`]: https://docs.rs/async-std/latest/async_std/task/fn.block_on.html
pub trait BlockExt {
    /// Block on a future to complete.
    fn block(self) -> Self::Output
    where
        Self: Future;
}

impl<F: Future> BlockExt for F {
    fn block(self) -> F::Output {
        AsyncRuntime::block_on(self)
    }
}