use iterator::{CrateConstructor, VSIter};
use node::Node;
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
use std::{fmt, fmt::Debug, fmt::Formatter, iter::FromIterator, ptr::null_mut};
use std::{hash::Hash, hash::Hasher, mem::drop, ptr::NonNull};
pub struct VSInner<T> {
size: AtomicUsize,
copies: AtomicUsize,
first_node: AtomicPtr<Node<T>>,
last_node: AtomicPtr<Node<T>>,
}
impl<T> Default for VSInner<T> {
#[inline]
fn default() -> Self {
trace!("Default VSInner");
Self {
size: AtomicUsize::new(0),
copies: AtomicUsize::new(1),
first_node: AtomicPtr::new(null_mut()),
last_node: AtomicPtr::new(null_mut()),
}
}
}
impl<T> VSInner<T> {
#[inline]
pub fn create_ref(&mut self) -> *mut Self {
info!("Cloning VSInner, increasing references count");
let _ = self.copies.fetch_add(1, Ordering::SeqCst);
self as *mut _
}
#[inline]
pub fn drop_ref(&self) {
info!("Decreasing references counter, drop all nodes if it's the last reference");
if self.copies.fetch_sub(1, Ordering::SeqCst) == 1 {
debug!("Last reference, dropping nodes");
let first = NonNull::new(self.first_node.swap(null_mut(), Ordering::SeqCst));
let _ = first.map(|nn| unsafe { drop(Box::from_raw(nn.as_ptr())) });
}
}
#[inline]
pub fn first_node(&self) -> *mut Node<T> {
trace!("First Node in VSInner");
self.first_node.load(Ordering::SeqCst)
}
#[inline]
pub fn len(&self) -> usize {
trace!("VSInner length");
self.size.load(Ordering::SeqCst)
}
#[inline]
pub fn is_empty(&self) -> bool {
trace!("VSInner is empty");
self.len() == 0
}
pub fn append(&self, value: T) {
trace!("Append to VSInner");
let ptr = Box::into_raw(Box::new(Node::new(value)));
if let Some(nn) = NonNull::new(self.last_node.swap(ptr, Ordering::SeqCst)) {
debug!("Adding element to the end of the list");
let before = unsafe { nn.as_ref().swap_next(ptr) };
debug_assert!(before.is_none(), "First node wasn't actually first");
} else {
debug!("First element to be added");
let before = self.first_node.swap(ptr, Ordering::SeqCst).is_null();
debug_assert!(
self.is_empty() || before,
"Last node wasn't empty but should"
);
}
trace!("Increased size");
let _ = self.size.fetch_add(1, Ordering::SeqCst);
}
}
impl<T: Debug> Debug for VSInner<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
trace!("Debug VSInner");
unsafe {
let first_node = self.first_node.load(Ordering::SeqCst);
let first_node = NonNull::new(first_node).map(|nn| &*nn.as_ptr());
let last_node = self.last_node.load(Ordering::SeqCst);
let last_node = NonNull::new(last_node).map(|nn| &*nn.as_ptr());
write!(
f,
"VoluntaryServitude {{ size: {:?}, copies: {:?}, first_node: {:?}, last_node: {:?} }}",
self.size.load(Ordering::SeqCst),
self.copies.load(Ordering::SeqCst),
first_node,
last_node
)
}
}
}
pub struct VoluntaryServitude<T> {
inner: AtomicPtr<VSInner<T>>,
}
pub type VS<T> = VoluntaryServitude<T>;
#[cfg(feature = "serde-traits")]
use serde_lib::{Deserialize, Deserializer};
#[cfg(feature = "serde-traits")]
impl<'a, T: 'a + Deserialize<'a>> Deserialize<'a> for VoluntaryServitude<T> {
fn deserialize<D: Deserializer<'a>>(des: D) -> Result<Self, D::Error> {
trace!("Deserialize VoluntaryServitude");
VSInner::deserialize(des).map(|inner| Self {
inner: AtomicPtr::new(Box::into_raw(Box::new(inner))),
})
}
}
impl<T> FromIterator<T> for VoluntaryServitude<T> {
#[inline]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
debug!("VSInner<T> from IntoIterator<T>");
let vs = vs![];
let _ = iter.into_iter().map(|v| vs.append(v)).count();
vs
}
}
impl<'a, T: 'a + Copy> FromIterator<&'a T> for VoluntaryServitude<T> {
#[inline]
fn from_iter<I: IntoIterator<Item = &'a T>>(iter: I) -> Self {
trace!("VoluntaryServitude<T> from IntoIterator<&'a T> where T: Copy");
VS::from_iter(iter.into_iter().cloned())
}
}
impl<T: Hash> Hash for VoluntaryServitude<T> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
trace!("Hash VoluntaryServitude");
self.iter().hash(state);
}
}
impl<T: PartialEq> PartialEq for VoluntaryServitude<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
trace!("PartialEq VoluntaryServitude");
let len = self.len();
if len == 0 && other.is_empty() {
return true;
};
self.iter()
.zip(other.iter())
.zip(0..len)
.filter(|((a, b), _)| a == b)
.count()
> 0
}
}
impl<T: Eq> Eq for VoluntaryServitude<T> {}
impl<T: Debug> Debug for VoluntaryServitude<T> {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
trace!("Debug VoluntaryServitude");
write!(f, "VoluntaryServitude {{ inner: {:?} }}", self.inner())
}
}
impl<T> Default for VoluntaryServitude<T> {
#[inline]
fn default() -> Self {
trace!("Default VoluntaryServitude");
Self {
inner: AtomicPtr::new(Box::into_raw(Box::new(VSInner::default()))),
}
}
}
impl<T> Drop for VoluntaryServitude<T> {
#[inline]
fn drop(&mut self) {
debug!("Drop VoluntaryServitude");
unsafe { (*self.inner.load(Ordering::SeqCst)).drop_ref() };
}
}
impl<T> VoluntaryServitude<T> {
#[inline]
fn inner(&self) -> &VSInner<T> {
trace!("VSInner from VoluntaryServitude");
unsafe { &*self.inner.load(Ordering::SeqCst) }
}
#[inline]
pub fn len(&self) -> usize {
self.inner().len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.inner().is_empty()
}
#[inline]
pub fn iter<'a>(&self) -> VSIter<'a, T> {
debug!("Iter VoluntaryServitude");
unsafe { VSIter::new(&mut *(*self.inner.load(Ordering::SeqCst)).create_ref()) }
}
#[inline]
pub fn clear(&self) {
debug!("Clear VoluntaryServitude");
let ptr = Box::into_raw(Box::new(VSInner::<T>::default()));
unsafe { (*self.inner.swap(ptr, Ordering::SeqCst)).drop_ref() };
}
#[inline]
pub fn append(&self, value: T) {
self.inner().append(value);
}
}
#[cfg(test)]
mod tests {
use super::*;
fn setup_logger() {
#[cfg(feature = "logs")]
::setup_logger();
}
#[test]
fn voluntary_servitude_len_append_clear() {
setup_logger();
let list = vs![1, 2, 3];
assert_eq!(list.len(), 3);
list.append(4);
assert_eq!(list.len(), 4);
list.clear();
assert!(list.is_empty());
list.append(4);
assert_eq!(list.len(), 1);
}
#[test]
fn test_send() {
fn assert_send<T: Send>() {}
assert_send::<VoluntaryServitude<()>>();
}
#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<VoluntaryServitude<()>>();
}
#[test]
fn partial_eq() {
assert_eq!(vs![1, 2, 3], vs![1, 2, 3]);
let vs = vs![2, 3, 4];
assert_eq!(&vs, &vs);
}
}