1 | //! Minimal and reusable non-blocking I/O layer |
2 | //! |
3 | //! The ultimate goal of this crate is *code reuse*. With this crate you can |
4 | //! write *core* I/O APIs that can then be adapted to operate in either blocking |
5 | //! or non-blocking manner. Furthermore those APIs are not tied to a particular |
6 | //! asynchronous model and can be adapted to work with the `futures` model or |
7 | //! with the `async` / `await` model. |
8 | //! |
9 | //! # Core idea |
10 | //! |
11 | //! The [`WouldBlock`](enum.Error.html) error variant signals that the operation |
12 | //! can't be completed *right now* and would need to block to complete. |
13 | //! [`WouldBlock`](enum.Error.html) is a special error in the sense that's not |
14 | //! *fatal*; the operation can still be completed by retrying again later. |
15 | //! |
16 | //! [`nb::Result`](type.Result.html) is based on the API of |
17 | //! [`std::io::Result`](https://doc.rust-lang.org/std/io/type.Result.html), |
18 | //! which has a `WouldBlock` variant in its |
19 | //! [`ErrorKind`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html). |
20 | //! |
21 | //! We can map [`WouldBlock`](enum.Error.html) to different blocking and |
22 | //! non-blocking models: |
23 | //! |
24 | //! - In blocking mode: [`WouldBlock`](enum.Error.html) means try again right |
25 | //! now (i.e. busy wait) |
26 | //! - In `futures` mode: [`WouldBlock`](enum.Error.html) means |
27 | //! [`Async::NotReady`](https://docs.rs/futures) |
28 | //! - In `await` mode: [`WouldBlock`](enum.Error.html) means `yield` |
29 | //! (suspend the generator) |
30 | //! |
31 | //! # How to use this crate |
32 | //! |
33 | //! Application specific errors can be put inside the `Other` variant in the |
34 | //! [`nb::Error`](enum.Error.html) enum. |
35 | //! |
36 | //! So in your API instead of returning `Result<T, MyError>` return |
37 | //! `nb::Result<T, MyError>` |
38 | //! |
39 | //! ``` |
40 | //! enum MyError { |
41 | //! ThisError, |
42 | //! ThatError, |
43 | //! // .. |
44 | //! } |
45 | //! |
46 | //! // This is a blocking function, so it returns a normal `Result` |
47 | //! fn before() -> Result<(), MyError> { |
48 | //! // .. |
49 | //! # Ok(()) |
50 | //! } |
51 | //! |
52 | //! // This is now a potentially (read: *non*) blocking function so it returns `nb::Result` |
53 | //! // instead of blocking |
54 | //! fn after() -> nb::Result<(), MyError> { |
55 | //! // .. |
56 | //! # Ok(()) |
57 | //! } |
58 | //! ``` |
59 | //! |
60 | //! You can use `Infallible` to signal that some API has no fatal |
61 | //! errors but may block: |
62 | //! |
63 | //! ``` |
64 | //! use core::convert::Infallible; |
65 | //! |
66 | //! // This returns `Ok(())` or `Err(nb::Error::WouldBlock)` |
67 | //! fn maybe_blocking_api() -> nb::Result<(), Infallible> { |
68 | //! // .. |
69 | //! # Ok(()) |
70 | //! } |
71 | //! ``` |
72 | //! |
73 | //! Once your API uses [`nb::Result`] you can leverage the [`block!`], macro |
74 | //! to adapt it for blocking operation, or handle scheduling yourself. |
75 | //! |
76 | //! [`block!`]: macro.block.html |
77 | //! [`nb::Result`]: type.Result.html |
78 | //! |
79 | //! # Examples |
80 | //! |
81 | //! ## A Core I/O API |
82 | //! |
83 | //! Imagine the code (crate) below represents a Hardware Abstraction Layer for some microcontroller |
84 | //! (or microcontroller family). |
85 | //! |
86 | //! *In this and the following examples let's assume for simplicity that peripherals are treated |
87 | //! as global singletons and that no preemption is possible (i.e. interrupts are disabled).* |
88 | //! |
89 | //! ``` |
90 | //! # use core::convert::Infallible; |
91 | //! // This is the `hal` crate |
92 | //! use nb; |
93 | //! |
94 | //! /// An LED |
95 | //! pub struct Led; |
96 | //! |
97 | //! impl Led { |
98 | //! pub fn off(&self) { |
99 | //! // .. |
100 | //! } |
101 | //! pub fn on(&self) { |
102 | //! // .. |
103 | //! } |
104 | //! } |
105 | //! |
106 | //! /// Serial interface |
107 | //! pub struct Serial; |
108 | //! pub enum Error { |
109 | //! Overrun, |
110 | //! // .. |
111 | //! } |
112 | //! |
113 | //! impl Serial { |
114 | //! /// Reads a single byte from the serial interface |
115 | //! pub fn read(&self) -> nb::Result<u8, Error> { |
116 | //! // .. |
117 | //! # Ok(0) |
118 | //! } |
119 | //! |
120 | //! /// Writes a single byte to the serial interface |
121 | //! pub fn write(&self, byte: u8) -> nb::Result<(), Error> { |
122 | //! // .. |
123 | //! # Ok(()) |
124 | //! } |
125 | //! } |
126 | //! |
127 | //! /// A timer used for timeouts |
128 | //! pub struct Timer; |
129 | //! |
130 | //! impl Timer { |
131 | //! /// Waits until the timer times out |
132 | //! pub fn wait(&self) -> nb::Result<(), Infallible> { |
133 | //! //^ NOTE the `Infallible` indicates that this operation can block but has no |
134 | //! // other form of error |
135 | //! |
136 | //! // .. |
137 | //! # Ok(()) |
138 | //! } |
139 | //! } |
140 | //! ``` |
141 | //! |
142 | //! ## Blocking mode |
143 | //! |
144 | //! Turn on an LED for one second and *then* loops back serial data. |
145 | //! |
146 | //! ``` |
147 | //! use core::convert::Infallible; |
148 | //! use nb::block; |
149 | //! |
150 | //! use hal::{Led, Serial, Timer}; |
151 | //! |
152 | //! # fn main() -> Result<(), Infallible> { |
153 | //! // Turn the LED on for one second |
154 | //! Led.on(); |
155 | //! block!(Timer.wait())?; |
156 | //! Led.off(); |
157 | //! |
158 | //! // Serial interface loopback |
159 | //! # return Ok(()); |
160 | //! loop { |
161 | //! let byte = block!(Serial.read())?; |
162 | //! block!(Serial.write(byte))?; |
163 | //! } |
164 | //! # } |
165 | //! |
166 | //! # mod hal { |
167 | //! # use nb; |
168 | //! # use core::convert::Infallible; |
169 | //! # pub struct Led; |
170 | //! # impl Led { |
171 | //! # pub fn off(&self) {} |
172 | //! # pub fn on(&self) {} |
173 | //! # } |
174 | //! # pub struct Serial; |
175 | //! # impl Serial { |
176 | //! # pub fn read(&self) -> nb::Result<u8, Infallible> { Ok(0) } |
177 | //! # pub fn write(&self, _: u8) -> nb::Result<(), Infallible> { Ok(()) } |
178 | //! # } |
179 | //! # pub struct Timer; |
180 | //! # impl Timer { |
181 | //! # pub fn wait(&self) -> nb::Result<(), Infallible> { Ok(()) } |
182 | //! # } |
183 | //! # } |
184 | //! ``` |
185 | //! |
186 | //! # Features |
187 | //! |
188 | //! - `defmt-0-3` - unstable feature which adds [`defmt::Format`] impl for [`Error`]. |
189 | |
190 | #![no_std ] |
191 | |
192 | use core::fmt; |
193 | |
194 | /// A non-blocking result |
195 | pub type Result<T, E> = ::core::result::Result<T, Error<E>>; |
196 | |
197 | /// A non-blocking error |
198 | /// |
199 | /// The main use of this enum is to add a `WouldBlock` variant to an existing |
200 | /// error enum. |
201 | #[derive (Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
202 | pub enum Error<E> { |
203 | /// A different kind of error |
204 | Other(E), |
205 | /// This operation requires blocking behavior to complete |
206 | WouldBlock, |
207 | } |
208 | |
209 | #[cfg (feature = "defmt-0-3" )] |
210 | impl<E> defmt::Format for Error<E> |
211 | where |
212 | E: defmt::Format, |
213 | { |
214 | fn format(&self, f: defmt::Formatter) { |
215 | match *self { |
216 | Error::Other(ref e) => defmt::Format::format(e, f), |
217 | Error::WouldBlock => defmt::write!(f, "WouldBlock" ,), |
218 | } |
219 | } |
220 | } |
221 | |
222 | impl<E> fmt::Debug for Error<E> |
223 | where |
224 | E: fmt::Debug, |
225 | { |
226 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
227 | match *self { |
228 | Error::Other(ref e: &E) => fmt::Debug::fmt(self:e, f), |
229 | Error::WouldBlock => f.write_str(data:"WouldBlock" ), |
230 | } |
231 | } |
232 | } |
233 | |
234 | impl<E> Error<E> { |
235 | /// Maps an `Error<E>` to `Error<T>` by applying a function to a contained |
236 | /// `Error::Other` value, leaving an `Error::WouldBlock` value untouched. |
237 | pub fn map<T, F>(self, op: F) -> Error<T> |
238 | where |
239 | F: FnOnce(E) -> T, |
240 | { |
241 | match self { |
242 | Error::Other(e: E) => Error::Other(op(e)), |
243 | Error::WouldBlock => Error::WouldBlock, |
244 | } |
245 | } |
246 | } |
247 | |
248 | impl<E> From<E> for Error<E> { |
249 | fn from(error: E) -> Error<E> { |
250 | Error::Other(error) |
251 | } |
252 | } |
253 | |
254 | /// Turns the non-blocking expression `$e` into a blocking operation. |
255 | /// |
256 | /// This is accomplished by continuously calling the expression `$e` until it no |
257 | /// longer returns `Error::WouldBlock` |
258 | /// |
259 | /// # Input |
260 | /// |
261 | /// An expression `$e` that evaluates to `nb::Result<T, E>` |
262 | /// |
263 | /// # Output |
264 | /// |
265 | /// - `Ok(t)` if `$e` evaluates to `Ok(t)` |
266 | /// - `Err(e)` if `$e` evaluates to `Err(nb::Error::Other(e))` |
267 | #[macro_export ] |
268 | macro_rules! block { |
269 | ($e:expr) => { |
270 | loop { |
271 | #[allow(unreachable_patterns)] |
272 | match $e { |
273 | Err($crate::Error::Other(e)) => |
274 | { |
275 | #[allow(unreachable_code)] |
276 | break Err(e) |
277 | } |
278 | Err($crate::Error::WouldBlock) => {} |
279 | Ok(x) => break Ok(x), |
280 | } |
281 | } |
282 | }; |
283 | } |
284 | |