use super::{Split, ExactSizeSpliterator, IntoSpliterator};
use std::sync::Arc;
use std::ptr;
struct NoDropVec<T> {
inner: Vec<T>,
}
impl<T> Drop for NoDropVec<T> {
fn drop(&mut self) {
unsafe { self.inner.set_len(0) }
}
}
unsafe impl<T: Send> Sync for NoDropVec<T> {}
pub struct Iter<T> {
_items: Arc<NoDropVec<T>>,
cur: *mut T,
end: *mut T,
}
impl<T> Iterator for Iter<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
if self.cur == self.end {
None
} else {
let item = unsafe { ptr::read(self.cur) };
self.cur = unsafe { self.cur.offset(1) };
Some(item)
}
}
}
impl<T> Drop for Iter<T> {
fn drop(&mut self) {
while let Some(_) = self.next() {}
}
}
pub struct VecSplit<T> {
items: Arc<NoDropVec<T>>,
start: usize,
len: usize,
}
impl<T> IntoIterator for VecSplit<T> {
type IntoIter = Iter<T>;
type Item = T;
fn into_iter(self) -> Self::IntoIter {
let cur_ptr = unsafe { self.items.inner.as_ptr().offset(self.start as isize) };
let end_ptr = unsafe { cur_ptr.offset(self.len as isize) };
Iter {
_items: self.items,
cur: cur_ptr as *mut T,
end: end_ptr as *mut T,
}
}
}
impl<T: Send> Split for VecSplit<T> {
fn should_split(&self, mul: f32) -> Option<usize> {
if self.len > 1 && (self.len as f32 *mul) > 4096.0 { Some(self.len / 2) }
else { None }
}
fn split(self, mut idx: usize) -> (Self, Self) {
if idx > self.len { idx = self.len }
(
VecSplit { items: self.items.clone(), start: self.start, len: idx},
VecSplit { items: self.items, start: self.start + idx, len: self.len - idx }
)
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<T: Send> ExactSizeSpliterator for VecSplit<T> {
fn size(&self) -> usize {
self.len
}
}
impl<T: Send> IntoSpliterator for Vec<T> {
type Item = T;
type SplitIter = VecSplit<T>;
fn into_split_iter(self) -> VecSplit<T> {
let len = self.len();
VecSplit {
items: Arc::new(NoDropVec { inner: self }),
start: 0,
len: len,
}
}
}
#[cfg(test)]
mod tests {
use ::{IntoSpliterator, Spliterator, make_pool};
#[test]
fn it_works() {
let mut pool = make_pool(4).unwrap();
let v: Vec<_> = (0..10000).collect();
let doubled: Vec<_> = v.into_split_iter().map(|x| x * 2).collect(&pool.spawner());
assert_eq!(doubled, (0..10000).map(|x| x*2).collect::<Vec<_>>());
}
}