gear_core/message/
common.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        DispatchKind, GasLimit, StoredDelayedDispatch, StoredDispatch, StoredMessage, Value,
24    },
25};
26use core::ops::Deref;
27use gear_core_errors::{ReplyCode, SignalCode};
28use parity_scale_codec::{Decode, Encode};
29use scale_info::TypeInfo;
30
31/// An entity that is used for interaction between actors.
32/// Can transfer value and executes by programs in corresponding function: init, handle or handle_reply.
33#[derive(Clone, Debug, PartialEq, Eq, Decode, Encode)]
34pub struct Message {
35    /// Message id.
36    id: MessageId,
37    /// Message source.
38    source: ActorId,
39    /// Message destination.
40    destination: ActorId,
41    /// Message payload.
42    payload: Payload,
43    /// Message optional gas limit.
44    gas_limit: Option<GasLimit>,
45    /// Message value.
46    value: Value,
47    /// Message details like reply message ID, status code, etc.
48    details: Option<MessageDetails>,
49}
50
51impl From<Message> for StoredMessage {
52    fn from(message: Message) -> StoredMessage {
53        StoredMessage::new(
54            message.id,
55            message.source,
56            message.destination,
57            message.payload,
58            message.value,
59            message.details,
60        )
61    }
62}
63
64impl Message {
65    /// Create new message.
66    pub fn new(
67        id: MessageId,
68        source: ActorId,
69        destination: ActorId,
70        payload: Payload,
71        gas_limit: Option<GasLimit>,
72        value: Value,
73        details: Option<MessageDetails>,
74    ) -> Self {
75        Self {
76            id,
77            source,
78            destination,
79            payload,
80            gas_limit,
81            value,
82            details,
83        }
84    }
85
86    /// Into parts.
87    pub fn into_parts(
88        self,
89    ) -> (
90        MessageId,
91        ActorId,
92        ActorId,
93        Payload,
94        Option<GasLimit>,
95        Value,
96        Option<MessageDetails>,
97    ) {
98        (
99            self.id,
100            self.source,
101            self.destination,
102            self.payload,
103            self.gas_limit,
104            self.value,
105            self.details,
106        )
107    }
108
109    /// Convert Message into gasless StoredMessage.
110    pub fn into_stored(self) -> StoredMessage {
111        self.into()
112    }
113
114    /// Message id.
115    pub fn id(&self) -> MessageId {
116        self.id
117    }
118
119    /// Message source.
120    pub fn source(&self) -> ActorId {
121        self.source
122    }
123
124    /// Message destination.
125    pub fn destination(&self) -> ActorId {
126        self.destination
127    }
128
129    /// Message payload bytes.
130    pub fn payload_bytes(&self) -> &[u8] {
131        self.payload.inner()
132    }
133
134    /// Message optional gas limit.
135    pub fn gas_limit(&self) -> Option<GasLimit> {
136        self.gas_limit
137    }
138
139    /// Message value.
140    pub fn value(&self) -> Value {
141        self.value
142    }
143
144    /// Message reply.
145    pub fn reply_details(&self) -> Option<ReplyDetails> {
146        self.details.and_then(|d| d.to_reply_details())
147    }
148
149    /// Message signal.
150    pub fn signal_details(&self) -> Option<SignalDetails> {
151        self.details.and_then(|d| d.to_signal_details())
152    }
153
154    /// Returns bool defining if message is error reply.
155    pub fn is_error_reply(&self) -> bool {
156        self.details.map(|d| d.is_error_reply()).unwrap_or(false)
157    }
158
159    /// Returns bool defining if message is reply.
160    pub fn is_reply(&self) -> bool {
161        self.reply_details().is_some()
162    }
163}
164
165/// Message details data.
166#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Decode, Encode, TypeInfo, derive_more::From)]
167#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
168pub enum MessageDetails {
169    /// Reply details.
170    Reply(ReplyDetails),
171    /// Message details.
172    Signal(SignalDetails),
173}
174
175impl MessageDetails {
176    /// Returns bool defining if message is error reply.
177    pub fn is_error_reply(&self) -> bool {
178        self.to_reply_details()
179            .map(|d| d.code.is_error())
180            .unwrap_or(false)
181    }
182
183    /// Check if kind is reply.
184    pub fn is_reply_details(&self) -> bool {
185        matches!(self, Self::Reply(_))
186    }
187
188    /// Returns reply details.
189    pub fn to_reply_details(self) -> Option<ReplyDetails> {
190        match self {
191            MessageDetails::Reply(reply) => Some(reply),
192            MessageDetails::Signal(_) => None,
193        }
194    }
195
196    /// Check if kind is signal.
197    pub fn is_signal_details(&self) -> bool {
198        matches!(self, Self::Signal(_))
199    }
200
201    /// Reply signal details.
202    pub fn to_signal_details(self) -> Option<SignalDetails> {
203        match self {
204            MessageDetails::Reply(_) => None,
205            MessageDetails::Signal(signal) => Some(signal),
206        }
207    }
208}
209
210/// Reply details data.
211///
212/// Part of [`ReplyMessage`](crate::message::ReplyMessage) logic, containing data about on which message id
213/// this replies and its status code.
214#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Decode, Encode, TypeInfo)]
215#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
216pub struct ReplyDetails {
217    /// Message id, this message replies on.
218    to: MessageId,
219    /// Reply code.
220    code: ReplyCode,
221}
222
223impl ReplyDetails {
224    /// Constructor for details.
225    pub fn new(to: MessageId, code: ReplyCode) -> Self {
226        Self { to, code }
227    }
228
229    /// Returns message id replied to.
230    pub fn to_message_id(&self) -> MessageId {
231        self.to
232    }
233
234    /// Returns reply code of reply details.
235    pub fn to_reply_code(&self) -> ReplyCode {
236        self.code
237    }
238
239    /// Destructs details into parts.
240    pub fn into_parts(self) -> (MessageId, ReplyCode) {
241        (self.to, self.code)
242    }
243}
244
245/// Signal details data.
246#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Decode, Encode, TypeInfo)]
247#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
248pub struct SignalDetails {
249    /// Message id, which issues signal.
250    to: MessageId,
251    /// Signal code.
252    code: SignalCode,
253}
254
255impl SignalDetails {
256    /// Constructor for details.
257    pub fn new(to: MessageId, code: SignalCode) -> Self {
258        Self { to, code }
259    }
260
261    /// Returns message id signal sent from.
262    pub fn to_message_id(&self) -> MessageId {
263        self.to
264    }
265
266    /// Returns signal code of signal details.
267    pub fn to_signal_code(&self) -> SignalCode {
268        self.code
269    }
270
271    /// Destructs details into parts.
272    pub fn into_parts(self) -> (MessageId, SignalCode) {
273        (self.to, self.code)
274    }
275}
276
277/// Message with entry point.
278#[derive(Clone, Debug, PartialEq, Eq, Decode, Encode)]
279pub struct Dispatch {
280    /// Entry point for the message.
281    kind: DispatchKind,
282    /// Message.
283    message: Message,
284}
285
286impl From<Dispatch> for StoredDispatch {
287    fn from(dispatch: Dispatch) -> StoredDispatch {
288        StoredDispatch::new(dispatch.kind, dispatch.message.into(), None)
289    }
290}
291
292impl From<Dispatch> for StoredDelayedDispatch {
293    fn from(dispatch: Dispatch) -> StoredDelayedDispatch {
294        StoredDelayedDispatch::new(dispatch.kind, dispatch.message.into())
295    }
296}
297
298impl From<Dispatch> for (DispatchKind, Message) {
299    fn from(dispatch: Dispatch) -> (DispatchKind, Message) {
300        (dispatch.kind, dispatch.message)
301    }
302}
303
304impl Dispatch {
305    /// Create new Dispatch.
306    pub fn new(kind: DispatchKind, message: Message) -> Self {
307        Self { kind, message }
308    }
309
310    /// Convert Dispatch into gasless StoredDispatch with empty previous context.
311    pub fn into_stored(self) -> StoredDispatch {
312        self.into()
313    }
314
315    /// Convert Dispatch into gasless StoredDelayedDispatch.
316    pub fn into_stored_delayed(self) -> StoredDelayedDispatch {
317        self.into()
318    }
319
320    /// Decompose Dispatch for it's components: DispatchKind and Message.
321    pub fn into_parts(self) -> (DispatchKind, Message) {
322        self.into()
323    }
324
325    /// Entry point for the message.
326    pub fn kind(&self) -> DispatchKind {
327        self.kind
328    }
329
330    /// Dispatch message reference.
331    pub fn message(&self) -> &Message {
332        &self.message
333    }
334}
335
336impl Deref for Dispatch {
337    type Target = Message;
338
339    fn deref(&self) -> &Self::Target {
340        self.message()
341    }
342}