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 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
//! toad-async
// docs
#![doc(html_root_url = "https://docs.rs/toad-async/0.0.0")]
#![cfg_attr(any(docsrs, feature = "docs"), feature(doc_cfg))]
// -
// style
#![allow(clippy::unused_unit)]
// -
// deny
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![deny(missing_copy_implementations)]
#![cfg_attr(not(test), deny(unsafe_code))]
// -
// warnings
#![cfg_attr(not(test), warn(unreachable_pub))]
// -
// features
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "alloc")]
extern crate alloc as std_alloc;
/// Crate glob-reexport for API compatibility with the `nb` crate
pub mod nb {
pub use crate::{Error, Result};
}
/// Non-blocking `Result`
pub type Result<T, E> = core::result::Result<T, Error<E>>;
/// Either an error occurred or the operation would block
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Error<E> {
/// The operation would block
WouldBlock,
/// An error occurred
Other(E),
}
impl<E> Error<E> {
/// Map the error in [`Error::Other`]
pub fn map<F, R>(self, mut f: F) -> Error<R>
where F: FnMut(E) -> R
{
match self {
| Error::Other(e) => Error::Other(f(e)),
| Error::WouldBlock => Error::WouldBlock,
}
}
}
/// Poll the given function `f` until the result returned is not [`Error::WouldBlock`]
///
/// On `std` platforms, this will busy-wait with a small sleep (0.5 millis).
///
/// On `no-std` platforms, this will busy-wait.
pub fn block<T, E, F>(f: F) -> core::result::Result<T, E>
where F: Fn() -> Result<T, E>
{
loop {
match f() {
| Ok(ok) => break Ok(ok),
| Err(Error::Other(e)) => break Err(e),
| Err(Error::WouldBlock) => {
#[cfg(feature = "std")]
std::thread::sleep(std::time::Duration::from_nanos(500));
continue;
},
}
}
}
/// Helper methods for [`crate::Result`]
pub trait AsyncResult<T, E>
where Self: Sized
{
/// Map the error type contained in the result (if present)
/// preserving `Ok` and `Err(Error::WouldBlock)`
fn async_map_err<F, R>(self, f: F) -> Result<T, R>
where F: FnMut(E) -> R;
}
impl<T, E> AsyncResult<T, E> for Result<T, E> {
fn async_map_err<F, R>(self, mut f: F) -> Result<T, R>
where F: FnMut(E) -> R
{
self.map_err(|e| match e {
| Error::WouldBlock => Error::WouldBlock,
| Error::Other(e) => Error::Other(f(e)),
})
}
}
/// Helper methods for nullary closures returning [`crate::Result`]
pub trait AsyncPollable<T, E> {
/// Convenience method for [`crate::block`]
///
/// ```no_run
/// use std::fs::File;
/// use std::io;
///
/// use toad_async::{nb, AsyncPollable};
///
/// fn wait_for_file() -> nb::Result<File, io::Error> {
/// match File::open("foo.txt") {
/// | Ok(f) => Ok(f),
/// | Err(e) if e.kind() == io::ErrorKind::NotFound => Err(nb::Error::WouldBlock),
/// | Err(e) => Err(nb::Error::Other(e)),
/// }
/// }
///
/// let f: io::Result<File> = wait_for_file.block();
/// ```
fn block(self) -> core::result::Result<T, E>;
}
impl<F, T, E> AsyncPollable<T, E> for F where F: Fn() -> Result<T, E>
{
fn block(self) -> core::result::Result<T, E> {
crate::block(self)
}
}