use crate::{
ids::{MessageId, ProgramId},
message::{DispatchKind, GasLimit, Payload, StoredDispatch, StoredMessage, Value},
};
use alloc::string::ToString;
use core::{convert::TryInto, ops::Deref};
use gear_core_errors::{ReplyCode, SignalCode};
use scale_info::{
scale::{Decode, Encode},
TypeInfo,
};
#[derive(Clone, Default, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Decode, Encode, TypeInfo)]
pub struct Message {
id: MessageId,
source: ProgramId,
destination: ProgramId,
payload: Payload,
gas_limit: Option<GasLimit>,
value: Value,
details: Option<MessageDetails>,
}
impl From<Message> for StoredMessage {
fn from(message: Message) -> StoredMessage {
StoredMessage::new(
message.id,
message.source,
message.destination,
message.payload,
message.value,
message.details,
)
}
}
impl Message {
pub fn new(
id: MessageId,
source: ProgramId,
destination: ProgramId,
payload: Payload,
gas_limit: Option<GasLimit>,
value: Value,
details: Option<MessageDetails>,
) -> Self {
Self {
id,
source,
destination,
payload,
gas_limit,
value,
details,
}
}
pub fn into_stored(self) -> StoredMessage {
self.into()
}
pub fn id(&self) -> MessageId {
self.id
}
pub fn source(&self) -> ProgramId {
self.source
}
pub fn destination(&self) -> ProgramId {
self.destination
}
pub fn payload_bytes(&self) -> &[u8] {
self.payload.inner()
}
pub fn gas_limit(&self) -> Option<GasLimit> {
self.gas_limit
}
pub fn value(&self) -> Value {
self.value
}
pub fn reply_details(&self) -> Option<ReplyDetails> {
self.details.and_then(|d| d.to_reply_details())
}
pub fn signal_details(&self) -> Option<SignalDetails> {
self.details.and_then(|d| d.to_signal_details())
}
#[allow(clippy::result_large_err)]
pub fn with_string_payload<D: Decode + ToString>(self) -> Result<Self, Self> {
if let Ok(decoded) = D::decode(&mut self.payload.inner()) {
if let Ok(payload) = decoded.to_string().into_bytes().try_into() {
Ok(Self { payload, ..self })
} else {
Err(self)
}
} else {
Err(self)
}
}
pub fn is_error_reply(&self) -> bool {
self.details.map(|d| d.is_error_reply()).unwrap_or(false)
}
pub fn is_reply(&self) -> bool {
self.reply_details().is_some()
}
}
#[derive(
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
Decode,
Encode,
TypeInfo,
derive_more::From,
)]
pub enum MessageDetails {
Reply(ReplyDetails),
Signal(SignalDetails),
}
impl MessageDetails {
pub fn is_error_reply(&self) -> bool {
self.to_reply_details()
.map(|d| d.code.is_error())
.unwrap_or(false)
}
pub fn is_reply_details(&self) -> bool {
matches!(self, Self::Reply(_))
}
pub fn to_reply_details(self) -> Option<ReplyDetails> {
match self {
MessageDetails::Reply(reply) => Some(reply),
MessageDetails::Signal(_) => None,
}
}
pub fn is_signal_details(&self) -> bool {
matches!(self, Self::Signal(_))
}
pub fn to_signal_details(self) -> Option<SignalDetails> {
match self {
MessageDetails::Reply(_) => None,
MessageDetails::Signal(signal) => Some(signal),
}
}
}
#[derive(
Clone, Copy, Default, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Decode, Encode, TypeInfo,
)]
pub struct ReplyDetails {
to: MessageId,
code: ReplyCode,
}
impl ReplyDetails {
pub fn new(to: MessageId, code: ReplyCode) -> Self {
Self { to, code }
}
pub fn to_message_id(&self) -> MessageId {
self.to
}
pub fn to_reply_code(&self) -> ReplyCode {
self.code
}
pub fn into_parts(self) -> (MessageId, ReplyCode) {
(self.to, self.code)
}
}
#[derive(
Clone, Copy, Default, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Decode, Encode, TypeInfo,
)]
pub struct SignalDetails {
to: MessageId,
code: SignalCode,
}
impl SignalDetails {
pub fn new(to: MessageId, code: SignalCode) -> Self {
Self { to, code }
}
pub fn to_message_id(&self) -> MessageId {
self.to
}
pub fn to_signal_code(&self) -> SignalCode {
self.code
}
pub fn into_parts(self) -> (MessageId, SignalCode) {
(self.to, self.code)
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Decode, Encode, TypeInfo)]
pub struct Dispatch {
kind: DispatchKind,
message: Message,
}
impl From<Dispatch> for StoredDispatch {
fn from(dispatch: Dispatch) -> StoredDispatch {
StoredDispatch::new(dispatch.kind, dispatch.message.into(), None)
}
}
impl From<Dispatch> for (DispatchKind, Message) {
fn from(dispatch: Dispatch) -> (DispatchKind, Message) {
(dispatch.kind, dispatch.message)
}
}
impl Dispatch {
pub fn new(kind: DispatchKind, message: Message) -> Self {
Self { kind, message }
}
pub fn into_stored(self) -> StoredDispatch {
self.into()
}
pub fn into_parts(self) -> (DispatchKind, Message) {
self.into()
}
pub fn kind(&self) -> DispatchKind {
self.kind
}
pub fn message(&self) -> &Message {
&self.message
}
}
impl Deref for Dispatch {
type Target = Message;
fn deref(&self) -> &Self::Target {
self.message()
}
}