use tlb::{
Cell, Context, Error, Ref,
bits::{NBits, NoArgs, de::BitReaderExt, ser::BitWriterExt},
de::{CellDeserialize, CellParser, CellParserError},
ser::{CellBuilder, CellBuilderError, CellSerialize},
};
use crate::{currency::CurrencyCollection, library::LibRef, message::Message};
#[allow(clippy::large_enum_variant)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OutAction {
SendMsg(SendMsgAction),
SetCode(Cell),
ReserveCurrency(ReserveCurrencyAction),
ChangeLibrary(ChangeLibraryAction),
}
impl OutAction {
const SEND_MSG_PREFIX: u32 = 0x0ec3c86d;
const SET_CODE_PREFIX: u32 = 0xad4de08e;
const RESERVE_CURRENCY_PREFIX: u32 = 0x36e6b809;
const CHANGE_LIBRARY_PREFIX: u32 = 0x26fa1dd4;
}
impl CellSerialize for OutAction {
type Args = ();
#[inline]
fn store(&self, builder: &mut CellBuilder, _: Self::Args) -> Result<(), CellBuilderError> {
match self {
OutAction::SendMsg(action) => {
builder.pack(Self::SEND_MSG_PREFIX, ())?.store(action, ())?
}
OutAction::SetCode(new_code) => builder
.pack(Self::SET_CODE_PREFIX, ())?
.store_as::<_, Ref>(new_code, ())?,
OutAction::ReserveCurrency(action) => builder
.pack(Self::RESERVE_CURRENCY_PREFIX, ())?
.store(action, ())?,
OutAction::ChangeLibrary(action) => builder
.pack(Self::CHANGE_LIBRARY_PREFIX, ())?
.store(action, ())?,
};
Ok(())
}
}
impl<'de> CellDeserialize<'de> for OutAction {
type Args = ();
#[inline]
fn parse(parser: &mut CellParser<'de>, _: Self::Args) -> Result<Self, CellParserError<'de>> {
Ok(match parser.unpack(())? {
Self::SEND_MSG_PREFIX => Self::SendMsg(parser.parse(()).context("action_send_msg")?),
Self::SET_CODE_PREFIX => {
Self::SetCode(parser.parse_as::<_, Ref>(()).context("action_set_code")?)
}
Self::RESERVE_CURRENCY_PREFIX => {
Self::ReserveCurrency(parser.parse(()).context("action_reserve_currency")?)
}
Self::CHANGE_LIBRARY_PREFIX => {
Self::ChangeLibrary(parser.parse(()).context("action_change_library")?)
}
prefix => return Err(Error::custom(format!("unknown prefix {prefix:#0x}"))),
})
}
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SendMsgAction<T = Cell, IC = Cell, ID = Cell> {
pub mode: u8,
pub message: Message<T, IC, ID>,
}
impl<T, IC, ID> CellSerialize for SendMsgAction<T, IC, ID>
where
T: CellSerialize<Args: NoArgs>,
IC: CellSerialize<Args: NoArgs>,
ID: CellSerialize<Args: NoArgs>,
{
type Args = ();
#[inline]
fn store(&self, builder: &mut CellBuilder, _: Self::Args) -> Result<(), CellBuilderError> {
builder
.pack(self.mode, ())?
.store_as::<_, Ref>(&self.message, ())?;
Ok(())
}
}
impl<'de, T, IC, ID> CellDeserialize<'de> for SendMsgAction<T, IC, ID>
where
T: CellDeserialize<'de, Args: NoArgs>,
IC: CellDeserialize<'de, Args: NoArgs>,
ID: CellDeserialize<'de, Args: NoArgs>,
{
type Args = ();
#[inline]
fn parse(parser: &mut CellParser<'de>, _: Self::Args) -> Result<Self, CellParserError<'de>> {
Ok(Self {
mode: parser.unpack(())?,
message: parser.parse_as::<_, Ref>(())?,
})
}
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReserveCurrencyAction {
pub mode: u8,
pub currency: CurrencyCollection,
}
impl CellSerialize for ReserveCurrencyAction {
type Args = ();
#[inline]
fn store(&self, builder: &mut CellBuilder, _: Self::Args) -> Result<(), CellBuilderError> {
builder.pack(self.mode, ())?.store(&self.currency, ())?;
Ok(())
}
}
impl<'de> CellDeserialize<'de> for ReserveCurrencyAction {
type Args = ();
#[inline]
fn parse(parser: &mut CellParser<'de>, _: Self::Args) -> Result<Self, CellParserError<'de>> {
Ok(Self {
mode: parser.unpack(())?,
currency: parser.parse(())?,
})
}
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ChangeLibraryAction<R = Cell> {
pub mode: u8,
pub libref: LibRef<R>,
}
impl<R> CellSerialize for ChangeLibraryAction<R>
where
R: CellSerialize<Args: NoArgs>,
{
type Args = ();
#[inline]
fn store(&self, builder: &mut CellBuilder, _: Self::Args) -> Result<(), CellBuilderError> {
builder
.pack_as::<_, NBits<7>>(self.mode, ())?
.store(&self.libref, ())?;
Ok(())
}
}
impl<'de, R> CellDeserialize<'de> for ChangeLibraryAction<R>
where
R: CellDeserialize<'de, Args: NoArgs>,
{
type Args = ();
#[inline]
fn parse(parser: &mut CellParser<'de>, _: Self::Args) -> Result<Self, CellParserError<'de>> {
Ok(Self {
mode: parser.unpack_as::<_, NBits<7>>(())?,
libref: parser.parse(())?,
})
}
}