diff --git a/crates/dojo/core-cairo-test/Scarb.lock b/crates/dojo/core-cairo-test/Scarb.lock index 2c1a7ab14c..0e3efc0db1 100644 --- a/crates/dojo/core-cairo-test/Scarb.lock +++ b/crates/dojo/core-cairo-test/Scarb.lock @@ -3,7 +3,7 @@ version = 1 [[package]] name = "dojo" -version = "1.0.0-rc.0" +version = "1.0.9" dependencies = [ "dojo_plugin", ] diff --git a/crates/dojo/core/src/meta/layout.cairo b/crates/dojo/core/src/meta/layout.cairo index ce82b527f0..8e8d7ef9cd 100644 --- a/crates/dojo/core/src/meta/layout.cairo +++ b/crates/dojo/core/src/meta/layout.cairo @@ -15,6 +15,7 @@ pub enum Layout { // And `Box` is not serializable. So using a Span, even if it's to have // one element, does the trick. Array: Span, + FixedArray: Span<(Layout, u32)>, ByteArray, // there is one layout per variant. // the `selector` field identifies the variant @@ -30,6 +31,7 @@ pub impl LayoutCompareImpl of LayoutCompareTrait { (Layout::Struct(_), Layout::Struct(_)) => true, (Layout::Tuple(_), Layout::Tuple(_)) => true, (Layout::Array(_), Layout::Array(_)) => true, + (Layout::FixedArray(_), Layout::FixedArray(_)) => true, (Layout::ByteArray, Layout::ByteArray) => true, (Layout::Enum(_), Layout::Enum(_)) => true, _ => false diff --git a/crates/dojo/core/src/storage/layout.cairo b/crates/dojo/core/src/storage/layout.cairo index d29ca3235e..548ad24038 100644 --- a/crates/dojo/core/src/storage/layout.cairo +++ b/crates/dojo/core/src/storage/layout.cairo @@ -22,6 +22,9 @@ pub fn write_layout( Layout::Fixed(layout) => { write_fixed_layout(model, key, values, ref offset, layout); }, Layout::Struct(layout) => { write_struct_layout(model, key, values, ref offset, layout); }, Layout::Array(layout) => { write_array_layout(model, key, values, ref offset, layout); }, + Layout::FixedArray(layout) => { + write_fixed_array_layout(model, key, values, ref offset, layout); + }, Layout::Tuple(layout) => { write_tuple_layout(model, key, values, ref offset, layout); }, Layout::ByteArray => { write_byte_array_layout(model, key, values, ref offset); }, Layout::Enum(layout) => { write_enum_layout(model, key, values, ref offset, layout); } @@ -81,6 +84,38 @@ pub fn write_array_layout( }; } +/// Write array layout model record to the world storage. +/// +/// # Arguments +/// * `model` - the model selector. +/// * `key` - the model record key. +/// * `values` - the model record values. +/// * `offset` - the start of model record values in the `values` parameter. +/// * `item_layout` - the model record layout (temporary a Span because of type recursion issue). +pub fn write_fixed_array_layout( + model: felt252, + key: felt252, + values: Span, + ref offset: u32, + mut item_layout: Span<(Layout, u32)> +) { + let (item_layout, array_len): (Layout, u32) = *item_layout.pop_front().unwrap(); + assert((values.len() - offset) >= array_len, 'Invalid values length'); + + // first, read array size which is the first felt252 from values + assert(array_len.into() <= database::MAX_ARRAY_LENGTH, 'invalid array length'); + + // then, write the array size + database::set(model, key, values, offset, [packing::PACKING_MAX_BITS].span()); + offset += 1; + + // and then, write array items + for i in 0 + ..array_len { + write_layout(model, combine_key(key, i.into()), values, ref offset, item_layout); + }; +} + /// pub fn write_byte_array_layout( model: felt252, key: felt252, values: Span, ref offset: u32 @@ -212,6 +247,14 @@ pub fn delete_array_layout(model: felt252, key: felt252) { database::delete(model, key, [packing::PACKING_MAX_BITS].span()); } +pub fn delete_fixed_array_layout(model: felt252, key: felt252, mut layout: Span<(Layout, u32)>) { + let (item_layout, array_len): (Layout, u32) = *layout.pop_front().unwrap(); + database::delete(model, key, [packing::PACKING_MAX_BITS].span()); + for i in 0..array_len { + delete_layout(model, combine_key(key, i.into()), item_layout); + } +} + /// pub fn delete_byte_array_layout(model: felt252, key: felt252) { // The ByteArray internal structure is @@ -241,6 +284,7 @@ pub fn delete_layout(model: felt252, key: felt252, layout: Layout) { Layout::Fixed(layout) => { delete_fixed_layout(model, key, layout); }, Layout::Struct(layout) => { delete_struct_layout(model, key, layout); }, Layout::Array(_) => { delete_array_layout(model, key); }, + Layout::FixedArray(layout) => { delete_fixed_array_layout(model, key, layout); }, Layout::Tuple(layout) => { delete_tuple_layout(model, key, layout); }, Layout::ByteArray => { delete_byte_array_layout(model, key); }, Layout::Enum(layout) => { delete_enum_layout(model, key, layout); } @@ -323,6 +367,7 @@ pub fn read_layout(model: felt252, key: felt252, ref read_data: Array, Layout::Fixed(layout) => read_fixed_layout(model, key, ref read_data, layout), Layout::Struct(layout) => read_struct_layout(model, key, ref read_data, layout), Layout::Array(layout) => read_array_layout(model, key, ref read_data, layout), + Layout::FixedArray(layout) => read_fixed_array_layout(model, key, ref read_data, layout), Layout::Tuple(layout) => read_tuple_layout(model, key, ref read_data, layout), Layout::ByteArray => read_byte_array_layout(model, key, ref read_data), Layout::Enum(layout) => read_enum_layout(model, key, ref read_data, layout), @@ -378,6 +423,35 @@ pub fn read_array_layout( }; } +pub fn read_fixed_array_layout( + model: felt252, key: felt252, ref read_data: Array, mut layout: Span<(Layout, u32)> +) { + // read number of array items + let (item_layout, array_len): (Layout, u32) = *layout.pop_front().unwrap(); + let res = database::get(model, key, [packing::PACKING_MAX_BITS].span()); + assert(res.len() == 1, 'internal database error'); + + assert(array_len.into() <= database::MAX_ARRAY_LENGTH, 'invalid array length'); + + read_data.append(array_len.into()); + + let mut i = 0; + loop { + if i >= array_len { + break; + } + + let field_key = combine_key(key, i.into()); + read_layout(model, field_key, ref read_data, item_layout); + + i += 1; + }; + for i in 0 + ..array_len { + read_layout(model, combine_key(key, i.into()), ref read_data, item_layout); + }; +} + /// pub fn read_byte_array_layout(model: felt252, key: felt252, ref read_data: Array) { // The ByteArray internal structure is