use std::collections::VecDeque;
use std::io;
use std::sync::{Arc, Condvar, Mutex};
use std::time::{Duration, Instant};
#[derive(Debug)]
enum Control<T>
{
Elem(T),
Unblock,
}
#[derive(Debug)]
struct MessagesQueueInner<T>
where
T: Send,
{
queue: Mutex<VecDeque<Control<T>>>,
condvar: Condvar,
}
#[derive(Debug)]
pub struct MessageQueueSender<T>
where
T:Send
{
msg_queue: Arc<MessagesQueueInner<T>>,
}
impl<T> Clone for MessageQueueSender<T>
where T: Send
{
fn clone(&self) -> Self
{
Self{ msg_queue: self.msg_queue.clone() }
}
}
impl<T> MessageQueueSender<T>
where T: Send
{
pub
fn push(&self, value: T) -> io::Result<()>
{
let mut queue = self.msg_queue.queue.lock().unwrap();
queue.push_back(Control::Elem(value));
self.msg_queue.condvar.notify_one();
return Ok(());
}
}
#[derive(Debug, Clone)]
pub struct MessagesQueue<T>
where
T: Send,
{
msg_queue: Arc<MessagesQueueInner<T>>
}
impl<T> MessagesQueue<T>
where
T: Send,
{
pub
fn with_capacity(capacity: usize) -> MessagesQueue<T>
{
let msg_queue =
Arc::new(
MessagesQueueInner
{
queue: Mutex::new(VecDeque::with_capacity(capacity)),
condvar: Condvar::new(),
}
);
return Self{ msg_queue: msg_queue };
}
pub
fn create_sender(&self) -> MessageQueueSender<T>
{
MessageQueueSender{ msg_queue: self.msg_queue.clone() }
}
pub
fn unblock(&self) -> io::Result<()>
{
let mut queue = self.msg_queue.queue.lock().unwrap();
queue.push_back(Control::Unblock);
self.msg_queue.condvar.notify_one();
return Ok(());
}
pub
fn pop(&self) -> io::Result<Option<T>>
{
let mut queue = self.msg_queue.queue.lock().unwrap();
loop
{
match queue.pop_front()
{
Some(Control::Elem(value)) =>
return Ok(Some(value)),
Some(Control::Unblock) =>
return Ok(None),
None => (),
}
queue = self.msg_queue.condvar.wait(queue).unwrap();
}
}
pub
fn try_pop(&self) -> io::Result<Option<T>>
{
let mut queue = self.msg_queue.queue.lock().unwrap();
match queue.pop_front()
{
Some(Control::Elem(value)) =>
return Ok(Some(value)),
Some(Control::Unblock) | None =>
return Ok(None),
}
}
pub
fn pop_timeout(&self, timeout: Duration) -> io::Result<Option<T>>
{
let mut queue = self.msg_queue.queue.lock().unwrap();
let mut duration = timeout;
loop
{
match queue.pop_front()
{
Some(Control::Elem(value)) =>
return Ok(Some(value)),
Some(Control::Unblock) =>
return Ok(None),
None => (),
}
let now = Instant::now();
let (_queue, result) = self.msg_queue.condvar.wait_timeout(queue, timeout).unwrap();
queue = _queue;
let sleep_time = now.elapsed();
duration =
if duration > sleep_time
{
duration - sleep_time
}
else
{
Duration::from_millis(0)
};
if result.timed_out() ||
(duration.as_secs() == 0 && duration.subsec_nanos() < 1_000_000)
{
return Ok(None);
}
}
}
}