gear_common/storage/complex/
waitlist.rs

1// This file is part of Gear.
2
3// Copyright (C) 2022-2025 Gear Technologies Inc.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Module for waitlist implementation.
20//!
21//! Waitlist provides functionality of delaying messages execution,
22//! addressed to programs, by their storing out of message queue.
23
24use crate::storage::{
25    Callback, CountedByKey, DoubleMapStorage, GetCallback, Interval, IterableByKeyMap, IterableMap,
26    KeyFor,
27};
28use core::marker::PhantomData;
29
30pub type ValueWithInterval<T, B> = (T, Interval<B>);
31
32/// Represents waitlist managing logic.
33pub trait Waitlist {
34    /// First key type.
35    type Key1;
36    /// Second key type.
37    type Key2;
38    /// Stored values type.
39    type Value;
40    /// Block number type.
41    ///
42    /// Stored with `Self::Value`.
43    type BlockNumber;
44    /// Inner error type of waitlist storing algorithm.
45    type Error: WaitlistError;
46    /// Output error type of the waitlist.
47    type OutputError: From<Self::Error>;
48
49    /// Returns bool, defining does first key's waitlist contain second key.
50    fn contains(key1: &Self::Key1, key2: &Self::Key2) -> bool;
51
52    /// Inserts given value in waitlist.
53    fn insert(value: Self::Value, bn: Self::BlockNumber) -> Result<(), Self::OutputError>;
54
55    /// Removes and returns value from waitlist by given keys,
56    /// if present, else returns error.
57    fn remove(
58        key1: Self::Key1,
59        key2: Self::Key2,
60    ) -> Result<ValueWithInterval<Self::Value, Self::BlockNumber>, Self::OutputError>;
61
62    /// Removes all values from all key's waitlisted.
63    fn clear();
64}
65
66/// Represents store of waitlist's action callbacks.
67pub trait WaitlistCallbacks {
68    /// Callback relative type.
69    ///
70    /// This value represents main stored component in waitlist,
71    /// which uses this callbacks store.
72    type Value;
73    /// Callback relative type.
74    ///
75    /// This type represents block number of stored component in waitlist,
76    /// which uses this callbacks store.
77    type BlockNumber;
78
79    /// Callback used for getting current block number.
80    type GetBlockNumber: GetCallback<Self::BlockNumber>;
81    /// Callback on success `insert`.
82    type OnInsert: Callback<ValueWithInterval<Self::Value, Self::BlockNumber>>;
83    /// Callback on success `remove`.
84    type OnRemove: Callback<ValueWithInterval<Self::Value, Self::BlockNumber>>;
85}
86
87/// Represents waitlist error type.
88///
89/// Contains constructors for all existing errors.
90pub trait WaitlistError {
91    /// Occurs when given value already exists in waitlist.
92    fn duplicate_key() -> Self;
93
94    /// Occurs when element wasn't found in storage.
95    fn element_not_found() -> Self;
96}
97
98/// `Waitlist` implementation based on `DoubleMapStorage`.
99///
100/// Generic parameter `Error` requires `WaitlistError` implementation.
101/// Generic parameter `KeyGen` presents key generation for given values.
102/// Generic parameter `Callbacks` presents actions for success operations
103/// over waitlist.
104pub struct WaitlistImpl<T, Value, BlockNumber, Error, OutputError, Callbacks, KeyGen>(
105    PhantomData<(T, Error, OutputError, Callbacks, KeyGen)>,
106)
107where
108    T: DoubleMapStorage<Value = (Value, Interval<BlockNumber>)>,
109    Error: WaitlistError,
110    OutputError: From<Error>,
111    Callbacks: WaitlistCallbacks<Value = Value, BlockNumber = BlockNumber>,
112    KeyGen: KeyFor<Key = (T::Key1, T::Key2), Value = Value>;
113
114// Implementation of `Waitlist` for `WaitlistImpl`.
115impl<T, Value, BlockNumber, Error, OutputError, Callbacks, KeyGen> Waitlist
116    for WaitlistImpl<T, Value, BlockNumber, Error, OutputError, Callbacks, KeyGen>
117where
118    T: DoubleMapStorage<Value = (Value, Interval<BlockNumber>)>,
119    Error: WaitlistError,
120    OutputError: From<Error>,
121    Callbacks: WaitlistCallbacks<Value = Value, BlockNumber = BlockNumber>,
122    KeyGen: KeyFor<Key = (T::Key1, T::Key2), Value = Value>,
123{
124    type Key1 = T::Key1;
125    type Key2 = T::Key2;
126    type Value = Value;
127    type BlockNumber = BlockNumber;
128    type Error = Error;
129    type OutputError = OutputError;
130
131    fn contains(program_id: &Self::Key1, message_id: &Self::Key2) -> bool {
132        T::contains_keys(program_id, message_id)
133    }
134
135    fn insert(
136        message: Self::Value,
137        scheduled_at: Self::BlockNumber,
138    ) -> Result<(), Self::OutputError> {
139        let (key1, key2) = KeyGen::key_for(&message);
140
141        if Self::contains(&key1, &key2) {
142            return Err(Self::Error::duplicate_key().into());
143        }
144
145        let block_number = Callbacks::GetBlockNumber::call();
146        let message_with_bn = (
147            message,
148            Interval {
149                start: block_number,
150                finish: scheduled_at,
151            },
152        );
153
154        Callbacks::OnInsert::call(&message_with_bn);
155        T::insert(key1, key2, message_with_bn);
156        Ok(())
157    }
158
159    fn remove(
160        program_id: Self::Key1,
161        message_id: Self::Key2,
162    ) -> Result<ValueWithInterval<Self::Value, Self::BlockNumber>, Self::OutputError> {
163        if let Some(message_with_bn) = T::take(program_id, message_id) {
164            Callbacks::OnRemove::call(&message_with_bn);
165            Ok(message_with_bn)
166        } else {
167            Err(Self::Error::element_not_found().into())
168        }
169    }
170
171    fn clear() {
172        T::clear()
173    }
174}
175
176// Implementation of `CountedByKey` trait for `WaitlistImpl` in case,
177// when inner `DoubleMapStorage` implements `CountedByKey`.
178impl<T, Value, BlockNumber, Error, OutputError, Callbacks, KeyGen> CountedByKey
179    for WaitlistImpl<T, Value, BlockNumber, Error, OutputError, Callbacks, KeyGen>
180where
181    T: DoubleMapStorage<Value = (Value, Interval<BlockNumber>)> + CountedByKey<Key = T::Key1>,
182    Error: WaitlistError,
183    OutputError: From<Error>,
184    Callbacks: WaitlistCallbacks<Value = Value, BlockNumber = BlockNumber>,
185    KeyGen: KeyFor<Key = (T::Key1, T::Key2), Value = Value>,
186{
187    type Key = T::Key1;
188    type Length = T::Length;
189
190    fn len(key: &Self::Key) -> Self::Length {
191        T::len(key)
192    }
193}
194
195// Implementation of `IterableByKeyMap` trait for `WaitlistImpl` in case,
196// when inner `DoubleMapStorage` implements `IterableByKeyMap`.
197impl<T, Value, BlockNumber, Error, OutputError, Callbacks, KeyGen> IterableByKeyMap<T::Value>
198    for WaitlistImpl<T, Value, BlockNumber, Error, OutputError, Callbacks, KeyGen>
199where
200    T: DoubleMapStorage<Value = (Value, Interval<BlockNumber>)>
201        + IterableByKeyMap<T::Value, Key = T::Key1>,
202    Error: WaitlistError,
203    OutputError: From<Error>,
204    Callbacks: WaitlistCallbacks<Value = Value, BlockNumber = BlockNumber>,
205    KeyGen: KeyFor<Key = (T::Key1, T::Key2), Value = Value>,
206{
207    type Key = T::Key1;
208    type DrainIter = T::DrainIter;
209    type Iter = T::Iter;
210
211    fn drain_key(key: Self::Key) -> Self::DrainIter {
212        T::drain_key(key)
213    }
214
215    fn iter_key(key: Self::Key) -> Self::Iter {
216        T::iter_key(key)
217    }
218}
219
220// Implementation of `IterableMap` trait for `WaitlistImpl` in case,
221// when inner `DoubleMapStorage` implements `IterableMap`.
222impl<T, Value, BlockNumber, Error, OutputError, Callbacks, KeyGen> IterableMap<T::Value>
223    for WaitlistImpl<T, Value, BlockNumber, Error, OutputError, Callbacks, KeyGen>
224where
225    T: DoubleMapStorage<Value = (Value, Interval<BlockNumber>)> + IterableMap<T::Value>,
226    Error: WaitlistError,
227    OutputError: From<Error>,
228    Callbacks: WaitlistCallbacks<Value = Value, BlockNumber = BlockNumber>,
229    KeyGen: KeyFor<Key = (T::Key1, T::Key2), Value = Value>,
230{
231    type DrainIter = T::DrainIter;
232    type Iter = T::Iter;
233
234    fn drain() -> Self::DrainIter {
235        T::drain()
236    }
237
238    fn iter() -> Self::Iter {
239        T::iter()
240    }
241}