From 15292f54926978d946722905aa6f1721b42f41a1 Mon Sep 17 00:00:00 2001 From: Bengineer Date: Mon, 30 Dec 2024 23:25:21 +0000 Subject: [PATCH 01/14] Support for fixed sized arrays in models #2785: Added reding, writing and deleting of fixed arrays --- crates/dojo/core-cairo-test/Scarb.lock | 2 +- crates/dojo/core/src/meta/layout.cairo | 2 + crates/dojo/core/src/storage/layout.cairo | 74 +++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) 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 From 0cf1b45cf4398f141ec3499d16b07e877b5deb4e Mon Sep 17 00:00:00 2001 From: Bengineer Date: Mon, 30 Dec 2024 23:45:08 +0000 Subject: [PATCH 02/14] Support for fixed sized arrays in models #2785: Added Ty --- crates/dojo/core/src/meta/introspect.cairo | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/dojo/core/src/meta/introspect.cairo b/crates/dojo/core/src/meta/introspect.cairo index 448ae94f21..5c88b3a9ca 100644 --- a/crates/dojo/core/src/meta/introspect.cairo +++ b/crates/dojo/core/src/meta/introspect.cairo @@ -11,6 +11,7 @@ pub enum Ty { // And `Box` is not serializable. So using a Span, even if it's to have // one element, does the trick. Array: Span, + FixedArray: Span<(Ty, u32)>, ByteArray, } From 24ef8f333ba40205cea32b33d2c9649bf89ee4ff Mon Sep 17 00:00:00 2001 From: Bengineer Date: Tue, 31 Dec 2024 00:50:37 +0000 Subject: [PATCH 03/14] Support for fixed sized arrays in models #2785: Added introspect --- crates/dojo/core/src/meta/introspect.cairo | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/crates/dojo/core/src/meta/introspect.cairo b/crates/dojo/core/src/meta/introspect.cairo index 5c88b3a9ca..c96993e648 100644 --- a/crates/dojo/core/src/meta/introspect.cairo +++ b/crates/dojo/core/src/meta/introspect.cairo @@ -91,6 +91,21 @@ pub impl Introspect_bool of Introspect { } } +pub impl Introspect_FixedArray> of Introspect<[T; N]> { + fn size() -> Option { + match Introspect::::size() { + Option::Some(size) => Option::Some(size * N), + Option::None => Option::None + } + } + fn layout() -> Layout { + Layout::FixedArray([(Introspect::::layout(), N)].span()) + } + fn ty() -> Ty { + Ty::FixedArray([(Introspect::::ty(), N)].span()) + } +} + pub impl Introspect_u8 of Introspect { fn size() -> Option { Option::Some(1) From 54fbacd9fcba663d5c77eb15df3ef71801e5f4f8 Mon Sep 17 00:00:00 2001 From: Bengineer Date: Tue, 31 Dec 2024 00:56:07 +0000 Subject: [PATCH 04/14] Support for fixed sized arrays in models #2785: Added tests --- .../core-cairo-test/src/tests/meta/introspect.cairo | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo b/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo index bfa89e3023..743798e0e3 100644 --- a/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo +++ b/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo @@ -12,6 +12,13 @@ struct WithArray { arr: Array } +#[derive(Drop, Introspect)] +struct WithFixedArray { + value: u32, + arr: [u8; 3] +} + + #[derive(Drop, Introspect)] struct WithByteArray { value: u32, @@ -166,6 +173,12 @@ fn test_size_with_array() { assert!(Introspect::::size().is_none()); } +fn test_size_with_fixed_array() { + let size = Introspect::::size(); + assert!(size.is_some()); + assert!(size.unwrap() == 4); +} + #[test] fn test_size_with_byte_array() { assert!(Introspect::::size().is_none()); From b39dc3507badd051e50a66358ef0f93d47fdfc06 Mon Sep 17 00:00:00 2001 From: Bengineer Date: Tue, 31 Dec 2024 00:56:36 +0000 Subject: [PATCH 05/14] Stach --- Cargo.lock | 1 + crates/dojo/lang/Cargo.toml | 1 + .../src/derive_macros/introspect/layout.rs | 88 ++++++++++++++----- .../lang/src/derive_macros/introspect/ty.rs | 18 +++- .../src/derive_macros/introspect/utils.rs | 12 +++ 5 files changed, 97 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34ec7bcea5..d6cd8929b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4900,6 +4900,7 @@ dependencies = [ "cairo-lang-utils", "dojo-types 1.0.9", "itertools 0.12.1", + "regex", "serde", "smol_str", "starknet 0.12.0", diff --git a/crates/dojo/lang/Cargo.toml b/crates/dojo/lang/Cargo.toml index 07647d5dc6..1d139a2b46 100644 --- a/crates/dojo/lang/Cargo.toml +++ b/crates/dojo/lang/Cargo.toml @@ -20,6 +20,7 @@ cairo-lang-syntax.workspace = true cairo-lang-utils.workspace = true dojo-types.workspace = true itertools.workspace = true +regex.workspace = true serde.workspace = true smol_str.workspace = true starknet.workspace = true diff --git a/crates/dojo/lang/src/derive_macros/introspect/layout.rs b/crates/dojo/lang/src/derive_macros/introspect/layout.rs index 43667fe502..05828f939b 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/layout.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/layout.rs @@ -7,10 +7,16 @@ use cairo_lang_syntax::node::{ids, Terminal, TypedSyntaxNode}; use starknet::core::utils::get_selector_from_name; use super::utils::{ - get_array_item_type, get_tuple_item_types, is_array, is_byte_array, is_tuple, - is_unsupported_option_type, primitive_type_introspection, + get_array_item_type, get_fixed_array_type_and_size, get_tuple_item_types, is_array, + is_byte_array, is_fixed_array, is_tuple, is_unsupported_option_type, + primitive_type_introspection, }; +pub enum Wrapper { + Introspect, + Array(String), +} + /// build the full layout for every field in the Struct. pub fn build_field_layouts( db: &dyn SyntaxGroup, @@ -110,26 +116,62 @@ pub fn build_array_layout_from_type( ) -> String { let array_item_type = get_array_item_type(item_type); - if is_tuple(&array_item_type) { - format!( - "dojo::meta::Layout::Array( - array![ - {} - ].span() - )", - build_item_layout_from_type(diagnostics, diagnostic_item, &array_item_type) - ) - } else if is_array(&array_item_type) { - format!( - "dojo::meta::Layout::Array( - array![ - {} - ].span() - )", - build_array_layout_from_type(diagnostics, diagnostic_item, &array_item_type) - ) + match build_member_layout_from_type(diagnostics, diagnostic_item, &array_item_type) { + Wrapper::Introspect => { + format!("dojo::meta::introspect::Introspect::<{}>::layout()", array_item_type) + } + Wrapper::Array(layout) => { + format!( + "dojo::meta::Layout::Array( + array![ + {} + ].span(), + )", + layout + ) + } + } +} + +pub fn build_member_layout_from_type( + diagnostics: &mut Vec, + diagnostic_item: ids::SyntaxStablePtrId, + item_type: &str, +) -> Wrapper { + if is_array(item_type) { + Wrapper::Array(build_array_layout_from_type(diagnostics, diagnostic_item, item_type)) + } else if is_fixed_array(item_type) { + Wrapper::Array(build_fixed_array_layout_from_type(diagnostics, diagnostic_item, item_type)) + } else if is_tuple(item_type) { + Wrapper::Array(build_tuple_layout_from_type(diagnostics, diagnostic_item, item_type)) } else { - format!("dojo::meta::introspect::Introspect::<{}>::layout()", item_type) + Wrapper::Introspect + } +} + +pub fn build_fixed_array_layout_from_type( + diagnostics: &mut Vec, + diagnostic_item: ids::SyntaxStablePtrId, + item_type: &str, +) -> String { + let (array_item_type, array_size) = get_fixed_array_type_and_size(item_type); + match build_member_layout_from_type(diagnostics, diagnostic_item, &array_item_type) { + Wrapper::Introspect => { + format!( + "dojo::meta::introspect::Introspect::<({}, {})>::layout()", + array_item_type, array_size + ) + } + Wrapper::Array(layout) => { + format!( + "dojo::meta::Layout::FixedArray( + array![ + ({}, {}) + ].span(), + )", + layout, array_size + ) + } } } @@ -164,6 +206,8 @@ pub fn build_item_layout_from_type( ) -> String { if is_array(item_type) { build_array_layout_from_type(diagnostics, diagnostic_item, item_type) + } else if is_fixed_array(item_type) { + build_fixed_array_layout_from_type(diagnostics, diagnostic_item, item_type) } else if is_tuple(item_type) { build_tuple_layout_from_type(diagnostics, diagnostic_item, item_type) } else { @@ -343,6 +387,8 @@ pub fn get_packed_item_layout_from_type( vec!["ERROR".to_string()] } else if is_tuple(item_type) { get_packed_tuple_layout_from_type(diagnostics, diagnostic_item, item_type) + } else if is_fixed_array(item_type) { + // TODO: Implement fixed array packed layout } else { let primitives = primitive_type_introspection(); diff --git a/crates/dojo/lang/src/derive_macros/introspect/ty.rs b/crates/dojo/lang/src/derive_macros/introspect/ty.rs index d9e9e40a11..209c121e9d 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/ty.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/ty.rs @@ -5,7 +5,10 @@ use cairo_lang_syntax::node::db::SyntaxGroup; use cairo_lang_syntax::node::helpers::QueryAttrs; use cairo_lang_syntax::node::{Terminal, TypedSyntaxNode}; -use super::utils::{get_array_item_type, get_tuple_item_types, is_array, is_byte_array, is_tuple}; +use super::utils::{ + get_array_item_type, get_fixed_array_type_and_size, get_tuple_item_types, is_array, + is_byte_array, is_fixed_array, is_tuple, +}; pub fn build_struct_ty(db: &dyn SyntaxGroup, name: &String, struct_ast: &ItemStruct) -> String { let members_ty = struct_ast @@ -56,7 +59,7 @@ pub fn build_member_ty(db: &dyn SyntaxGroup, member: &Member) -> String { let attrs = if member.has_attr(db, "key") { vec!["'key'"] } else { vec![] }; format!( - "dojo::meta::introspect::Member {{ + "dojo::meta::introspect::FixedArray {{ name: '{name}', attrs: array![{}].span(), ty: {} @@ -107,6 +110,17 @@ pub fn build_item_ty_from_type(item_type: &String) -> String { )", build_item_ty_from_type(&array_item_type) ) + } else if is_fixed_array(item_type) { + let (array_item_type, size) = get_fixed_array_type_and_size(&item_type); + format!( + "dojo::meta::introspect::Ty::FixedArray( + array![ + ({}, {}) + ].span() + )", + build_item_ty_from_type(&array_item_type), + size + ) } else if is_byte_array(item_type) { "dojo::meta::introspect::Ty::ByteArray".to_string() } else if is_tuple(item_type) { diff --git a/crates/dojo/lang/src/derive_macros/introspect/utils.rs b/crates/dojo/lang/src/derive_macros/introspect/utils.rs index f57f6b6335..eac7efacfe 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/utils.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/utils.rs @@ -1,5 +1,8 @@ +use regex::Regex; use std::collections::HashMap; +const FIXED_ARRAY_REGEX: &str = r"\[[^;]+;\s*\d{1,10}\s*\]"; + #[derive(Clone, Default, Debug)] pub struct TypeIntrospection(pub usize, pub Vec); @@ -27,6 +30,11 @@ pub fn is_unsupported_option_type(ty: &str) -> bool { ty.starts_with("Option<(") } +pub fn is_fixed_array(ty: &str) -> bool { + let re = Regex::new(FIXED_ARRAY_REGEX).unwrap(); + re.is_match(ty) +} + pub fn is_byte_array(ty: &str) -> bool { ty.eq("ByteArray") } @@ -47,6 +55,10 @@ pub fn get_array_item_type(ty: &str) -> String { } } +pub fn get_fixed_array_type_and_size(ty: &str) -> (String, usize) { + let mut parts = ty.trim().strip_prefix('[').unwrap().strip_suffix(']').unwrap().split(';'); + (parts.next().unwrap().trim().to_string(), parts.last().unwrap().trim().parse().unwrap()) +} /// split a tuple in array of items (nested tuples are not splitted). /// example (u8, (u16, u32), u128) -> ["u8", "(u16, u32)", "u128"] pub fn get_tuple_item_types(ty: &str) -> Vec { From b0a88b091119a7a5f0a6477e73c11c0d8043231b Mon Sep 17 00:00:00 2001 From: Bengineer Date: Tue, 31 Dec 2024 01:31:34 +0000 Subject: [PATCH 06/14] Stach --- .../src/tests/meta/introspect.cairo | 21 ++-- crates/dojo/core/src/meta/introspect.cairo | 30 ++--- crates/dojo/core/src/meta/layout.cairo | 4 +- crates/dojo/core/src/storage/layout.cairo | 109 ++++++++---------- .../src/derive_macros/introspect/layout.rs | 99 ++++++++-------- .../lang/src/derive_macros/introspect/ty.rs | 27 ++--- .../src/derive_macros/introspect/utils.rs | 20 ++-- 7 files changed, 150 insertions(+), 160 deletions(-) diff --git a/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo b/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo index 743798e0e3..42ee23da31 100644 --- a/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo +++ b/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo @@ -12,12 +12,11 @@ struct WithArray { arr: Array } -#[derive(Drop, Introspect)] -struct WithFixedArray { - value: u32, - arr: [u8; 3] -} - +// #[derive(Drop, Introspect)] +// struct WithFixedArray { +// value: u32, +// arr: [u8; 3] +// } #[derive(Drop, Introspect)] struct WithByteArray { @@ -173,11 +172,11 @@ fn test_size_with_array() { assert!(Introspect::::size().is_none()); } -fn test_size_with_fixed_array() { - let size = Introspect::::size(); - assert!(size.is_some()); - assert!(size.unwrap() == 4); -} +// fn test_size_with_fixed_array() { +// let size = Introspect::::size(); +// assert!(size.is_some()); +// assert!(size.unwrap() == 4); +// } #[test] fn test_size_with_byte_array() { diff --git a/crates/dojo/core/src/meta/introspect.cairo b/crates/dojo/core/src/meta/introspect.cairo index c96993e648..be5dc40b8c 100644 --- a/crates/dojo/core/src/meta/introspect.cairo +++ b/crates/dojo/core/src/meta/introspect.cairo @@ -11,7 +11,7 @@ pub enum Ty { // And `Box` is not serializable. So using a Span, even if it's to have // one element, does the trick. Array: Span, - FixedArray: Span<(Ty, u32)>, + // FixedArray: Span<(Ty, u32)>, ByteArray, } @@ -91,20 +91,20 @@ pub impl Introspect_bool of Introspect { } } -pub impl Introspect_FixedArray> of Introspect<[T; N]> { - fn size() -> Option { - match Introspect::::size() { - Option::Some(size) => Option::Some(size * N), - Option::None => Option::None - } - } - fn layout() -> Layout { - Layout::FixedArray([(Introspect::::layout(), N)].span()) - } - fn ty() -> Ty { - Ty::FixedArray([(Introspect::::ty(), N)].span()) - } -} +// pub impl Introspect_FixedArray> of Introspect<[T; N]> { +// fn size() -> Option { +// match Introspect::::size() { +// Option::Some(size) => Option::Some(size * N), +// Option::None => Option::None +// } +// } +// fn layout() -> Layout { +// Layout::FixedArray([(Introspect::::layout(), N)].span()) +// } +// fn ty() -> Ty { +// Ty::FixedArray([(Introspect::::ty(), N)].span()) +// } +// } pub impl Introspect_u8 of Introspect { fn size() -> Option { diff --git a/crates/dojo/core/src/meta/layout.cairo b/crates/dojo/core/src/meta/layout.cairo index 8e8d7ef9cd..25d0d284be 100644 --- a/crates/dojo/core/src/meta/layout.cairo +++ b/crates/dojo/core/src/meta/layout.cairo @@ -15,7 +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)>, + // FixedArray: Span<(Layout, u32)>, ByteArray, // there is one layout per variant. // the `selector` field identifies the variant @@ -31,7 +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::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 548ad24038..1818351182 100644 --- a/crates/dojo/core/src/storage/layout.cairo +++ b/crates/dojo/core/src/storage/layout.cairo @@ -22,9 +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::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); } @@ -92,29 +92,29 @@ pub fn write_array_layout( /// * `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_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( @@ -247,13 +247,13 @@ 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_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) { @@ -284,7 +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::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); } @@ -367,7 +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::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), @@ -423,34 +423,23 @@ 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'); +// 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; - } +// assert(array_len.into() <= database::MAX_ARRAY_LENGTH, 'invalid array length'); - let field_key = combine_key(key, i.into()); - read_layout(model, field_key, ref read_data, item_layout); +// read_data.append(array_len.into()); - i += 1; - }; - for i in 0 - ..array_len { - read_layout(model, combine_key(key, i.into()), ref read_data, item_layout); - }; -} +// 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) { diff --git a/crates/dojo/lang/src/derive_macros/introspect/layout.rs b/crates/dojo/lang/src/derive_macros/introspect/layout.rs index 05828f939b..e3e2a398fd 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/layout.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/layout.rs @@ -7,9 +7,8 @@ use cairo_lang_syntax::node::{ids, Terminal, TypedSyntaxNode}; use starknet::core::utils::get_selector_from_name; use super::utils::{ - get_array_item_type, get_fixed_array_type_and_size, get_tuple_item_types, is_array, - is_byte_array, is_fixed_array, is_tuple, is_unsupported_option_type, - primitive_type_introspection, + get_array_item_type, get_tuple_item_types, is_array, is_byte_array, is_tuple, + is_unsupported_option_type, primitive_type_introspection, }; pub enum Wrapper { @@ -96,6 +95,14 @@ pub fn get_layout_from_type_clause( let tuple_type = expr.as_syntax_node().get_text(db); build_tuple_layout_from_type(diagnostics, type_clause.stable_ptr().0, &tuple_type) } + // Expr::FixedSizeArray(fixed_size_array) => { + // let fixed_array_type = fixed_size_array.as_syntax_node().get_text(db); + // build_fixed_array_layout_from_type( + // diagnostics, + // type_clause.stable_ptr().0, + // &fixed_array_type, + // ) + // } _ => { diagnostics.push(PluginDiagnostic { stable_ptr: type_clause.stable_ptr().0, @@ -133,47 +140,47 @@ pub fn build_array_layout_from_type( } } -pub fn build_member_layout_from_type( - diagnostics: &mut Vec, - diagnostic_item: ids::SyntaxStablePtrId, - item_type: &str, -) -> Wrapper { - if is_array(item_type) { - Wrapper::Array(build_array_layout_from_type(diagnostics, diagnostic_item, item_type)) - } else if is_fixed_array(item_type) { - Wrapper::Array(build_fixed_array_layout_from_type(diagnostics, diagnostic_item, item_type)) - } else if is_tuple(item_type) { - Wrapper::Array(build_tuple_layout_from_type(diagnostics, diagnostic_item, item_type)) - } else { - Wrapper::Introspect - } -} +// pub fn build_member_layout_from_type( +// diagnostics: &mut Vec, +// diagnostic_item: ids::SyntaxStablePtrId, +// item_type: &str, +// ) -> Wrapper { +// if is_array(item_type) { +// Wrapper::Array(build_array_layout_from_type(diagnostics, diagnostic_item, item_type)) +// // } else if is_fixed_array(item_type) { +// // Wrapper::Array(build_fixed_array_layout_from_type(diagnostics, diagnostic_item, item_type)) +// } else if is_tuple(item_type) { +// Wrapper::Array(build_tuple_layout_from_type(diagnostics, diagnostic_item, item_type)) +// } else { +// Wrapper::Introspect +// } +// } -pub fn build_fixed_array_layout_from_type( - diagnostics: &mut Vec, - diagnostic_item: ids::SyntaxStablePtrId, - item_type: &str, -) -> String { - let (array_item_type, array_size) = get_fixed_array_type_and_size(item_type); - match build_member_layout_from_type(diagnostics, diagnostic_item, &array_item_type) { - Wrapper::Introspect => { - format!( - "dojo::meta::introspect::Introspect::<({}, {})>::layout()", - array_item_type, array_size - ) - } - Wrapper::Array(layout) => { - format!( - "dojo::meta::Layout::FixedArray( - array![ - ({}, {}) - ].span(), - )", - layout, array_size - ) - } - } -} +// pub fn build_fixed_array_layout_from_type( +// diagnostics: &mut Vec, +// diagnostic_item: ids::SyntaxStablePtrId, +// item_type: &str, +// ) -> String { +// let (array_item_type, array_size) = get_fixed_array_type_and_size(item_type); +// match build_member_layout_from_type(diagnostics, diagnostic_item, &array_item_type) { +// Wrapper::Introspect => { +// format!( +// "dojo::meta::introspect::Introspect::<({}, {})>::layout()", +// array_item_type, array_size +// ) +// } +// Wrapper::Array(layout) => { +// format!( +// "dojo::meta::Layout::FixedArray( +// array![ +// ({}, {}) +// ].span(), +// )", +// layout, array_size +// ) +// } +// } +// } /// Build the tuple layout describing the provided tuple type. /// item_type could be something like (u8, u32, u128) for example. @@ -206,8 +213,8 @@ pub fn build_item_layout_from_type( ) -> String { if is_array(item_type) { build_array_layout_from_type(diagnostics, diagnostic_item, item_type) - } else if is_fixed_array(item_type) { - build_fixed_array_layout_from_type(diagnostics, diagnostic_item, item_type) + // } else if is_fixed_array(item_type) { + // build_fixed_array_layout_from_type(diagnostics, diagnostic_item, item_type) } else if is_tuple(item_type) { build_tuple_layout_from_type(diagnostics, diagnostic_item, item_type) } else { @@ -387,8 +394,6 @@ pub fn get_packed_item_layout_from_type( vec!["ERROR".to_string()] } else if is_tuple(item_type) { get_packed_tuple_layout_from_type(diagnostics, diagnostic_item, item_type) - } else if is_fixed_array(item_type) { - // TODO: Implement fixed array packed layout } else { let primitives = primitive_type_introspection(); diff --git a/crates/dojo/lang/src/derive_macros/introspect/ty.rs b/crates/dojo/lang/src/derive_macros/introspect/ty.rs index 209c121e9d..177a22ef5f 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/ty.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/ty.rs @@ -5,10 +5,7 @@ use cairo_lang_syntax::node::db::SyntaxGroup; use cairo_lang_syntax::node::helpers::QueryAttrs; use cairo_lang_syntax::node::{Terminal, TypedSyntaxNode}; -use super::utils::{ - get_array_item_type, get_fixed_array_type_and_size, get_tuple_item_types, is_array, - is_byte_array, is_fixed_array, is_tuple, -}; +use super::utils::{get_array_item_type, get_tuple_item_types, is_array, is_byte_array, is_tuple}; pub fn build_struct_ty(db: &dyn SyntaxGroup, name: &String, struct_ast: &ItemStruct) -> String { let members_ty = struct_ast @@ -110,17 +107,17 @@ pub fn build_item_ty_from_type(item_type: &String) -> String { )", build_item_ty_from_type(&array_item_type) ) - } else if is_fixed_array(item_type) { - let (array_item_type, size) = get_fixed_array_type_and_size(&item_type); - format!( - "dojo::meta::introspect::Ty::FixedArray( - array![ - ({}, {}) - ].span() - )", - build_item_ty_from_type(&array_item_type), - size - ) + // } else if is_fixed_array(item_type) { + // let (array_item_type, size) = get_fixed_array_type_and_size(&item_type); + // format!( + // "dojo::meta::introspect::Ty::FixedArray( + // array![ + // ({}, {}) + // ].span() + // )", + // build_item_ty_from_type(&array_item_type), + // size + // ) } else if is_byte_array(item_type) { "dojo::meta::introspect::Ty::ByteArray".to_string() } else if is_tuple(item_type) { diff --git a/crates/dojo/lang/src/derive_macros/introspect/utils.rs b/crates/dojo/lang/src/derive_macros/introspect/utils.rs index eac7efacfe..af9c7d08e8 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/utils.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/utils.rs @@ -1,7 +1,7 @@ -use regex::Regex; +// use regex::Regex; use std::collections::HashMap; -const FIXED_ARRAY_REGEX: &str = r"\[[^;]+;\s*\d{1,10}\s*\]"; +// const FIXED_ARRAY_REGEX: &str = r"\[[^;]+;\s*\d{1,10}\s*\]"; #[derive(Clone, Default, Debug)] pub struct TypeIntrospection(pub usize, pub Vec); @@ -30,10 +30,10 @@ pub fn is_unsupported_option_type(ty: &str) -> bool { ty.starts_with("Option<(") } -pub fn is_fixed_array(ty: &str) -> bool { - let re = Regex::new(FIXED_ARRAY_REGEX).unwrap(); - re.is_match(ty) -} +// pub fn is_fixed_array(ty: &str) -> bool { +// let re = Regex::new(FIXED_ARRAY_REGEX).unwrap(); +// re.is_match(ty) +// } pub fn is_byte_array(ty: &str) -> bool { ty.eq("ByteArray") @@ -55,10 +55,10 @@ pub fn get_array_item_type(ty: &str) -> String { } } -pub fn get_fixed_array_type_and_size(ty: &str) -> (String, usize) { - let mut parts = ty.trim().strip_prefix('[').unwrap().strip_suffix(']').unwrap().split(';'); - (parts.next().unwrap().trim().to_string(), parts.last().unwrap().trim().parse().unwrap()) -} +// pub fn get_fixed_array_type_and_size(ty: &str) -> (String, usize) { +// let mut parts = ty.trim().strip_prefix('[').unwrap().strip_suffix(']').unwrap().split(';'); +// (parts.next().unwrap().trim().to_string(), parts.last().unwrap().trim().parse().unwrap()) +// } /// split a tuple in array of items (nested tuples are not splitted). /// example (u8, (u16, u32), u128) -> ["u8", "(u16, u32)", "u128"] pub fn get_tuple_item_types(ty: &str) -> Vec { From 64765f1e00a1210889f2f7c47668d3e567796208 Mon Sep 17 00:00:00 2001 From: Bengineer Date: Tue, 31 Dec 2024 02:21:21 +0000 Subject: [PATCH 07/14] Support for fixed sized arrays in models #2785: Debugging --- .../src/tests/meta/introspect.cairo | 10 +- crates/dojo/core/src/meta/introspect.cairo | 31 ++-- crates/dojo/core/src/meta/layout.cairo | 4 +- crates/dojo/core/src/storage/layout.cairo | 98 ++++++------- .../src/derive_macros/introspect/layout.rs | 136 +++++++++++------- .../lang/src/derive_macros/introspect/ty.rs | 29 ++-- .../src/derive_macros/introspect/utils.rs | 20 +-- 7 files changed, 183 insertions(+), 145 deletions(-) diff --git a/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo b/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo index 42ee23da31..b93ec55098 100644 --- a/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo +++ b/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo @@ -12,11 +12,11 @@ struct WithArray { arr: Array } -// #[derive(Drop, Introspect)] -// struct WithFixedArray { -// value: u32, -// arr: [u8; 3] -// } +#[derive(Drop, Introspect)] +struct WithFixedArray { + value: u32, + arr: [u8; 3] +} #[derive(Drop, Introspect)] struct WithByteArray { diff --git a/crates/dojo/core/src/meta/introspect.cairo b/crates/dojo/core/src/meta/introspect.cairo index be5dc40b8c..5a8f1f53f3 100644 --- a/crates/dojo/core/src/meta/introspect.cairo +++ b/crates/dojo/core/src/meta/introspect.cairo @@ -11,7 +11,7 @@ pub enum Ty { // And `Box` is not serializable. So using a Span, even if it's to have // one element, does the trick. Array: Span, - // FixedArray: Span<(Ty, u32)>, + FixedArray: Span<(Ty, u32)>, ByteArray, } @@ -91,20 +91,21 @@ pub impl Introspect_bool of Introspect { } } -// pub impl Introspect_FixedArray> of Introspect<[T; N]> { -// fn size() -> Option { -// match Introspect::::size() { -// Option::Some(size) => Option::Some(size * N), -// Option::None => Option::None -// } -// } -// fn layout() -> Layout { -// Layout::FixedArray([(Introspect::::layout(), N)].span()) -// } -// fn ty() -> Ty { -// Ty::FixedArray([(Introspect::::ty(), N)].span()) -// } -// } +pub impl Introspect_FixedArray> of Introspect<[T; N]> { + fn size() -> Option { + match Introspect::::size() { + Option::Some(size) => Option::Some(size * N), + Option::None => Option::None + } + } + fn layout() -> Layout { + Layout::FixedArray([(Introspect::::layout(), N)].span()) + } + fn ty() -> Ty { + Ty::FixedArray([(Introspect::::ty(), N)].span()) + } +} + pub impl Introspect_u8 of Introspect { fn size() -> Option { diff --git a/crates/dojo/core/src/meta/layout.cairo b/crates/dojo/core/src/meta/layout.cairo index 25d0d284be..8e8d7ef9cd 100644 --- a/crates/dojo/core/src/meta/layout.cairo +++ b/crates/dojo/core/src/meta/layout.cairo @@ -15,7 +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)>, + FixedArray: Span<(Layout, u32)>, ByteArray, // there is one layout per variant. // the `selector` field identifies the variant @@ -31,7 +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::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 1818351182..5310a1ec4c 100644 --- a/crates/dojo/core/src/storage/layout.cairo +++ b/crates/dojo/core/src/storage/layout.cairo @@ -22,9 +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::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); } @@ -92,29 +92,29 @@ pub fn write_array_layout( /// * `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_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( @@ -247,13 +247,13 @@ 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_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) { @@ -284,7 +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::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); } @@ -367,7 +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::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), @@ -423,23 +423,23 @@ 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'); +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'); + assert(array_len.into() <= database::MAX_ARRAY_LENGTH, 'invalid array length'); -// read_data.append(array_len.into()); + read_data.append(array_len.into()); -// for i in 0 -// ..array_len { -// read_layout(model, combine_key(key, i.into()), ref read_data, item_layout); -// }; -// } + 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) { diff --git a/crates/dojo/lang/src/derive_macros/introspect/layout.rs b/crates/dojo/lang/src/derive_macros/introspect/layout.rs index e3e2a398fd..08cbdb0f06 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/layout.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/layout.rs @@ -7,8 +7,9 @@ use cairo_lang_syntax::node::{ids, Terminal, TypedSyntaxNode}; use starknet::core::utils::get_selector_from_name; use super::utils::{ - get_array_item_type, get_tuple_item_types, is_array, is_byte_array, is_tuple, - is_unsupported_option_type, primitive_type_introspection, + get_array_item_type, get_fixed_array_type_and_size, get_tuple_item_types, is_array, + is_byte_array, is_fixed_array, is_tuple, is_unsupported_option_type, + primitive_type_introspection, }; pub enum Wrapper { @@ -95,14 +96,14 @@ pub fn get_layout_from_type_clause( let tuple_type = expr.as_syntax_node().get_text(db); build_tuple_layout_from_type(diagnostics, type_clause.stable_ptr().0, &tuple_type) } - // Expr::FixedSizeArray(fixed_size_array) => { - // let fixed_array_type = fixed_size_array.as_syntax_node().get_text(db); - // build_fixed_array_layout_from_type( - // diagnostics, - // type_clause.stable_ptr().0, - // &fixed_array_type, - // ) - // } + Expr::FixedSizeArray(fixed_size_array) => { + let fixed_array_type = fixed_size_array.as_syntax_node().get_text(db); + build_fixed_array_layout_from_type( + diagnostics, + type_clause.stable_ptr().0, + &fixed_array_type, + ) + } _ => { diagnostics.push(PluginDiagnostic { stable_ptr: type_clause.stable_ptr().0, @@ -121,6 +122,31 @@ pub fn build_array_layout_from_type( diagnostic_item: ids::SyntaxStablePtrId, item_type: &str, ) -> String { + // let array_item_type = get_array_item_type(item_type); + + // if is_tuple(&array_item_type) { + // format!( + // "dojo::meta::Layout::Array( + // array![ + // {} + // ].span() + // )", + // build_item_layout_from_type(diagnostics, diagnostic_item, &array_item_type) + // ) + // } else if is_array(&array_item_type) { + // format!( + // "dojo::meta::Layout::Array( + // array![ + // {} + // ].span() + // )", + // build_array_layout_from_type(diagnostics, diagnostic_item, &array_item_type) + // ) + // } else { + // format!("dojo::meta::introspect::Introspect::<{}>::layout()", item_type) + // } + // } + let array_item_type = get_array_item_type(item_type); match build_member_layout_from_type(diagnostics, diagnostic_item, &array_item_type) { @@ -140,47 +166,47 @@ pub fn build_array_layout_from_type( } } -// pub fn build_member_layout_from_type( -// diagnostics: &mut Vec, -// diagnostic_item: ids::SyntaxStablePtrId, -// item_type: &str, -// ) -> Wrapper { -// if is_array(item_type) { -// Wrapper::Array(build_array_layout_from_type(diagnostics, diagnostic_item, item_type)) -// // } else if is_fixed_array(item_type) { -// // Wrapper::Array(build_fixed_array_layout_from_type(diagnostics, diagnostic_item, item_type)) -// } else if is_tuple(item_type) { -// Wrapper::Array(build_tuple_layout_from_type(diagnostics, diagnostic_item, item_type)) -// } else { -// Wrapper::Introspect -// } -// } - -// pub fn build_fixed_array_layout_from_type( -// diagnostics: &mut Vec, -// diagnostic_item: ids::SyntaxStablePtrId, -// item_type: &str, -// ) -> String { -// let (array_item_type, array_size) = get_fixed_array_type_and_size(item_type); -// match build_member_layout_from_type(diagnostics, diagnostic_item, &array_item_type) { -// Wrapper::Introspect => { -// format!( -// "dojo::meta::introspect::Introspect::<({}, {})>::layout()", -// array_item_type, array_size -// ) -// } -// Wrapper::Array(layout) => { -// format!( -// "dojo::meta::Layout::FixedArray( -// array![ -// ({}, {}) -// ].span(), -// )", -// layout, array_size -// ) -// } -// } -// } +pub fn build_member_layout_from_type( + diagnostics: &mut Vec, + diagnostic_item: ids::SyntaxStablePtrId, + item_type: &str, +) -> Wrapper { + if is_array(item_type) { + Wrapper::Array(build_array_layout_from_type(diagnostics, diagnostic_item, item_type)) + } else if is_fixed_array(item_type) { + Wrapper::Array(build_fixed_array_layout_from_type(diagnostics, diagnostic_item, item_type)) + } else if is_tuple(item_type) { + Wrapper::Array(build_tuple_layout_from_type(diagnostics, diagnostic_item, item_type)) + } else { + Wrapper::Introspect + } +} + +pub fn build_fixed_array_layout_from_type( + diagnostics: &mut Vec, + diagnostic_item: ids::SyntaxStablePtrId, + item_type: &str, +) -> String { + let (array_item_type, array_size) = get_fixed_array_type_and_size(item_type); + match build_member_layout_from_type(diagnostics, diagnostic_item, &array_item_type) { + Wrapper::Introspect => { + format!( + "dojo::meta::introspect::Introspect::<[{}; {}]>::layout()", + array_item_type, array_size + ) + } + Wrapper::Array(layout) => { + format!( + "dojo::meta::Layout::FixedArray( + array![ + ({}, {}) + ].span(), + )", + layout, array_size + ) + } + } +} /// Build the tuple layout describing the provided tuple type. /// item_type could be something like (u8, u32, u128) for example. @@ -368,6 +394,14 @@ pub fn get_packed_field_layout_from_type_clause( let tuple_type = expr.as_syntax_node().get_text(db); get_packed_tuple_layout_from_type(diagnostics, type_clause.stable_ptr().0, &tuple_type) } + // Expr::FixedSizeArray(fixed_size_array) => { + // let fixed_array_type = fixed_size_array.as_syntax_node().get_text(db); + // get_packed_item_layout_from_type( + // diagnostics, + // type_clause.stable_ptr().0, + // fixed_array_type.trim(), + // ) + // } _ => { diagnostics.push(PluginDiagnostic { stable_ptr: type_clause.stable_ptr().0, diff --git a/crates/dojo/lang/src/derive_macros/introspect/ty.rs b/crates/dojo/lang/src/derive_macros/introspect/ty.rs index 177a22ef5f..32f1c941ee 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/ty.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/ty.rs @@ -5,7 +5,10 @@ use cairo_lang_syntax::node::db::SyntaxGroup; use cairo_lang_syntax::node::helpers::QueryAttrs; use cairo_lang_syntax::node::{Terminal, TypedSyntaxNode}; -use super::utils::{get_array_item_type, get_tuple_item_types, is_array, is_byte_array, is_tuple}; +use super::utils::{ + get_array_item_type, get_fixed_array_type_and_size, get_tuple_item_types, is_array, + is_byte_array, is_fixed_array, is_tuple, +}; pub fn build_struct_ty(db: &dyn SyntaxGroup, name: &String, struct_ast: &ItemStruct) -> String { let members_ty = struct_ast @@ -56,7 +59,7 @@ pub fn build_member_ty(db: &dyn SyntaxGroup, member: &Member) -> String { let attrs = if member.has_attr(db, "key") { vec!["'key'"] } else { vec![] }; format!( - "dojo::meta::introspect::FixedArray {{ + "dojo::meta::introspect::Member {{ name: '{name}', attrs: array![{}].span(), ty: {} @@ -107,17 +110,17 @@ pub fn build_item_ty_from_type(item_type: &String) -> String { )", build_item_ty_from_type(&array_item_type) ) - // } else if is_fixed_array(item_type) { - // let (array_item_type, size) = get_fixed_array_type_and_size(&item_type); - // format!( - // "dojo::meta::introspect::Ty::FixedArray( - // array![ - // ({}, {}) - // ].span() - // )", - // build_item_ty_from_type(&array_item_type), - // size - // ) + } else if is_fixed_array(item_type) { + let (array_item_type, size) = get_fixed_array_type_and_size(&item_type); + format!( + "dojo::meta::introspect::Ty::FixedArray( + array![ + ({}, {}) + ].span() + )", + build_item_ty_from_type(&array_item_type), + size + ) } else if is_byte_array(item_type) { "dojo::meta::introspect::Ty::ByteArray".to_string() } else if is_tuple(item_type) { diff --git a/crates/dojo/lang/src/derive_macros/introspect/utils.rs b/crates/dojo/lang/src/derive_macros/introspect/utils.rs index af9c7d08e8..eac7efacfe 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/utils.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/utils.rs @@ -1,7 +1,7 @@ -// use regex::Regex; +use regex::Regex; use std::collections::HashMap; -// const FIXED_ARRAY_REGEX: &str = r"\[[^;]+;\s*\d{1,10}\s*\]"; +const FIXED_ARRAY_REGEX: &str = r"\[[^;]+;\s*\d{1,10}\s*\]"; #[derive(Clone, Default, Debug)] pub struct TypeIntrospection(pub usize, pub Vec); @@ -30,10 +30,10 @@ pub fn is_unsupported_option_type(ty: &str) -> bool { ty.starts_with("Option<(") } -// pub fn is_fixed_array(ty: &str) -> bool { -// let re = Regex::new(FIXED_ARRAY_REGEX).unwrap(); -// re.is_match(ty) -// } +pub fn is_fixed_array(ty: &str) -> bool { + let re = Regex::new(FIXED_ARRAY_REGEX).unwrap(); + re.is_match(ty) +} pub fn is_byte_array(ty: &str) -> bool { ty.eq("ByteArray") @@ -55,10 +55,10 @@ pub fn get_array_item_type(ty: &str) -> String { } } -// pub fn get_fixed_array_type_and_size(ty: &str) -> (String, usize) { -// let mut parts = ty.trim().strip_prefix('[').unwrap().strip_suffix(']').unwrap().split(';'); -// (parts.next().unwrap().trim().to_string(), parts.last().unwrap().trim().parse().unwrap()) -// } +pub fn get_fixed_array_type_and_size(ty: &str) -> (String, usize) { + let mut parts = ty.trim().strip_prefix('[').unwrap().strip_suffix(']').unwrap().split(';'); + (parts.next().unwrap().trim().to_string(), parts.last().unwrap().trim().parse().unwrap()) +} /// split a tuple in array of items (nested tuples are not splitted). /// example (u8, (u16, u32), u128) -> ["u8", "(u16, u32)", "u128"] pub fn get_tuple_item_types(ty: &str) -> Vec { From 26fb851f7a79924a66624b71ecd033fba986c5f4 Mon Sep 17 00:00:00 2001 From: "remy.baranx@gmail.com" Date: Sun, 5 Jan 2025 08:47:31 +0100 Subject: [PATCH 08/14] feat: support introspect of fixed size array --- .../src/tests/meta/introspect.cairo | 116 +++++++++++++++++- .../src/derive_macros/introspect/layout.rs | 55 ++++++++- .../lang/src/derive_macros/introspect/size.rs | 19 ++- .../lang/src/derive_macros/introspect/ty.rs | 22 +++- .../src/derive_macros/introspect/utils.rs | 17 +++ 5 files changed, 223 insertions(+), 6 deletions(-) diff --git a/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo b/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo index bfa89e3023..4c55673eb7 100644 --- a/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo +++ b/crates/dojo/core-cairo-test/src/tests/meta/introspect.cairo @@ -111,6 +111,31 @@ struct Generic { value: T, } +#[derive(Drop, Introspect)] +struct StructWithFixedArray { + x: [u8; 3] +} + +#[derive(Drop, Introspect)] +struct StructWithComplexFixedArray { + x: [[EnumWithSameData; 2]; 3] +} + +#[derive(Drop, Introspect)] +enum EnumWithFixedArray { + A: [u8; 3] +} + +#[derive(Drop, IntrospectPacked)] +struct StructWithFixedArrayPacked { + x: [u8; 3] +} + +#[derive(Drop, IntrospectPacked)] +enum EnumWithFixedArrayPacked { + A: [u8; 3] +} + fn field(selector: felt252, layout: Layout) -> FieldLayout { FieldLayout { selector, layout } } @@ -123,6 +148,10 @@ fn tuple(values: Array) -> Layout { Layout::Tuple(values.span()) } +fn fixed_array(inner_layout: Layout, size: u32) -> Layout { + Layout::FixedArray(array![(inner_layout, size)].span()) +} + fn _enum(values: Array>) -> Layout { let mut items = array![]; let mut i = 0; @@ -212,7 +241,6 @@ fn test_size_of_enum_with_same_tuple_variant_data() { assert!(size.unwrap() == 4); } - #[test] fn test_size_of_struct_with_option() { let size = Introspect::::size(); @@ -225,6 +253,41 @@ fn test_size_of_enum_with_variant_data() { assert!(size.is_none()); } +#[test] +fn test_size_of_struct_with_fixed_array() { + let size = Introspect::::size(); + assert!(size.is_some()); + assert!(size.unwrap() == 3); +} + +#[test] +fn test_size_of_struct_with_complex_fixed_array() { + let size = Introspect::::size(); + assert!(size.is_some()); + assert!(size.unwrap() == 18); +} + +#[test] +fn test_size_of_packed_struct_with_fixed_array() { + let size = Introspect::::size(); + assert!(size.is_some()); + assert!(size.unwrap() == 3); +} + +#[test] +fn test_size_of_enum_with_fixed_array() { + let size = Introspect::::size(); + assert!(size.is_some()); + assert!(size.unwrap() == 4); +} + +#[test] +fn test_size_of_packed_enum_with_fixed_array() { + let size = Introspect::::size(); + assert!(size.is_some()); + assert!(size.unwrap() == 4); +} + #[test] fn test_layout_of_enum_without_variant_data() { let layout = Introspect::::layout(); @@ -264,6 +327,56 @@ fn test_layout_of_struct_with_option() { assert!(layout == expected); } +#[test] +fn test_layout_of_struct_with_fixed_array() { + let layout = Introspect::::layout(); + let expected = Layout::Struct( + array![field(selector!("x"), fixed_array(Introspect::::layout(), 3))].span() + ); + + assert!(layout == expected); +} + +#[test] +fn test_layout_of_struct_with_complex_fixed_array() { + let layout = Introspect::::layout(); + let expected = Layout::Struct( + array![ + field( + selector!("x"), + fixed_array(fixed_array(Introspect::::layout(), 2), 3) + ) + ] + .span() + ); + + assert!(layout == expected); +} + +#[test] +fn test_layout_of_packed_struct_with_fixed_array() { + let layout = Introspect::::layout(); + let expected = Layout::Fixed([8, 8, 8].span()); + + assert!(layout == expected); +} + +#[test] +fn test_layout_of_enum_with_fixed_array() { + let layout = Introspect::::layout(); + let expected = _enum(array![Option::Some(fixed_array(Introspect::::layout(), 3))]); + + assert!(layout == expected); +} + +#[test] +fn test_layout_of_packed_enum_with_fixed_array() { + let layout = Introspect::::layout(); + let expected = Layout::Fixed([8, 8, 8, 8].span()); + + assert!(layout == expected); +} + #[test] fn test_layout_of_packed_struct() { let layout = Introspect::::layout(); @@ -286,7 +399,6 @@ fn test_layout_of_not_packed_inner_struct() { let _ = Introspect::::layout(); } - #[test] fn test_layout_of_packed_enum() { let layout = Introspect::::layout(); diff --git a/crates/dojo/lang/src/derive_macros/introspect/layout.rs b/crates/dojo/lang/src/derive_macros/introspect/layout.rs index 43667fe502..3e40c129e3 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/layout.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/layout.rs @@ -7,8 +7,9 @@ use cairo_lang_syntax::node::{ids, Terminal, TypedSyntaxNode}; use starknet::core::utils::get_selector_from_name; use super::utils::{ - get_array_item_type, get_tuple_item_types, is_array, is_byte_array, is_tuple, - is_unsupported_option_type, primitive_type_introspection, + get_array_item_type, get_fixed_array_inner_type_and_size, get_tuple_item_types, is_array, + is_byte_array, is_fixed_array, is_tuple, is_unsupported_option_type, + primitive_type_introspection, }; /// build the full layout for every field in the Struct. @@ -90,6 +91,14 @@ pub fn get_layout_from_type_clause( let tuple_type = expr.as_syntax_node().get_text(db); build_tuple_layout_from_type(diagnostics, type_clause.stable_ptr().0, &tuple_type) } + Expr::FixedSizeArray(expr) => { + let fixed_array_type = expr.as_syntax_node().get_text(db); + build_fixed_array_layout_from_type( + diagnostics, + type_clause.stable_ptr().0, + &fixed_array_type, + ) + } _ => { diagnostics.push(PluginDiagnostic { stable_ptr: type_clause.stable_ptr().0, @@ -155,6 +164,24 @@ pub fn build_tuple_layout_from_type( ) } +/// +pub fn build_fixed_array_layout_from_type( + diagnostics: &mut Vec, + diagnostic_item: ids::SyntaxStablePtrId, + array_type: &str, +) -> String { + let (inner_type, array_size) = get_fixed_array_inner_type_and_size(array_type); + let array_type_layout = build_item_layout_from_type(diagnostics, diagnostic_item, &inner_type); + + format!( + "dojo::meta::layout::Layout::FixedArray( + array![ + ({array_type_layout}, {array_size}) + ].span() + )" + ) +} + /// Build the layout describing the provided type. /// item_type could be any type (array, tuple, struct, ...) pub fn build_item_layout_from_type( @@ -166,6 +193,8 @@ pub fn build_item_layout_from_type( build_array_layout_from_type(diagnostics, diagnostic_item, item_type) } else if is_tuple(item_type) { build_tuple_layout_from_type(diagnostics, diagnostic_item, item_type) + } else if is_fixed_array(item_type) { + build_fixed_array_layout_from_type(diagnostics, diagnostic_item, item_type) } else { // For Option, T cannot be a tuple if is_unsupported_option_type(item_type) { @@ -317,6 +346,14 @@ pub fn get_packed_field_layout_from_type_clause( let tuple_type = expr.as_syntax_node().get_text(db); get_packed_tuple_layout_from_type(diagnostics, type_clause.stable_ptr().0, &tuple_type) } + Expr::FixedSizeArray(expr) => { + let array_type = expr.as_syntax_node().get_text(db); + get_packed_fixed_array_layout_from_type( + diagnostics, + type_clause.stable_ptr().0, + &array_type, + ) + } _ => { diagnostics.push(PluginDiagnostic { stable_ptr: type_clause.stable_ptr().0, @@ -343,6 +380,8 @@ pub fn get_packed_item_layout_from_type( vec!["ERROR".to_string()] } else if is_tuple(item_type) { get_packed_tuple_layout_from_type(diagnostics, diagnostic_item, item_type) + } else if is_fixed_array(item_type) { + get_packed_fixed_array_layout_from_type(diagnostics, diagnostic_item, item_type) } else { let primitives = primitive_type_introspection(); @@ -368,3 +407,15 @@ pub fn get_packed_tuple_layout_from_type( .flat_map(|x| get_packed_item_layout_from_type(diagnostics, diagnostic_item, x)) .collect::>() } + +pub fn get_packed_fixed_array_layout_from_type( + diagnostics: &mut Vec, + diagnostic_item: ids::SyntaxStablePtrId, + array_type: &str, +) -> Vec { + let (inner_type, array_size) = get_fixed_array_inner_type_and_size(array_type); + let inner_type_layout = + get_packed_item_layout_from_type(diagnostics, diagnostic_item, &inner_type).join(","); + + (0..array_size.trim().parse().unwrap()).map(|_| inner_type_layout.clone()).collect::>() +} diff --git a/crates/dojo/lang/src/derive_macros/introspect/size.rs b/crates/dojo/lang/src/derive_macros/introspect/size.rs index efb81ea25d..320b0dae3f 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/size.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/size.rs @@ -4,7 +4,8 @@ use cairo_lang_syntax::node::helpers::QueryAttrs; use cairo_lang_syntax::node::TypedSyntaxNode; use super::utils::{ - get_tuple_item_types, is_array, is_byte_array, is_tuple, primitive_type_introspection, + get_fixed_array_inner_type_and_size, get_tuple_item_types, is_array, is_byte_array, + is_fixed_array, is_tuple, primitive_type_introspection, }; pub fn compute_struct_layout_size( @@ -149,6 +150,10 @@ pub fn get_field_size_from_type_clause( let tuple_type = expr.as_syntax_node().get_text(db).trim().to_string(); compute_tuple_size_from_type(&tuple_type) } + Expr::FixedSizeArray(expr) => { + let array_type = expr.as_syntax_node().get_text(db).trim().to_string(); + compute_fixed_array_size_from_type(&array_type) + } _ => { // field type already checked while building the layout vec!["ERROR".to_string()] @@ -181,6 +186,8 @@ pub fn compute_item_size_from_type(item_type: &String) -> Vec { vec!["Option::None".to_string()] } else if is_tuple(item_type) { compute_tuple_size_from_type(item_type) + } else if is_fixed_array(item_type) { + compute_fixed_array_size_from_type(item_type) } else { let primitives = primitive_type_introspection(); @@ -198,3 +205,13 @@ pub fn compute_tuple_size_from_type(tuple_type: &str) -> Vec { .flat_map(compute_item_size_from_type) .collect::>() } + +pub fn compute_fixed_array_size_from_type(array_type: &str) -> Vec { + let (inner_type, array_size) = get_fixed_array_inner_type_and_size(array_type); + let inner_type_size = compute_item_size_from_type(&inner_type); + + (0..array_size.trim().parse().unwrap()) + .map(|_| inner_type_size.clone()) + .flatten() + .collect::>() +} diff --git a/crates/dojo/lang/src/derive_macros/introspect/ty.rs b/crates/dojo/lang/src/derive_macros/introspect/ty.rs index d9e9e40a11..fb001e94f6 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/ty.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/ty.rs @@ -5,7 +5,10 @@ use cairo_lang_syntax::node::db::SyntaxGroup; use cairo_lang_syntax::node::helpers::QueryAttrs; use cairo_lang_syntax::node::{Terminal, TypedSyntaxNode}; -use super::utils::{get_array_item_type, get_tuple_item_types, is_array, is_byte_array, is_tuple}; +use super::utils::{ + get_array_item_type, get_fixed_array_inner_type_and_size, get_tuple_item_types, is_array, + is_byte_array, is_fixed_array, is_tuple, +}; pub fn build_struct_ty(db: &dyn SyntaxGroup, name: &String, struct_ast: &ItemStruct) -> String { let members_ty = struct_ast @@ -89,6 +92,10 @@ pub fn build_ty_from_type_clause(db: &dyn SyntaxGroup, type_clause: &TypeClause) let tuple_type = expr.as_syntax_node().get_text(db).trim().to_string(); build_tuple_ty_from_type(&tuple_type) } + Expr::FixedSizeArray(expr) => { + let array_type = expr.as_syntax_node().get_text(db).trim().to_string(); + build_fixed_array_ty_from_type(&array_type) + } _ => { // diagnostic message already handled in layout building "ERROR".to_string() @@ -111,6 +118,8 @@ pub fn build_item_ty_from_type(item_type: &String) -> String { "dojo::meta::introspect::Ty::ByteArray".to_string() } else if is_tuple(item_type) { build_tuple_ty_from_type(item_type) + } else if is_fixed_array(item_type) { + build_fixed_array_ty_from_type(item_type) } else { format!("dojo::meta::introspect::Introspect::<{}>::ty()", item_type) } @@ -131,3 +140,14 @@ pub fn build_tuple_ty_from_type(item_type: &str) -> String { tuple_items ) } + +pub fn build_fixed_array_ty_from_type(array_type: &str) -> String { + let (inner_type, array_size) = get_fixed_array_inner_type_and_size(array_type); + let inner_type_ty = build_item_ty_from_type(&inner_type); + + format!( + "dojo::meta::introspect::Ty::FixedArray( + array![({inner_type_ty}, {array_size})].span() + )" + ) +} diff --git a/crates/dojo/lang/src/derive_macros/introspect/utils.rs b/crates/dojo/lang/src/derive_macros/introspect/utils.rs index f57f6b6335..2a6f1b1549 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/utils.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/utils.rs @@ -39,6 +39,10 @@ pub fn is_tuple(ty: &str) -> bool { ty.starts_with('(') } +pub fn is_fixed_array(ty: &str) -> bool { + ty.starts_with('[') && ty.ends_with(']') +} + pub fn get_array_item_type(ty: &str) -> String { if ty.starts_with("Array<") { ty.trim().strip_prefix("Array<").unwrap().strip_suffix('>').unwrap().to_string() @@ -47,6 +51,19 @@ pub fn get_array_item_type(ty: &str) -> String { } } +pub fn trim_first_and_last_chars(s: &str) -> &str { + let mut chars = s.trim().chars(); + chars.next(); + chars.next_back(); + chars.as_str() +} + +pub fn get_fixed_array_inner_type_and_size(ty: &str) -> (String, String) { + let ty = trim_first_and_last_chars(ty); + let res: Vec<&str> = ty.rsplitn(2, ';').collect(); + (res[1].trim().to_string(), res[0].trim().to_string()) +} + /// split a tuple in array of items (nested tuples are not splitted). /// example (u8, (u16, u32), u128) -> ["u8", "(u16, u32)", "u128"] pub fn get_tuple_item_types(ty: &str) -> Vec { From 5f179814216934030640547fdac707d5e9889bba Mon Sep 17 00:00:00 2001 From: Bengineer Date: Mon, 6 Jan 2025 12:54:26 +0000 Subject: [PATCH 09/14] Merged remy changes --- .../src/derive_macros/introspect/layout.rs | 58 +++++++------------ .../lang/src/derive_macros/introspect/ty.rs | 2 +- .../src/derive_macros/introspect/utils.rs | 17 ++---- 3 files changed, 25 insertions(+), 52 deletions(-) diff --git a/crates/dojo/lang/src/derive_macros/introspect/layout.rs b/crates/dojo/lang/src/derive_macros/introspect/layout.rs index 6d0190916f..84ba1061bc 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/layout.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/layout.rs @@ -182,32 +182,6 @@ pub fn build_member_layout_from_type( } } -pub fn build_fixed_array_layout_from_type( - diagnostics: &mut Vec, - diagnostic_item: ids::SyntaxStablePtrId, - item_type: &str, -) -> String { - let (array_item_type, array_size) = get_fixed_array_type_and_size(item_type); - match build_member_layout_from_type(diagnostics, diagnostic_item, &array_item_type) { - Wrapper::Introspect => { - format!( - "dojo::meta::introspect::Introspect::<[{}; {}]>::layout()", - array_item_type, array_size - ) - } - Wrapper::Array(layout) => { - format!( - "dojo::meta::Layout::FixedArray( - array![ - ({}, {}) - ].span(), - )", - layout, array_size - ) - } - } -} - /// Build the tuple layout describing the provided tuple type. /// item_type could be something like (u8, u32, u128) for example. pub fn build_tuple_layout_from_type( @@ -230,22 +204,30 @@ pub fn build_tuple_layout_from_type( ) } -/// pub fn build_fixed_array_layout_from_type( diagnostics: &mut Vec, diagnostic_item: ids::SyntaxStablePtrId, - array_type: &str, + item_type: &str, ) -> String { - let (inner_type, array_size) = get_fixed_array_inner_type_and_size(array_type); - let array_type_layout = build_item_layout_from_type(diagnostics, diagnostic_item, &inner_type); - - format!( - "dojo::meta::layout::Layout::FixedArray( - array![ - ({array_type_layout}, {array_size}) - ].span() - )" - ) + let (array_item_type, array_size) = get_fixed_array_inner_type_and_size(item_type); + match build_member_layout_from_type(diagnostics, diagnostic_item, &array_item_type) { + Wrapper::Introspect => { + format!( + "dojo::meta::introspect::Introspect::<[{}; {}]>::layout()", + array_item_type, array_size + ) + } + Wrapper::Array(layout) => { + format!( + "dojo::meta::Layout::FixedArray( + array![ + ({}, {}) + ].span(), + )", + layout, array_size + ) + } + } } /// Build the layout describing the provided type. diff --git a/crates/dojo/lang/src/derive_macros/introspect/ty.rs b/crates/dojo/lang/src/derive_macros/introspect/ty.rs index bd785a710a..87070cf4e7 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/ty.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/ty.rs @@ -115,7 +115,7 @@ pub fn build_item_ty_from_type(item_type: &String) -> String { build_item_ty_from_type(&array_item_type) ) } else if is_fixed_array(item_type) { - let (array_item_type, size) = get_fixed_array_type_and_size(&item_type); + let (array_item_type, size) = get_fixed_array_inner_type_and_size(&item_type); format!( "dojo::meta::introspect::Ty::FixedArray( array![ diff --git a/crates/dojo/lang/src/derive_macros/introspect/utils.rs b/crates/dojo/lang/src/derive_macros/introspect/utils.rs index e8eb06a2c9..bb1fdbdb7f 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/utils.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/utils.rs @@ -1,7 +1,7 @@ use regex::Regex; use std::collections::HashMap; -const FIXED_ARRAY_REGEX: &str = r"\[[^;]+;\s*\d{1,10}\s*\]"; +const FIXED_ARRAY_REGEX: &str = r"\[.+;\s*(\d{1,10}|([a-zA-Z_{1}][a-zA-Z0-9_]*))\s*\]"; // Matches [*;(u32 or variable_name)] #[derive(Clone, Default, Debug)] pub struct TypeIntrospection(pub usize, pub Vec); @@ -38,13 +38,9 @@ pub fn is_array(ty: &str) -> bool { ty.starts_with("Array<") || ty.starts_with("Span<") } -// pub fn is_fixed_array(ty: &str) -> bool { -// let re = Regex::new(FIXED_ARRAY_REGEX).unwrap(); -// re.is_match(ty) -// } - pub fn is_fixed_array(ty: &str) -> bool { - ty.starts_with('[') && ty.ends_with(']') + let re = Regex::new(FIXED_ARRAY_REGEX).unwrap(); + re.is_match(ty) } pub fn is_tuple(ty: &str) -> bool { @@ -58,16 +54,11 @@ pub fn get_array_item_type(ty: &str) -> String { ty.trim().strip_prefix("Span<").unwrap().strip_suffix('>').unwrap().to_string() } } - -pub fn get_fixed_array_type_and_size(ty: &str) -> (String, usize) { - let mut parts = ty.trim().strip_prefix('[').unwrap().strip_suffix(']').unwrap().rsplit(2, ';'); - (parts.next().unwrap().trim().to_string(), parts.last().unwrap().trim().parse().unwrap()) -} pub fn trim_first_and_last_chars(s: &str) -> &str { let mut chars = s.trim().chars(); chars.next(); chars.next_back(); - chars.as_str() + chars.as_str().trim() } pub fn get_fixed_array_inner_type_and_size(ty: &str) -> (String, String) { From b121e74f52da8fb4df50ce73b38cd45717bb2fa7 Mon Sep 17 00:00:00 2001 From: Bengineer Date: Mon, 6 Jan 2025 12:57:13 +0000 Subject: [PATCH 10/14] Merged remy changes --- .../src/derive_macros/introspect/layout.rs | 57 ++++++++++++------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/crates/dojo/lang/src/derive_macros/introspect/layout.rs b/crates/dojo/lang/src/derive_macros/introspect/layout.rs index 84ba1061bc..5bb4176f5d 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/layout.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/layout.rs @@ -204,30 +204,47 @@ pub fn build_tuple_layout_from_type( ) } +// pub fn build_fixed_array_layout_from_type( +// diagnostics: &mut Vec, +// diagnostic_item: ids::SyntaxStablePtrId, +// item_type: &str, +// ) -> String { +// let (array_item_type, array_size) = get_fixed_array_inner_type_and_size(item_type); +// match build_member_layout_from_type(diagnostics, diagnostic_item, &array_item_type) { +// Wrapper::Introspect => { +// format!( +// "dojo::meta::introspect::Introspect::<[{}; {}]>::layout()", +// array_item_type, array_size +// ) +// } +// Wrapper::Array(layout) => { +// format!( +// "dojo::meta::Layout::FixedArray( +// array![ +// ({}, {}) +// ].span(), +// )", +// layout, array_size +// ) +// } +// } +// } + pub fn build_fixed_array_layout_from_type( diagnostics: &mut Vec, diagnostic_item: ids::SyntaxStablePtrId, - item_type: &str, + array_type: &str, ) -> String { - let (array_item_type, array_size) = get_fixed_array_inner_type_and_size(item_type); - match build_member_layout_from_type(diagnostics, diagnostic_item, &array_item_type) { - Wrapper::Introspect => { - format!( - "dojo::meta::introspect::Introspect::<[{}; {}]>::layout()", - array_item_type, array_size - ) - } - Wrapper::Array(layout) => { - format!( - "dojo::meta::Layout::FixedArray( - array![ - ({}, {}) - ].span(), - )", - layout, array_size - ) - } - } + let (inner_type, array_size) = get_fixed_array_inner_type_and_size(array_type); + let array_type_layout = build_item_layout_from_type(diagnostics, diagnostic_item, &inner_type); + + format!( + "dojo::meta::layout::Layout::FixedArray( + array![ + ({array_type_layout}, {array_size}) + ].span() + )" + ) } /// Build the layout describing the provided type. From c6d4dc31c0c9769142ebc31c44d00723224d8b3e Mon Sep 17 00:00:00 2001 From: "remy.baranx@gmail.com" Date: Mon, 6 Jan 2025 15:22:47 +0100 Subject: [PATCH 11/14] some fixes --- .../src/tests/model/model.cairo | 26 +++ crates/dojo/core/src/storage/layout.cairo | 179 +++++++----------- .../src/derive_macros/introspect/layout.rs | 106 +++-------- 3 files changed, 118 insertions(+), 193 deletions(-) diff --git a/crates/dojo/core-cairo-test/src/tests/model/model.cairo b/crates/dojo/core-cairo-test/src/tests/model/model.cairo index ff48b33192..56f0fcd3e3 100644 --- a/crates/dojo/core-cairo-test/src/tests/model/model.cairo +++ b/crates/dojo/core-cairo-test/src/tests/model/model.cairo @@ -25,11 +25,21 @@ struct Foo2 { v2: u32 } + +#[derive(Copy, Drop, Serde, Debug)] +#[dojo::model] +struct ModelWithFixedArray { + #[key] + k1: u8, + v1: [u16; 3] +} + fn namespace_def() -> NamespaceDef { NamespaceDef { namespace: "dojo_cairo_test", resources: [ TestResource::Model(m_Foo::TEST_CLASS_HASH.try_into().unwrap()), TestResource::Model(m_Foo2::TEST_CLASS_HASH.try_into().unwrap()), + TestResource::Model(m_ModelWithFixedArray::TEST_CLASS_HASH.try_into().unwrap()), ].span() } } @@ -181,3 +191,19 @@ fn test_model_ptr_from_entity_id() { let v1 = world.read_member(ptr, selector!("v1")); assert!(foo.v1 == v1); } + +#[test] +fn test_model_with_fixed_array() { + let mut world = spawn_foo_world(); + let model = ModelWithFixedArray { k1: 1, v1: [4, 32, 256] }; + + world.write_model(@model); + let read_model: ModelWithFixedArray = world.read_model(model.keys()); + + assert!(model.v1 == read_model.v1); + + world.erase_model(@model); + let read_model: ModelWithFixedArray = world.read_model(model.keys()); + + assert!(read_model.v1 == [0, 0, 0]); +} diff --git a/crates/dojo/core/src/storage/layout.cairo b/crates/dojo/core/src/storage/layout.cairo index 5310a1ec4c..286577ce12 100644 --- a/crates/dojo/core/src/storage/layout.cairo +++ b/crates/dojo/core/src/storage/layout.cairo @@ -71,20 +71,14 @@ pub fn write_array_layout( // and then, write array items let item_layout = *item_layout.at(0); - let mut i = 0; - loop { - if i >= array_len { - break; - } - let key = combine_key(key, i.into()); - - write_layout(model, key, values, ref offset, item_layout); - - i += 1; - }; + for i in 0 + ..array_len { + let key = combine_key(key, i.into()); + write_layout(model, key, values, ref offset, item_layout); + }; } -/// Write array layout model record to the world storage. +/// Write fixed array layout model record to the world storage. /// /// # Arguments /// * `model` - the model selector. @@ -100,16 +94,10 @@ pub fn write_fixed_array_layout( 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; + // Note: no need to write the array length as it is fixed at compile-time + // and stored in the layout. - // and then, write array items for i in 0 ..array_len { write_layout(model, combine_key(key, i.into()), values, ref offset, item_layout); @@ -155,19 +143,14 @@ pub fn write_byte_array_layout( pub fn write_struct_layout( model: felt252, key: felt252, values: Span, ref offset: u32, layout: Span ) { - let mut i = 0; - loop { - if i >= layout.len() { - break; - } - - let field_layout = *layout.at(i); - let field_key = combine_key(key, field_layout.selector); - - write_layout(model, field_key, values, ref offset, field_layout.layout); + for i in 0 + ..layout + .len() { + let field_layout = *layout.at(i); + let field_key = combine_key(key, field_layout.selector); - i += 1; - } + write_layout(model, field_key, values, ref offset, field_layout.layout); + }; } /// Write tuple layout model record to the world storage. @@ -181,19 +164,14 @@ pub fn write_struct_layout( pub fn write_tuple_layout( model: felt252, key: felt252, values: Span, ref offset: u32, layout: Span ) { - let mut i = 0; - loop { - if i >= layout.len() { - break; - } - - let field_layout = *layout.at(i); - let key = combine_key(key, i.into()); - - write_layout(model, key, values, ref offset, field_layout); + for i in 0 + ..layout + .len() { + let field_layout = *layout.at(i); + let key = combine_key(key, i.into()); - i += 1; - }; + write_layout(model, key, values, ref offset, field_layout); + }; } pub fn write_enum_layout( @@ -247,9 +225,14 @@ pub fn delete_array_layout(model: felt252, key: felt252) { database::delete(model, key, [packing::PACKING_MAX_BITS].span()); } +/// Delete a fixed array layout model record from the world storage. +/// +/// # Arguments +/// * `model` - the model selector. +/// * `key` - the model record key. +/// * `layout` - the model layout. 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); } @@ -298,19 +281,14 @@ pub fn delete_layout(model: felt252, key: felt252, layout: Layout) { /// * `key` - the model record key. /// * `layout` - list of field layouts. pub fn delete_struct_layout(model: felt252, key: felt252, layout: Span) { - let mut i = 0; - loop { - if i >= layout.len() { - break; - } - - let field_layout = *layout.at(i); - let key = combine_key(key, field_layout.selector); - - delete_layout(model, key, field_layout.layout); + for i in 0 + ..layout + .len() { + let field_layout = *layout.at(i); + let key = combine_key(key, field_layout.selector); - i += 1; - } + delete_layout(model, key, field_layout.layout); + }; } /// Delete a tuple layout model record from the world storage. @@ -320,19 +298,14 @@ pub fn delete_struct_layout(model: felt252, key: felt252, layout: Span) { - let mut i = 0; - loop { - if i >= layout.len() { - break; - } - - let field_layout = *layout.at(i); - let key = combine_key(key, i.into()); - - delete_layout(model, key, field_layout); + for i in 0 + ..layout + .len() { + let field_layout = *layout.at(i); + let key = combine_key(key, i.into()); - i += 1; - } + delete_layout(model, key, field_layout); + }; } pub fn delete_enum_layout(model: felt252, key: felt252, variant_layouts: Span) { @@ -410,31 +383,24 @@ pub fn read_array_layout( let item_layout = *layout.at(0); let array_len: u32 = array_len.try_into().unwrap(); - 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 { + let field_key = combine_key(key, i.into()); + read_layout(model, field_key, ref read_data, item_layout); + }; } +/// Read a fixed array layout model record. +/// +/// # Arguments +/// * `model` - the model selector +/// * `key` - model record key. +/// * `read_data` - the read data. +/// * `layout` - the array item 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()); - for i in 0 ..array_len { read_layout(model, combine_key(key, i.into()), ref read_data, item_layout); @@ -477,19 +443,14 @@ pub fn read_byte_array_layout(model: felt252, key: felt252, ref read_data: Array pub fn read_struct_layout( model: felt252, key: felt252, ref read_data: Array, layout: Span ) { - let mut i = 0; - loop { - if i >= layout.len() { - break; - } - - let field_layout = *layout.at(i); - let field_key = combine_key(key, field_layout.selector); - - read_layout(model, field_key, ref read_data, field_layout.layout); + for i in 0 + ..layout + .len() { + let field_layout = *layout.at(i); + let field_key = combine_key(key, field_layout.selector); - i += 1; - } + read_layout(model, field_key, ref read_data, field_layout.layout); + }; } /// Read a tuple layout model record. @@ -502,18 +463,14 @@ pub fn read_struct_layout( pub fn read_tuple_layout( model: felt252, key: felt252, ref read_data: Array, layout: Span ) { - let mut i = 0; - loop { - if i >= layout.len() { - break; - } - - let field_layout = *layout.at(i); - let field_key = combine_key(key, i.into()); - read_layout(model, field_key, ref read_data, field_layout); + for i in 0 + ..layout + .len() { + let field_layout = *layout.at(i); + let field_key = combine_key(key, i.into()); - i += 1; - }; + read_layout(model, field_key, ref read_data, field_layout); + }; } pub fn read_enum_layout( diff --git a/crates/dojo/lang/src/derive_macros/introspect/layout.rs b/crates/dojo/lang/src/derive_macros/introspect/layout.rs index 5bb4176f5d..2a93f60dbb 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/layout.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/layout.rs @@ -122,36 +122,11 @@ pub fn build_array_layout_from_type( diagnostic_item: ids::SyntaxStablePtrId, item_type: &str, ) -> String { - // let array_item_type = get_array_item_type(item_type); - - // if is_tuple(&array_item_type) { - // format!( - // "dojo::meta::Layout::Array( - // array![ - // {} - // ].span() - // )", - // build_item_layout_from_type(diagnostics, diagnostic_item, &array_item_type) - // ) - // } else if is_array(&array_item_type) { - // format!( - // "dojo::meta::Layout::Array( - // array![ - // {} - // ].span() - // )", - // build_array_layout_from_type(diagnostics, diagnostic_item, &array_item_type) - // ) - // } else { - // format!("dojo::meta::introspect::Introspect::<{}>::layout()", item_type) - // } - // } - let array_item_type = get_array_item_type(item_type); match build_member_layout_from_type(diagnostics, diagnostic_item, &array_item_type) { Wrapper::Introspect => { - format!("dojo::meta::introspect::Introspect::<{}>::layout()", array_item_type) + format!("dojo::meta::introspect::Introspect::<{}>::layout()", item_type) } Wrapper::Array(layout) => { format!( @@ -204,47 +179,28 @@ pub fn build_tuple_layout_from_type( ) } -// pub fn build_fixed_array_layout_from_type( -// diagnostics: &mut Vec, -// diagnostic_item: ids::SyntaxStablePtrId, -// item_type: &str, -// ) -> String { -// let (array_item_type, array_size) = get_fixed_array_inner_type_and_size(item_type); -// match build_member_layout_from_type(diagnostics, diagnostic_item, &array_item_type) { -// Wrapper::Introspect => { -// format!( -// "dojo::meta::introspect::Introspect::<[{}; {}]>::layout()", -// array_item_type, array_size -// ) -// } -// Wrapper::Array(layout) => { -// format!( -// "dojo::meta::Layout::FixedArray( -// array![ -// ({}, {}) -// ].span(), -// )", -// layout, array_size -// ) -// } -// } -// } - pub fn build_fixed_array_layout_from_type( diagnostics: &mut Vec, diagnostic_item: ids::SyntaxStablePtrId, - array_type: &str, + item_type: &str, ) -> String { - let (inner_type, array_size) = get_fixed_array_inner_type_and_size(array_type); - let array_type_layout = build_item_layout_from_type(diagnostics, diagnostic_item, &inner_type); - - format!( - "dojo::meta::layout::Layout::FixedArray( - array![ - ({array_type_layout}, {array_size}) - ].span() - )" - ) + let (array_item_type, array_size) = get_fixed_array_inner_type_and_size(item_type); + match build_member_layout_from_type(diagnostics, diagnostic_item, &array_item_type) { + Wrapper::Introspect => { + format!( + "dojo::meta::introspect::Introspect::<[{array_item_type}; {array_size}]>::layout()", + ) + } + Wrapper::Array(layout) => { + format!( + "dojo::meta::Layout::FixedArray( + array![ + ({layout}, {array_size}) + ].span(), + )", + ) + } + } } /// Build the layout describing the provided type. @@ -256,8 +212,6 @@ pub fn build_item_layout_from_type( ) -> String { if is_array(item_type) { build_array_layout_from_type(diagnostics, diagnostic_item, item_type) - // } else if is_fixed_array(item_type) { - // build_fixed_array_layout_from_type(diagnostics, diagnostic_item, item_type) } else if is_tuple(item_type) { build_tuple_layout_from_type(diagnostics, diagnostic_item, item_type) } else if is_fixed_array(item_type) { @@ -327,27 +281,15 @@ pub fn generate_cairo_code_for_fixed_layout_with_custom_types(layouts: &[String] .join(",\n"); format!( - "let mut layouts = array![ + "let layouts = array![ {layouts_repr} ]; let mut merged_layout = ArrayTrait::::new(); - loop {{ - match ArrayTrait::pop_front(ref layouts) {{ - Option::Some(mut layout) => {{ - match layout {{ - dojo::meta::Layout::Fixed(mut l) => {{ - loop {{ - match SpanTrait::pop_front(ref l) {{ - Option::Some(x) => merged_layout.append(*x), - Option::None(_) => {{ break; }} - }}; - }}; - }}, - _ => panic!(\"A packed model layout must contain Fixed layouts only.\"), - }}; - }}, - Option::None(_) => {{ break; }} + for layout in layouts {{ + match layout {{ + dojo::meta::Layout::Fixed(mut l) => merged_layout.append_span(l), + _ => panic!(\"A packed model layout must contain Fixed layouts only.\"), }}; }}; From 0d7f0ed9e2bd176fd288ccbc795e0987732f571a Mon Sep 17 00:00:00 2001 From: Bengineer Date: Fri, 10 Jan 2025 15:56:36 +0000 Subject: [PATCH 12/14] formated --- crates/dojo/lang/src/derive_macros/introspect/utils.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/dojo/lang/src/derive_macros/introspect/utils.rs b/crates/dojo/lang/src/derive_macros/introspect/utils.rs index bb1fdbdb7f..d3f532c882 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/utils.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/utils.rs @@ -1,7 +1,9 @@ -use regex::Regex; use std::collections::HashMap; -const FIXED_ARRAY_REGEX: &str = r"\[.+;\s*(\d{1,10}|([a-zA-Z_{1}][a-zA-Z0-9_]*))\s*\]"; // Matches [*;(u32 or variable_name)] +use regex::Regex; + +// Matches [*;(u32 or variable_name)] +const FIXED_ARRAY_REGEX: &str = r"\[.+;\s*(\d{1,10}|([a-zA-Z_{1}][a-zA-Z0-9_]*))\s*\]"; #[derive(Clone, Default, Debug)] pub struct TypeIntrospection(pub usize, pub Vec); From 75abcb91bbfba02d2b51fc7139962313956ef9aa Mon Sep 17 00:00:00 2001 From: Bengineer Date: Fri, 10 Jan 2025 16:20:53 +0000 Subject: [PATCH 13/14] fix: changed flatten map to flat_map --- crates/dojo/lang/src/derive_macros/introspect/size.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/dojo/lang/src/derive_macros/introspect/size.rs b/crates/dojo/lang/src/derive_macros/introspect/size.rs index 320b0dae3f..3c34c9e72b 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/size.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/size.rs @@ -211,7 +211,6 @@ pub fn compute_fixed_array_size_from_type(array_type: &str) -> Vec { let inner_type_size = compute_item_size_from_type(&inner_type); (0..array_size.trim().parse().unwrap()) - .map(|_| inner_type_size.clone()) - .flatten() + .flat_map(|_| inner_type_size.clone()) .collect::>() } From 59cb8f3715a1ed5435fa60cfa8ad85e6441834f3 Mon Sep 17 00:00:00 2001 From: Bengineer Date: Fri, 10 Jan 2025 16:36:57 +0000 Subject: [PATCH 14/14] fix: take away unneeded reference --- crates/dojo/lang/src/derive_macros/introspect/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/dojo/lang/src/derive_macros/introspect/ty.rs b/crates/dojo/lang/src/derive_macros/introspect/ty.rs index 87070cf4e7..10fd5581e5 100644 --- a/crates/dojo/lang/src/derive_macros/introspect/ty.rs +++ b/crates/dojo/lang/src/derive_macros/introspect/ty.rs @@ -115,7 +115,7 @@ pub fn build_item_ty_from_type(item_type: &String) -> String { build_item_ty_from_type(&array_item_type) ) } else if is_fixed_array(item_type) { - let (array_item_type, size) = get_fixed_array_inner_type_and_size(&item_type); + let (array_item_type, size) = get_fixed_array_inner_type_and_size(item_type); format!( "dojo::meta::introspect::Ty::FixedArray( array![