gear_core/message/
user.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 super::{MessageDetails, StoredMessage};
20use crate::{
21    buffer::Payload,
22    ids::{ActorId, MessageId},
23    message::{ReplyDetails, Value},
24};
25use core::convert::TryFrom;
26use gear_core_errors::ReplyCode;
27use parity_scale_codec::{Decode, Encode};
28use scale_decode::DecodeAsType;
29use scale_encode::EncodeAsType;
30use scale_info::TypeInfo;
31
32/// Message sent to user and deposited as event.
33#[derive(
34    Clone, Debug, PartialEq, Eq, Hash, Decode, DecodeAsType, Encode, EncodeAsType, TypeInfo,
35)]
36pub struct UserMessage {
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 value.
46    #[codec(compact)]
47    value: Value,
48    /// Message details: reply message ID and reply code if exists.
49    details: Option<ReplyDetails>,
50}
51
52impl UserMessage {
53    /// Create new UserMessage.
54    pub fn new(
55        id: MessageId,
56        source: ActorId,
57        destination: ActorId,
58        payload: Payload,
59        value: Value,
60        details: Option<ReplyDetails>,
61    ) -> Self {
62        Self {
63            id,
64            source,
65            destination,
66            payload,
67            value,
68            details,
69        }
70    }
71
72    /// Message id.
73    pub fn id(&self) -> MessageId {
74        self.id
75    }
76
77    /// Message source.
78    pub fn source(&self) -> ActorId {
79        self.source
80    }
81
82    /// Message destination.
83    pub fn destination(&self) -> ActorId {
84        self.destination
85    }
86
87    /// Message payload bytes.
88    pub fn payload_bytes(&self) -> &[u8] {
89        &self.payload
90    }
91
92    /// Message value.
93    pub fn value(&self) -> Value {
94        self.value
95    }
96
97    /// Message reply details.
98    pub fn details(&self) -> Option<ReplyDetails> {
99        self.details
100    }
101
102    /// Returns `ReplyCode` of message if reply.
103    pub fn reply_code(&self) -> Option<ReplyCode> {
104        self.details.map(|d| d.to_reply_code())
105    }
106}
107
108#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
109pub struct FromStoredMessageError;
110
111impl TryFrom<StoredMessage> for UserMessage {
112    type Error = FromStoredMessageError;
113
114    fn try_from(stored: StoredMessage) -> Result<Self, Self::Error> {
115        let some_details = stored.details.is_some();
116        let details = stored.details.and_then(|d| d.to_reply_details());
117
118        if details.is_none() && some_details {
119            return Err(FromStoredMessageError);
120        }
121
122        Ok(Self {
123            id: stored.id,
124            source: stored.source,
125            destination: stored.destination,
126            payload: stored.payload,
127            value: stored.value,
128            details,
129        })
130    }
131}
132
133impl From<UserMessage> for StoredMessage {
134    fn from(user: UserMessage) -> Self {
135        let details = user.details.map(MessageDetails::Reply);
136
137        StoredMessage {
138            id: user.id,
139            source: user.source,
140            destination: user.destination,
141            payload: user.payload,
142            value: user.value,
143            details,
144        }
145    }
146}
147
148/// Message sent to user and added to mailbox.
149///
150/// May be represented only with `DispatchKind::Handle`,
151/// so does not contain message details.
152#[derive(
153    Clone, Debug, PartialEq, Eq, Hash, Decode, DecodeAsType, Encode, EncodeAsType, TypeInfo,
154)]
155pub struct UserStoredMessage {
156    /// Message id.
157    id: MessageId,
158    /// Message source.
159    source: ActorId,
160    /// Message destination.
161    destination: ActorId,
162    /// Message payload.
163    payload: Payload,
164    /// Message value.
165    #[codec(compact)]
166    value: Value,
167}
168
169impl UserStoredMessage {
170    /// Create new UserStoredMessage.
171    pub fn new(
172        id: MessageId,
173        source: ActorId,
174        destination: ActorId,
175        payload: Payload,
176        value: Value,
177    ) -> Self {
178        Self {
179            id,
180            source,
181            destination,
182            payload,
183            value,
184        }
185    }
186
187    /// Message id.
188    pub fn id(&self) -> MessageId {
189        self.id
190    }
191
192    /// Message source.
193    pub fn source(&self) -> ActorId {
194        self.source
195    }
196
197    /// Message destination.
198    pub fn destination(&self) -> ActorId {
199        self.destination
200    }
201
202    /// Message payload bytes.
203    pub fn payload_bytes(&self) -> &[u8] {
204        &self.payload
205    }
206
207    /// Message value.
208    pub fn value(&self) -> Value {
209        self.value
210    }
211}
212
213#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
214pub struct UserStoredMessageConvertError;
215
216impl TryFrom<StoredMessage> for UserStoredMessage {
217    type Error = UserStoredMessageConvertError;
218
219    fn try_from(stored: StoredMessage) -> Result<Self, Self::Error> {
220        if stored.details().is_some() {
221            return Err(UserStoredMessageConvertError);
222        }
223
224        Ok(Self {
225            id: stored.id,
226            source: stored.source,
227            destination: stored.destination,
228            payload: stored.payload,
229            value: stored.value,
230        })
231    }
232}
233
234impl TryFrom<UserMessage> for UserStoredMessage {
235    type Error = UserStoredMessageConvertError;
236
237    fn try_from(user: UserMessage) -> Result<Self, Self::Error> {
238        if user.details().is_some() {
239            return Err(UserStoredMessageConvertError);
240        }
241
242        Ok(Self {
243            id: user.id,
244            source: user.source,
245            destination: user.destination,
246            payload: user.payload,
247            value: user.value,
248        })
249    }
250}
251
252impl From<UserStoredMessage> for StoredMessage {
253    fn from(user_stored: UserStoredMessage) -> Self {
254        StoredMessage {
255            id: user_stored.id,
256            source: user_stored.source,
257            destination: user_stored.destination,
258            payload: user_stored.payload,
259            value: user_stored.value,
260            details: None,
261        }
262    }
263}