StorePacking
, the
compiler automatically uses StoreUsingPacking
to handle storage operations. As such, a type
cannot implement both Store
and StorePacking
.
pub trait StorePacking
felt252
, and storage operations are expensive. By packing
multiple values into fewer slots, you can significantly reduce gas costs. For example:
felt252
StorePacking
, ensure that the PackedT
type implements Store
. The packed
representation must preserve all necessary information to allow unpacking back to the original
type. Additionally, the pack
and unpack
operations must be reversible, meaning that packing
followed by unpacking should return the original value.
use starknet::storage_access::StorePacking;
#[derive(Drop)]
struct Sizes {
tiny: u8, // 8 bits
small: u32, // 32 bits
medium: u64, // 64 bits
}
const TWO_POW_8: u128 = 0x100;
const TWO_POW_40: u128 = 0x10000000000;
impl SizesStorePacking of StorePacking {
fn pack(value: Sizes) -> u128 {
value.tiny.into() +
(value.small.into() * TWO_POW_8) +
(value.medium.into() * TWO_POW_40)
}
fn unpack(value: u128) -> Sizes {
let tiny = value & 0xff;
let small = (value / TWO_POW_8) & 0xffffffff;
let medium = (value / TWO_POW_40);
Sizes {
tiny: tiny.try_into().unwrap(),
small: small.try_into().unwrap(),
medium: medium.try_into().unwrap(),
}
}
}
StorePacking
for Sizes
, the Sizes
will be stored in its packed form,
using a single storage slot instead of 3. When retrieved, it will automatically be unpacked back
into the original type.
fn pack(value: T) -> PackedT
fn unpack(value: PackedT) -> T