This is my enum
use anchor_lang::solana_program::pubkey::Pubkey;
use bytemuck;
#[repr(C)]
#[derive(Clone, Copy, Debug, Contiguous)]
pub enum PaymentOption {
Native,
Token { mint: Pubkey },
}
I have tried using the Contiguous
trait but it doesn’t support fielded enums.
My Cargo.toml
deps
[dependencies]
anchor-lang = "0.29.0"
bytemuck = "1.18.0"
Pubkey size is 32 bytes.
1
You can not implement Contiguous
for your type.
The reason for this not that it can’t be derived, nothing stops you from manually implementing it. Instead the fact that Contiguous
is an unsafe
trait, which means that the implementor must conform to rules documented by the library.
To soundly implement Contiguous
, you need the following (from bytemuck
‘s docs):
The size of
C
andC::Int
must be the same, and neither may be a ZST.
(Note: alignment is explicitly allowed to differ)
C::Int
must be a primitive integer, and not a wrapper type. In the
future, this may be lifted to include cases where the behavior is
identical for a relevant set of traits (Ord, arithmetic, …).All
C::Int
s which are in the inclusive range betweenC::MIN_VALUE
andC::MAX_VALUE
are bitwise identical to unique valid instances of
C
.There exist no instances of
C
such that their bitpatterns, when
interpreted as instances ofC::Int
, fall outside of theMAX_VALUE
/
MIN_VALUE
range — It is legal for unsafe code to assume that if it
gets aC
that implementsContiguous
, it is in the appropriate range.Finally, you promise not to provide overridden implementations of
Contiguous::from_integer
andContiguous::into_integer
.
First, the enum would need to be converted from #[repr(C)]
to #[repr(Int)]
(with Int = u8
for example).
Such enums are stored as a discriminant followed by a C-union of C-structs of variants.
In our case, this would mean that everything with discriminant 0 would allow arbitrary values in the C-union. This however contradicts our rule #3: while all bit patterns correspond to a valid value, they are not unique.
This could be solved by swapping the field order of the enum, and setting Contiguous::MAX_VALUE
to one more than the maximal bit pattern of discriminant 0, and thus allowing only one bit pattern for discriminant 1.
What finally dooms us is rule #2:
The type Int
must be a primitive integer.
PubKey
is #[repr(transparent)
and bytemuck::Pod
over an [u8, 32]
, but there is no primitive integer type larger than [u8; 33]
to contain it.
Any option to implement it manually? E.g. see the Playground
use bytemuck; // 1.16.3
#[derive(Clone, Copy, Debug)]
struct Pubkey {
_key: i32
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum PaymentOption {
Native,
Token { mint: Pubkey },
}
unsafe impl bytemuck::Contiguous for PaymentOption {
type Int = i32;
const MIN_VALUE: i32 = i32::MIN;
const MAX_VALUE: i32 = i32::MAX;
}
1