use alloc::{boxed::Box, vec};
use core::ffi::c_void;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum ChannelError {
WouldBlock,
TransportError,
}
#[cfg(feature = "std")]
impl From<std::io::Error> for ChannelError {
fn from(value: std::io::Error) -> Self {
match value.kind() {
std::io::ErrorKind::WouldBlock => ChannelError::WouldBlock,
_ => ChannelError::TransportError,
}
}
}
#[cfg(not(feature = "std"))]
impl<E: embedded_io::Error + Sized> From<E> for ChannelError {
fn from(value: E) -> Self {
match value.kind() {
_ => ChannelError::TransportError,
}
}
}
pub trait Channel: Send {
fn get_id(&self) -> i32;
fn read(&mut self, buf: &mut [u8]) -> Result<usize, ChannelError>;
fn write(&mut self, buf: &[u8]) -> Result<usize, ChannelError>;
fn flush(&mut self) -> Result<(), ChannelError>;
fn close(&mut self) -> Result<(), ChannelError>;
}
impl core::fmt::Debug for dyn Channel {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Channel")
.field("id", &self.get_id())
.finish()
}
}
unsafe extern "C" fn raw_read(data: *mut c_void, buf: *mut u8, len: i32) -> i32 {
let channel: *mut Box<dyn Channel> = data as *mut _;
let channel = channel.as_mut().unwrap();
let mut read_buf = vec![0u8; len as usize];
match channel.read(&mut read_buf) {
Ok(n) => {
let src_ptr = read_buf.as_mut_ptr();
core::ptr::copy_nonoverlapping(src_ptr, buf, len as usize);
n as i32
}
Err(ChannelError::WouldBlock) => 0,
Err(_) => -1,
}
}
unsafe extern "C" fn raw_write(data: *mut c_void, buf: *mut u8, len: i32) -> i32 {
let channel: *mut Box<dyn Channel> = data as *mut _;
let channel = channel.as_mut().unwrap();
let mut write_buf = vec![0u8; len as usize];
core::ptr::copy_nonoverlapping(buf, write_buf.as_mut_ptr(), len as usize);
match channel.as_mut().write(&write_buf) {
Ok(n) => n as i32,
Err(ChannelError::WouldBlock) => 0,
Err(_) => -1,
}
}
unsafe extern "C" fn raw_flush(data: *mut c_void) {
let channel: *mut Box<dyn Channel> = data as *mut _;
let channel = channel.as_mut().unwrap();
let _ = channel.as_mut().flush();
}
unsafe extern "C" fn raw_close(data: *mut c_void) {
let channel: *mut Box<dyn Channel> = data as *mut _;
let channel = channel.as_mut().unwrap();
let _ = channel.as_mut().close();
}
impl From<Box<dyn Channel>> for libosdp_sys::osdp_channel {
fn from(val: Box<dyn Channel>) -> Self {
let id = val.get_id();
let data = Box::into_raw(Box::new(val));
libosdp_sys::osdp_channel {
id,
data: data as *mut c_void,
recv: Some(raw_read),
send: Some(raw_write),
flush: Some(raw_flush),
close: Some(raw_close),
}
}
}