Skip to content

Commit

Permalink
Deduplicate event reading code.
Browse files Browse the repository at this point in the history
  • Loading branch information
mgottschlag committed May 14, 2020
1 parent 139be3f commit 21d1704
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 53 deletions.
29 changes: 6 additions & 23 deletions src/async_tokio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@ use mio::{PollOpt, Ready, Token};
use tokio::io::PollEvented;

use std::io;
use std::mem;
use std::os::unix::io::AsRawFd;
use std::pin::Pin;
use std::slice;

use super::errors::event_err;
use super::{ffi, LineEvent, LineEventHandle, Result};
use super::{LineEvent, LineEventHandle, Result};

struct PollWrapper {
handle: LineEventHandle,
Expand Down Expand Up @@ -123,26 +121,11 @@ impl Stream for AsyncLineEventHandle {
return Poll::Ready(Some(Err(e.into())));
}

// TODO: This code should not be duplicated here.
let mut data: ffi::gpioevent_data = unsafe { mem::zeroed() };
let mut data_as_buf = unsafe {
slice::from_raw_parts_mut(
&mut data as *mut ffi::gpioevent_data as *mut u8,
mem::size_of::<ffi::gpioevent_data>(),
)
};
match nix::unistd::read(
self.evented.get_ref().handle.file.as_raw_fd(),
&mut data_as_buf,
) {
Ok(bytes_read) => {
if bytes_read != mem::size_of::<ffi::gpioevent_data>() {
let e = nix::Error::Sys(nix::errno::Errno::EIO);
Poll::Ready(Some(Err(event_err(e))))
} else {
Poll::Ready(Some(Ok(LineEvent(data))))
}
}
match self.evented.get_ref().handle.read_event() {
Ok(Some(event)) => Poll::Ready(Some(Ok(event))),
Ok(None) => Poll::Ready(Some(Err(event_err(nix::Error::Sys(
nix::errno::Errno::EIO,
))))),
Err(nix::Error::Sys(nix::errno::Errno::EAGAIN)) => {
self.evented.clear_read_ready(cx, ready)?;
Poll::Pending
Expand Down
59 changes: 29 additions & 30 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -950,21 +950,10 @@ impl LineEventHandle {
/// kernel for the line which matches the subscription criteria
/// specified in the `event_flags` when the handle was created.
pub fn get_event(&self) -> Result<LineEvent> {
let mut data: ffi::gpioevent_data = unsafe { mem::zeroed() };
let mut data_as_buf = unsafe {
slice::from_raw_parts_mut(
&mut data as *mut ffi::gpioevent_data as *mut u8,
mem::size_of::<ffi::gpioevent_data>(),
)
};
let bytes_read =
nix::unistd::read(self.file.as_raw_fd(), &mut data_as_buf).map_err(event_err)?;

if bytes_read != mem::size_of::<ffi::gpioevent_data>() {
let e = nix::Error::Sys(nix::errno::Errno::EIO);
Err(event_err(e))
} else {
Ok(LineEvent(data))
match self.read_event() {
Ok(Some(event)) => Ok(event),
Ok(None) => Err(event_err(nix::Error::Sys(nix::errno::Errno::EIO))),
Err(e) => Err(event_err(e)),
}
}

Expand All @@ -984,6 +973,28 @@ impl LineEventHandle {
pub fn line(&self) -> &Line {
&self.line
}

/// Helper function which returns the line event if a complete event was read, Ok(None) if not
/// enough data was read or the error returned by `read()`.
///
/// This function allows access to the raw `nix::Error` as required, for example, to theck
/// whether read() returned -EAGAIN.
pub(crate) fn read_event(&self) -> std::result::Result<Option<LineEvent>, nix::Error> {
let mut data: ffi::gpioevent_data = unsafe { mem::zeroed() };
let mut data_as_buf = unsafe {
slice::from_raw_parts_mut(
&mut data as *mut ffi::gpioevent_data as *mut u8,
mem::size_of::<ffi::gpioevent_data>(),
)
};
let bytes_read = nix::unistd::read(self.file.as_raw_fd(), &mut data_as_buf)?;

if bytes_read != mem::size_of::<ffi::gpioevent_data>() {
Ok(None)
} else {
Ok(Some(LineEvent(data)))
}
}
}

impl AsRawFd for LineEventHandle {
Expand All @@ -997,21 +1008,9 @@ impl Iterator for LineEventHandle {
type Item = Result<LineEvent>;

fn next(&mut self) -> Option<Result<LineEvent>> {
let mut data: ffi::gpioevent_data = unsafe { mem::zeroed() };
let mut data_as_buf = unsafe {
slice::from_raw_parts_mut(
&mut data as *mut ffi::gpioevent_data as *mut u8,
mem::size_of::<ffi::gpioevent_data>(),
)
};
match nix::unistd::read(self.file.as_raw_fd(), &mut data_as_buf) {
Ok(bytes_read) => {
if bytes_read != mem::size_of::<ffi::gpioevent_data>() {
None
} else {
Some(Ok(LineEvent(data)))
}
}
match self.read_event() {
Ok(None) => None,
Ok(Some(event)) => Some(Ok(event)),
Err(e) => Some(Err(event_err(e))),
}
}
Expand Down

0 comments on commit 21d1704

Please sign in to comment.