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