diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7665c24..5a8e9de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,9 @@ on: name: Continuous integration +env: + RUSTFLAGS: '-D warnings' + jobs: ci-linux: runs-on: ubuntu-latest @@ -37,9 +40,8 @@ jobs: - uses: actions-rs/cargo@v1 with: command: check - args: --target=${{ matrix.TARGET }} --features unstable + args: --target=${{ matrix.TARGET }} - uses: actions-rs/cargo@v1 - if: ${{ matrix.rust == 'nightly' }} with: command: test - args: --target=${{ matrix.TARGET }} --features unstable + args: --target=${{ matrix.TARGET }} diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index adc3a6e..d67f81a 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -4,6 +4,10 @@ on: pull_request: name: Clippy check + +env: + RUSTFLAGS: '-D warnings' + jobs: clippy_check: runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index d558354..d0201b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed + +- [breaking-change] The `unstable` feature and its code has been removed. + This includes the macros `try_nb!` and `await!`. + +## [v0.1.2] - 2019-04-21 + +### Added + +- `Error` gained a `map` method that lets you transform the error in the + `Error::Other` variant into a different type. + +- `Error` now implements the `From` trait. + ## [v0.1.1] - 2018-01-10 ### Fixed @@ -17,5 +31,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). Initial release -[Unreleased]: https://github.com/japaric/nb/compare/v0.1.1...HEAD -[v0.1.1]: https://github.com/japaric/nb/compare/v0.1.0...v0.1.1 +[Unreleased]: https://github.com/rust-embedded/nb/compare/v0.1.2...HEAD +[v0.1.2]: https://github.com/rust-embedded/nb/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/rust-embedded/nb/compare/v0.1.0...v0.1.1 diff --git a/Cargo.toml b/Cargo.toml index 4164ef4..88c6015 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,10 +9,5 @@ repository = "https://github.com/rust-embedded/nb" homepage = "https://github.com/rust-embedded/nb" documentation = "https://docs.rs/nb" readme = "README.md" -version = "0.1.1" - -[features] -unstable = [] - -[dev-dependencies] -futures = "0.1.17" +version = "0.1.2" +edition = "2018" diff --git a/src/lib.rs b/src/lib.rs index 3bc561d..359f61a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,29 +57,24 @@ //! } //! ``` //! -//! You can use the *never type* (`!`) to signal that some API has no fatal +//! You can use `Infallible` to signal that some API has no fatal //! errors but may block: //! //! ``` -//! #![feature(never_type)] +//! use core::convert::Infallible; //! //! // This returns `Ok(())` or `Err(nb::Error::WouldBlock)` -//! fn maybe_blocking_api() -> nb::Result<(), !> { +//! fn maybe_blocking_api() -> nb::Result<(), Infallible> { //! // .. //! # Ok(()) //! } //! ``` //! -//! Once your API uses [`nb::Result`](type.Result.html) you can leverage the -//! [`block!`], [`try_nb!`] and [`await!`] macros to adapt it for blocking -//! operation, or for non-blocking operation with `futures` or `await`. -//! -//! **NOTE** Currently, both `try_nb!` and `await!` are feature gated behind the `unstable` Cargo -//! feature. +//! Once your API uses [`nb::Result`] you can leverage the [`block!`], macro +//! to adapt it for blocking operation, or handle scheduling yourself. //! //! [`block!`]: macro.block.html -//! [`try_nb!`]: macro.try_nb.html -//! [`await!`]: macro.await.html +//! [`nb::Result`]: type.Result.html //! //! # Examples //! @@ -92,12 +87,9 @@ //! as global singletons and that no preemption is possible (i.e. interrupts are disabled).* //! //! ``` -//! #![feature(never_type)] -//! +//! # use core::convert::Infallible; //! // This is the `hal` crate -//! // Note that it doesn't depend on the `futures` crate -//! -//! extern crate nb; +//! use nb; //! //! /// An LED //! pub struct Led; @@ -137,8 +129,8 @@ //! //! impl Timer { //! /// Waits until the timer times out -//! pub fn wait(&self) -> nb::Result<(), !> { -//! //^ NOTE the `!` indicates that this operation can block but has no +//! pub fn wait(&self) -> nb::Result<(), Infallible> { +//! //^ NOTE the `Infallible` indicates that this operation can block but has no //! // other form of error //! //! // .. @@ -152,28 +144,25 @@ //! Turn on an LED for one second and *then* loops back serial data. //! //! ``` -//! # #![feature(never_type)] -//! #[macro_use(block)] -//! extern crate nb; +//! use nb::block; //! //! use hal::{Led, Serial, Timer}; //! -//! fn main() { -//! // Turn the LED on for one second -//! Led.on(); -//! block!(Timer.wait()).unwrap(); // NOTE(unwrap) E = ! -//! Led.off(); -//! -//! // Serial interface loopback -//! # return; -//! loop { -//! let byte = block!(Serial.read()).unwrap(); -//! block!(Serial.write(byte)).unwrap(); -//! } +//! // Turn the LED on for one second +//! Led.on(); +//! block!(Timer.wait()).unwrap(); // NOTE(unwrap) E = Infallible +//! Led.off(); +//! +//! // Serial interface loopback +//! # return; +//! loop { +//! let byte = block!(Serial.read()).unwrap(); +//! block!(Serial.write(byte)).unwrap(); //! } //! //! # mod hal { //! # use nb; +//! # use core::convert::Infallible; //! # pub struct Led; //! # impl Led { //! # pub fn off(&self) {} @@ -186,180 +175,12 @@ //! # } //! # pub struct Timer; //! # impl Timer { -//! # pub fn wait(&self) -> nb::Result<(), !> { Ok(()) } -//! # } -//! # } -//! ``` -//! -//! ## `futures` -//! -//! Blinks an LED every second *and* loops back serial data. Both tasks run -//! concurrently. -//! -//! ``` -//! #![feature(conservative_impl_trait)] -//! #![feature(never_type)] -//! -//! extern crate futures; -//! #[macro_use(try_nb)] -//! extern crate nb; -//! -//! use futures::{Async, Future}; -//! use futures::future::{self, Loop}; -//! use hal::{Error, Led, Serial, Timer}; -//! -//! /// `futures` version of `Timer.wait` -//! /// -//! /// This returns a future that must be polled to completion -//! fn wait() -> impl Future { -//! future::poll_fn(|| { -//! Ok(Async::Ready(try_nb!(Timer.wait()))) -//! }) -//! } -//! -//! /// `futures` version of `Serial.read` -//! /// -//! /// This returns a future that must be polled to completion -//! fn read() -> impl Future { -//! future::poll_fn(|| { -//! Ok(Async::Ready(try_nb!(Serial.read()))) -//! }) -//! } -//! -//! /// `futures` version of `Serial.write` -//! /// -//! /// This returns a future that must be polled to completion -//! fn write(byte: u8) -> impl Future { -//! future::poll_fn(move || { -//! Ok(Async::Ready(try_nb!(Serial.write(byte)))) -//! }) -//! } -//! -//! fn main() { -//! // Tasks -//! let mut blinky = future::loop_fn::<_, (), _, _>(true, |state| { -//! wait().map(move |_| { -//! if state { -//! Led.on(); -//! } else { -//! Led.off(); -//! } -//! -//! Loop::Continue(!state) -//! }) -//! }); -//! -//! let mut loopback = future::loop_fn::<_, (), _, _>((), |_| { -//! read().and_then(|byte| { -//! write(byte) -//! }).map(|_| { -//! Loop::Continue(()) -//! }) -//! }); -//! -//! // Event loop -//! loop { -//! blinky.poll().unwrap(); // NOTE(unwrap) E = ! -//! loopback.poll().unwrap(); -//! # break -//! } -//! } -//! -//! # mod hal { -//! # use nb; -//! # pub struct Led; -//! # impl Led { -//! # pub fn off(&self) {panic!()} -//! # pub fn on(&self) {} -//! # } -//! # #[derive(Debug)] -//! # pub enum Error {} -//! # pub struct Serial; -//! # impl Serial { -//! # pub fn read(&self) -> nb::Result { Err(nb::Error::WouldBlock) } -//! # pub fn write(&self, _: u8) -> nb::Result<(), Error> { Err(nb::Error::WouldBlock) } -//! # } -//! # pub struct Timer; -//! # impl Timer { -//! # pub fn wait(&self) -> nb::Result<(), !> { Err(nb::Error::WouldBlock) } -//! # } -//! # } -//! ``` -//! -//! ## `await!` -//! -//! This is equivalent to the `futures` example but with much less boilerplate. -//! -//! ``` -//! #![feature(generator_trait)] -//! #![feature(generators)] -//! #![feature(never_type)] -//! -//! #[macro_use(await)] -//! extern crate nb; -//! -//! extern crate core; -//! use core::ops::Generator; -//! use core::pin::Pin; -//! -//! use hal::{Led, Serial, Timer}; -//! -//! fn main() { -//! // Tasks -//! let mut blinky = || { -//! let mut state = false; -//! loop { -//! // `await!` means suspend / yield instead of blocking -//! await!(Timer.wait()).unwrap(); // NOTE(unwrap) E = ! -//! -//! state = !state; -//! -//! if state { -//! Led.on(); -//! } else { -//! Led.off(); -//! } -//! } -//! }; -//! -//! let mut loopback = || { -//! loop { -//! let byte = await!(Serial.read()).unwrap(); -//! await!(Serial.write(byte)).unwrap(); -//! } -//! }; -//! -//! let blinky = Pin::new(&mut blinky); -//! let loopback = Pin::new(&mut loopback); -//! // Event loop -//! loop { -//! blinky.resume(()); -//! loopback.resume(()); -//! # break -//! } -//! } -//! -//! # mod hal { -//! # use nb; -//! # pub struct Led; -//! # impl Led { -//! # pub fn off(&self) {} -//! # pub fn on(&self) {} -//! # } -//! # pub struct Serial; -//! # impl Serial { -//! # pub fn read(&self) -> nb::Result { Err(nb::Error::WouldBlock) } -//! # pub fn write(&self, _: u8) -> nb::Result<(), ()> { Err(nb::Error::WouldBlock) } -//! # } -//! # pub struct Timer; -//! # impl Timer { -//! # pub fn wait(&self) -> nb::Result<(), !> { Err(nb::Error::WouldBlock) } +//! # pub fn wait(&self) -> nb::Result<(), Infallible> { Ok(()) } //! # } //! # } //! ``` #![no_std] -#![deny(warnings)] use core::fmt; @@ -410,46 +231,6 @@ impl From for Error { } } -/// Await operation (*won't work until the language gains support for -/// generators*) -/// -/// This macro evaluates the expression `$e` *cooperatively* yielding control -/// back to the (generator) caller whenever `$e` evaluates to -/// `Error::WouldBlock`. -/// -/// # Requirements -/// -/// This macro must be called within a generator body. -/// -/// # Input -/// -/// An expression `$e` that evaluates to `nb::Result` -/// -/// # Output -/// -/// - `Ok(t)` if `$e` evaluates to `Ok(t)` -/// - `Err(e)` if `$e` evaluates to `Err(nb::Error::Other(e))` -#[cfg(feature = "unstable")] -#[macro_export] -macro_rules! await { - ($e:expr) => { - loop { - #[allow(unreachable_patterns)] - match $e { - Err($crate::Error::Other(e)) => - { - #[allow(unreachable_code)] - break Err(e) - } - Err($crate::Error::WouldBlock) => {} // yield (see below) - Ok(x) => break Ok(x), - } - - yield - } - }; -} - /// Turns the non-blocking expression `$e` into a blocking operation. /// /// This is accomplished by continuously calling the expression `$e` until it no @@ -480,40 +261,3 @@ macro_rules! block { } }; } - -/// Future adapter -/// -/// This is a *try* operation from a `nb::Result` to a `futures::Poll` -/// -/// # Requirements -/// -/// This macro must be called within a function / closure that has signature -/// `fn(..) -> futures::Poll`. -/// -/// This macro requires that the [`futures`] crate is in the root of the crate. -/// -/// [`futures`]: https://crates.io/crates/futures -/// -/// # Input -/// -/// An expression `$e` that evaluates to `nb::Result` -/// -/// # Early return -/// -/// - `Ok(Async::NotReady)` if `$e` evaluates to `Err(nb::Error::WouldBlock)` -/// - `Err(e)` if `$e` evaluates to `Err(nb::Error::Other(e))` -/// -/// # Output -/// -/// `t` if `$e` evaluates to `Ok(t)` -#[cfg(feature = "unstable")] -#[macro_export] -macro_rules! try_nb { - ($e:expr) => { - match $e { - Err($crate::Error::Other(e)) => return Err(e), - Err($crate::Error::WouldBlock) => return Ok(::futures::Async::NotReady), - Ok(x) => x, - } - }; -}