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