Skip to content

Commit caf5bed

Browse files
committed
fix DojoStore for generic structs/enums
1 parent e19dc4d commit caf5bed

File tree

4 files changed

+133
-45
lines changed

4 files changed

+133
-45
lines changed

crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ fn test_generic_struct_introspect() {
189189
);
190190
}
191191

192-
193192
#[test]
194193
fn test_generic_enum_introspect() {
195194
let size = Introspect::<GenericEnum<u32>>::size();

crates/dojo/core-cairo-test/src/tests/storage/dojo_store.cairo

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,30 @@ enum EComplex {
2828
B,
2929
}
3030

31+
32+
#[derive(Drop, Introspect, Serde, Debug, PartialEq)]
33+
struct GenericStruct<T> {
34+
value: T,
35+
}
36+
37+
#[derive(Drop, Introspect, Serde, Default, Debug, PartialEq)]
38+
enum GenericEnum<T> {
39+
#[default]
40+
A: T,
41+
}
42+
43+
#[derive(Drop, Introspect, Serde, Debug, PartialEq)]
44+
struct UseGenericStruct {
45+
x: GenericStruct<u16>,
46+
y: u8,
47+
}
48+
49+
#[derive(Drop, Introspect, Serde, Debug, PartialEq)]
50+
struct UseGenericEnum {
51+
x: GenericEnum<u16>,
52+
y: u8,
53+
}
54+
3155
#[test]
3256
fn test_dojo_store_primitives() {
3357
// felt252
@@ -292,6 +316,75 @@ fn test_dojo_store_tuples() {
292316
);
293317
}
294318

319+
#[test]
320+
fn test_dojo_store_generic_struct() {
321+
let s = GenericStruct::<u32> { value: 1234567 };
322+
323+
let mut serialized = array![];
324+
DojoStore::serialize(@s, ref serialized);
325+
assert_eq!(serialized, array![1234567], "DojoStore<GenericStruct<u32>> serialization failed");
326+
327+
let mut values = [1234567].span();
328+
let res = DojoStore::<GenericStruct<u32>>::deserialize(ref values);
329+
assert_eq!(
330+
res,
331+
Option::Some(GenericStruct::<u32> { value: 1234567 }),
332+
"DojoStore<GenericStruct<u32>> deserialization failed",
333+
);
334+
}
335+
336+
#[test]
337+
fn test_dojo_store_generic_enum() {
338+
let e = GenericEnum::<u32>::A(1234567);
339+
340+
let mut serialized = array![];
341+
DojoStore::serialize(@e, ref serialized);
342+
assert_eq!(serialized, array![1, 1234567], "DojoStore<GenericEnum<u32>> serialization failed");
343+
344+
let mut values = [1, 1234567].span();
345+
let res = DojoStore::<GenericEnum<u32>>::deserialize(ref values);
346+
assert_eq!(
347+
res,
348+
Option::Some(GenericEnum::<u32>::A(1234567)),
349+
"DojoStore<GenericEnum<u32>> deserialization failed",
350+
);
351+
}
352+
353+
354+
#[test]
355+
fn test_dojo_store_use_generic_struct() {
356+
let s = UseGenericStruct { x: GenericStruct { value: 12345 }, y: 42 };
357+
358+
let mut serialized = array![];
359+
DojoStore::serialize(@s, ref serialized);
360+
assert_eq!(serialized, array![12345, 42], "DojoStore<UseGenericStruct> serialization failed");
361+
362+
let mut values = [12345, 42].span();
363+
let res = DojoStore::<UseGenericStruct>::deserialize(ref values);
364+
assert_eq!(
365+
res,
366+
Option::Some(UseGenericStruct { x: GenericStruct { value: 12345 }, y: 42 }),
367+
"DojoStore<UseGenericStruct> deserialization failed",
368+
);
369+
}
370+
371+
#[test]
372+
fn test_dojo_store_use_generic_enum() {
373+
let e = UseGenericEnum { x: GenericEnum::A(12345), y: 42 };
374+
375+
let mut serialized = array![];
376+
DojoStore::serialize(@e, ref serialized);
377+
assert_eq!(serialized, array![1, 12345, 42], "DojoStore<UseGenericEnum> serialization failed");
378+
379+
let mut values = [1, 12345, 42].span();
380+
let res = DojoStore::<UseGenericEnum>::deserialize(ref values);
381+
assert_eq!(
382+
res,
383+
Option::Some(UseGenericEnum { x: GenericEnum::A(12345), y: 42 }),
384+
"DojoStore<UseGenericEnum> deserialization failed",
385+
);
386+
}
387+
295388
#[test]
296389
fn test_mix() {
297390
let e = EComplex::A(

crates/dojo/core/src/storage/dojo_store.cairo

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,48 @@
1+
// Might not be necessary from Cairo 2.11
12
pub impl ContractAddressDefault of Default<core::starknet::ContractAddress> {
23
fn default() -> core::starknet::ContractAddress {
34
core::starknet::contract_address_const::<0>()
45
}
56
}
67

7-
/// Handle data (de)serialization to be stored into
8-
/// the world storage.
9-
///
10-
/// The default implementation of this trait uses Serde.
11-
pub trait DojoStore<T, +Serde<T>> {
12-
fn serialize(
13-
self: @T, ref serialized: Array<felt252>,
14-
) {
15-
Serde::<T>::serialize(self, ref serialized);
16-
}
17-
fn deserialize(ref values: Span<felt252>) -> Option<T> {
18-
Serde::<T>::deserialize(ref values)
8+
/// Handle data (de)serialization to be stored into the world storage.
9+
pub trait DojoStore<T> {
10+
fn serialize(self: @T, ref serialized: Array<felt252>);
11+
fn deserialize(ref values: Span<felt252>) -> Option<T>;
12+
}
13+
14+
/// The default implementation of DojoStore uses Serde.
15+
mod default_impl {
16+
pub impl SerdeBasedDojoStore<T, +Serde<T>> of super::DojoStore<T> {
17+
fn serialize(self: @T, ref serialized: Array<felt252>) {
18+
Serde::serialize(self, ref serialized);
19+
}
20+
fn deserialize(ref values: Span<felt252>) -> Option<T> {
21+
Serde::<T>::deserialize(ref values)
22+
}
1923
}
2024
}
2125

22-
impl DojoStore_felt252 of DojoStore<felt252>;
23-
impl DojoStore_bool of DojoStore<bool>;
24-
impl DojoStore_u8 of DojoStore<u8>;
25-
impl DojoStore_u16 of DojoStore<u16>;
26-
impl DojoStore_u32 of DojoStore<u32>;
27-
impl DojoStore_u64 of DojoStore<u64>;
28-
impl DojoStore_u128 of DojoStore<u128>;
29-
impl DojoStore_u256 of DojoStore<u256>;
30-
impl DojoStore_i8 of DojoStore<i8>;
31-
impl DojoStore_i16 of DojoStore<i16>;
32-
impl DojoStore_i32 of DojoStore<i32>;
33-
impl DojoStore_i64 of DojoStore<i64>;
34-
impl DojoStore_i128 of DojoStore<i128>;
35-
impl DojoStore_ContractAddress of DojoStore<starknet::ContractAddress>;
36-
impl DojoStore_ClassHash of DojoStore<starknet::ClassHash>;
37-
impl DojoStore_EthAddress of DojoStore<starknet::EthAddress>;
38-
impl DojoStore_ByteArray of DojoStore<ByteArray>;
26+
pub impl DojoStore_felt252 = default_impl::SerdeBasedDojoStore<felt252>;
27+
pub impl DojoStore_bool = default_impl::SerdeBasedDojoStore<bool>;
28+
pub impl DojoStore_u8 = default_impl::SerdeBasedDojoStore<u8>;
29+
pub impl DojoStore_u16 = default_impl::SerdeBasedDojoStore<u16>;
30+
pub impl DojoStore_u32 = default_impl::SerdeBasedDojoStore<u32>;
31+
pub impl DojoStore_u64 = default_impl::SerdeBasedDojoStore<u64>;
32+
pub impl DojoStore_u128 = default_impl::SerdeBasedDojoStore<u128>;
33+
pub impl DojoStore_u256 = default_impl::SerdeBasedDojoStore<u256>;
34+
pub impl DojoStore_i8 = default_impl::SerdeBasedDojoStore<i8>;
35+
pub impl DojoStore_i16 = default_impl::SerdeBasedDojoStore<i16>;
36+
pub impl DojoStore_i32 = default_impl::SerdeBasedDojoStore<i32>;
37+
pub impl DojoStore_i64 = default_impl::SerdeBasedDojoStore<i64>;
38+
pub impl DojoStore_i128 = default_impl::SerdeBasedDojoStore<i128>;
39+
pub impl DojoStore_ContractAddress = default_impl::SerdeBasedDojoStore<starknet::ContractAddress>;
40+
pub impl DojoStore_ClassHash = default_impl::SerdeBasedDojoStore<starknet::ClassHash>;
41+
pub impl DojoStore_EthAddress = default_impl::SerdeBasedDojoStore<starknet::EthAddress>;
42+
pub impl DojoStore_ByteArray = default_impl::SerdeBasedDojoStore<ByteArray>;
3943

4044
/// Specific implementation of DojoStore for Option<T>.
41-
impl DojoStore_option<T, +Serde<T>, +DojoStore<T>, +Serde<Option<T>>> of DojoStore<Option<T>> {
45+
impl DojoStore_option<T, +DojoStore<T>> of DojoStore<Option<T>> {
4246
fn serialize(self: @Option<T>, ref serialized: Array<felt252>) {
4347
match self {
4448
Option::Some(x) => {
@@ -63,7 +67,7 @@ impl DojoStore_option<T, +Serde<T>, +DojoStore<T>, +Serde<Option<T>>> of DojoSto
6367
}
6468
}
6569

66-
fn serialize_array_helper<T, +Serde<T>, +DojoStore<T>, +Drop<T>>(
70+
fn serialize_array_helper<T, +DojoStore<T>, +Drop<T>>(
6771
mut input: Span<T>, ref output: Array<felt252>,
6872
) {
6973
match input.pop_front() {
@@ -75,7 +79,7 @@ fn serialize_array_helper<T, +Serde<T>, +DojoStore<T>, +Drop<T>>(
7579
}
7680
}
7781

78-
fn deserialize_array_helper<T, +Serde<T>, +DojoStore<T>, +Drop<T>>(
82+
fn deserialize_array_helper<T, +DojoStore<T>, +Drop<T>>(
7983
ref serialized: Span<felt252>, mut curr_output: Array<T>, remaining: felt252,
8084
) -> Option<Array<T>> {
8185
if remaining == 0 {
@@ -85,10 +89,9 @@ fn deserialize_array_helper<T, +Serde<T>, +DojoStore<T>, +Drop<T>>(
8589
deserialize_array_helper(ref serialized, curr_output, remaining - 1)
8690
}
8791

88-
8992
/// Specific implementation of DojoStore for Array<T>,
9093
/// to call DojoStore for array items instead of Serde directly.
91-
impl DojoStore_array<T, +Drop<T>, +Serde<T>, +DojoStore<T>> of DojoStore<Array<T>> {
94+
impl DojoStore_array<T, +Drop<T>, +DojoStore<T>> of DojoStore<Array<T>> {
9295
fn serialize(self: @Array<T>, ref serialized: Array<felt252>) {
9396
DojoStore::serialize(@self.len(), ref serialized);
9497
serialize_array_helper(self.span(), ref serialized);
@@ -100,4 +103,3 @@ impl DojoStore_array<T, +Drop<T>, +Serde<T>, +DojoStore<T>> of DojoStore<Array<T
100103
deserialize_array_helper(ref values, arr, length)
101104
}
102105
}
103-

crates/dojo/lang/src/derive_macros/introspect/mod.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,8 @@ pub fn handle_introspect_struct(
3333

3434
let inspect_gen_impls =
3535
build_generic_impls(&gen_types, &["+dojo::meta::introspect::Introspect".to_string()], &[]);
36-
let dojo_store_gen_impls = build_generic_impls(
37-
&gen_types,
38-
&["+dojo::storage::DojoStore".to_string(), "+core::serde::Serde".to_string()],
39-
&[format!("+core::serde::Serde<{struct_name_with_generics}>")],
40-
);
36+
let dojo_store_gen_impls =
37+
build_generic_impls(&gen_types, &["+dojo::storage::DojoStore".to_string()], &[]);
4138

4239
let struct_size = size::compute_struct_layout_size(db, &struct_ast, packed);
4340
let ty = ty::build_struct_ty(db, &struct_name_with_generics, &struct_ast);
@@ -95,10 +92,7 @@ pub fn handle_introspect_enum(
9592
let dojo_store_gen_impls = build_generic_impls(
9693
&gen_types,
9794
&["+dojo::storage::DojoStore".to_string(), "+core::serde::Serde".to_string()],
98-
&[
99-
format!("+core::serde::Serde<{enum_name_with_generics}>"),
100-
format!("+core::traits::Default<{enum_name_with_generics}>"),
101-
],
95+
&[format!("+core::traits::Default<{enum_name_with_generics}>")],
10296
);
10397

10498
let variant_sizes = size::compute_enum_variant_sizes(db, &enum_ast);

0 commit comments

Comments
 (0)