use crate::types::int;
use std::marker::PhantomData;
use std::ptr::NonNull;
pub(crate) struct Node<T> {
next: NonNull<Node<T>>,
prev: NonNull<Node<T>>,
pub(crate) value: Option<T>,
}
pub struct Ring<T> {
ptr: Option<NonNull<Node<T>>>,
_marker: PhantomData<Node<T>>,
}
impl<T> Ring<T> {
#[allow(non_snake_case)]
pub fn new_single() -> Ring<T> {
let node = Box::new(Node {
next: NonNull::dangling(),
prev: NonNull::dangling(),
value: None,
});
let raw = Box::into_raw(node);
unsafe {
let nn = NonNull::new_unchecked(raw);
(*raw).next = nn;
(*raw).prev = nn;
Ring { ptr: Some(nn), _marker: PhantomData }
}
}
pub fn nil() -> Ring<T> {
Ring { ptr: None, _marker: PhantomData }
}
fn from_ptr(p: NonNull<Node<T>>) -> Ring<T> {
Ring { ptr: Some(p), _marker: PhantomData }
}
#[allow(dead_code)]
fn is_nil(&self) -> bool { self.ptr.is_none() }
#[allow(non_snake_case)]
pub fn Len(&self) -> int {
let start = match self.ptr { Some(p) => p, None => return 0 };
unsafe {
let mut n: int = 1;
let mut p = (*start.as_ptr()).next;
while p != start {
n += 1;
p = (*p.as_ptr()).next;
}
n
}
}
#[allow(non_snake_case)]
pub fn Next(&self) -> Ring<T> {
match self.ptr {
None => Ring::nil(),
Some(p) => unsafe { Ring::from_ptr((*p.as_ptr()).next) },
}
}
#[allow(non_snake_case)]
pub fn Prev(&self) -> Ring<T> {
match self.ptr {
None => Ring::nil(),
Some(p) => unsafe { Ring::from_ptr((*p.as_ptr()).prev) },
}
}
#[allow(non_snake_case)]
pub fn Move(&self, mut n: int) -> Ring<T> {
let mut p = match self.ptr { Some(x) => x, None => return Ring::nil() };
unsafe {
while n < 0 { p = (*p.as_ptr()).prev; n += 1; }
while n > 0 { p = (*p.as_ptr()).next; n -= 1; }
}
Ring::from_ptr(p)
}
#[allow(non_snake_case)]
pub fn Link(&self, s: &Ring<T>) -> Ring<T> {
let r_ptr = match self.ptr { Some(x) => x, None => return Ring::nil() };
let n = unsafe { (*r_ptr.as_ptr()).next };
if let Some(s_ptr) = s.ptr {
unsafe {
let p = (*s_ptr.as_ptr()).prev;
(*r_ptr.as_ptr()).next = s_ptr;
(*s_ptr.as_ptr()).prev = r_ptr;
(*n.as_ptr()).prev = p;
(*p.as_ptr()).next = n;
}
}
Ring::from_ptr(n)
}
#[allow(non_snake_case)]
pub fn Unlink(&self, n: int) -> Ring<T> {
if n <= 0 { return Ring::nil(); }
self.Link(&self.Move(n + 1))
}
#[allow(non_snake_case)]
pub fn Do<F: FnMut(&Option<T>)>(&self, mut f: F) {
let start = match self.ptr { Some(p) => p, None => return };
unsafe {
f(&(*start.as_ptr()).value);
let mut p = (*start.as_ptr()).next;
while p != start {
f(&(*p.as_ptr()).value);
p = (*p.as_ptr()).next;
}
}
}
#[allow(non_snake_case)]
pub fn Value(&self) -> Option<T> where T: Clone {
self.ptr.map(|p| unsafe { (*p.as_ptr()).value.clone() }).flatten()
}
#[allow(non_snake_case)]
pub fn SetValue(&self, v: T) {
if let Some(p) = self.ptr {
unsafe { (*p.as_ptr()).value = Some(v); }
}
}
pub fn ptr_eq(&self, other: &Ring<T>) -> bool {
match (self.ptr, other.ptr) {
(Some(a), Some(b)) => a == b,
(None, None) => true,
_ => false,
}
}
}
#[allow(non_snake_case)]
pub fn New<T>(n: int) -> Ring<T> {
if n <= 0 { return Ring::nil(); }
let first = Box::new(Node {
next: NonNull::dangling(),
prev: NonNull::dangling(),
value: None,
});
let first_raw = Box::into_raw(first);
let first_nn = unsafe { NonNull::new_unchecked(first_raw) };
let mut p = first_nn;
for _ in 1..n {
let node = Box::new(Node {
next: NonNull::dangling(),
prev: p,
value: None,
});
let raw = Box::into_raw(node);
let nn = unsafe { NonNull::new_unchecked(raw) };
unsafe { (*p.as_ptr()).next = nn; }
p = nn;
}
unsafe {
(*p.as_ptr()).next = first_nn;
(*first_nn.as_ptr()).prev = p;
}
Ring { ptr: Some(first_nn), _marker: PhantomData }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_ring_of_5() {
let r = New::<i64>(5);
assert_eq!(r.Len(), 5);
let mut p = r.Next();
for _ in 0..4 { p = p.Next(); }
assert!(p.ptr_eq(&r));
}
#[test]
fn new_ring_of_zero_is_nil() {
let r = New::<i64>(0);
assert_eq!(r.Len(), 0);
}
#[test]
fn value_get_set() {
let r = New::<i64>(3);
r.SetValue(10);
r.Next().SetValue(20);
r.Next().Next().SetValue(30);
let mut sum = 0i64;
r.Do(|v| { if let Some(x) = v { sum += x; } });
assert_eq!(sum, 60);
}
#[test]
fn move_wraps() {
let r = New::<i64>(4);
assert!(r.Move(4).ptr_eq(&r));
assert!(r.Move(-4).ptr_eq(&r));
assert!(r.Move(0).ptr_eq(&r));
}
#[test]
fn single_element_self_refs() {
let r: Ring<i64> = Ring::new_single();
assert_eq!(r.Len(), 1);
assert!(r.Next().ptr_eq(&r));
assert!(r.Prev().ptr_eq(&r));
}
}