Skip to main content

semantic_operators/
blocking.rs

1//! An explicit synchronous facade owning its Tokio runtime.
2use crate::{Answers, Error, ErrorKind, Provider, Request, Result, ask};
3/// A provider plus an owned runtime. Async callers use the provider directly.
4pub struct Blocking<P: Provider> {
5    provider: P,
6    runtime: Option<tokio::runtime::Runtime>,
7}
8impl<P: Provider> Blocking<P> {
9    /// Build a private runtime with timers and I/O enabled.
10    ///
11    /// # Errors
12    /// Returns `Runtime` if the owned Tokio runtime cannot be created.
13    pub fn new(provider: P) -> Result<Self> {
14        let runtime = tokio::runtime::Builder::new_multi_thread()
15            .enable_all()
16            .build()
17            .map_err(|_| Error::new(ErrorKind::Runtime, "unable to create blocking runtime"))?;
18        Ok(Self {
19            provider,
20            runtime: Some(runtime),
21        })
22    }
23    /// Run one checked request. Reject nesting inside an active Tokio runtime.
24    ///
25    /// # Errors
26    /// Returns `Runtime` inside an active Tokio runtime or if this facade has
27    /// shut down. Otherwise propagates request, provider, and response-validation
28    /// errors from the checked async call.
29    pub fn ask(&self, request: &Request) -> Result<Answers> {
30        if tokio::runtime::Handle::try_current().is_ok() {
31            return Err(Error::new(
32                ErrorKind::Runtime,
33                "blocking facade cannot run inside a Tokio runtime",
34            ));
35        }
36        self.runtime
37            .as_ref()
38            .ok_or_else(|| Error::new(ErrorKind::Runtime, "runtime is shut down"))?
39            .block_on(ask(&self.provider, request))
40    }
41}
42impl<P: Provider> Drop for Blocking<P> {
43    fn drop(&mut self) {
44        if let Some(runtime) = self.runtime.take() {
45            runtime.shutdown_background();
46        }
47    }
48}