diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 628c3e5..be1e377 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,12 +4,9 @@ on: - "gh-readonly-queue/**" pull_request: # Run CI for PRs on any branch merge_group: # Run CI for the GitHub merge queue - name: Build - env: RUSTFLAGS: '--deny warnings' - jobs: build: runs-on: ubuntu-latest @@ -32,86 +29,50 @@ jobs: - s390x-unknown-linux-gnu - x86_64-unknown-linux-gnu - x86_64-unknown-linux-musl - include: # MSRV - - rust: 1.82.0 + - rust: 1.85.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 - + - uses: actions/checkout@v4 + - name: Install cross + run: cargo install cross --git https://github.com/cross-rs/cross --locked - name: Build - uses: actions-rs/cargo@v1 - with: - command: build - args: --target=${{ matrix.TARGET }} - + run: cross build --target=${{ matrix.TARGET }} - name: Build all features - uses: actions-rs/cargo@v1 - with: - command: build - args: --target=${{ matrix.TARGET }} --all-features - + run: cross build --target=${{ matrix.TARGET }} --all-features - name: Test - uses: actions-rs/cargo@v1 - with: - use-cross: true - command: test - args: --target=${{ matrix.TARGET }} - + run: cross test --target=${{ matrix.TARGET }} - name: Test all features - uses: actions-rs/cargo@v1 - with: - use-cross: true - command: test - args: --target=${{ matrix.TARGET }} --all-features - + run: cross test --target=${{ matrix.TARGET }} --all-features checks: runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable with: - profile: minimal - toolchain: stable components: rustfmt - + - uses: Swatinem/rust-cache@v2 + - name: Ensure rustfmt is installed + run: rustup component add rustfmt - name: Doc - uses: actions-rs/cargo@v1 - with: - command: doc - + run: cargo doc - name: Formatting - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check - + run: cargo fmt --all -- --check clippy: runs-on: ubuntu-latest env: RUSTFLAGS: '--allow warnings' steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: - profile: minimal - toolchain: 1.82.0 + toolchain: 1.85.0 components: clippy - - - uses: actions-rs/clippy-check@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} + - uses: Swatinem/rust-cache@v2 + - name: Clippy + run: cargo clippy --all-targets --all-features -- -D warnings \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 135e768..e64896e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ Versioning](https://semver.org/spec/v2.0.0.html). ### Changed -- MSRV is now 1.82.0. +- MSRV is now 1.85.0. ## [v0.6.0] - 2023-09-11 diff --git a/Cargo.toml b/Cargo.toml index c7d44a9..9e76bb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,18 +20,17 @@ name = "async_tokio" required-features = ["async-tokio"] [dependencies] -bitflags = "2.4" +bitflags = "2.13" libc = "0.2" -nix = { version = "0.27", features = ["ioctl"] } +nix = { version = "0.31", features = ["ioctl"] } tokio = { version = "1", features = ["io-std", "net"], optional = true } futures = { version = "0.3", optional = true } [dev-dependencies] -quicli = "0.4" -structopt = "0.3" +clap = { version = "4", features = ["derive"] } anyhow = "1.0" tokio = { version = "1", features = ["io-std", "rt-multi-thread", "macros", "net"] } -nix = { version = "0.27", features = ["ioctl", "poll"] } +nix = { version = "0.31", features = ["ioctl", "poll"] } [package.metadata.docs.rs] # To build locally: diff --git a/README.md b/README.md index a44d08d..35a059c 100644 --- a/README.md +++ b/README.md @@ -206,7 +206,7 @@ to be considered reliable. ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.82.0 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.85.0 and up. It *might* compile with older versions but that may change in any new patch release. ## License diff --git a/examples/async_tokio.rs b/examples/async_tokio.rs index 6fd90cd..6b6e595 100644 --- a/examples/async_tokio.rs +++ b/examples/async_tokio.rs @@ -6,11 +6,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use clap::Parser; use futures::stream::StreamExt; use gpio_cdev::{AsyncLineEventHandle, Chip, EventRequestFlags, LineRequestFlags}; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] struct Cli { /// The gpiochip device (e.g. /dev/gpiochip0) chip: String, @@ -27,18 +27,15 @@ async fn do_main(args: Cli) -> std::result::Result<(), gpio_cdev::Error> { "gpioevents", )?)?; - loop { - match events.next().await { - Some(event) => println!("{:?}", event?), - None => break, - }; + while let Some(event) = events.next().await { + println!("{:?}", event?); } Ok(()) } #[tokio::main] -async fn main() { - let args = Cli::from_args(); - do_main(args).await.unwrap(); +async fn main() -> std::result::Result<(), gpio_cdev::Error> { + let args = Cli::parse(); + do_main(args).await } diff --git a/examples/blinky.rs b/examples/blinky.rs index 8578648..89ce9ba 100644 --- a/examples/blinky.rs +++ b/examples/blinky.rs @@ -6,13 +6,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use clap::Parser; use gpio_cdev::{Chip, LineRequestFlags}; -use quicli::prelude::*; use std::thread::sleep; use std::time::{Duration, Instant}; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] struct Cli { /// The gpiochip device (e.g. /dev/gpiochip0) chip: String, @@ -45,10 +44,7 @@ fn do_main(args: Cli) -> std::result::Result<(), gpio_cdev::Error> { Ok(()) } -fn main() -> CliResult { - let args = Cli::from_args(); - do_main(args).or_else(|e| { - error!("{:?}", e); - Ok(()) - }) +fn main() -> std::result::Result<(), gpio_cdev::Error> { + let args = Cli::parse(); + do_main(args) } diff --git a/examples/driveoutput.rs b/examples/driveoutput.rs index 1e2be61..4bb03ec 100644 --- a/examples/driveoutput.rs +++ b/examples/driveoutput.rs @@ -6,11 +6,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use clap::Parser; use gpio_cdev::{Chip, LineRequestFlags}; -use quicli::prelude::*; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] struct Cli { /// The gpiochip device (e.g. /dev/gpiochip0) chip: String, @@ -41,10 +40,7 @@ fn do_main(args: Cli) -> std::result::Result<(), gpio_cdev::Error> { Ok(()) } -fn main() -> CliResult { - let args = Cli::from_args(); - do_main(args).or_else(|e| { - error!("{:?}", e); - Ok(()) - }) +fn main() -> std::result::Result<(), gpio_cdev::Error> { + let args = Cli::parse(); + do_main(args) } diff --git a/examples/gpioevents.rs b/examples/gpioevents.rs index 3f02877..a362705 100644 --- a/examples/gpioevents.rs +++ b/examples/gpioevents.rs @@ -6,11 +6,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use clap::Parser; use gpio_cdev::{Chip, EventRequestFlags, LineRequestFlags}; -use quicli::prelude::*; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] struct Cli { /// The gpiochip device (e.g. /dev/gpiochip0) chip: String, @@ -33,10 +32,7 @@ fn do_main(args: Cli) -> std::result::Result<(), gpio_cdev::Error> { Ok(()) } -fn main() -> CliResult { - let args = Cli::from_args(); - do_main(args).or_else(|e| { - error!("{:?}", e); - Ok(()) - }) +fn main() -> std::result::Result<(), gpio_cdev::Error> { + let args = Cli::parse(); + do_main(args) } diff --git a/examples/lsgpio.rs b/examples/lsgpio.rs index 414aedb..e2c0eca 100644 --- a/examples/lsgpio.rs +++ b/examples/lsgpio.rs @@ -19,56 +19,54 @@ fn main() { } }; - for chip in chip_iterator { - if let Ok(chip) = chip { - println!( - "GPIO chip: {}, \"{}\", \"{}\", {} GPIO Lines", - chip.path().to_string_lossy(), - chip.name(), - chip.label(), - chip.num_lines() - ); - for line in chip.lines() { - match line.info() { - Ok(info) => { - let mut flags = vec![]; + for chip in chip_iterator.flatten() { + println!( + "GPIO chip: {}, \"{}\", \"{}\", {} GPIO Lines", + chip.path().to_string_lossy(), + chip.name(), + chip.label(), + chip.num_lines() + ); + for line in chip.lines() { + match line.info() { + Ok(info) => { + let mut flags = vec![]; - if info.is_kernel() { - flags.push("kernel"); - } + if info.is_kernel() { + flags.push("kernel"); + } - if info.direction() == LineDirection::Out { - flags.push("output"); - } + if info.direction() == LineDirection::Out { + flags.push("output"); + } - if info.is_active_low() { - flags.push("active-low"); - } - if info.is_open_drain() { - flags.push("open-drain"); - } - if info.is_open_source() { - flags.push("open-source"); - } + if info.is_active_low() { + flags.push("active-low"); + } + if info.is_open_drain() { + flags.push("open-drain"); + } + if info.is_open_source() { + flags.push("open-source"); + } - let usage = if !flags.is_empty() { - format!("[{}]", flags.join(" ")) - } else { - "".to_owned() - }; + let usage = if !flags.is_empty() { + format!("[{}]", flags.join(" ")) + } else { + "".to_owned() + }; - println!( - "\tline {lineno:>3}: {name} {consumer} {usage}", - lineno = info.line().offset(), - name = info.name().unwrap_or("unused"), - consumer = info.consumer().unwrap_or("unused"), - usage = usage, - ); - } - Err(e) => println!("\tError getting line info: {:?}", e), + println!( + "\tline {lineno:>3}: {name} {consumer} {usage}", + lineno = info.line().offset(), + name = info.name().unwrap_or("unused"), + consumer = info.consumer().unwrap_or("unused"), + usage = usage, + ); } + Err(e) => println!("\tError getting line info: {:?}", e), } - println!(); } + println!(); } } diff --git a/examples/monitor.rs b/examples/monitor.rs index 7925907..73e6d9a 100644 --- a/examples/monitor.rs +++ b/examples/monitor.rs @@ -6,15 +6,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use clap::Parser; use gpio_cdev::*; use nix::poll::*; -use quicli::prelude::*; -use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd}; -use structopt::StructOpt; +use std::os::{ + fd::AsFd, + unix::io::{AsRawFd, FromRawFd, OwnedFd}, +}; type PollEventFlags = nix::poll::PollFlags; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] struct Cli { /// The gpiochip device (e.g. /dev/gpiochip0) chip: String, @@ -47,12 +49,12 @@ fn do_main(args: Cli) -> anyhow::Result<()> { .collect(); let mut pollfds: Vec = ownedfd .iter() - .map(|fd| PollFd::new(fd, PollEventFlags::POLLIN | PollEventFlags::POLLPRI)) + .map(|fd| PollFd::new(fd.as_fd(), PollEventFlags::POLLIN | PollEventFlags::POLLPRI)) .collect(); loop { // poll for an event on any of the lines - if poll(&mut pollfds, -1)? == 0 { + if poll(&mut pollfds, PollTimeout::NONE)? == 0 { println!("Timeout?!?"); } else { for i in 0..pollfds.len() { @@ -76,10 +78,7 @@ fn do_main(args: Cli) -> anyhow::Result<()> { } } -fn main() -> CliResult { - let args = Cli::from_args(); - do_main(args).or_else(|e| { - error!("{:?}", e); - Ok(()) - }) +fn main() -> anyhow::Result<()> { + let args = Cli::parse(); + do_main(args) } diff --git a/examples/multioutput.rs b/examples/multioutput.rs index 4f0acae..72e6fbd 100644 --- a/examples/multioutput.rs +++ b/examples/multioutput.rs @@ -6,11 +6,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use clap::Parser; use gpio_cdev::{Chip, LineRequestFlags}; -use quicli::prelude::*; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] struct Cli { /// The gpiochip device (e.g. /dev/gpiochip0) chip: String, @@ -49,10 +48,7 @@ fn do_main(args: Cli) -> std::result::Result<(), gpio_cdev::Error> { Ok(()) } -fn main() -> CliResult { - let args = Cli::from_args(); - do_main(args).or_else(|e| { - error!("{:?}", e); - Ok(()) - }) +fn main() -> std::result::Result<(), gpio_cdev::Error> { + let args = Cli::parse(); + do_main(args) } diff --git a/examples/multiread.rs b/examples/multiread.rs index f79e027..67e0d59 100644 --- a/examples/multiread.rs +++ b/examples/multiread.rs @@ -6,11 +6,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use clap::Parser; use gpio_cdev::{Chip, LineRequestFlags}; -use quicli::prelude::*; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] struct Cli { /// The gpiochip device (e.g. /dev/gpiochip0) chip: String, @@ -29,10 +28,7 @@ fn do_main(args: Cli) -> std::result::Result<(), gpio_cdev::Error> { Ok(()) } -fn main() -> CliResult { - let args = Cli::from_args(); - do_main(args).or_else(|e| { - error!("{:?}", e); - Ok(()) - }) +fn main() -> std::result::Result<(), gpio_cdev::Error> { + let args = Cli::parse(); + do_main(args) } diff --git a/examples/readall.rs b/examples/readall.rs index dc9ec15..a5ce385 100644 --- a/examples/readall.rs +++ b/examples/readall.rs @@ -6,11 +6,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use clap::Parser; use gpio_cdev::{Chip, LineRequestFlags}; -use quicli::prelude::*; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] struct Cli { /// The gpiochip device (e.g. /dev/gpiochip0) chip: String, @@ -27,10 +26,7 @@ fn do_main(args: Cli) -> std::result::Result<(), gpio_cdev::Error> { Ok(()) } -fn main() -> CliResult { - let args = Cli::from_args(); - do_main(args).or_else(|e| { - error!("{:?}", e); - Ok(()) - }) +fn main() -> std::result::Result<(), gpio_cdev::Error> { + let args = Cli::parse(); + do_main(args) } diff --git a/examples/readinput.rs b/examples/readinput.rs index 5a61993..d227491 100644 --- a/examples/readinput.rs +++ b/examples/readinput.rs @@ -6,11 +6,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use clap::Parser; use gpio_cdev::{Chip, LineRequestFlags}; -use quicli::prelude::*; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] struct Cli { /// The gpiochip device (e.g. /dev/gpiochip0) chip: String, @@ -28,10 +27,7 @@ fn do_main(args: Cli) -> std::result::Result<(), gpio_cdev::Error> { Ok(()) } -fn main() -> CliResult { - let args = Cli::from_args(); - do_main(args).or_else(|e| { - error!("{:?}", e); - Ok(()) - }) +fn main() -> std::result::Result<(), gpio_cdev::Error> { + let args = Cli::parse(); + do_main(args) } diff --git a/examples/tit_for_tat.rs b/examples/tit_for_tat.rs index c22768f..0e3821e 100644 --- a/examples/tit_for_tat.rs +++ b/examples/tit_for_tat.rs @@ -6,13 +6,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use clap::Parser; use gpio_cdev::{Chip, EventRequestFlags, EventType, LineRequestFlags}; -use quicli::prelude::*; use std::thread::sleep; use std::time::Duration; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] struct Cli { /// The gpiochip device (e.g. /dev/gpiochip0) chip: String, @@ -55,10 +54,7 @@ fn do_main(args: Cli) -> std::result::Result<(), gpio_cdev::Error> { Ok(()) } -fn main() -> CliResult { - let args = Cli::from_args(); - do_main(args).or_else(|e| { - error!("{:?}", e); - Ok(()) - }) +fn main() -> std::result::Result<(), gpio_cdev::Error> { + let args = Cli::parse(); + do_main(args) } diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..552d6d6 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "1.85.0" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index b8b6506..2a204e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,9 +123,11 @@ pub use crate::async_tokio::AsyncLineEventHandle; pub use errors::*; unsafe fn rstr_lcpy(dst: *mut libc::c_char, src: &str, length: usize) { - let copylen = min(src.len() + 1, length); - ptr::copy_nonoverlapping(src.as_bytes().as_ptr().cast(), dst, copylen - 1); - slice::from_raw_parts_mut(dst, length)[copylen - 1] = 0; + unsafe { + let copylen = min(src.len() + 1, length); + ptr::copy_nonoverlapping(src.as_bytes().as_ptr().cast(), dst, copylen - 1); + slice::from_raw_parts_mut(dst, length)[copylen - 1] = 0; + } } #[derive(Debug)] @@ -396,10 +398,12 @@ pub enum LineDirection { } unsafe fn cstrbuf_to_string(buf: &[libc::c_char]) -> Option { - if buf[0] == 0 { - None - } else { - Some(CStr::from_ptr(buf.as_ptr()).to_string_lossy().into_owned()) + unsafe { + if buf[0] == 0 { + None + } else { + Some(CStr::from_ptr(buf.as_ptr()).to_string_lossy().into_owned()) + } } }