Skip to main content

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