use super::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListenerHandle(pub(crate) String);
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamHandle(pub(crate) String);
#[derive(Debug)]
pub struct RecvError;
impl core::fmt::Display for RecvError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "stream closed")
}
}
impl std::error::Error for RecvError {}
#[derive(Debug, PartialEq, Eq)]
pub enum TryRecvError {
Empty,
Closed,
}
impl core::fmt::Display for TryRecvError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Empty => write!(f, "no message available"),
Self::Closed => write!(f, "stream closed"),
}
}
}
impl std::error::Error for TryRecvError {}
#[derive(Debug)]
pub struct SendError;
impl core::fmt::Display for SendError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "stream closed")
}
}
impl std::error::Error for SendError {}
#[repr(u8)]
enum ReadStatus {
Data = 0x00,
Closed = 0x01,
Pending = 0x02,
}
impl ReadStatus {
fn from_byte(b: u8) -> Option<Self> {
match b {
b if b == Self::Data as u8 => Some(Self::Data),
b if b == Self::Closed as u8 => Some(Self::Closed),
b if b == Self::Pending as u8 => Some(Self::Pending),
_ => None,
}
}
}
pub fn bind_unix(path: impl AsRef<[u8]>) -> Result<ListenerHandle, SysError> {
let bytes = unsafe { astrid_net_bind_unix(path.as_ref().to_vec())? };
let handle_str = String::from_utf8(bytes).map_err(|e| SysError::ApiError(e.to_string()))?;
Ok(ListenerHandle(handle_str))
}
pub fn accept(listener: &ListenerHandle) -> Result<StreamHandle, SysError> {
let bytes = unsafe { astrid_net_accept(listener.0.as_bytes().to_vec())? };
let handle_str = String::from_utf8(bytes).map_err(|e| SysError::ApiError(e.to_string()))?;
Ok(StreamHandle(handle_str))
}
pub fn try_accept(listener: &ListenerHandle) -> Result<Option<StreamHandle>, SysError> {
let bytes = unsafe { astrid_net_poll_accept(listener.0.as_bytes().to_vec())? };
if bytes.is_empty() {
return Ok(None);
}
let handle_str = String::from_utf8(bytes).map_err(|e| SysError::ApiError(e.to_string()))?;
Ok(Some(StreamHandle(handle_str)))
}
pub fn recv(stream: &StreamHandle) -> Result<Vec<u8>, RecvError> {
loop {
match try_recv(stream) {
Ok(bytes) => return Ok(bytes),
Err(TryRecvError::Closed) => return Err(RecvError),
Err(TryRecvError::Empty) => {
std::thread::sleep(std::time::Duration::from_millis(1));
}
}
}
}
pub fn try_recv(stream: &StreamHandle) -> Result<Vec<u8>, TryRecvError> {
let bytes =
unsafe { astrid_net_read(stream.0.as_bytes().to_vec()).map_err(|_| TryRecvError::Closed)? };
let status = bytes
.first()
.and_then(|&b| ReadStatus::from_byte(b))
.ok_or(TryRecvError::Closed)?;
match status {
ReadStatus::Data => Ok(bytes[1..].to_vec()),
ReadStatus::Closed => Err(TryRecvError::Closed),
ReadStatus::Pending => Err(TryRecvError::Empty),
}
}
pub fn send(stream: &StreamHandle, data: &[u8]) -> Result<(), SendError> {
unsafe {
astrid_net_write(stream.0.as_bytes().to_vec(), data.to_vec()).map_err(|_| SendError)?
};
Ok(())
}
pub fn close(stream: &StreamHandle) -> Result<(), SysError> {
unsafe { astrid_net_close_stream(stream.0.as_bytes().to_vec())? };
Ok(())
}