diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..2f02147ec --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* rust-embedded/embedded-linux diff --git a/.github/bors.toml b/.github/bors.toml new file mode 100644 index 000000000..975deccbd --- /dev/null +++ b/.github/bors.toml @@ -0,0 +1,31 @@ +block_labels = ["needs-decision"] +delete_merged_branches = true +required_approvals = 1 +status = [ + "CI (stable, aarch64-unknown-linux-gnu)", + "CI (stable, arm-unknown-linux-gnueabi)", + "CI (stable, armv7-unknown-linux-gnueabihf)", + "CI (stable, i686-unknown-linux-gnu)", + "CI (stable, i686-unknown-linux-musl)", + "CI (stable, mips-unknown-linux-gnu)", + "CI (stable, mips64-unknown-linux-gnuabi64)", + "CI (stable, mips64el-unknown-linux-gnuabi64)", + "CI (stable, mipsel-unknown-linux-gnu)", + "CI (stable, powerpc-unknown-linux-gnu)", + "CI (stable, powerpc64le-unknown-linux-gnu)", + "CI (stable, s390x-unknown-linux-gnu)", + "CI (stable, x86_64-unknown-linux-gnu)", + "CI (stable, x86_64-unknown-linux-musl)", + "CI (stable, x86_64-apple-darwin)", + + "CI (stable, --features=async-tokio, x86_64-unknown-linux-gnu)", + "CI (stable, --features=mio-evented, x86_64-unknown-linux-gnu)", + + "CI (1.46.0, --features=async-tokio, x86_64-unknown-linux-gnu)", + "CI (1.46.0, --features=mio-evented, x86_64-unknown-linux-gnu)", + "CI (1.46.0, x86_64-unknown-linux-gnu)", + "CI (1.46.0, x86_64-apple-darwin)", + + "checks" +] +timeout_sec = 7200 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..7ac99968a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,129 @@ +on: + push: + branches: [ staging, trying, master ] + pull_request: + +name: CI + +env: + RUSTFLAGS: '--deny warnings' + +jobs: + ci-linux: + name: CI + runs-on: ubuntu-latest + strategy: + matrix: + rust: [stable] + FEATURES: ["", "--features=async-tokio", "--features=mio-evented"] + TARGET: + - aarch64-unknown-linux-gnu + - arm-unknown-linux-gnueabi + - armv7-unknown-linux-gnueabihf + - i686-unknown-linux-gnu + - i686-unknown-linux-musl + - mips-unknown-linux-gnu + - mips64-unknown-linux-gnuabi64 + - mips64el-unknown-linux-gnuabi64 + - mipsel-unknown-linux-gnu + - powerpc-unknown-linux-gnu + # - powerpc64-unknown-linux-gnu + - powerpc64le-unknown-linux-gnu + - s390x-unknown-linux-gnu + - x86_64-unknown-linux-gnu + - x86_64-unknown-linux-musl + + include: + # MSRV + - rust: 1.46.0 + TARGET: x86_64-unknown-linux-gnu + + # Test nightly but don't fail + - rust: nightly + TARGET: x86_64-unknown-linux-gnu + experimental: true + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + target: ${{ matrix.TARGET }} + override: true + + - name: Build + uses: actions-rs/cargo@v1 + with: + command: build + args: --target=${{ matrix.TARGET }} ${{ matrix.FEATURES }} + + - name: Test + uses: actions-rs/cargo@v1 + with: + use-cross: true + command: test + args: --target=${{ matrix.TARGET }} ${{ matrix.FEATURES }} + + ci-macos: + name: CI-macOS + runs-on: macos-11 + + strategy: + matrix: + rust: [stable, 1.46.0] + TARGET: [x86_64-apple-darwin] + + steps: + - uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + target: ${{ matrix.TARGET }} + override: true + + - uses: actions-rs/cargo@v1 + with: + command: build + args: --target=${{ matrix.TARGET }} + + checks: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + components: rustfmt + + - name: Doc + uses: actions-rs/cargo@v1 + with: + command: doc + + - name: Formatting + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + + clippy: + runs-on: ubuntu-latest + env: + RUSTFLAGS: '--allow warnings' + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: 1.46.0 + components: clippy + + - uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f5991441d..000000000 --- a/.travis.yml +++ /dev/null @@ -1,40 +0,0 @@ -language: rust -rust: - - 1.31.1 - - stable - - beta - - nightly - -os: - - linux - - osx - -addons: - apt: - packages: - - libcurl4-openssl-dev - - libelf-dev - - libdw-dev - - binutils-dev - -before_script: - - pip2 install 'travis-cargo<0.2' --user - -env: - global: - - TRAVIS_CARGO_NIGHTLY_FEATURE="" - - PATH="$(python -m site --user-base)/bin:$PATH" - - secure: "Ez5eIIgmsfNoV9NQ9H6KrAYX/Dxx6EUQEyyLMoSFvgJuMaPsyWlsDQDKbl9G+aNDNdSWYtYVFc4/fCW+H7a13HjVwB2CH2mChHSeguO8FSAkWns8tkZ+71SKL5/hg3Ig2m+kvfDjjV1O8seFEgTDP3enHFoRTmBSZHeNryo1ITM=" - -script: - - | - travis-cargo build -- --features=use_tokio && - travis-cargo test -- --features=use_tokio && - travis-cargo build -- --features=mio-evented && - travis-cargo test -- --features=mio-evented && - travis-cargo build -- && - travis-cargo test -- && - travis-cargo --only stable doc -- --features=use_tokio - -after_success: - - '[ $TRAVIS_OS_NAME == linux ] && travis-cargo coveralls --no-sudo --verify' diff --git a/CHANGELOG.md b/CHANGELOG.md index ba5b9147d..c6782f50d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,10 @@ ### Changed -- Migrated to 'tokio' crate. -- Minimmum supported Rust version updated to 1.31 +- [breaking-change] Renamed `use_tokio` feature `async-tokio`. +- Migrated to 'tokio' crate. +- Updated `nix` to version 0.22. +- Minimmum supported Rust version updated to 1.46.0. ## [0.5.3] - 2018-04-19 diff --git a/Cargo.toml b/Cargo.toml index 9cb83025d..3622735eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,20 +1,23 @@ [package] name = "sysfs_gpio" version = "0.5.4" -authors = ["Paul Osborne "] +authors = [ + "Paul Osborne ", + "The Embedded Linux Team ", +] license = "MIT/Apache-2.0" repository = "https://github.com/rust-embedded/rust-sysfs-gpio" homepage = "https://github.com/rust-embedded/rust-sysfs-gpio" -documentation = "http://rust-embedded.github.io/rust-sysfs-gpio/" +documentation = "https://docs.rs/sysfs_gpio/" description = "Provides access to GPIOs using the Linux sysfs interface." readme = "README.md" [features] mio-evented = ["mio"] -use_tokio = ["futures", "tokio", "mio-evented"] +async-tokio = ["futures", "tokio", "mio-evented"] [dependencies] futures = { version = "0.1", optional = true } -nix = "0.14.0" +nix = "0.22" mio = { version = "0.6", optional = true } tokio = { version = "0.1", optional = true } diff --git a/LICENSE-MIT b/LICENSE-MIT index c70652f01..2ca22fdb9 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,7 @@ The MIT License (MIT) Copyright (c) 2015 Paul Osborne +Copyright (c) 2021 The Rust Embedded Linux Team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 1ae30cb13..d8a5fa4d9 100644 --- a/README.md +++ b/README.md @@ -82,11 +82,11 @@ The following features are planned for the library: - [x] Support for configuring interrupts on GPIO - [x] Support for polling on GPIO with configured interrupt - [x] Support for asynchronous polling using `mio` or `tokio` (requires - enabling the `mio-evented` or `use_tokio` crate features, respectively) + enabling the `mio-evented` or `async-tokio` crate features, respectively) ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.31 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.46.0 and up. It *might* compile with older versions but that may change in any new patch release. ## Cross Compiling diff --git a/examples/tokio.rs b/examples/tokio.rs index 9395e9c51..a0810b3ce 100644 --- a/examples/tokio.rs +++ b/examples/tokio.rs @@ -1,20 +1,20 @@ -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] extern crate futures; -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] extern crate sysfs_gpio; -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] extern crate tokio; -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] use std::env; -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] use futures::{lazy, Future, Stream}; -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] use sysfs_gpio::{Direction, Edge, Pin}; -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] fn stream(pin_nums: Vec) -> sysfs_gpio::Result<()> { // NOTE: this currently runs forever and as such if // the app is stopped (Ctrl-C), no cleanup will happen @@ -44,7 +44,7 @@ fn stream(pin_nums: Vec) -> sysfs_gpio::Result<()> { Ok(()) } -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] fn main() { let pins: Vec = env::args() .skip(1) @@ -57,7 +57,7 @@ fn main() { } } -#[cfg(not(feature = "use_tokio"))] +#[cfg(not(feature = "async-tokio"))] fn main() { println!("This example requires the `tokio` feature to be enabled."); } diff --git a/src/error.rs b/src/error.rs index 12793f4ec..5b9a46b31 100644 --- a/src/error.rs +++ b/src/error.rs @@ -17,15 +17,6 @@ pub enum Error { } impl ::std::error::Error for Error { - fn description(&self) -> &str { - match *self { - Error::Io(ref e) => e.description(), - Error::Unexpected(_) => "An Unexpected Error Occurred", - Error::InvalidPath(_) => "A Provided Path was invalid", - Error::Unsupported(_) => "Operation is not supported on target os", - } - } - fn cause(&self) -> Option<&dyn std::error::Error> { match *self { Error::Io(ref e) => Some(e), @@ -53,9 +44,6 @@ impl convert::From for Error { #[cfg(not(target_os = "wasi"))] impl convert::From for Error { fn from(e: nix::Error) -> Error { - match e { - nix::Error::Sys(errno) => Error::Io(errno.into()), - other => Error::Unexpected(format!("{:?}", other)), // should just be dealing with errno case - } + Error::Io(e.into()) } } diff --git a/src/lib.rs b/src/lib.rs index 67a65ada8..044c406fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ //! //! The methods exposed by this library are centered around //! the `Pin` struct and map pretty directly the API exposed -//! by the kernel in syfs (https://www.kernel.org/doc/Documentation/gpio/sysfs.txt). +//! by the kernel in syfs . //! //! # Examples //! @@ -42,26 +42,28 @@ //! } //! ``` -#[cfg(feature = "use_tokio")] +#![cfg_attr(feature = "async-tokio", allow(deprecated))] + +#[cfg(feature = "async-tokio")] extern crate futures; #[cfg(feature = "mio-evented")] extern crate mio; #[cfg(not(target_os = "wasi"))] extern crate nix; -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] extern crate tokio; use std::fs; use std::fs::File; use std::io; use std::io::prelude::*; -#[cfg(any(target_os = "linux", target_os = "android", feature = "use_tokio"))] +#[cfg(any(target_os = "linux", target_os = "android", feature = "async-tokio"))] use std::io::SeekFrom; #[cfg(not(target_os = "wasi"))] use std::os::unix::prelude::*; use std::path::Path; -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] use futures::{Async, Poll, Stream}; #[cfg(feature = "mio-evented")] use mio::unix::EventedFd; @@ -71,7 +73,7 @@ use mio::Evented; use nix::sys::epoll::*; #[cfg(not(target_os = "wasi"))] use nix::unistd::close; -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] use tokio::reactor::{Handle, PollEvented}; pub use error::Error; @@ -126,7 +128,7 @@ fn flush_input_from_file(dev_file: &mut File, max: usize) -> io::Result { } /// Get the pin value from the provided file -#[cfg(any(target_os = "linux", target_os = "android", feature = "use_tokio"))] +#[cfg(any(target_os = "linux", target_os = "android", feature = "async-tokio"))] fn get_value_from_file(dev_file: &mut File) -> Result { let mut s = String::with_capacity(10); dev_file.seek(SeekFrom::Start(0))?; @@ -161,7 +163,7 @@ impl Pin { /// /// This function does not export the provided pin_num. pub fn new(pin_num: u64) -> Pin { - Pin { pin_num: pin_num } + Pin { pin_num } } /// Create a new Pin with the provided path @@ -198,7 +200,7 @@ impl Pin { .file_name() .and_then(|filename| filename.to_str()) .and_then(|filename_str| filename_str.trim_start_matches("gpio").parse::().ok()) - .ok_or(Error::InvalidPath(format!("{:?}", path.as_ref()))) + .ok_or_else(|| Error::InvalidPath(format!("{:?}", path.as_ref()))) } /// Get the pin number @@ -475,10 +477,10 @@ impl Pin { /// The PinStream object can be used with the `tokio` crate. You should probably call /// `set_edge()` before using this. /// - /// This method is only available when the `use_tokio` crate feature is enabled. - #[cfg(feature = "use_tokio")] + /// This method is only available when the `async-tokio` crate feature is enabled. + #[cfg(feature = "async-tokio")] pub fn get_stream_with_handle(&self, handle: &Handle) -> Result { - PinStream::init_with_handle(self.clone(), handle) + PinStream::init_with_handle(*self, handle) } /// Get a Stream of pin interrupts for this pin @@ -486,10 +488,10 @@ impl Pin { /// The PinStream object can be used with the `tokio` crate. You should probably call /// `set_edge()` before using this. /// - /// This method is only available when the `use_tokio` crate feature is enabled. - #[cfg(feature = "use_tokio")] + /// This method is only available when the `async-tokio` crate feature is enabled. + #[cfg(feature = "async-tokio")] pub fn get_stream(&self) -> Result { - PinStream::init(self.clone()) + PinStream::init(*self) } /// Get a Stream of pin values for this pin @@ -502,13 +504,10 @@ impl Pin { /// it could end up producing the same value multiple times if the value has changed back /// between when the interrupt occurred and when the value was read. /// - /// This method is only available when the `use_tokio` crate feature is enabled. - #[cfg(feature = "use_tokio")] + /// This method is only available when the `async-tokio` crate feature is enabled. + #[cfg(feature = "async-tokio")] pub fn get_value_stream_with_handle(&self, handle: &Handle) -> Result { - Ok(PinValueStream(PinStream::init_with_handle( - self.clone(), - handle, - )?)) + Ok(PinValueStream(PinStream::init_with_handle(*self, handle)?)) } /// Get a Stream of pin values for this pin @@ -521,10 +520,10 @@ impl Pin { /// it could end up producing the same value multiple times if the value has changed back /// between when the interrupt occurred and when the value was read. /// - /// This method is only available when the `use_tokio` crate feature is enabled. - #[cfg(feature = "use_tokio")] + /// This method is only available when the `async-tokio` crate feature is enabled. + #[cfg(feature = "async-tokio")] pub fn get_value_stream(&self) -> Result { - Ok(PinValueStream(PinStream::init(self.clone())?)) + Ok(PinValueStream(PinStream::init(*self)?)) } } @@ -568,9 +567,9 @@ impl PinPoller { match epoll_ctl(epoll_fd, EpollOp::EpollCtlAdd, devfile_fd, &mut event) { Ok(_) => Ok(PinPoller { - pin_num: pin_num, - devfile: devfile, - epoll_fd: epoll_fd, + pin_num, + devfile, + epoll_fd, }), Err(err) => { let _ = close(epoll_fd); // cleanup @@ -639,7 +638,7 @@ pub struct AsyncPinPoller { impl AsyncPinPoller { fn new(pin_num: u64) -> Result { let devfile = File::open(&format!("/sys/class/gpio/gpio{}/value", pin_num))?; - Ok(AsyncPinPoller { devfile: devfile }) + Ok(AsyncPinPoller { devfile }) } } @@ -670,23 +669,23 @@ impl Evented for AsyncPinPoller { } } -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] pub struct PinStream { evented: PollEvented, skipped_first_event: bool, } -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] impl PinStream { pub fn init_with_handle(pin: Pin, handle: &Handle) -> Result { Ok(PinStream { - evented: PollEvented::new(pin.get_async_poller()?, &handle)?, + evented: PollEvented::new(pin.get_async_poller()?, handle)?, skipped_first_event: false, }) } } -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] impl PinStream { pub fn init(pin: Pin) -> Result { Ok(PinStream { @@ -696,7 +695,7 @@ impl PinStream { } } -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] impl Stream for PinStream { type Item = (); type Error = Error; @@ -704,7 +703,7 @@ impl Stream for PinStream { fn poll(&mut self) -> Poll, Self::Error> { Ok(match self.evented.poll_read() { Async::Ready(()) => { - self.evented.need_read(); + self.evented.need_read()?; if self.skipped_first_event { Async::Ready(Some(())) } else { @@ -717,10 +716,10 @@ impl Stream for PinStream { } } -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] pub struct PinValueStream(PinStream); -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] impl PinValueStream { #[inline] fn get_value(&mut self) -> Result { @@ -728,7 +727,7 @@ impl PinValueStream { } } -#[cfg(feature = "use_tokio")] +#[cfg(feature = "async-tokio")] impl Stream for PinValueStream { type Item = u8; type Error = Error;