SborEnumVariantFor

Trait SborEnumVariantFor 

Source
pub trait SborEnumVariantFor<TEnum, X>
where TEnum: SborEnum<X>, X: CustomValueKind,
{ type VariantFields: SborTuple<X>; type VariantFieldsRef<'a>: SborTuple<X> where Self: 'a, Self::VariantFields: 'a; type OwnedVariant: IsSborFixedEnumVariant<Self::VariantFields>; type BorrowedVariant<'a>: IsSborFixedEnumVariant<Self::VariantFieldsRef<'a>> where Self: 'a, Self::VariantFields: 'a; const DISCRIMINATOR: u8; const IS_FLATTENED: bool; // Required methods fn from_variant_fields(variant_fields: Self::VariantFields) -> Self; fn as_variant_fields_ref(&self) -> Self::VariantFieldsRef<'_>; fn into_enum(self) -> TEnum; // Provided methods fn as_encodable_variant<'a>(&'a self) -> Self::BorrowedVariant<'a> { ... } fn from_decoded_variant(variant: Self::OwnedVariant) -> Self where Self: Sized { ... } }
Expand description

This trait is output for unique unskipped single children of enum variants, when #[sbor(impl_variant_traits)] is specified on an Enum or #[sbor(impl_variant_trait)] is specified on a single Enum variant.

It allows considering this type as representing an enum variant type under its parent enum. There are two flavours of how this embedding works in SBOR:

  • In unflattened variants, it is a variant with fields (Self,)
  • In flattened variants (only possible for tuple types) it is a variant with fields Self

This trait pairs well with the #[sbor(flatten)] attribute, for implementing the “enum variant is singleton struct type” pattern, which allows a number of benefits:

  • A function can take or return a particular variant
  • If code size is important (e.g. when building Scrypto), we want to enable pruning of any serialization code we don’t need. Using as_encodable_variant and from_decoded_variant avoids pulling in the parent TEnum serialization code; and the serialization code for any unused types in other discriminators

§Note on generic parameter ordering

On this trait, we do not put X first, as is normal with the SBOR traits.

Instead, TEnum comes before X so that the trait can be implemented on any foreign type assuming TEnum is local. This is so that the cryptic orphan rule discussed in this stack overflow comment is satisfied https://stackoverflow.com/a/63131661

With this ordering we have P0 = X, T0 = Child Type (possibly foreign), T1 = TEnum, T2 = X, which passes the check.

Required Associated Constants§

Required Associated Types§

Source

type VariantFields: SborTuple<X>

VariantFields is either Self if IS_FLATTENED else is (Self,)

Source

type VariantFieldsRef<'a>: SborTuple<X> where Self: 'a, Self::VariantFields: 'a

VariantFieldsRef is either &Self if IS_FLATTENED else is (&Self,)

Source

type OwnedVariant: IsSborFixedEnumVariant<Self::VariantFields>

This should always be SborFixedEnumVariant<{ [DISCRIMINATOR] as u8 }, Self::VariantFields>

§Why is this required as an associated type?

Ideally we’d not need this and just have as_encodable_variant return SborFixedEnumVariant<{ Self::DISCRIMINATOR as u8 }, Self::VariantFieldsRef<'_>> But this gets “error: generic parameters may not be used in const operations”

§Why doesn’t this require VecDecode<X>?

We don’t want a compiler error if a type only implements Categorize (and so gets this trait) but not Decode. Really I’d like to say OwnedVariant: VecDecode<X> if Self: VecDecode<X> but Rust doesn’t support that. Instead, users will need to add the bound on the associated type themselves.

Source

type BorrowedVariant<'a>: IsSborFixedEnumVariant<Self::VariantFieldsRef<'a>> where Self: 'a, Self::VariantFields: 'a

Should always be SborFixedEnumVariant<{ [DISCRIMINATOR] as u8 }, &'a Self::VariantFields>

§Why is this required as an associated type?

Ideally we’d not need this and just have as_encodable_variant return SborFixedEnumVariant<{ Self::DISCRIMINATOR }, Self::VariantFields> But this gets “error: generic parameters may not be used in const operations” which needs the const-generics feature which has been in progress for a number of years. See https://github.com/rust-lang/project-const-generics/issues/31

§Why doesn’t this require VecEncode<X>?

We don’t want a compiler error if a type only implements Categorize (and so gets this trait) but not Encode. Really I’d like to say BorrowedVariant<'a>: VecEncode<X> if Self: VecEncode<X> but Rust doesn’t support that. Instead, users will need to add the bound on the associated type themselves.

Instead, you can express a trait bound as such:

pub trait MyNewSuperTrait:
    for<'a> SborEnumVariantFor<
       TEnum,
       X,
       OwnedVariant: ManifestDecode,
       BorrowedVariant<'a>: ManifestEncode,
    >
{}

Required Methods§

Source

fn from_variant_fields(variant_fields: Self::VariantFields) -> Self

Source

fn as_variant_fields_ref(&self) -> Self::VariantFieldsRef<'_>

Source

fn into_enum(self) -> TEnum

Provided Methods§

Source

fn as_encodable_variant<'a>(&'a self) -> Self::BorrowedVariant<'a>

Can be used to encode the type as a variant under TEnum, like this: encoder.encode(x.as_encodable_variant()).

To use this pattern in a generic context, you will likely need to add a bound like for<'a> T::BorrowedVariant<'a>: VecEncode<X>.

Source

fn from_decoded_variant(variant: Self::OwnedVariant) -> Self
where Self: Sized,

Can be used to decode the type from an encoded variant, like this: T::from_decoded_variant(decoder.decode()?).

To use this pattern in a generic context, you will likely need to add a bound like T::OwnedVariant: VecDecode<X>.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§