#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
use std::error;
use std::fmt;
use std::sync::atomic::{self, AtomicUsize, Ordering};
use crate::bounded::Bounded;
use crate::unbounded::Unbounded;
mod bounded;
mod unbounded;
pub struct ConcurrentQueue<T>(Inner<T>);
unsafe impl<T: Send> Send for ConcurrentQueue<T> {}
unsafe impl<T: Send> Sync for ConcurrentQueue<T> {}
enum Inner<T> {
Bounded(Bounded<T>),
Unbounded(Unbounded<T>),
}
impl<T> ConcurrentQueue<T> {
pub fn bounded(cap: usize) -> ConcurrentQueue<T> {
ConcurrentQueue(Inner::Bounded(Bounded::new(cap)))
}
pub fn unbounded() -> ConcurrentQueue<T> {
ConcurrentQueue(Inner::Unbounded(Unbounded::new()))
}
pub fn push(&self, value: T) -> Result<(), PushError<T>> {
match &self.0 {
Inner::Bounded(q) => q.push(value),
Inner::Unbounded(q) => q.push(value),
}
}
pub fn pop(&self) -> Result<T, PopError> {
match &self.0 {
Inner::Bounded(q) => q.pop(),
Inner::Unbounded(q) => q.pop(),
}
}
pub fn is_empty(&self) -> bool {
match &self.0 {
Inner::Bounded(q) => q.is_empty(),
Inner::Unbounded(q) => q.is_empty(),
}
}
pub fn is_full(&self) -> bool {
match &self.0 {
Inner::Bounded(q) => q.is_full(),
Inner::Unbounded(q) => q.is_full(),
}
}
pub fn len(&self) -> usize {
match &self.0 {
Inner::Bounded(q) => q.len(),
Inner::Unbounded(q) => q.len(),
}
}
pub fn capacity(&self) -> Option<usize> {
match &self.0 {
Inner::Bounded(q) => Some(q.capacity()),
Inner::Unbounded(_) => None,
}
}
pub fn close(&self) -> bool {
match &self.0 {
Inner::Bounded(q) => q.close(),
Inner::Unbounded(q) => q.close(),
}
}
pub fn is_closed(&self) -> bool {
match &self.0 {
Inner::Bounded(q) => q.is_closed(),
Inner::Unbounded(q) => q.is_closed(),
}
}
}
impl<T> fmt::Debug for ConcurrentQueue<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ConcurrentQueue")
.field("len", &self.len())
.field("capacity", &self.capacity())
.field("is_closed", &self.is_closed())
.finish()
}
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum PopError {
Empty,
Closed,
}
impl PopError {
pub fn is_empty(&self) -> bool {
match self {
PopError::Empty => true,
PopError::Closed => false,
}
}
pub fn is_closed(&self) -> bool {
match self {
PopError::Empty => false,
PopError::Closed => true,
}
}
}
impl error::Error for PopError {}
impl fmt::Debug for PopError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PopError::Empty => write!(f, "Empty"),
PopError::Closed => write!(f, "Closed"),
}
}
}
impl fmt::Display for PopError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PopError::Empty => write!(f, "Empty"),
PopError::Closed => write!(f, "Closed"),
}
}
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum PushError<T> {
Full(T),
Closed(T),
}
impl<T> PushError<T> {
pub fn into_inner(self) -> T {
match self {
PushError::Full(t) => t,
PushError::Closed(t) => t,
}
}
pub fn is_full(&self) -> bool {
match self {
PushError::Full(_) => true,
PushError::Closed(_) => false,
}
}
pub fn is_closed(&self) -> bool {
match self {
PushError::Full(_) => false,
PushError::Closed(_) => true,
}
}
}
impl<T: fmt::Debug> error::Error for PushError<T> {}
impl<T: fmt::Debug> fmt::Debug for PushError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PushError::Full(t) => f.debug_tuple("Full").field(t).finish(),
PushError::Closed(t) => f.debug_tuple("Closed").field(t).finish(),
}
}
}
impl<T> fmt::Display for PushError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PushError::Full(_) => write!(f, "Full"),
PushError::Closed(_) => write!(f, "Closed"),
}
}
}
#[inline]
fn full_fence() {
if cfg!(any(target_arch = "x86", target_arch = "x86_64")) {
let a = AtomicUsize::new(0);
a.compare_and_swap(0, 1, Ordering::SeqCst);
} else {
atomic::fence(Ordering::SeqCst);
}
}