pallet_tasks/
queue.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use crate::Config;
use core::marker::PhantomData;
use frame_support::storage::{StorageDoubleMap, StorageMap};
use polkadot_sdk::{frame_support, sp_runtime};
use scale_codec::FullCodec;
use sp_runtime::Saturating;
use time_primitives::NetworkId;

pub type Index = u64;

pub trait QueueT<T: Config, Value> {
	/// Push an item onto the end of the queue.
	fn push(&self, value: Value);
	/// Remove an item from the queue.
	fn remove(&self, index: Index) -> Option<Value>;
	/// Pop an item from the beginning of the queue.
	fn pop(&self) -> Option<Value>;
}

pub struct QueueImpl<T, Value, InsertIndex, RemoveIndex, Queue> {
	network: NetworkId,
	_phantom: PhantomData<(T, Value, InsertIndex, RemoveIndex, Queue)>,
}

impl<T, Value, InsertIndex, RemoveIndex, Queue>
	QueueImpl<T, Value, InsertIndex, RemoveIndex, Queue>
{
	pub fn new(network: NetworkId) -> QueueImpl<T, Value, InsertIndex, RemoveIndex, Queue> {
		Self { network, _phantom: PhantomData }
	}
}

impl<T: Config, Value, InsertIndex, RemoveIndex, Queue> QueueT<T, Value>
	for QueueImpl<T, Value, InsertIndex, RemoveIndex, Queue>
where
	Value: FullCodec,
	InsertIndex: StorageMap<NetworkId, Index, Query = Option<Index>>,
	RemoveIndex: StorageMap<NetworkId, Index, Query = Option<Index>>,
	Queue: StorageDoubleMap<NetworkId, Index, Value, Query = Option<Value>>,
{
	fn pop(&self) -> Option<Value> {
		let remove_i = RemoveIndex::get(self.network).unwrap_or_default();
		self.remove(remove_i)
	}

	fn push(&self, value: Value) {
		let insert_i = InsertIndex::get(self.network).unwrap_or_default();
		Queue::insert(self.network, insert_i, value);
		InsertIndex::insert(self.network, insert_i.saturating_plus_one());
	}

	fn remove(&self, index: Index) -> Option<Value> {
		let insert_i = InsertIndex::get(self.network).unwrap_or_default();
		let mut remove_i = RemoveIndex::get(self.network).unwrap_or_default();
		if remove_i >= insert_i {
			return None;
		}
		let value = Queue::take(self.network, index);
		if index == remove_i {
			remove_i = remove_i.saturating_plus_one();
			while Queue::get(self.network, remove_i).is_none() && remove_i < insert_i {
				remove_i = remove_i.saturating_plus_one();
			}
			RemoveIndex::insert(self.network, remove_i);
		}
		value
	}
}