Last active
February 6, 2024 18:58
-
-
Save shurizzle/1f676ede91630f37b0e4958a93e3700c to your computer and use it in GitHub Desktop.
Blocking and async
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use core::fmt; | |
use std::{future::Future, pin::Pin}; | |
use url::Url; | |
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] | |
#[non_exhaustive] | |
pub struct OpaqueError; | |
impl fmt::Display for OpaqueError { | |
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
write!(f, "shit happens") | |
} | |
} | |
impl std::error::Error for OpaqueError {} | |
#[allow(async_fn_in_trait)] | |
pub trait HttpClient { | |
async fn get(&self, url: Url) -> Result<String, OpaqueError>; | |
} | |
impl HttpClient for reqwest::Client { | |
async fn get(&self, url: Url) -> Result<String, OpaqueError> { | |
let req = self.get(url).build().map_err(|_| OpaqueError)?; | |
let res = self.execute(req).await.map_err(|_| OpaqueError)?; | |
res.text().await.map_err(|_| OpaqueError) | |
} | |
} | |
impl HttpClient for ureq::Agent { | |
async fn get(&self, url: Url) -> Result<String, OpaqueError> { | |
self.request_url("GET", &url) | |
.call() | |
.map_err(|_| OpaqueError)? | |
.into_string() | |
.map_err(|_| OpaqueError) | |
} | |
} | |
struct ApiClient<Http: HttpClient>(Http); | |
impl<Http: HttpClient> ApiClient<Http> { | |
pub fn new(client: Http) -> Self { | |
Self(client) | |
} | |
pub async fn index(&self) -> Result<String, OpaqueError> { | |
self.0 | |
.get(Url::parse("https://www.example.org/").unwrap()) | |
.await | |
} | |
} | |
fn block_on<O, F: Future<Output = O>>(mut f: F) -> O { | |
use std::task::{Context, Poll::*, RawWaker, RawWakerVTable, Waker}; | |
unsafe fn clone(_: *const ()) -> RawWaker { | |
RawWaker::new(core::ptr::null(), &WAKER_VTABLE) | |
} | |
unsafe fn wake(_: *const ()) {} | |
unsafe fn wake_by_ref(_: *const ()) {} | |
unsafe fn drop(_: *const ()) {} | |
const WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop); | |
let mut pin = unsafe { Pin::new_unchecked(&mut f) }; | |
let raw_waker = RawWaker::new(core::ptr::null(), &WAKER_VTABLE); | |
let waker = unsafe { Waker::from_raw(raw_waker) }; | |
let mut ctx = Context::from_waker(&waker); | |
loop { | |
match F::poll(pin.as_mut(), &mut ctx) { | |
Ready(res) => return res, | |
Pending => (), | |
} | |
} | |
} | |
pub struct AsyncClient(ApiClient<reqwest::Client>); | |
pub struct BlockingClient(ApiClient<ureq::Agent>); | |
impl AsyncClient { | |
#[inline] | |
pub fn new() -> Self { | |
Self(ApiClient::new(reqwest::Client::new())) | |
} | |
#[inline] | |
pub async fn index(&self) -> Result<String, OpaqueError> { | |
self.0.index().await | |
} | |
} | |
impl Default for AsyncClient { | |
#[inline] | |
fn default() -> Self { | |
Self::new() | |
} | |
} | |
impl BlockingClient { | |
#[inline] | |
pub fn new() -> Self { | |
Self(ApiClient::new(ureq::AgentBuilder::new().build())) | |
} | |
#[inline] | |
pub fn index(&self) -> Result<String, OpaqueError> { | |
block_on(self.0.index()) | |
} | |
} | |
impl Default for BlockingClient { | |
#[inline] | |
fn default() -> Self { | |
Self::new() | |
} | |
} | |
// #[tokio::main] | |
// async fn main() { | |
// let client = AsyncClient::new(); | |
// _ = dbg!(client.index().await); | |
// } | |
fn main() { | |
let client = BlockingClient::new(); | |
_ = dbg!(client.index()); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "blocking-async" | |
version = "0.1.0" | |
edition = "2021" | |
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |
[dependencies] | |
reqwest = "0.11.24" | |
tokio = { version = "1.36.0", features = ["full"] } | |
ureq = "2.9.4" | |
url = "*" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment