summaryrefslogtreecommitdiff
path: root/src/iterator/iterator.rs
blob: 1e389a4d4e698292555f665af0268d56dca2f011 (plain)
use std::iter::{Enumerate, Fuse, Skip, Take};

use super::{ConsumedIteratorGuard, IteratorGuard, LockingIterator};

use crate::{
	lockable::{Lockable, RawLock, Sharable},
	Keyable,
};

impl<L, Key> LockingIterator<L, Key> {
	pub(crate) const fn new(key: Key, lockable: L) -> Self {
		Self { key, lockable }
	}

	fn with_iterator<M>(self, f: impl FnOnce(L) -> M) -> LockingIterator<M, Key> {
		LockingIterator {
			key: self.key,
			lockable: f(self.lockable),
		}
	}
}

impl<'a, I: Iterator<Item = &'a L>, L: 'a + Lockable + RawLock, Key: Keyable>
	LockingIterator<I, Key>
{
	pub fn lock_next(&'a mut self) -> Option<IteratorGuard<'a, <L as Lockable>::Guard<'a>, Key>> {
		if let Some(lock) = self.lockable.next() {
			unsafe {
				lock.raw_write();
				let guard = lock.guard();

				Some(IteratorGuard {
					_key: &self.key,
					guard,
				})
			}
		} else {
			None
		}
	}

	pub fn lock_last(self) -> Option<ConsumedIteratorGuard<<L as Lockable>::Guard<'a>, Key>> {
		self.lockable.last().map(|lock| unsafe {
			lock.raw_write();
			let guard = lock.guard();

			ConsumedIteratorGuard {
				key: self.key,
				guard,
			}
		})
	}
}

impl<'a, I: Iterator<Item = &'a L>, L: 'a + Sharable + RawLock, Key: Keyable>
	LockingIterator<I, Key>
{
	pub fn read_next(
		&'a mut self,
	) -> Option<IteratorGuard<'a, <L as Sharable>::ReadGuard<'a>, Key>> {
		if let Some(lock) = self.lockable.next() {
			unsafe {
				lock.raw_read();
				let guard = lock.read_guard();

				Some(IteratorGuard {
					_key: &self.key,
					guard,
				})
			}
		} else {
			None
		}
	}

	pub fn read_last(self) -> Option<ConsumedIteratorGuard<<L as Sharable>::ReadGuard<'a>, Key>> {
		self.lockable.last().map(|lock| unsafe {
			lock.raw_read();
			let guard = lock.read_guard();

			ConsumedIteratorGuard {
				key: self.key,
				guard,
			}
		})
	}
}

impl<L: Iterator, Key> LockingIterator<L, Key> {
	pub fn size_hint(&self) -> (usize, Option<usize>) {
		self.lockable.size_hint()
	}

	pub fn enumerate(self) -> LockingIterator<Enumerate<L>, Key> {
		self.with_iterator(Iterator::enumerate)
	}

	pub fn skip(self, n: usize) -> LockingIterator<Skip<L>, Key> {
		self.with_iterator(|i| i.skip(n))
	}

	pub fn take(self, n: usize) -> LockingIterator<Take<L>, Key> {
		self.with_iterator(|i| i.take(n))
	}

	pub fn fuse(self) -> LockingIterator<Fuse<L>, Key> {
		self.with_iterator(Iterator::fuse)
	}
}