use std::{ iter::{Fuse, Peekable, Skip, Take}, marker::PhantomData, }; use super::{ContextGuard, LockingIterator}; use crate::{ context::LockingTuple, lockable::{Lockable, RawLock, Sharable}, ThreadKey, }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum TryLockNextError { FinishedIteration, WouldBlock, } impl<'l, I, O> LockingIterator<'l, I, O> { fn with_iterator(self, f: impl FnOnce(I) -> M) -> LockingIterator<'l, M, O> { LockingIterator { key: self.key, iterator: f(self.iterator), outer: self.outer, } } /// Exit out of the current scope of the locking iterator into the parent. /// /// After using one the recurse methods, it is possible to regain access to /// the parent by exiting out of the scope of the child. Doing this will make /// it impossible to re-enter this scope again. /// /// # Example /// /// ``` /// use happylock::{Mutex, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// /// let key = ThreadKey::get().unwrap(); /// let data = ([Mutex::new(1), Mutex::new(2), Mutex::new(3)], Mutex::new(true)); /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let tuple = ctx.tuple(key); /// let mut iter = tuple.recurse_0_iter(); /// /// let mut sum = 0; /// while let Some(item) = iter.lock_next() { /// sum += **item; /// } /// /// let tuple = iter.exit(); /// let (should_assert, _) = tuple.lock_1(); /// if **should_assert { /// assert_eq!(sum, 6); /// } /// ``` pub fn exit(self) -> O { self.outer } } impl<'c, L: Iterator, I: IntoIterator, O> LockingIterator<'c, L, O> { /// Create a new `LockingIterator` based on the next element in the iterator. /// /// If a list contains a list of locks, then this method can be used to /// recurse into the next element of the list. To go back to the parent scope, /// use [`LockingIterator::exit`] on the new list. /// /// # Example /// /// ``` /// use happylock::{Mutex, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// /// let key = ThreadKey::get().unwrap(); /// let data = [ /// [Mutex::new(1), Mutex::new(2), Mutex::new(3)], /// [Mutex::new(4), Mutex::new(5), Mutex::new(6)], /// ]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let mut iter = ctx.iter(key); /// /// let mut sums = Vec::new(); /// while let Some(mut list) = iter.recurse_next() { /// let mut sum = 0; /// while let Some(item) = list.lock_next() { /// sum += **item; /// } /// sums.push(sum); /// iter = list.exit(); /// } /// /// assert_eq!(sums, vec![6, 15]); /// ``` pub fn recurse_next( mut self, ) -> Option::IntoIter, Self>> { if let Some(iterator) = self.iterator.next() { Some(LockingIterator { key: self.key, iterator: iterator.into_iter(), outer: self, }) } else { None } } /// Create a new `LockingIterator` based on the next element in the iterator. /// /// If a list contains a list of locks, then this method can be used to /// recurse into the next element of the list. To go back to the parent scope, /// use [`LockingIterator::exit`] on the new list. /// /// # Example /// /// ``` /// use happylock::{Mutex, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// /// let key = ThreadKey::get().unwrap(); /// let data = [ /// [Mutex::new(1), Mutex::new(2), Mutex::new(3)], /// [Mutex::new(4), Mutex::new(5), Mutex::new(6)], /// ]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let iter = ctx.iter(key); /// /// let mut list = iter.recurse_last().unwrap(); /// let mut sum = 0; /// while let Some(item) = list.lock_next() { /// sum += **item; /// } /// /// assert_eq!(sum, 15); /// ``` pub fn recurse_last(self) -> Option::IntoIter, O>> { if let Some(iterator) = self.iterator.last() { Some(LockingIterator { key: self.key, iterator: iterator.into_iter(), outer: self.outer, }) } else { None } } } impl<'c, L: Iterator, T: 'c, O> LockingIterator<'c, L, O> { /// Create a new `LockingIterator` based on the next element in the iterator. /// /// If a list contains a list of locks, then this method can be used to /// recurse into the next element of the list. To go back to the parent scope, /// use [`LockingIterator::exit`] on the new list. /// /// # Example /// /// ``` /// use happylock::{Mutex, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// /// let key = ThreadKey::get().unwrap(); /// let data = [ /// (Mutex::new(true), Mutex::new(1)), /// (Mutex::new(false), Mutex::new(2)), /// (Mutex::new(true), Mutex::new(3)), /// ]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let mut iter = ctx.iter(key); /// /// let mut sum = 0; /// while let Some(tuple) = iter.recurse_next_tuple() { /// let (should_count, mut tuple) = tuple.lock_0(); /// if **should_count { /// let num = tuple.lock_mut_1(); /// sum += **num; /// } /// iter = tuple.exit(); /// } /// /// assert_eq!(sum, 4); /// ``` pub fn recurse_next_tuple(mut self) -> Option> { if let Some(tuple) = self.iterator.next() { Some(LockingTuple { key: self.key, _lockable: PhantomData, tuple, outer: self, }) } else { None } } /// Create a new `LockingIterator` based on the next element in the iterator. /// /// If a list contains a list of locks, then this method can be used to /// recurse into the next element of the list. To go back to the parent scope, /// use [`LockingIterator::exit`] on the new list. /// /// # Example /// /// ``` /// use happylock::{Mutex, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// /// let key = ThreadKey::get().unwrap(); /// let data = [ /// (Mutex::new(true), Mutex::new(1)), /// (Mutex::new(false), Mutex::new(2)), /// (Mutex::new(true), Mutex::new(3)), /// ]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let iter = ctx.iter(key); /// /// let tuple = iter.recurse_last_tuple().unwrap(); /// let (should_count, mut tuple) = tuple.lock_0(); /// if **should_count { /// let num = tuple.lock_mut_1(); /// assert_eq!(**num, 3); /// } else { /// panic!(); /// } /// ``` pub fn recurse_last_tuple(self) -> Option> { if let Some(tuple) = self.iterator.last() { Some(LockingTuple { key: self.key, _lockable: PhantomData, tuple, outer: self.outer, }) } else { None } } } impl<'c, L: 'c + Iterator, I: 'c + RawLock + Lockable, O> LockingIterator<'c, L, O> { /// Advances the iterator, locking the next element and returning a guard to /// the inner data. /// /// Returns `None` when iteration is finished. Individual iterator /// implementations may choose to resume iteration, and so calling `next()` /// again may or may not eventually start returning `Some(Item)` again at some /// point. /// /// # Example /// /// ``` /// use happylock::{Mutex, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// /// let key = ThreadKey::get().unwrap(); /// let data = [Mutex::new(1), Mutex::new(3), Mutex::new(8)]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let mut iter = ctx.iter(key); /// /// let mut sum = 0; /// while let Some(item) = iter.lock_next() { /// sum += **item; /// } /// /// assert_eq!(sum, 12); /// ``` pub fn lock_next(&mut self) -> Option::Guard<'c>, ThreadKey>> { if let Some(lock) = self.iterator.next() { unsafe { lock.raw_write(); let guard = lock.guard(); Some(ContextGuard { _key: self.key, guard, }) } } else { None } } /// Consumes the iterator, returning the last element, without locking any /// other elements. /// /// This method will evaluate the iterator until it returns `None`. While /// doing so, it keeps track of the current element. After `None` is returned, /// `lock_last()` will then lock the last element it saw and return the /// lock's data. /// /// # Panics /// /// This function might panic if the iterator is infinite. /// /// # Example /// /// ``` /// use happylock::{Mutex, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// /// let key = ThreadKey::get().unwrap(); /// let data = [Mutex::new(1), Mutex::new(3), Mutex::new(8)]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let iter = ctx.iter(key); /// /// let last = iter.lock_last().unwrap(); /// assert_eq!(**last, 8); /// ``` pub fn lock_last(self) -> Option::Guard<'c>, ThreadKey>> { self.iterator.last().map(|lock| unsafe { lock.raw_write(); let guard = lock.guard(); ContextGuard { _key: self.key, guard, } }) } } impl<'c, L: 'c + Iterator, I: 'c + RawLock + Lockable, O> LockingIterator<'c, Peekable, O> { /// Attempts to lock the next element and returning a guard to /// the inner data. /// /// # Errors /// /// Returns `Err(TryLockNextError::FinishedIteration)` when iteration is /// finished. Individual iterator implementations may choose to resume /// iteration, and so calling `next()` again may or may not eventually start /// returning `Some(Item)` again at some point. /// /// Returns `Err(TryLockNextError::WouldBlock)` if the next lock in the /// iterator is already locked. This will not advance the iterator. /// /// # Example /// /// ``` /// use happylock::{Mutex, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// use happylock::context::iterator::TryLockNextError; /// /// let key = ThreadKey::get().unwrap(); /// let data = [Mutex::new(1), Mutex::new(3), Mutex::new(8)]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let mut iter = ctx.iter(key).peekable(); /// /// let mut sum = 0; /// loop { /// match iter.try_lock_next() { /// Ok(item) => sum += **item, /// Err(TryLockNextError::WouldBlock) => continue, /// Err(TryLockNextError::FinishedIteration) => break, /// } /// } /// /// assert_eq!(sum, 12); /// ``` pub fn try_lock_next( &mut self, ) -> Result::Guard<'c>, ThreadKey>, TryLockNextError> { if let Some(lock) = self.iterator.peek().copied() { unsafe { if lock.raw_try_write() { // safety: we just saw that there is a valid value let lock = self.iterator.next().unwrap_unchecked(); let guard = lock.guard(); Ok(ContextGuard { _key: self.key, guard, }) } else { Err(TryLockNextError::WouldBlock) } } } else { Err(TryLockNextError::FinishedIteration) } } } impl<'c, L: 'c + Iterator, I: 'c + RawLock + Sharable, O> LockingIterator<'c, L, O> { /// Advances the iterator, acquiring a shared lock to the next element and /// returning a guard to the inner data. /// /// Returns `None` when iteration is finished. Individual iterator /// implementations may choose to resume iteration, and so calling `next()` /// again may or may not eventually start returning `Some(Item)` again at some /// point. /// /// # Example /// /// ``` /// use happylock::{RwLock, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// /// let key = ThreadKey::get().unwrap(); /// let data = [RwLock::new(1), RwLock::new(3), RwLock::new(8)]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let mut iter = ctx.iter(key); /// /// let mut sum = 0; /// while let Some(item) = iter.read_next() { /// sum += **item; /// } /// /// assert_eq!(sum, 12); /// ``` pub fn read_next( &mut self, ) -> Option::ReadGuard<'c>, ThreadKey>> { if let Some(lock) = self.iterator.next() { unsafe { lock.raw_read(); let guard = lock.read_guard(); Some(ContextGuard { _key: self.key, guard, }) } } else { None } } /// Consumes the iterator, returning the last element with readonly access, /// without locking any other elements. /// /// This method will evaluate the iterator until it returns `None`. While /// doing so, it keeps track of the current element. After `None` is returned, /// `lock_last()` will then lock the last element it saw and return the /// lock's data. /// /// # Panics /// /// This function might panic if the iterator is infinite. /// /// # Example /// /// ``` /// use happylock::{RwLock, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// /// let key = ThreadKey::get().unwrap(); /// let data = [RwLock::new(1), RwLock::new(3), RwLock::new(8)]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let iter = ctx.iter(key); /// /// let last = iter.read_last().unwrap(); /// assert_eq!(**last, 8); /// ``` pub fn read_last(self) -> Option::ReadGuard<'c>, ThreadKey>> { self.iterator.last().map(|lock| unsafe { lock.raw_read(); let guard = lock.read_guard(); ContextGuard { _key: self.key, guard, } }) } } impl<'c, L: 'c + Iterator, I: 'c + RawLock + Sharable, O> LockingIterator<'c, Peekable, O> { /// Attempts to acquire a shared lock the next element and returning a guard /// to the inner data. /// /// # Errors /// /// Returns `Err(TryLockNextError::FinishedIteration)` when iteration is /// finished. Individual iterator implementations may choose to resume /// iteration, and so calling `next()` again may or may not eventually start /// returning `Some(Item)` again at some point. /// /// Returns `Err(TryLockNextError::WouldBlock)` if the next lock in the /// iterator is already locked. This will not advance the iterator. /// /// # Example /// /// ``` /// use happylock::{RwLock, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// use happylock::context::iterator::TryLockNextError; /// /// let key = ThreadKey::get().unwrap(); /// let data = [RwLock::new(1), RwLock::new(3), RwLock::new(8)]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let mut iter = ctx.iter(key).peekable(); /// /// let mut sum = 0; /// loop { /// match iter.try_read_next() { /// Ok(item) => sum += **item, /// Err(TryLockNextError::WouldBlock) => continue, /// Err(TryLockNextError::FinishedIteration) => break, /// } /// } /// /// assert_eq!(sum, 12); /// ``` pub fn try_read_next( &mut self, ) -> Result::ReadGuard<'c>, ThreadKey>, TryLockNextError> { if let Some(lock) = self.iterator.peek().copied() { unsafe { if lock.raw_try_read() { // safety: we just saw that there is a valid value let lock = self.iterator.next().unwrap_unchecked(); let guard = lock.read_guard(); Ok(ContextGuard { _key: self.key, guard, }) } else { Err(TryLockNextError::WouldBlock) } } } else { Err(TryLockNextError::FinishedIteration) } } } impl<'l, L: Iterator, O> LockingIterator<'l, L, O> { /// Advances the iterator, without locking the next element in the iterator. /// /// Returns `false` when iteration is finished. Individual iterator /// implementations may choose to resume iteration, and so calling /// `skip_next()` again may or may not eventually start returning `true` again /// at some point. /// /// # Example /// /// ``` /// use happylock::{Mutex, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// /// let key = ThreadKey::get().unwrap(); /// let data = [Mutex::new(1), Mutex::new(3), Mutex::new(8)]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let mut iter = ctx.iter(key); /// /// iter.skip_next(); /// assert!(iter.lock_next().is_some_and(|v| **v == 3)); /// ``` pub fn skip_next(&mut self) -> bool { self.iterator.next().is_some() } /// Advances the iterator, skipping `n` elements without locking. /// /// See [`Iterator::skip`] for more information. /// /// # Example /// /// ``` /// use happylock::{Mutex, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// /// let key = ThreadKey::get().unwrap(); /// let data = [Mutex::new(1), Mutex::new(3), Mutex::new(8)]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let mut iter = ctx.iter(key); /// /// iter.skip_mut(2); /// assert!(iter.lock_next().is_some_and(|v| **v == 8)); /// ``` pub fn skip_mut(&mut self, n: usize) { for _ in 0..n { self.iterator.next(); } } /// Returns the bounds on the remaining length of the iterator. /// /// See [`Iterator::size_hint`] for more information. /// /// # Example /// /// ``` /// use happylock::{Mutex, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// /// let key = ThreadKey::get().unwrap(); /// let data = [Mutex::new(1), Mutex::new(2), Mutex::new(3)]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let mut iter = ctx.iter(key); /// /// assert_eq!((3, Some(3)), iter.size_hint()); /// let _ = iter.skip_next(); /// assert_eq!((2, Some(2)), iter.size_hint()); /// ``` #[must_use] pub fn size_hint(&self) -> (usize, Option) { self.iterator.size_hint() } /// Creates a new [`LockingIterator`] that skips the first `n` elements. /// /// Unlike `skip_next` or `skip_mut`, this method does not modify the iterator /// in place. Instead, it returns a new iterator which skips the first `n` /// elements. /// /// See [`Iterator::skip`] for more information. /// /// # Example /// /// ``` /// use happylock::{Mutex, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// /// let key = ThreadKey::get().unwrap(); /// let data = [Mutex::new(1), Mutex::new(2), Mutex::new(3)]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let mut iter = ctx.iter(key).skip(2); /// /// assert!(iter.lock_next().is_some_and(|v| **v == 3)); /// assert!(iter.lock_next().is_none()); /// ``` #[must_use] pub fn skip(self, n: usize) -> LockingIterator<'l, Skip, O> { self.with_iterator(|i| i.skip(n)) } /// Creates a new [`LockingIterator`] that yields only the first `n` elements, /// or fewer if the iterator ends sooner. /// /// See [`Iterator::take`] for more information. /// /// # Example /// /// ``` /// use happylock::{Mutex, ThreadKey}; /// use happylock::collection::OwnedLockCollection; /// /// let key = ThreadKey::get().unwrap(); /// let data = [Mutex::new(1), Mutex::new(2), Mutex::new(3)]; /// let locks = OwnedLockCollection::new(data); /// let mut ctx = locks.context(); /// let mut iter = ctx.iter(key).take(2); /// /// assert!(iter.lock_next().is_some_and(|v| **v == 1)); /// assert!(iter.lock_next().is_some_and(|v| **v == 2)); /// assert!(iter.lock_next().is_none()); /// ``` #[must_use] pub fn take(self, n: usize) -> LockingIterator<'l, Take, O> { self.with_iterator(|i| i.take(n)) } /// Creates a new [`LockingIterator`] that ends after the first `None` /// /// See [`Iterator::fuse`] for more information #[must_use] pub fn fuse(self) -> LockingIterator<'l, Fuse, O> { self.with_iterator(Iterator::fuse) } /// Creates a new [`LockingIterator`] which has access to the /// [`try_lock_next`] and/or [`try_read_next`] methods. /// /// See [`Iterator::peekable`] for more information /// /// [`try_lock_next`]: `LockingIterator::try_lock_next` /// [`try_read_next`]: `LockingIterator::try_read_next` #[must_use] pub fn peekable(self) -> LockingIterator<'l, Peekable, O> { self.with_iterator(Iterator::peekable) } }