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