use std::collections::{BTreeSet, VecDeque};
use crate::cap::CapId;
use crate::error::{Error, Result};
use crate::lane::LaneId;
use crate::value::Value;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ChannelId(pub u64);
impl std::fmt::Display for ChannelId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ch{}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Direction {
Send,
Receive,
Both,
}
impl Direction {
pub fn can_send(self) -> bool {
matches!(self, Direction::Send | Direction::Both)
}
pub fn can_receive(self) -> bool {
matches!(self, Direction::Receive | Direction::Both)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Message {
pub from: LaneId,
pub payload: Value,
pub caps: Vec<CapId>,
pub sequence: u64,
}
#[derive(Debug, Clone)]
pub struct Channel {
pub id: ChannelId,
pub name: String,
pub direction: Direction,
queue: VecDeque<Message>,
next_sequence: u64,
closed: bool,
pub subscribers: BTreeSet<u64>,
pub sent: u64,
pub received: u64,
}
impl Channel {
pub fn new(id: ChannelId, name: impl Into<String>, direction: Direction) -> Self {
Self {
id,
name: name.into(),
direction,
queue: VecDeque::new(),
next_sequence: 0,
closed: false,
subscribers: BTreeSet::new(),
sent: 0,
received: 0,
}
}
pub fn can_send(&self) -> bool {
self.direction.can_send() && !self.closed
}
pub fn can_receive(&self) -> bool {
self.direction.can_receive() && !self.queue.is_empty()
}
pub fn send(&mut self, from: LaneId, payload: Value, caps: Vec<CapId>) -> Result<Message> {
if self.closed {
return Err(Error::InvalidArgument("channel is closed"));
}
if !self.direction.can_send() {
return Err(Error::InvalidArgument("channel is receive-only"));
}
let message = Message {
from,
payload,
caps,
sequence: self.next_sequence,
};
self.next_sequence += 1;
self.sent += 1;
self.queue.push_back(message.clone());
Ok(message)
}
pub fn recv(&mut self) -> Result<Option<Message>> {
if !self.direction.can_receive() {
return Err(Error::InvalidArgument("channel is send-only"));
}
match self.queue.pop_front() {
Some(message) => {
self.received += 1;
Ok(Some(message))
}
None => Ok(None),
}
}
pub fn peek(&self) -> Option<&Message> {
self.queue.front()
}
pub fn len(&self) -> usize {
self.queue.len()
}
pub fn is_empty(&self) -> bool {
self.queue.is_empty()
}
pub fn close(&mut self) {
self.closed = true;
}
pub fn is_closed(&self) -> bool {
self.closed
}
}