Documentation
use core::pin::pin;
use core::sync::atomic::Ordering::*;
use core::{
    cell::UnsafeCell,
    marker::PhantomData,
    mem,
    ops::{Deref, DerefMut},
    pin::Pin,
    ptr,
    sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize},
    task::{Poll, Waker},
};

use alloc::boxed::Box;

pub type AtomicNode<T> = AtomicPtr<Node<T>>;

pub struct Queue<T> {
    head: AtomicNode<T>,
    tail: AtomicNode<T>,

    len: AtomicUsize,
}

pub struct Node<T> {
    val: T,
    next: AtomicNode<T>,
}

impl<T: Send> Queue<T> {
    pub fn len(&self) -> usize {
        self.len.load(Acquire)
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
    pub const fn new() -> Self {
        Self {
            head: AtomicPtr::new(ptr::null_mut()),
            tail: AtomicPtr::new(ptr::null_mut()),
            len: AtomicUsize::new(0),
        }
    }

    pub unsafe fn enqueue(&self, value: T) {
        let node = Box::into_raw(Box::new(Node {
            val: value,
            next: AtomicPtr::new(ptr::null_mut()),
        }));

        loop {
            let tail = self.tail.load(Acquire);

            // If empty queue
            if tail.is_null() {
                if let Ok(_) =
                    self.head
                        .compare_exchange_weak(ptr::null_mut(), node, Release, Acquire)
                {
                    self.tail.store(node, Release);
                    self.len.fetch_add(1, AcqRel);
                    return;
                }
                continue;
            }

            // Non-empty queue - try to link to current tail
            if let Ok(_) =
                (*tail)
                    .next
                    .compare_exchange_weak(ptr::null_mut(), node, Release, Acquire)
            {
                self.tail.store(node, Release);
                self.len.fetch_add(1, AcqRel);
                return;
            }
        }
    }

    pub unsafe fn dequeue(&self) -> Option<T> {
        loop {
            let head = self.head.load(Acquire);
            if head.is_null() {
                return None;
            }

            let next = (*head).next.load(Acquire);

            if let Ok(_) = self
                .head
                .compare_exchange_weak(head, next, Release, Acquire)
            {
                if next.is_null() {
                    self.tail.store(ptr::null_mut(), Release);
                }

                let node = Box::from_raw(head);
                self.len.fetch_sub(1, AcqRel);
                return Some(node.val);
            }
        }
    }
}