#[macro_export]
macro_rules! i {
($x:expr) => {
$x.try_into().expect("Parse Error")
};
}
#[macro_export]
macro_rules! well_known_scrypto_custom_type {
($t:ty, $value_kind:expr, $schema_type:expr, $size:expr, $well_known_type:ident, $well_known_type_data_method:ident$(,)?) => {
impl sbor::Categorize<$crate::data::scrypto::ScryptoCustomValueKind> for $t {
#[inline]
fn value_kind() -> sbor::ValueKind<$crate::data::scrypto::ScryptoCustomValueKind> {
sbor::ValueKind::Custom($value_kind)
}
}
impl<E: sbor::Encoder<$crate::data::scrypto::ScryptoCustomValueKind>>
sbor::Encode<$crate::data::scrypto::ScryptoCustomValueKind, E> for $t
{
#[inline]
fn encode_value_kind(&self, encoder: &mut E) -> Result<(), sbor::EncodeError> {
encoder.write_value_kind(Self::value_kind())
}
#[inline]
fn encode_body(&self, encoder: &mut E) -> Result<(), sbor::EncodeError> {
encoder.write_slice(&self.to_vec())
}
}
impl<D: sbor::Decoder<$crate::data::scrypto::ScryptoCustomValueKind>>
sbor::Decode<$crate::data::scrypto::ScryptoCustomValueKind, D> for $t
{
fn decode_body_with_value_kind(
decoder: &mut D,
value_kind: sbor::ValueKind<$crate::data::scrypto::ScryptoCustomValueKind>,
) -> Result<Self, sbor::DecodeError> {
decoder.check_preloaded_value_kind(value_kind, Self::value_kind())?;
let slice = decoder.read_slice($size)?;
Self::try_from(slice).map_err(|_| sbor::DecodeError::InvalidCustomValue)
}
}
impl sbor::Describe<$crate::data::scrypto::ScryptoCustomTypeKind> for $t {
const TYPE_ID: sbor::RustTypeId = sbor::RustTypeId::WellKnown(
$crate::data::scrypto::well_known_scrypto_custom_types::$well_known_type,
);
fn type_data() -> sbor::TypeData<$crate::data::scrypto::ScryptoCustomTypeKind, sbor::RustTypeId> {
$crate::data::scrypto::well_known_scrypto_custom_types::$well_known_type_data_method()
}
}
};
}
#[macro_export]
macro_rules! manifest_type {
($t:ty, $value_kind:expr, $size: expr$(,)?) => {
impl sbor::Categorize<$crate::data::manifest::ManifestCustomValueKind> for $t {
#[inline]
fn value_kind() -> sbor::ValueKind<$crate::data::manifest::ManifestCustomValueKind> {
sbor::ValueKind::Custom($value_kind)
}
}
impl<E: sbor::Encoder<$crate::data::manifest::ManifestCustomValueKind>>
sbor::Encode<$crate::data::manifest::ManifestCustomValueKind, E> for $t
{
#[inline]
fn encode_value_kind(&self, encoder: &mut E) -> Result<(), sbor::EncodeError> {
encoder.write_value_kind(Self::value_kind())
}
#[inline]
fn encode_body(&self, encoder: &mut E) -> Result<(), sbor::EncodeError> {
encoder.write_slice(&self.to_vec())
}
}
impl<D: sbor::Decoder<$crate::data::manifest::ManifestCustomValueKind>>
sbor::Decode<$crate::data::manifest::ManifestCustomValueKind, D> for $t
{
fn decode_body_with_value_kind(
decoder: &mut D,
value_kind: sbor::ValueKind<$crate::data::manifest::ManifestCustomValueKind>,
) -> Result<Self, sbor::DecodeError> {
decoder.check_preloaded_value_kind(value_kind, Self::value_kind())?;
let slice = decoder.read_slice($size)?;
Self::try_from(slice).map_err(|_| sbor::DecodeError::InvalidCustomValue)
}
}
};
}
#[macro_export]
macro_rules! scrypto_describe_for_manifest_type {
($t:ty, $well_known_type:ident, $well_known_type_data_method:ident$(,)?) => {
impl sbor::Describe<$crate::data::scrypto::ScryptoCustomTypeKind> for $t {
const TYPE_ID: sbor::RustTypeId = sbor::RustTypeId::WellKnown(
$crate::data::scrypto::well_known_scrypto_custom_types::$well_known_type,
);
fn type_data() -> sbor::TypeData<$crate::data::scrypto::ScryptoCustomTypeKind, sbor::RustTypeId> {
$crate::data::scrypto::well_known_scrypto_custom_types::$well_known_type_data_method()
}
}
}
}
#[macro_export]
macro_rules! count {
() => {0usize};
($a:expr) => {1usize};
($a:expr, $($rest:expr),*) => {1usize + $crate::count!($($rest),*)};
}
#[macro_export]
macro_rules! scrypto_args {
($($args: expr),*) => {{
use sbor::Encoder;
let mut buf = sbor::rust::vec::Vec::new();
let mut encoder = $crate::data::scrypto::ScryptoEncoder::new(
&mut buf,
$crate::data::scrypto::SCRYPTO_SBOR_V1_MAX_DEPTH,
);
encoder
.write_payload_prefix($crate::data::scrypto::SCRYPTO_SBOR_V1_PAYLOAD_PREFIX)
.unwrap();
encoder
.write_value_kind($crate::data::scrypto::ScryptoValueKind::Tuple)
.unwrap();
encoder.write_size($crate::count!($(stringify!($args)),*)).unwrap();
$(
let arg = $args;
encoder.encode(&arg).unwrap();
)*
buf
}};
}
#[macro_export]
macro_rules! manifest_args {
($($args: expr),*$(,)?) => {{
use sbor::Encoder;
let mut buf = sbor::rust::vec::Vec::new();
let mut encoder = $crate::data::manifest::ManifestEncoder::new(&mut buf, $crate::data::manifest::MANIFEST_SBOR_V1_MAX_DEPTH);
encoder.write_payload_prefix($crate::data::manifest::MANIFEST_SBOR_V1_PAYLOAD_PREFIX).unwrap();
encoder.write_value_kind($crate::data::manifest::ManifestValueKind::Tuple).unwrap();
encoder.write_size($crate::count!($(stringify!($args)),*)).unwrap();
$(
let arg = $args;
encoder.encode(&arg).unwrap();
)*
let value = $crate::data::manifest::manifest_decode(&buf).unwrap();
ManifestArgs::new_from_tuple_or_panic(value)
}};
}
#[macro_export]
macro_rules! to_manifest_value_and_unwrap {
( $value:expr ) => {{
$crate::data::manifest::to_manifest_value($value).unwrap()
}};
}
#[macro_export]
macro_rules! define_untyped_manifest_type_wrapper {
(
$scrypto_ty: ty => $manifest_ty_ident: ident ($inner_ty: ty)
) => {
#[cfg_attr(
feature = "fuzzing",
derive(::arbitrary::Arbitrary, ::serde::Serialize, ::serde::Deserialize)
)]
#[derive(
Debug,
Clone,
PartialEq,
Eq,
$crate::prelude::ManifestEncode,
$crate::prelude::ManifestCategorize,
)]
#[sbor(transparent)]
pub struct $manifest_ty_ident($inner_ty);
const _: () = {
impl $manifest_ty_ident {
pub fn new(
value: impl Into<$scrypto_ty>,
) -> Result<Self, $crate::prelude::ConversionError> {
let value = Into::<$scrypto_ty>::into(value);
let encoded_scrypto_bytes = $crate::prelude::scrypto_encode(&value)
.map_err($crate::prelude::ConversionError::EncodeError)?;
let scrypto_value = $crate::prelude::scrypto_decode::<
$crate::prelude::ScryptoValue,
>(&encoded_scrypto_bytes)
.map_err($crate::prelude::ConversionError::DecodeError)?;
let manifest_value =
$crate::prelude::scrypto_value_to_manifest_value(scrypto_value)?;
let encoded_manifest_bytes = $crate::prelude::manifest_encode(&manifest_value)
.map_err($crate::prelude::ConversionError::EncodeError)?;
$crate::prelude::manifest_decode(&encoded_manifest_bytes)
.map(Self)
.map_err($crate::prelude::ConversionError::DecodeError)
}
pub fn try_into_typed(
self,
) -> Result<$scrypto_ty, $crate::prelude::ConversionError> {
let value = self.0;
let encoded_manifest_bytes = $crate::prelude::manifest_encode(&value)
.map_err($crate::prelude::ConversionError::EncodeError)?;
let manifest_value = $crate::prelude::manifest_decode::<
$crate::prelude::ManifestValue,
>(&encoded_manifest_bytes)
.map_err($crate::prelude::ConversionError::DecodeError)?;
let scrypto_value =
$crate::prelude::manifest_value_to_scrypto_value(manifest_value)?;
let encoded_scrypto_bytes = $crate::prelude::scrypto_encode(&scrypto_value)
.map_err($crate::prelude::ConversionError::EncodeError)?;
$crate::prelude::scrypto_decode::<$scrypto_ty>(&encoded_scrypto_bytes)
.map_err($crate::prelude::ConversionError::DecodeError)
}
}
impl<T> From<T> for $manifest_ty_ident
where
T: Into<$scrypto_ty>,
{
fn from(value: T) -> Self {
Self::new(value).expect(concat!(
"Conversion from ",
stringify!($scrypto_ty),
" into ",
stringify!($manifest_ty_ident),
" failed despite not being expected to fail"
))
}
}
impl TryFrom<$manifest_ty_ident> for $scrypto_ty {
type Error = $crate::prelude::ConversionError;
fn try_from(value: $manifest_ty_ident) -> Result<Self, Self::Error> {
value.try_into_typed()
}
}
impl $crate::prelude::Describe<$crate::prelude::ScryptoCustomTypeKind>
for $manifest_ty_ident
{
const TYPE_ID: $crate::prelude::RustTypeId =
<$scrypto_ty as $crate::prelude::Describe<
$crate::prelude::ScryptoCustomTypeKind,
>>::TYPE_ID;
fn type_data() -> $crate::prelude::TypeData<
$crate::prelude::ScryptoCustomTypeKind,
$crate::prelude::RustTypeId,
> {
<$scrypto_ty as Describe<$crate::prelude::ScryptoCustomTypeKind>>::type_data()
}
fn add_all_dependencies(
aggregator: &mut $crate::prelude::TypeAggregator<$crate::prelude::ScryptoCustomTypeKind>
) {
<$scrypto_ty as Describe<$crate::prelude::ScryptoCustomTypeKind>>::add_all_dependencies(aggregator)
}
}
impl<D: $crate::prelude::Decoder<$crate::prelude::ManifestCustomValueKind>> $crate::prelude::Decode<$crate::prelude::ManifestCustomValueKind, D> for $manifest_ty_ident
{
#[inline]
fn decode_body_with_value_kind(
decoder: &mut D,
value_kind: $crate::prelude::ValueKind<$crate::prelude::ManifestCustomValueKind>,
) -> Result<Self, $crate::prelude::DecodeError> {
::lazy_static::lazy_static! {
static ref SCHEMA: ($crate::prelude::LocalTypeId, $crate::prelude::VersionedSchema<$crate::prelude::ScryptoCustomSchema>) = $crate::prelude::generate_full_schema_from_single_type::<
$scrypto_ty,
$crate::prelude::ScryptoCustomSchema
>();
}
let inner_value = <$inner_ty
as $crate::prelude::Decode<$crate::prelude::ManifestCustomValueKind, D>
>::decode_body_with_value_kind(decoder, value_kind)?;
let encoded = $crate::prelude::manifest_encode(&inner_value).map_err(|_| $crate::prelude::DecodeError::InvalidCustomValue)?;
$crate::prelude::validate_payload_against_schema::<$crate::prelude::ManifestCustomExtension, _>(
&encoded,
SCHEMA.1.v1(),
SCHEMA.0,
&(),
$crate::prelude::MANIFEST_SBOR_V1_MAX_DEPTH
)
.map_err(|_| $crate::prelude::DecodeError::InvalidCustomValue)?;
Ok(Self(inner_value))
}
}
};
};
}
#[cfg(test)]
mod test {
use crate::prelude::*;
#[test]
fn decoding_into_opaque_value_with_incorrect_schema_fails() {
#[derive(ScryptoSbor)]
pub enum MyEnum {
Variant(u32),
}
#[derive(ScryptoSbor, ManifestSbor)]
pub enum MyOtherEnum {
Variant(Decimal),
}
define_untyped_manifest_type_wrapper!(
MyEnum => ManifestMyEnum(EnumVariantValue<ManifestCustomValueKind, ManifestCustomValue>)
);
let encoded = manifest_encode(&MyOtherEnum::Variant(Decimal::ONE)).unwrap();
let decoded = manifest_decode::<ManifestMyEnum>(&encoded);
assert_eq!(decoded, Err(DecodeError::InvalidCustomValue))
}
}