Skip to main content

gear_core/message/
incoming.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, StoredDispatch, StoredMessage, Value,
9        common::MessageDetails,
10    },
11};
12use alloc::sync::Arc;
13use core::ops::Deref;
14
15/// Incoming message.
16///
17/// Used for program execution.
18#[derive(Clone, Debug, PartialEq, Eq)]
19#[cfg_attr(any(feature = "mock", test), derive(Default))]
20pub struct IncomingMessage {
21    /// Message id.
22    id: MessageId,
23    /// Message source.
24    source: ActorId,
25    /// Message payload.
26    payload: Arc<Payload>,
27    /// Message gas limit. Required here.
28    gas_limit: GasLimit,
29    /// Message value.
30    value: Value,
31    /// Message details like reply message ID, status code, etc.
32    details: Option<MessageDetails>,
33}
34
35impl IncomingMessage {
36    /// Create new IncomingMessage.
37    pub fn new(
38        id: MessageId,
39        source: ActorId,
40        payload: Payload,
41        gas_limit: GasLimit,
42        value: Value,
43        details: Option<MessageDetails>,
44    ) -> Self {
45        Self {
46            id,
47            source,
48            gas_limit,
49            value,
50            details,
51            payload: Arc::new(payload),
52        }
53    }
54
55    /// Convert IncomingMessage into gasless StoredMessage.
56    pub fn into_stored(self, destination: ActorId) -> StoredMessage {
57        StoredMessage::new(
58            self.id,
59            self.source,
60            destination,
61            Arc::try_unwrap(self.payload).unwrap_or_else(|payload| {
62                log::error!(
63                    "IncomingMessage payload has multiple references, this is unexpected behavior"
64                );
65                Arc::unwrap_or_clone(payload)
66            }),
67            self.value,
68            self.details,
69        )
70    }
71
72    /// Message payload.
73    pub fn payload(&self) -> Arc<Payload> {
74        self.payload.clone()
75    }
76
77    /// Message id.
78    pub fn id(&self) -> MessageId {
79        self.id
80    }
81
82    /// Message source.
83    pub fn source(&self) -> ActorId {
84        self.source
85    }
86
87    /// Message gas limit.
88    pub fn gas_limit(&self) -> GasLimit {
89        self.gas_limit
90    }
91
92    /// Message value.
93    pub fn value(&self) -> Value {
94        self.value
95    }
96
97    /// Message details.
98    pub fn details(&self) -> Option<MessageDetails> {
99        self.details
100    }
101
102    /// Returns bool defining if message is error reply.
103    pub fn is_error_reply(&self) -> bool {
104        self.details.map(|d| d.is_error_reply()).unwrap_or(false)
105    }
106
107    /// Returns bool defining if message is reply.
108    pub fn is_reply(&self) -> bool {
109        self.details.map(|d| d.is_reply_details()).unwrap_or(false)
110    }
111}
112
113/// Incoming message with entry point and previous execution context, if exists.
114#[derive(Clone, Debug, PartialEq, Eq)]
115#[cfg_attr(any(feature = "mock", test), derive(Default))]
116pub struct IncomingDispatch {
117    /// Entry point.
118    kind: DispatchKind,
119    /// Incoming message.
120    message: IncomingMessage,
121    /// Previous execution context, if exists.
122    context: Option<ContextStore>,
123}
124
125impl From<IncomingDispatch> for (DispatchKind, IncomingMessage, Option<ContextStore>) {
126    fn from(dispatch: IncomingDispatch) -> (DispatchKind, IncomingMessage, Option<ContextStore>) {
127        (dispatch.kind, dispatch.message, dispatch.context)
128    }
129}
130
131impl IncomingDispatch {
132    /// Create new IncomingDispatch.
133    pub fn new(
134        kind: DispatchKind,
135        message: IncomingMessage,
136        context: Option<ContextStore>,
137    ) -> Self {
138        Self {
139            kind,
140            message,
141            context,
142        }
143    }
144
145    /// Convert IncomingDispatch into gasless StoredDispatch with updated (or recently set) context.
146    pub fn into_stored(self, destination: ActorId, context: ContextStore) -> StoredDispatch {
147        StoredDispatch::new(
148            self.kind,
149            self.message.into_stored(destination),
150            Some(context),
151        )
152    }
153
154    /// Decompose IncomingDispatch for it's components: DispatchKind, IncomingMessage and `Option<ContextStore>`.
155    pub fn into_parts(self) -> (DispatchKind, IncomingMessage, Option<ContextStore>) {
156        self.into()
157    }
158
159    /// Entry point for the message.
160    pub fn kind(&self) -> DispatchKind {
161        self.kind
162    }
163
164    /// Dispatch message reference.
165    pub fn message(&self) -> &IncomingMessage {
166        &self.message
167    }
168
169    /// Previous execution context reference, if exists.
170    pub fn context(&self) -> &Option<ContextStore> {
171        &self.context
172    }
173
174    /// Previous execution context mutable reference, if exists.
175    pub fn context_mut(&mut self) -> &mut Option<ContextStore> {
176        &mut self.context
177    }
178}
179
180impl Deref for IncomingDispatch {
181    type Target = IncomingMessage;
182
183    fn deref(&self) -> &Self::Target {
184        self.message()
185    }
186}