icsneoc2 0.1002002.0-rc.4

High-level Rust interface for Intrepid Control Systems vehicle network adapters
Documentation
//! Diagnostic events from the library and individual devices.
//!
//! Events report warnings, errors, and informational messages produced by
//! the underlying C library. Use [`events`] to poll for pending events,
//! optionally filtered to a specific [`Device`].
//!
//! # Example
//!
//! ```no_run
//! use icsneoc2::event;
//!
//! // Poll global (library-level) events
//! for ev in event::events(None)? {
//!     println!("{ev}");
//! }
//! # Ok::<(), icsneoc2::Error>(())
//! ```

use crate::device::Device;
use crate::error::Result;
use crate::functions::{check, ffi_string};
use crate::sys;

/// An event handle returned by the C library.
///
/// Each `Event` wraps an opaque `icsneoc2_event_t` pointer. The event is
/// freed automatically on drop via `icsneoc2_event_free`.
///
/// Implements [`Display`](std::fmt::Display) to print the event description.
pub struct Event(pub(crate) *mut sys::icsneoc2_event_t);

// SAFETY: derived from a Device which is Send + Sync; lifetime guarantees
// the device outlives any Event obtained from it.
unsafe impl Send for Event {}
unsafe impl Sync for Event {}

impl Drop for Event {
    fn drop(&mut self) {
        if !self.0.is_null() {
            let raw = unsafe { sys::icsneoc2_event_free(self.0) };
            match sys::Error::try_from(raw) {
                Ok(sys::Error::Success) => {}
                Ok(code) => {
                    eprintln!("Failed to free event: {code:?}");
                }
                Err(e) => eprintln!("Failed to free event: {e}"),
            }
        }
    }
}

impl std::fmt::Debug for Event {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Event({self})")
    }
}

impl std::fmt::Display for Event {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match ffi_string(255, |buf, len| unsafe {
            sys::icsneoc2_event_description_get(self.0, buf, len)
        }) {
            Ok(s) => write!(f, "{s}"),
            Err(_) => write!(f, "<event {:?}>", self.0),
        }
    }
}

/// Retrieves all pending events from the library's event queue.
///
/// Pass `None` for global (library-level) events, or `Some(&device)` for
/// events specific to that device.
///
/// Events are consumed from the queue — calling this twice without new
/// activity will return an empty `Vec` the second time.
pub fn events(device: Option<&Device>) -> Result<Vec<Event>> {
    let mut events = Vec::new();
    loop {
        let mut event: *mut sys::icsneoc2_event_t = std::ptr::null_mut();
        let device_ptr = device
            .as_ref()
            .map(|d| d.as_mut_ptr())
            .unwrap_or(std::ptr::null_mut());
        check(unsafe { sys::icsneoc2_event_get(&raw mut event, device_ptr) })?;
        if event.is_null() {
            break;
        }
        events.push(Event(event));
    }
    Ok(events)
}