Skip to main content

gear_common/storage/complex/
mailbox.rs

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