From 24964ced3a4d9f25e5356259374c633f97e8d90f Mon Sep 17 00:00:00 2001 From: Benjamin <158306087+bengineer42@users.noreply.github.com> Date: Tue, 5 Nov 2024 21:38:56 +0000 Subject: [PATCH] Re added members and converted ModelPtr to a struct (#2634) * added member access back into the world store * added tests * simpolifying modelptr * Made model ptr a struct * added test * CHanged to match Model convention * Merged in main * Fixed lib * added tests * Empty commit * added tests * simpolifying modelptr * Made model ptr a struct * Empty commit * removed duplicate test * fix: remove ptrs to let user manage this part * fix: fix spaces --------- Co-authored-by: glihm --- Cargo.lock | 28 ++--- Cargo.toml | 6 +- crates/dojo/core-cairo-test/src/lib.cairo | 6 +- .../src/tests/helpers/helpers.cairo | 2 +- .../src/tests/model/model.cairo | 113 ++++++++---------- crates/dojo/core/src/lib.cairo | 6 +- crates/dojo/core/src/model/model.cairo | 41 ++++++- crates/dojo/core/src/model/storage.cairo | 23 ++-- crates/dojo/core/src/world/storage.cairo | 82 +++++++------ examples/simple/src/lib.cairo | 9 +- 10 files changed, 168 insertions(+), 148 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b916467c27..e85734ffff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2727,7 +2727,7 @@ dependencies = [ [[package]] name = "cairo-lang-macro" version = "0.1.0" -source = "git+https://github.com/remybar/scarb?rev=fbad7d8d6bdb763b413055d8d9f8b7995672f145#fbad7d8d6bdb763b413055d8d9f8b7995672f145" +source = "git+https://github.com/dojoengine/scarb?rev=b9965b7e2f0d97f2a97f18ca9a75bac541de7d84#b9965b7e2f0d97f2a97f18ca9a75bac541de7d84" dependencies = [ "cairo-lang-macro-attributes", "cairo-lang-macro-stable", @@ -3974,7 +3974,7 @@ dependencies = [ [[package]] name = "create-output-dir" version = "1.0.0" -source = "git+https://github.com/remybar/scarb?rev=fbad7d8d6bdb763b413055d8d9f8b7995672f145#fbad7d8d6bdb763b413055d8d9f8b7995672f145" +source = "git+https://github.com/dojoengine/scarb?rev=b9965b7e2f0d97f2a97f18ca9a75bac541de7d84#b9965b7e2f0d97f2a97f18ca9a75bac541de7d84" dependencies = [ "anyhow", "core-foundation 0.10.0", @@ -4678,7 +4678,7 @@ dependencies = [ [[package]] name = "dojo-lang" version = "1.0.0-rc.1" -source = "git+https://github.com/remybar/dojo.git?branch=upgradeable_models#f6cff5f8b3d5265f0b9656a8df57d84531248565" +source = "git+https://github.com/dojoengine/dojo?rev=8b2d976c9d65cee1b5a5c5f3c8e49223507c1995#8b2d976c9d65cee1b5a5c5f3c8e49223507c1995" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -4696,7 +4696,7 @@ dependencies = [ "cairo-lang-utils", "camino", "convert_case 0.6.0", - "dojo-types 1.0.0-rc.1 (git+https://github.com/remybar/dojo.git?branch=upgradeable_models)", + "dojo-types 1.0.0-rc.1 (git+https://github.com/dojoengine/dojo?rev=8b2d976c9d65cee1b5a5c5f3c8e49223507c1995)", "indoc 1.0.9", "itertools 0.12.1", "regex", @@ -4789,7 +4789,7 @@ dependencies = [ [[package]] name = "dojo-types" version = "1.0.0-rc.1" -source = "git+https://github.com/remybar/dojo.git?branch=upgradeable_models#f6cff5f8b3d5265f0b9656a8df57d84531248565" +source = "git+https://github.com/dojoengine/dojo?rev=8b2d976c9d65cee1b5a5c5f3c8e49223507c1995#8b2d976c9d65cee1b5a5c5f3c8e49223507c1995" dependencies = [ "anyhow", "cainome 0.4.6", @@ -12358,7 +12358,7 @@ dependencies = [ [[package]] name = "scarb" version = "2.8.4" -source = "git+https://github.com/remybar/scarb?rev=fbad7d8d6bdb763b413055d8d9f8b7995672f145#fbad7d8d6bdb763b413055d8d9f8b7995672f145" +source = "git+https://github.com/dojoengine/scarb?rev=b9965b7e2f0d97f2a97f18ca9a75bac541de7d84#b9965b7e2f0d97f2a97f18ca9a75bac541de7d84" dependencies = [ "anyhow", "async-trait", @@ -12388,7 +12388,7 @@ dependencies = [ "derive_builder", "dialoguer", "directories", - "dojo-lang 1.0.0-rc.1 (git+https://github.com/remybar/dojo.git?branch=upgradeable_models)", + "dojo-lang 1.0.0-rc.1 (git+https://github.com/dojoengine/dojo?rev=8b2d976c9d65cee1b5a5c5f3c8e49223507c1995)", "dunce", "fs4", "fs_extra", @@ -12408,8 +12408,8 @@ dependencies = [ "redb", "reqwest 0.11.27", "scarb-build-metadata", - "scarb-metadata 1.12.0 (git+https://github.com/remybar/scarb?rev=fbad7d8d6bdb763b413055d8d9f8b7995672f145)", - "scarb-stable-hash 1.0.0 (git+https://github.com/remybar/scarb?rev=fbad7d8d6bdb763b413055d8d9f8b7995672f145)", + "scarb-metadata 1.12.0 (git+https://github.com/dojoengine/scarb?rev=b9965b7e2f0d97f2a97f18ca9a75bac541de7d84)", + "scarb-stable-hash 1.0.0 (git+https://github.com/dojoengine/scarb?rev=b9965b7e2f0d97f2a97f18ca9a75bac541de7d84)", "scarb-ui", "semver 1.0.23", "serde", @@ -12439,7 +12439,7 @@ dependencies = [ [[package]] name = "scarb-build-metadata" version = "2.8.4" -source = "git+https://github.com/remybar/scarb?rev=fbad7d8d6bdb763b413055d8d9f8b7995672f145#fbad7d8d6bdb763b413055d8d9f8b7995672f145" +source = "git+https://github.com/dojoengine/scarb?rev=b9965b7e2f0d97f2a97f18ca9a75bac541de7d84#b9965b7e2f0d97f2a97f18ca9a75bac541de7d84" dependencies = [ "cargo_metadata", ] @@ -12460,7 +12460,7 @@ dependencies = [ [[package]] name = "scarb-metadata" version = "1.12.0" -source = "git+https://github.com/remybar/scarb?rev=fbad7d8d6bdb763b413055d8d9f8b7995672f145#fbad7d8d6bdb763b413055d8d9f8b7995672f145" +source = "git+https://github.com/dojoengine/scarb?rev=b9965b7e2f0d97f2a97f18ca9a75bac541de7d84#b9965b7e2f0d97f2a97f18ca9a75bac541de7d84" dependencies = [ "camino", "derive_builder", @@ -12483,7 +12483,7 @@ dependencies = [ [[package]] name = "scarb-stable-hash" version = "1.0.0" -source = "git+https://github.com/remybar/scarb?rev=fbad7d8d6bdb763b413055d8d9f8b7995672f145#fbad7d8d6bdb763b413055d8d9f8b7995672f145" +source = "git+https://github.com/dojoengine/scarb?rev=b9965b7e2f0d97f2a97f18ca9a75bac541de7d84#b9965b7e2f0d97f2a97f18ca9a75bac541de7d84" dependencies = [ "data-encoding", "xxhash-rust", @@ -12492,14 +12492,14 @@ dependencies = [ [[package]] name = "scarb-ui" version = "0.1.5" -source = "git+https://github.com/remybar/scarb?rev=fbad7d8d6bdb763b413055d8d9f8b7995672f145#fbad7d8d6bdb763b413055d8d9f8b7995672f145" +source = "git+https://github.com/dojoengine/scarb?rev=b9965b7e2f0d97f2a97f18ca9a75bac541de7d84#b9965b7e2f0d97f2a97f18ca9a75bac541de7d84" dependencies = [ "anyhow", "camino", "clap", "console", "indicatif", - "scarb-metadata 1.12.0 (git+https://github.com/remybar/scarb?rev=fbad7d8d6bdb763b413055d8d9f8b7995672f145)", + "scarb-metadata 1.12.0 (git+https://github.com/dojoengine/scarb?rev=b9965b7e2f0d97f2a97f18ca9a75bac541de7d84)", "serde", "serde_json", "tracing-core", diff --git a/Cargo.toml b/Cargo.toml index 359dc33d6c..4b4e311644 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -192,10 +192,8 @@ rpassword = "7.2.0" rstest = "0.18.2" rstest_reuse = "0.6.0" salsa = "0.16.1" -scarb = { git = "https://github.com/remybar/scarb", rev = "fbad7d8d6bdb763b413055d8d9f8b7995672f145" } -scarb-ui = { git = "https://github.com/remybar/scarb", rev = "fbad7d8d6bdb763b413055d8d9f8b7995672f145" } -#scarb = { git = "https://github.com/dojoengine/scarb", branch = "dojo-284" } -#scarb-ui = { git = "https://github.com/dojoengine/scarb", branch = "dojo-284" } +scarb = { git = "https://github.com/dojoengine/scarb", rev = "b9965b7e2f0d97f2a97f18ca9a75bac541de7d84" } +scarb-ui = { git = "https://github.com/dojoengine/scarb", rev = "b9965b7e2f0d97f2a97f18ca9a75bac541de7d84" } semver = "1.0.5" serde = { version = "1.0", features = [ "derive" ] } serde_json = { version = "1.0", features = [ "arbitrary_precision" ] } diff --git a/crates/dojo/core-cairo-test/src/lib.cairo b/crates/dojo/core-cairo-test/src/lib.cairo index 9958808c42..7517f85da7 100644 --- a/crates/dojo/core-cairo-test/src/lib.cairo +++ b/crates/dojo/core-cairo-test/src/lib.cairo @@ -23,9 +23,9 @@ mod tests { mod event; } - // mod model { - // mod model; - // } + mod model { + mod model; + } mod storage { mod database; diff --git a/crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo b/crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo index e247fd16e7..f0e859ec86 100644 --- a/crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo +++ b/crates/dojo/core-cairo-test/src/tests/helpers/helpers.cairo @@ -197,7 +197,7 @@ pub mod bar { let mut world = self.world(@"dojo"); let ptr = ModelPtr::< Foo - >::Id(core::poseidon::poseidon_hash_span([get_caller_address().into()].span())); + > { id: core::poseidon::poseidon_hash_span([get_caller_address().into()].span()) }; world.erase_model_ptr(ptr); } } 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 ec5f2c93a4..47e978253e 100644 --- a/crates/dojo/core-cairo-test/src/tests/model/model.cairo +++ b/crates/dojo/core-cairo-test/src/tests/model/model.cairo @@ -1,7 +1,6 @@ -use dojo::model::{Model, ModelValue, ModelStorage, ModelValueStorage, ModelMemberStorage}; -use dojo::world::{IWorldDispatcherTrait, WorldStorageTrait, WorldStorage}; - -use crate::tests::helpers::{deploy_world}; +use dojo::model::{Model, ModelValue, ModelStorage, ModelValueStorage}; +use dojo::world::WorldStorage; +use dojo_cairo_test::{spawn_test_world, NamespaceDef, TestResource}; #[derive(Copy, Drop, Serde, Debug)] #[dojo::model] @@ -26,6 +25,19 @@ struct Foo2 { v2: u32 } +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()), + ].span() + } +} + +fn spawn_foo_world() -> WorldStorage { + spawn_test_world([namespace_def()].span()) +} + #[test] fn test_model_definition() { let definition = dojo::model::Model::::definition(); @@ -64,35 +76,29 @@ fn test_from_values_bad_data() { } #[test] -fn test_get_and_update_model_value() { - let world = deploy_world(); - world.register_model("dojo", foo::TEST_CLASS_HASH.try_into().unwrap()); - - let mut world = WorldStorageTrait::new(world, "dojo"); +fn test_read_and_update_model_value() { + let mut world = spawn_foo_world(); let foo = Foo { k1: 1, k2: 2, v1: 3, v2: 4 }; world.write_model(@foo); let entity_id = foo.entity_id(); - let mut model_value: FooValue = world.read_model_value(foo.key()); + let mut model_value: FooValue = world.read_value(foo.key()); assert_eq!(model_value.v1, foo.v1); assert_eq!(model_value.v2, foo.v2); model_value.v1 = 12; model_value.v2 = 18; - world.write_model_value_from_id(entity_id, @model_value); + world.write_value_from_id(entity_id, @model_value); - let read_values: FooValue = world.read_model_value(foo.key()); + let read_values: FooValue = world.read_value(foo.key()); assert!(read_values.v1 == model_value.v1 && read_values.v2 == model_value.v2); } #[test] fn test_delete_model_value() { - let world = deploy_world(); - world.register_model("dojo", foo::TEST_CLASS_HASH.try_into().unwrap()); - - let mut world = WorldStorageTrait::new(world, "dojo"); + let mut world = spawn_foo_world(); let foo = Foo { k1: 1, k2: 2, v1: 3, v2: 4 }; world.write_model(@foo); @@ -100,37 +106,31 @@ fn test_delete_model_value() { let entity_id = foo.entity_id(); ModelStorage::::erase_model(ref world, @foo); - let read_values: FooValue = world.read_model_value_from_id(entity_id); + let read_values: FooValue = world.read_value_from_id(entity_id); assert!(read_values.v1 == 0 && read_values.v2 == 0); } #[test] -fn test_get_and_set_field_name() { - let world = deploy_world(); - world.register_model("dojo", foo::TEST_CLASS_HASH.try_into().unwrap()); - - let mut world = WorldStorageTrait::new(world, "dojo"); +fn test_read_and_write_field_name() { + let mut world = spawn_foo_world(); let foo = Foo { k1: 1, k2: 2, v1: 3, v2: 4 }; world.write_model(@foo); // Inference fails here, we need something better without too generics // which also fails. - let v1 = world.read_member(foo.key(), selector!("v1")); + let v1 = world.read_member(foo.ptr(), selector!("v1")); assert!(foo.v1 == v1); - world.write_member_from_id(foo.entity_id(), selector!("v1"), 42); + world.write_member(foo.ptr(), selector!("v1"), 42); - let v1 = world.read_member_from_id(foo.key(), selector!("v1")); + let v1 = world.read_member(foo.ptr(), selector!("v1")); assert!(v1 == 42); } #[test] -fn test_get_and_set_from_model() { - let world = deploy_world(); - world.register_model("dojo", foo::TEST_CLASS_HASH.try_into().unwrap()); - - let mut world = WorldStorageTrait::new(world, "dojo"); +fn test_read_and_write_from_model() { + let mut world = spawn_foo_world(); let foo = Foo { k1: 1, k2: 2, v1: 3, v2: 4 }; world.write_model(@foo); @@ -142,10 +142,7 @@ fn test_get_and_set_from_model() { #[test] fn test_delete_from_model() { - let world = deploy_world(); - world.register_model("dojo", foo::TEST_CLASS_HASH.try_into().unwrap()); - - let mut world = WorldStorageTrait::new(world, "dojo"); + let mut world = spawn_foo_world(); let foo = Foo { k1: 1, k2: 2, v1: 3, v2: 4 }; world.write_model(@foo); @@ -156,41 +153,31 @@ fn test_delete_from_model() { } #[test] -fn test_get_and_set_member_from_model() { - let world = deploy_world(); - world.register_model("dojo", foo::TEST_CLASS_HASH.try_into().unwrap()); - - let mut world = WorldStorageTrait::new(world, "dojo"); - +fn test_model_ptr_from_key() { + let mut world = spawn_foo_world(); let foo = Foo { k1: 1, k2: 2, v1: 3, v2: 4 }; + let ptr = Model::::ptr_from_key(foo.key()); world.write_model(@foo); - - let key: (u8, felt252) = foo.key(); - let v1: u128 = world.read_member(key, selector!("v1")); - - assert!(v1 == 3); - - world.write_member(key, selector!("v1"), 42); - let foo: Foo = world.read_model(key); - assert!(foo.v1 == 42); + let v1 = world.read_member(ptr, selector!("v1")); + assert!(foo.v1 == v1); } #[test] -fn test_get_and_set_field_name_from_model() { - let world = deploy_world(); - world.register_model("dojo", foo::TEST_CLASS_HASH.try_into().unwrap()); - - let mut world = WorldStorageTrait::new(world, "dojo"); - +fn test_model_ptr_from_keys() { + let mut world = spawn_foo_world(); let foo = Foo { k1: 1, k2: 2, v1: 3, v2: 4 }; + let ptr = Model::::ptr_from_keys(foo.keys()); world.write_model(@foo); + let v1 = world.read_member(ptr, selector!("v1")); + assert!(foo.v1 == v1); +} - // Currently we don't have automatic field id computation. To be done. - // @remy/@ben. - - let v1 = world.read_member((foo.k1, foo.k2), selector!("v1")); - assert!(v1 == 3); - - world.write_member((foo.k1, foo.k2), selector!("v1"), 42); - assert!(v1 == 42); +#[test] +fn test_model_ptr_from_entity_id() { + let mut world = spawn_foo_world(); + let foo = Foo { k1: 1, k2: 2, v1: 3, v2: 4 }; + let ptr = Model::::ptr_from_id(foo.entity_id()); + world.write_model(@foo); + let v1 = world.read_member(ptr, selector!("v1")); + assert!(foo.v1 == v1); } diff --git a/crates/dojo/core/src/lib.cairo b/crates/dojo/core/src/lib.cairo index 64fa4dcff3..f2271b1ac2 100644 --- a/crates/dojo/core/src/lib.cairo +++ b/crates/dojo/core/src/lib.cairo @@ -42,7 +42,7 @@ pub mod model { pub use definition::{ModelIndex, ModelDefinition, ModelDef}; pub mod model; - pub use model::{Model, KeyParser}; + pub use model::{Model, KeyParser, ModelPtr}; pub mod model_value; pub use model_value::{ModelValue, ModelValueKey}; @@ -54,9 +54,7 @@ pub mod model { pub use metadata::ResourceMetadata; pub mod storage; - pub use storage::{ - ModelStorage, ModelStorageTest, ModelValueStorage, ModelValueStorageTest, ModelPtr, - }; + pub use storage::{ModelStorage, ModelStorageTest, ModelValueStorage, ModelValueStorageTest,}; } pub mod storage { diff --git a/crates/dojo/core/src/model/model.cairo b/crates/dojo/core/src/model/model.cairo index c136da1f2c..0744537c2d 100644 --- a/crates/dojo/core/src/model/model.cairo +++ b/crates/dojo/core/src/model/model.cairo @@ -1,10 +1,17 @@ use dojo::{ - meta::{Layout, introspect::Struct, layout::compute_packed_size}, utils::entity_id_from_keys + meta::{Layout, introspect::Struct, layout::compute_packed_size}, + utils::{entity_id_from_keys, find_model_field_layout, entity_id_from_key} }; use super::{ModelDefinition, ModelDef}; - /// Trait `KeyParser` defines a trait for parsing keys from a given model. +/// +/// A pointer to a model, which can be expressed by an entity id. +#[derive(Copy, Drop, Serde, Debug, PartialEq)] +pub struct ModelPtr { + pub id: felt252, +} + pub trait KeyParser { /// Parses the key from the given model. fn parse_key(self: @M) -> K; @@ -39,6 +46,8 @@ pub trait Model { fn schema() -> Struct; /// Returns the memory layout of the model. fn layout() -> Layout; + /// Returns the layout of a field in the model. + fn field_layout(field_selector: felt252) -> Option; /// Returns the unpacked size of the model. Only applicable for fixed size models. fn unpacked_size() -> Option; /// Returns the packed size of the model. Only applicable for fixed size models. @@ -49,6 +58,14 @@ pub trait Model { fn definition() -> ModelDef; /// Returns the selector of the model computed for the given namespace hash. fn selector(namespace_hash: felt252) -> felt252; + /// Returns the pointer to the model from the key. + fn ptr_from_key, +Drop>(key: K) -> ModelPtr; + /// Returns the pointer to the model from the keys. + fn ptr_from_keys(keys: Span) -> ModelPtr; + /// Returns the pointer to the model from the entity id. + fn ptr_from_id(entity_id: felt252) -> ModelPtr; + /// Returns the ptr of the model. + fn ptr(self: @M) -> ModelPtr; } pub impl ModelImpl, +ModelDefinition, +Serde> of Model { @@ -88,6 +105,10 @@ pub impl ModelImpl, +ModelDefinition, +Serde> of Model< ModelDefinition::::layout() } + fn field_layout(field_selector: felt252) -> Option { + find_model_field_layout(Self::layout(), field_selector) + } + fn schema() -> Struct { ModelDefinition::::schema() } @@ -113,4 +134,20 @@ pub impl ModelImpl, +ModelDefinition, +Serde> of Model< unpacked_size: Self::unpacked_size() } } + + fn ptr_from_key, +Drop>(key: K) -> ModelPtr { + ModelPtr { id: entity_id_from_key(@key) } + } + + fn ptr_from_keys(keys: Span) -> ModelPtr { + ModelPtr { id: entity_id_from_keys(keys) } + } + + fn ptr_from_id(entity_id: felt252) -> ModelPtr { + ModelPtr:: { id: entity_id } + } + + fn ptr(self: @M) -> ModelPtr { + ModelPtr:: { id: self.entity_id() } + } } diff --git a/crates/dojo/core/src/model/storage.cairo b/crates/dojo/core/src/model/storage.cairo index ca9336bbd4..9530348387 100644 --- a/crates/dojo/core/src/model/storage.cairo +++ b/crates/dojo/core/src/model/storage.cairo @@ -1,17 +1,7 @@ -use dojo::model::model_value::ModelValueKey; +use dojo::{model::{ModelPtr, model_value::ModelValueKey}}; // TODO: define the right interface for member accesses. -/// A pointer to a model, which can be expressed by an entity id. -/// It's different from `ModelIndex` which is used for low level accesses. -#[derive(Copy, Drop, Serde, Debug, PartialEq)] -pub enum ModelPtr { - // The id of the model. - Id: felt252, - // The keys of the model as span. - Keys: Span, -} - /// A `ModelStorage` trait that abstracts where the storage is. /// /// Currently it's only world storage, but this will be useful when we have other @@ -41,9 +31,18 @@ pub trait ModelStorage { /// The ptr is mostly used for type inferrence. fn erase_model_ptr(ref self: S, ptr: ModelPtr); - /// Deletes multiple models of type `M` using the provided entity ids. + /// Deletes a model of type `M` using the provided entity id. + /// The ptr is mostly used for type inferrence. fn erase_models_ptrs(ref self: S, ptrs: Span>); + /// Retrieves a model of type `M` using the provided entity idref . + fn read_member>(self: @S, ptr: ModelPtr, field_selector: felt252) -> T; + + /// Retrieves a model of type `M` using the provided entity id. + fn write_member, +Drop>( + ref self: S, ptr: ModelPtr, field_selector: felt252, value: T + ); + /// Returns the current namespace hash. fn namespace_hash(self: @S) -> felt252; } diff --git a/crates/dojo/core/src/world/storage.cairo b/crates/dojo/core/src/world/storage.cairo index 1ea1c0719b..3c9a8ff3db 100644 --- a/crates/dojo/core/src/world/storage.cairo +++ b/crates/dojo/core/src/world/storage.cairo @@ -6,7 +6,8 @@ use dojo::model::{Model, ModelIndex, ModelValueKey, ModelValue, ModelStorage, Mo use dojo::event::{Event, EventStorage}; use dojo::meta::Layout; use dojo::utils::{ - entity_id_from_key, entity_id_from_keys, serialize_inline, find_model_field_layout + entity_id_from_key, entity_id_from_keys, serialize_inline, find_model_field_layout, + deserialize_unwrap }; use starknet::{ContractAddress, ClassHash}; @@ -16,6 +17,13 @@ pub struct WorldStorage { pub namespace_hash: felt252, } +fn field_layout_unwrap>(field_selector: felt252) -> Layout { + match Model::::field_layout(field_selector) { + Option::Some(layout) => layout, + Option::None => panic_with_felt252('bad member id') + } +} + #[generate_trait] pub impl WorldStorageInternalImpl of WorldStorageTrait { fn new(world: IWorldDispatcher, namespace: @ByteArray) -> WorldStorage { @@ -152,43 +160,56 @@ pub impl ModelStorageWorldStorageImpl, +Drop> of ModelStorage) { - let mut keys: Array = array![]; + let mut ids: Array = array![]; for m in models { - keys.append(ModelIndex::Keys(Model::::keys(*m))); + ids.append(ModelIndex::Id(Model::::entity_id(*m))); }; IWorldDispatcherTrait::delete_entities( self.dispatcher, Model::::selector(self.namespace_hash), - keys.span(), + ids.span(), Model::::layout() ); } fn erase_model_ptr(ref self: WorldStorage, ptr: ModelPtr) { - let entity_id = match ptr { - ModelPtr::Id(id) => id, - ModelPtr::Keys(keys) => entity_id_from_keys(keys), - }; - IWorldDispatcherTrait::delete_entity( self.dispatcher, Model::::selector(self.namespace_hash), - ModelIndex::Id(entity_id), + ModelIndex::Id(ptr.id), Model::::layout() ); } + fn read_member>( + self: @WorldStorage, ptr: ModelPtr, field_selector: felt252 + ) -> T { + deserialize_unwrap( + IWorldDispatcherTrait::entity( + *self.dispatcher, + Model::::selector(*self.namespace_hash), + ModelIndex::MemberId((ptr.id, field_selector)), + field_layout_unwrap::(field_selector) + ) + ) + } + fn write_member, +Drop>( + ref self: WorldStorage, ptr: ModelPtr, field_selector: felt252, value: T + ) { + IWorldDispatcherTrait::set_entity( + self.dispatcher, + Model::::selector(self.namespace_hash), + ModelIndex::MemberId((ptr.id, field_selector)), + serialize_inline(@value), + field_layout_unwrap::(field_selector) + ); + } + fn erase_models_ptrs(ref self: WorldStorage, ptrs: Span>) { let mut indexes: Array = array![]; - for p in ptrs { - indexes - .append( - match p { - ModelPtr::Id(id) => ModelIndex::Id(*id), - ModelPtr::Keys(keys) => ModelIndex::Id(entity_id_from_keys(*keys)), - } - ); + for ptr in ptrs { + indexes.append(ModelIndex::Id(*ptr.id)); }; IWorldDispatcherTrait::delete_entities( @@ -358,7 +379,7 @@ pub impl EventStorageTestWorldStorageImpl< /// checks. #[cfg(target: "test")] pub impl ModelStorageTestWorldStorageImpl< - M, +Model + M, +Model, +Drop > of dojo::model::ModelStorageTest { fn write_model_test(ref self: WorldStorage, model: @M) { let world_test = dojo::world::IWorldTestDispatcher { @@ -399,11 +420,6 @@ pub impl ModelStorageTestWorldStorageImpl< } fn erase_model_ptr_test(ref self: WorldStorage, ptr: ModelPtr) { - let entity_id = match ptr { - ModelPtr::Id(id) => id, - ModelPtr::Keys(keys) => entity_id_from_keys(keys), - }; - let world_test = dojo::world::IWorldTestDispatcher { contract_address: self.dispatcher.contract_address }; @@ -411,32 +427,21 @@ pub impl ModelStorageTestWorldStorageImpl< dojo::world::IWorldTestDispatcherTrait::delete_entity_test( world_test, Model::::selector(self.namespace_hash), - ModelIndex::Id(entity_id), + ModelIndex::Id(ptr.id), Model::::layout() ); } fn erase_models_ptrs_test(ref self: WorldStorage, ptrs: Span>) { - let mut ids: Array = array![]; - for p in ptrs { - ids - .append( - match p { - ModelPtr::Id(id) => *id, - ModelPtr::Keys(keys) => entity_id_from_keys(*keys), - } - ); - }; - let world_test = dojo::world::IWorldTestDispatcher { contract_address: self.dispatcher.contract_address }; - for i in ids { + for ptr in ptrs { dojo::world::IWorldTestDispatcherTrait::delete_entity_test( world_test, Model::::selector(self.namespace_hash), - ModelIndex::Id(i), + ModelIndex::Id(*ptr.id), Model::::layout() ); } @@ -533,3 +538,4 @@ fn get_serialized_member( Option::None => panic_with_felt252('bad member id') } } + diff --git a/examples/simple/src/lib.cairo b/examples/simple/src/lib.cairo index 59336f593d..682d9039c1 100644 --- a/examples/simple/src/lib.cairo +++ b/examples/simple/src/lib.cairo @@ -39,7 +39,7 @@ pub trait MyInterface { #[dojo::contract] pub mod c1 { use super::{MyInterface, M, E, EH, MValue}; - use dojo::model::{ModelStorage, ModelValueStorage, Model, ModelPtr}; + use dojo::model::{ModelStorage, ModelValueStorage, Model}; use dojo::event::EventStorage; fn dojo_init(self: @ContractState, v: felt252) { @@ -91,7 +91,7 @@ pub mod c1 { mv.v = 12; world.write_value_from_id(entity_id, @mv); - world.erase_model_ptr(ModelPtr::::Id(entity_id)); + world.erase_model_ptr(Model::::ptr_from_id(entity_id)); } } @@ -139,10 +139,5 @@ mod tests { let m: M = world.read_model(0); assert!(m.v == 0xff, "invalid b"); - //let m2 = M { a: 120, b: 244, }; - - // `write_model_test` goes over permissions checks. - //starknet::testing::set_contract_address(123.try_into().unwrap()); - //world.write_model_test(@m2); } }