Skip to main content

gear_core/message/
stored.rs

1// Copyright (C) Gear Technologies Inc.
2// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
3
4use crate::{
5    buffer::Payload,
6    ids::{ActorId, MessageId},
7    message::{
8        ContextStore, DispatchKind, GasLimit, IncomingDispatch, IncomingMessage, ReplyDetails,
9        Value, common::MessageDetails,
10    },
11};
12use core::ops::Deref;
13use gear_core_errors::ReplyCode;
14use parity_scale_codec::{Decode, Encode};
15use scale_decode::DecodeAsType;
16use scale_encode::EncodeAsType;
17use scale_info::TypeInfo;
18
19/// Stored message.
20///
21/// Gasless Message for storing.
22#[derive(
23    Clone, Debug, PartialEq, Eq, Hash, Decode, DecodeAsType, Encode, EncodeAsType, TypeInfo,
24)]
25pub struct StoredMessage {
26    /// Message id.
27    pub(super) id: MessageId,
28    /// Message source.
29    pub(super) source: ActorId,
30    /// Message destination.
31    pub(super) destination: ActorId,
32    /// Message payload.
33    pub(super) payload: Payload,
34    /// Message value.
35    #[codec(compact)]
36    pub(super) value: Value,
37    /// Message details like reply message ID, status code, etc.
38    pub(super) details: Option<MessageDetails>,
39}
40
41impl StoredMessage {
42    /// Create new StoredMessage.
43    pub fn new(
44        id: MessageId,
45        source: ActorId,
46        destination: ActorId,
47        payload: Payload,
48        value: Value,
49        details: Option<MessageDetails>,
50    ) -> Self {
51        Self {
52            id,
53            source,
54            destination,
55            payload,
56            value,
57            details,
58        }
59    }
60
61    /// Into parts.
62    pub fn into_parts(
63        self,
64    ) -> (
65        MessageId,
66        ActorId,
67        ActorId,
68        Payload,
69        Value,
70        Option<MessageDetails>,
71    ) {
72        (
73            self.id,
74            self.source,
75            self.destination,
76            self.payload,
77            self.value,
78            self.details,
79        )
80    }
81
82    /// Convert StoredMessage into IncomingMessage for program processing.
83    pub fn into_incoming(self, gas_limit: GasLimit) -> IncomingMessage {
84        IncomingMessage::new(
85            self.id,
86            self.source,
87            self.payload,
88            gas_limit,
89            self.value,
90            self.details,
91        )
92    }
93
94    /// Message id.
95    pub fn id(&self) -> MessageId {
96        self.id
97    }
98
99    /// Message source.
100    pub fn source(&self) -> ActorId {
101        self.source
102    }
103
104    /// Message destination.
105    pub fn destination(&self) -> ActorId {
106        self.destination
107    }
108
109    /// Message payload bytes.
110    pub fn payload_bytes(&self) -> &[u8] {
111        &self.payload
112    }
113
114    /// Message value.
115    pub fn value(&self) -> Value {
116        self.value
117    }
118
119    /// Message details.
120    pub fn details(&self) -> Option<MessageDetails> {
121        self.details
122    }
123
124    /// Message reply.
125    pub fn reply_details(&self) -> Option<ReplyDetails> {
126        self.details.and_then(|d| d.to_reply_details())
127    }
128
129    /// Returns bool defining if message is error reply.
130    pub fn is_error_reply(&self) -> bool {
131        self.details.map(|d| d.is_error_reply()).unwrap_or(false)
132    }
133
134    /// Returns bool defining if message is reply.
135    pub fn is_reply(&self) -> bool {
136        self.details.map(|d| d.is_reply_details()).unwrap_or(false)
137    }
138
139    /// Returns `ReplyCode` of message if reply.
140    pub fn reply_code(&self) -> Option<ReplyCode> {
141        self.details
142            .and_then(|d| d.to_reply_details().map(|d| d.to_reply_code()))
143    }
144}
145
146/// Stored message with entry point and previous execution context, if exists.
147#[derive(
148    Clone, Debug, PartialEq, Eq, Hash, Decode, DecodeAsType, Encode, EncodeAsType, TypeInfo,
149)]
150pub struct StoredDispatch {
151    /// Entry point.
152    kind: DispatchKind,
153    /// Stored message.
154    message: StoredMessage,
155    /// Previous execution context.
156    context: Option<ContextStore>,
157}
158
159impl From<StoredDispatch> for (DispatchKind, StoredMessage, Option<ContextStore>) {
160    fn from(dispatch: StoredDispatch) -> (DispatchKind, StoredMessage, Option<ContextStore>) {
161        (dispatch.kind, dispatch.message, dispatch.context)
162    }
163}
164
165impl StoredDispatch {
166    /// Create new StoredDispatch.
167    pub fn new(kind: DispatchKind, message: StoredMessage, context: Option<ContextStore>) -> Self {
168        Self {
169            kind,
170            message,
171            context,
172        }
173    }
174
175    /// Convert StoredDispatch into IncomingDispatch for program processing.
176    pub fn into_incoming(self, gas_limit: GasLimit) -> IncomingDispatch {
177        IncomingDispatch::new(
178            self.kind,
179            self.message.into_incoming(gas_limit),
180            self.context,
181        )
182    }
183
184    /// Decompose StoredDispatch for it's components: DispatchKind, StoredMessage and `Option<ContextStore>`.
185    pub fn into_parts(self) -> (DispatchKind, StoredMessage, Option<ContextStore>) {
186        self.into()
187    }
188
189    /// Entry point for the message.
190    pub fn kind(&self) -> DispatchKind {
191        self.kind
192    }
193
194    /// Dispatch message reference.
195    pub fn message(&self) -> &StoredMessage {
196        &self.message
197    }
198
199    /// Previous execution context reference, if exists.
200    pub fn context(&self) -> &Option<ContextStore> {
201        &self.context
202    }
203}
204
205impl Deref for StoredDispatch {
206    type Target = StoredMessage;
207
208    fn deref(&self) -> &Self::Target {
209        self.message()
210    }
211}
212
213impl From<StoredDelayedDispatch> for StoredDispatch {
214    fn from(dispatch: StoredDelayedDispatch) -> Self {
215        StoredDispatch::new(dispatch.kind, dispatch.message, None)
216    }
217}
218
219/// Stored message with entry point.
220///
221/// We could use just [`StoredDispatch`]
222/// but delayed messages always don't have [`ContextStore`]
223/// so we designate this fact via new type.
224#[derive(
225    Clone, Debug, PartialEq, Eq, Hash, Decode, DecodeAsType, Encode, EncodeAsType, TypeInfo,
226)]
227pub struct StoredDelayedDispatch {
228    /// Entry point.
229    kind: DispatchKind,
230    /// Stored message.
231    message: StoredMessage,
232}
233
234impl From<StoredDelayedDispatch> for (DispatchKind, StoredMessage) {
235    fn from(dispatch: StoredDelayedDispatch) -> (DispatchKind, StoredMessage) {
236        (dispatch.kind, dispatch.message)
237    }
238}
239
240impl StoredDelayedDispatch {
241    /// Create new StoredDelayedDispatch.
242    pub fn new(kind: DispatchKind, message: StoredMessage) -> Self {
243        Self { kind, message }
244    }
245
246    /// Decompose StoredDelayedDispatch for it's components: DispatchKind, StoredMessage.
247    pub fn into_parts(self) -> (DispatchKind, StoredMessage) {
248        self.into()
249    }
250
251    /// Entry point for the message.
252    pub fn kind(&self) -> DispatchKind {
253        self.kind
254    }
255
256    /// Dispatch message reference.
257    pub fn message(&self) -> &StoredMessage {
258        &self.message
259    }
260}
261
262impl Deref for StoredDelayedDispatch {
263    type Target = StoredMessage;
264
265    fn deref(&self) -> &Self::Target {
266        self.message()
267    }
268}