use super::common::ReplyDetails;
use crate::{
buffer::Payload,
ids::{ActorId, MessageId, prelude::*},
message::{
Dispatch, DispatchKind, GasLimit, Message, Packet, StoredDispatch, StoredMessage, Value,
},
};
use gear_core_errors::{ErrorReplyReason, ReplyCode, SuccessReplyReason};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ReplyMessage {
id: MessageId,
payload: Payload,
gas_limit: Option<GasLimit>,
value: Value,
code: ReplyCode,
}
impl ReplyMessage {
pub fn from_packet(id: MessageId, packet: ReplyPacket) -> Self {
Self {
id,
payload: packet.payload,
gas_limit: packet.gas_limit,
value: packet.value,
code: packet.code,
}
}
pub fn system(
origin_msg_id: MessageId,
payload: Payload,
value: Value,
err: impl Into<ErrorReplyReason>,
) -> Self {
let id = MessageId::generate_reply(origin_msg_id);
let packet = ReplyPacket::system(payload, value, err);
Self::from_packet(id, packet)
}
pub fn auto(origin_msg_id: MessageId) -> Self {
let id = MessageId::generate_reply(origin_msg_id);
let packet = ReplyPacket::auto();
Self::from_packet(id, packet)
}
pub fn into_message(
self,
program_id: ActorId,
destination: ActorId,
origin_msg_id: MessageId,
) -> Message {
Message::new(
self.id,
program_id,
destination,
self.payload,
self.gas_limit,
self.value,
Some(ReplyDetails::new(origin_msg_id, self.code).into()),
)
}
pub fn into_stored(
self,
program_id: ActorId,
destination: ActorId,
origin_msg_id: MessageId,
) -> StoredMessage {
self.into_message(program_id, destination, origin_msg_id)
.into()
}
pub fn into_dispatch(
self,
source: ActorId,
destination: ActorId,
origin_msg_id: MessageId,
) -> Dispatch {
Dispatch::new(
DispatchKind::Reply,
self.into_message(source, destination, origin_msg_id),
)
}
pub fn into_stored_dispatch(
self,
source: ActorId,
destination: ActorId,
origin_msg_id: MessageId,
) -> StoredDispatch {
self.into_dispatch(source, destination, origin_msg_id)
.into()
}
pub fn id(&self) -> MessageId {
self.id
}
pub fn payload_bytes(&self) -> &[u8] {
&self.payload
}
pub fn gas_limit(&self) -> Option<GasLimit> {
self.gas_limit
}
pub fn value(&self) -> Value {
self.value
}
pub fn code(&self) -> ReplyCode {
self.code
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ReplyPacket {
payload: Payload,
gas_limit: Option<GasLimit>,
value: Value,
code: ReplyCode,
}
#[cfg(test)]
impl Default for ReplyPacket {
fn default() -> Self {
Self::auto()
}
}
impl ReplyPacket {
pub fn new(payload: Payload, value: Value) -> Self {
Self {
payload,
gas_limit: None,
value,
code: ReplyCode::Success(SuccessReplyReason::Manual),
}
}
pub fn new_with_gas(payload: Payload, gas_limit: GasLimit, value: Value) -> Self {
Self {
payload,
gas_limit: Some(gas_limit),
value,
code: ReplyCode::Success(SuccessReplyReason::Manual),
}
}
pub fn maybe_with_gas(payload: Payload, gas_limit: Option<GasLimit>, value: Value) -> Self {
match gas_limit {
None => Self::new(payload, value),
Some(gas_limit) => Self::new_with_gas(payload, gas_limit, value),
}
}
pub fn system(payload: Payload, value: Value, err: impl Into<ErrorReplyReason>) -> Self {
Self {
payload,
gas_limit: None,
value,
code: ReplyCode::error(err),
}
}
pub fn auto() -> Self {
Self {
payload: Default::default(),
gas_limit: Some(0),
value: 0,
code: ReplyCode::Success(SuccessReplyReason::Auto),
}
}
pub(super) fn try_prepend(&mut self, mut data: Payload) -> Result<(), Payload> {
if data.try_extend_from_slice(self.payload_bytes()).is_err() {
Err(data)
} else {
self.payload = data;
Ok(())
}
}
pub fn code(&self) -> ReplyCode {
self.code
}
}
impl Packet for ReplyPacket {
fn payload_bytes(&self) -> &[u8] {
&self.payload
}
fn payload_len(&self) -> u32 {
self.payload.len_u32()
}
fn gas_limit(&self) -> Option<GasLimit> {
self.gas_limit
}
fn value(&self) -> Value {
self.value
}
fn kind() -> DispatchKind {
DispatchKind::Reply
}
}