diff --git a/utilities/src/linked_item.rs b/utilities/src/linked_item.rs index 0d8bf7ae317aaee46a812ccc337f4958bdf0c7e3..8e93c0b214dceabf133ebd2c658e530458fb100b 100644 --- a/utilities/src/linked_item.rs +++ b/utilities/src/linked_item.rs @@ -1,5 +1,5 @@ use codec::{Decode, Encode}; -use rstd::{iter, marker}; +use rstd::{iter, marker, prelude::*}; use sr_primitives::{traits::Member, RuntimeDebug}; use support::{Parameter, StorageMap}; @@ -17,11 +17,11 @@ impl<Item> Default for LinkedItem<Item> { pub struct LinkedList<Storage, Key, Item>(rstd::marker::PhantomData<(Storage, Key, Item)>); -impl<'a, Storage, Key, Value> LinkedList<Storage, Key, Value> +impl<Storage, Key, Value> LinkedList<Storage, Key, Value> where Value: Parameter + Member + Copy, Key: Parameter, - Storage: StorageMap<(Key, Option<Value>), LinkedItem<Value>, Query = Option<LinkedItem<Value>>>, + Storage: 'static + StorageMap<(Key, Option<Value>), LinkedItem<Value>, Query = Option<LinkedItem<Value>>>, { fn read_head(key: &Key) -> LinkedItem<Value> { Self::read(key, None) @@ -88,66 +88,73 @@ where } } - pub fn enumerate(key: &'a Key) -> Enumerator<'a, Key, Value, Self> { - Enumerator::<'a, Key, Value, Self> { - key, - should_take: false, - linkage: Self::read_head(key), - _phantom: Default::default(), - } + pub fn enumerate(key: &Key) -> Enumerator<Key, Value, Self> { + Enumerator::<Key, Value, Self>::new(key, false, Self::read_head(key)) } - pub fn take_all(key: &'a Key) -> Enumerator<'a, Key, Value, Self> { - Enumerator::<'a, Key, Value, Self> { - key, - should_take: true, - linkage: Self::read_head(key), - _phantom: Default::default(), - } + pub fn take_all(key: &Key) -> Enumerator<Key, Value, Self> { + Enumerator::<Key, Value, Self>::new(key, true, Self::read_head(key)) } } -pub struct Enumerator<'a, Key, Value, LinkedList> { - key: &'a Key, +pub struct Enumerator<Key, Value, LinkedList> { + key: Key, should_take: bool, linkage: LinkedItem<Value>, + next_fn: fn(&mut Enumerator<Key, Value, LinkedList>) -> Option<Value>, _phantom: marker::PhantomData<LinkedList>, } -impl<'a, Key, Value, Storage> iter::Iterator for Enumerator<'a, Key, Value, LinkedList<Storage, Key, Value>> +impl<Key, Value, Storage> Enumerator<Key, Value, LinkedList<Storage, Key, Value>> where Key: Parameter, Value: Parameter + Member + Copy, - Storage: StorageMap<(Key, Option<Value>), LinkedItem<Value>, Query = Option<LinkedItem<Value>>>, + Storage: 'static + StorageMap<(Key, Option<Value>), LinkedItem<Value>, Query = Option<LinkedItem<Value>>>, { - type Item = Value; - - fn next(&mut self) -> Option<Self::Item> { + fn new(key: &Key, should_take: bool, linkage: LinkedItem<Value>) -> Self { + Self { + key: key.clone(), + should_take, + linkage, + next_fn: Self::next, + _phantom: Default::default(), + } + } + fn next(&mut self) -> Option<Value> { let next_value = self.linkage.next?; if self.should_take { - self.linkage = <LinkedList<Storage, Key, Value>>::take(self.key, next_value); + self.linkage = <LinkedList<Storage, Key, Value>>::take(&self.key, next_value); } else { - self.linkage = <LinkedList<Storage, Key, Value>>::read(self.key, Some(next_value)); + self.linkage = <LinkedList<Storage, Key, Value>>::read(&self.key, Some(next_value)); } Some(next_value) } } -// FIXME: error[E0366]: Implementations of Drop cannot be specialized -// impl<'a, Key, Value, Storage> Drop for Enumerator<'a, Key, Value, LinkedList<Storage, Key, Value>> -// where -// Key: Parameter, -// Value: Parameter + Member + Copy, -// Storage: StorageMap<(Key, Option<Value>), LinkedItem<Value>, Query = Option<LinkedItem<Value>>>, -// { -// fn drop(&mut self) { -// if !self.should_take { -// return -// } - -// while self.next() != None {} -// } -// } +impl<Key, Value, Storage> iter::Iterator for Enumerator<Key, Value, LinkedList<Storage, Key, Value>> +where + Key: Parameter, + Value: Parameter + Member + Copy, + Storage: 'static + StorageMap<(Key, Option<Value>), LinkedItem<Value>, Query = Option<LinkedItem<Value>>>, +{ + type Item = Value; + + fn next(&mut self) -> Option<Self::Item> { + let next_fn = self.next_fn; + next_fn(self) + } +} + +impl<Key, Value, LinkedList> Drop for Enumerator<Key, Value, LinkedList> { + fn drop(&mut self) { + if !self.should_take { + return; + } + + let next_fn = self.next_fn; + while next_fn(self).is_some() {} + } +} #[cfg(test)] mod tests { @@ -386,4 +393,22 @@ mod tests { assert_eq!(TestLinkedList::enumerate(&0).collect::<Vec<_>>(), []); }); } + + #[test] + fn linked_list_take_all_is_safe() { + new_test_ext().execute_with(|| { + assert_eq!(TestLinkedList::take_all(&0).collect::<Vec<_>>(), []); + + TestLinkedList::append(&0, 1); + TestLinkedList::append(&0, 2); + TestLinkedList::append(&0, 3); + + let _ = TestLinkedList::take_all(&0); + + assert_eq!(TestItem::get(&(0, Some(1))), None); + assert_eq!(TestItem::get(&(0, Some(2))), None); + assert_eq!(TestItem::get(&(0, Some(3))), None); + assert_eq!(TestLinkedList::enumerate(&0).collect::<Vec<_>>(), []); + }); + } }