diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 57a4fd54..4b8a421d 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -84,9 +84,15 @@ jobs: command: build args: --target=${{ inputs.target }} + - name: Build | build library with all features + uses: actions-rs/cargo@v1 + with: + command: build + args: --target=${{ inputs.target }} --all-features + - name: Build | build examples if: ${{ inputs.disable_extra_builds == false }} - run: cargo build --examples --target=${{ inputs.target }} + run: cargo build --examples --target=${{ inputs.target }} --all-features - name: Build | build tests if: ${{ inputs.disable_extra_builds == false }} diff --git a/Cargo.toml b/Cargo.toml index 25ad79c1..c9728db7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,9 +39,17 @@ features = [ [dependencies] serde = { version = "1.0", features = ["derive"], optional = true } +embedded-hal = { version = "=1.0.0-alpha.9", optional = true } +embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true } +nb = { version = "1", optional = true } [dev-dependencies] clap = "3.1.6" [features] default = ["libudev"] +embedded = ["embedded-hal", "embedded-hal-nb", "nb"] + +[[example]] +name = "embedded_hal" +required-features = ["embedded"] diff --git a/examples/embedded_hal.rs b/examples/embedded_hal.rs new file mode 100644 index 00000000..f463374a --- /dev/null +++ b/examples/embedded_hal.rs @@ -0,0 +1,24 @@ +//! This example does not actually do anything, but it shows that a serialport +//! instance can be passed to functions / drivers that expect a type that +//! implements the embedded-hal traits. + +fn take_nonblocking_reader>(_r: &R) { + // do nothing, but things should typecheck +} + +fn take_nonblocking_writer>(_w: &W) { + // do nothing, but things should typecheck +} + +fn take_blocking_writer>(_w: &W) { + // do nothing, but things should typecheck +} + +fn main() { + let port = serialport::new("/dev/null", 9600) + .open() + .expect("This example isn't meant for running. It just demonstrates compatibility with embedded-hal on a type level."); + take_nonblocking_reader(&port); + take_nonblocking_writer(&port); + take_blocking_writer(&port); +} diff --git a/src/embedded.rs b/src/embedded.rs new file mode 100644 index 00000000..bd263fd1 --- /dev/null +++ b/src/embedded.rs @@ -0,0 +1,87 @@ +//! Opt-in support for embedded-hal traits. +//! +//! Can be enabled with the "embedded" cargo feature. + +use std::io; + +use embedded_hal::serial::{ErrorType, ErrorKind}; + +use crate::SerialPort; + +#[derive(Debug, Copy, Clone)] +pub struct SerialError { + kind: io::ErrorKind, +} + +impl embedded_hal::serial::Error for SerialError { + fn kind(&self) -> ErrorKind { + #[allow(clippy::match_single_binding)] + match self.kind { + _ => ErrorKind::Other, + } + } +} + +impl From for SerialError { + fn from(e: io::Error) -> Self { + SerialError { + kind: e.kind(), + } + } +} + +impl ErrorType for Box { + type Error = SerialError; +} + + +mod nonblocking { + use super::*; + use embedded_hal_nb::serial; + + fn io_error_to_nb(err: io::Error) -> nb::Error { + match err.kind() { + io::ErrorKind::WouldBlock | io::ErrorKind::Interrupted => nb::Error::WouldBlock, + other => nb::Error::Other(SerialError { kind: other }), + } + } + + impl serial::Read for Box { + fn read(&mut self) -> nb::Result { + let mut buffer = [0; 1]; + let bytes_read = io::Read::read(self, &mut buffer).map_err(io_error_to_nb)?; + if bytes_read > 0 { + Ok(buffer[0]) + } else { + Err(nb::Error::WouldBlock) + } + } + } + + impl serial::Write for Box { + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + io::Write::write(self, &[word]) + .map_err(io_error_to_nb) + .map(|_| ()) + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + io::Write::flush(self).map_err(io_error_to_nb) + } + } +} + +mod blocking { + use super::*; + use embedded_hal::serial; + + impl serial::Write for Box { + fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + Ok(io::Write::write_all(self, buffer)?) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + Ok(io::Write::flush(self)?) + } + } +} diff --git a/src/lib.rs b/src/lib.rs index cc3f2833..d0f0ebf8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,9 @@ mod windows; #[cfg(windows)] pub use windows::COMPort; +#[cfg(feature = "embedded")] +mod embedded; + /// A type for results generated by interacting with serial ports /// /// The `Err` type is hard-wired to [`serialport::Error`](struct.Error.html).