Skip to content

Commit

Permalink
fix(dojo-lang): use PluginDiagnostic instead of panic for model keys …
Browse files Browse the repository at this point in the history
…verification (#1327)
  • Loading branch information
glihm authored Dec 22, 2023
1 parent e351f0f commit 3c55d86
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 20 deletions.
12 changes: 1 addition & 11 deletions crates/dojo-lang/src/introspect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,17 +275,7 @@ fn handle_introspect_internal(
}
});

if size_precompute > 0 {
size.push(format!("{}", size_precompute));
}

if size.is_empty() {
panic!(
"The model `{}` has only keys, ensure you have at least one field without the #[key] \
attribute.",
name
);
}
size.push(format!("{}", size_precompute));

RewriteNode::interpolate_patched(
"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ dependencies = [

[[package]]
name = "dojo"
version = "0.4.1"
version = "0.4.2"
dependencies = [
"dojo_plugin",
]
Expand Down
2 changes: 1 addition & 1 deletion crates/dojo-lang/src/manifest_test_data/manifest
Original file line number Diff line number Diff line change
Expand Up @@ -1374,7 +1374,7 @@ test_manifest_file
{
"name": "dojo_examples::models::position",
"address": null,
"class_hash": "0x2b233bba9a232a5e891c85eca9f67beedca7a12f9768729ff017bcb62d25c9d",
"class_hash": "0x4cd20d231b04405a77b184c115dc60637e186504fad7f0929bd76cbd09c10b",
"abi": [
{
"type": "function",
Expand Down
9 changes: 8 additions & 1 deletion crates/dojo-lang/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,14 @@ pub fn handle_model_struct(

if keys.is_empty() {
diagnostics.push(PluginDiagnostic {
message: "Model must define atleast one #[key] attribute".into(),
message: "Model must define at least one #[key] attribute".into(),
stable_ptr: struct_ast.name(db).stable_ptr().untyped(),
});
}

if keys.len() == members.len() {
diagnostics.push(PluginDiagnostic {
message: "Model must define at least one member that is not a key".into(),
stable_ptr: struct_ast.name(db).stable_ptr().untyped(),
});
}
Expand Down
2 changes: 1 addition & 1 deletion crates/dojo-lang/src/plugin_test_data/introspect
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ impl GenericStructSerde<T, +core::serde::Serde<T>, +core::traits::Destruct<T>> o
impl GenericStructIntrospect<T, impl TIntrospect: dojo::database::introspect::Introspect<T>> of dojo::database::introspect::Introspect<GenericStruct<T>> {
#[inline(always)]
fn size() -> usize {
dojo::database::introspect::Introspect::<T>::size()
dojo::database::introspect::Introspect::<T>::size() + 0
}

#[inline(always)]
Expand Down
172 changes: 169 additions & 3 deletions crates/dojo-lang/src/plugin_test_data/model
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ struct Roles {
role_ids: Array<u8>
}

#[derive(Model, Serde)]
struct OnlyKeyModel {
#[key]
id: felt252
}

use starknet::ContractAddress;

#[derive(Model, Copy, Drop, Serde)]
Expand Down Expand Up @@ -520,11 +526,16 @@ mod player {
}

//! > expected_diagnostics
error: Model must define atleast one #[key] attribute
error: Model must define at least one #[key] attribute
--> test_src/lib.cairo:36:8
struct Roles {
^***^

error: Model must define at least one member that is not a key
--> test_src/lib.cairo:41:8
struct OnlyKeyModel {
^**********^

error: Unsupported attribute.
--> test_src/lib.cairo[Position]:73:13
#[starknet::contract]
Expand All @@ -535,6 +546,11 @@ error: Unsupported attribute.
#[starknet::contract]
^*******************^

error: Unsupported attribute.
--> test_src/lib.cairo[OnlyKeyModel]:68:13
#[starknet::contract]
^*******************^

error: Unsupported attribute.
--> test_src/lib.cairo[Player]:77:13
#[starknet::contract]
Expand Down Expand Up @@ -600,6 +616,36 @@ error: Unsupported attribute.
#[external(v0)]
^*************^

error: Unsupported attribute.
--> test_src/lib.cairo[OnlyKeyModel]:72:17
#[storage]
^********^

error: Unsupported attribute.
--> test_src/lib.cairo[OnlyKeyModel]:75:17
#[external(v0)]
^*************^

error: Unsupported attribute.
--> test_src/lib.cairo[OnlyKeyModel]:80:17
#[external(v0)]
^*************^

error: Unsupported attribute.
--> test_src/lib.cairo[OnlyKeyModel]:85:17
#[external(v0)]
^*************^

error: Unsupported attribute.
--> test_src/lib.cairo[OnlyKeyModel]:93:17
#[external(v0)]
^*************^

error: Unsupported attribute.
--> test_src/lib.cairo[OnlyKeyModel]:100:17
#[external(v0)]
^*************^

error: Unsupported attribute.
--> test_src/lib.cairo[Player]:81:17
#[storage]
Expand Down Expand Up @@ -670,6 +716,12 @@ struct Roles {
role_ids: Array<u8>
}

#[derive(Model, Serde)]
struct OnlyKeyModel {
#[key]
id: felt252
}

use starknet::ContractAddress;

#[derive(Model, Copy, Drop, Serde)]
Expand Down Expand Up @@ -786,7 +838,7 @@ impl PositionSerde of core::serde::Serde::<Position> {
impl PositionIntrospect<> of dojo::database::introspect::Introspect<Position<>> {
#[inline(always)]
fn size() -> usize {
dojo::database::introspect::Introspect::<Vec3>::size()
dojo::database::introspect::Introspect::<Vec3>::size() + 0
}

#[inline(always)]
Expand Down Expand Up @@ -905,7 +957,7 @@ impl RolesSerde of core::serde::Serde::<Roles> {
impl RolesIntrospect<> of dojo::database::introspect::Introspect<Roles<>> {
#[inline(always)]
fn size() -> usize {
dojo::database::introspect::Introspect::<Array<u8>>::size()
dojo::database::introspect::Introspect::<Array<u8>>::size() + 0
}

#[inline(always)]
Expand Down Expand Up @@ -971,6 +1023,120 @@ impl RolesIntrospect<> of dojo::database::introspect::Introspect<Roles<>> {
dojo::database::introspect::Introspect::<Roles>::ty()
}
}
impl OnlyKeyModelSerde of core::serde::Serde::<OnlyKeyModel> {
fn serialize(self: @OnlyKeyModel, ref output: core::array::Array<felt252>) {
core::serde::Serde::serialize(self.id, ref output)
}
fn deserialize(ref serialized: core::array::Span<felt252>) -> core::option::Option<OnlyKeyModel> {
core::option::Option::Some(OnlyKeyModel {
id: core::serde::Serde::deserialize(ref serialized)?,
})
}
}

impl OnlyKeyModelModel of dojo::model::Model<OnlyKeyModel> {
#[inline(always)]
fn name(self: @OnlyKeyModel) -> felt252 {
'OnlyKeyModel'
}

#[inline(always)]
fn keys(self: @OnlyKeyModel) -> Span<felt252> {
let mut serialized = core::array::ArrayTrait::new();
core::array::ArrayTrait::append(ref serialized, *self.id);
core::array::ArrayTrait::span(@serialized)
}

#[inline(always)]
fn values(self: @OnlyKeyModel) -> Span<felt252> {
let mut serialized = core::array::ArrayTrait::new();

core::array::ArrayTrait::span(@serialized)
}

#[inline(always)]
fn layout(self: @OnlyKeyModel) -> Span<u8> {
let mut layout = core::array::ArrayTrait::new();
dojo::database::introspect::Introspect::<OnlyKeyModel>::layout(ref layout);
core::array::ArrayTrait::span(@layout)
}

#[inline(always)]
fn packed_size(self: @OnlyKeyModel) -> usize {
let mut layout = self.layout();
dojo::packing::calculate_packed_size(ref layout)
}
}


impl OnlyKeyModelIntrospect<> of dojo::database::introspect::Introspect<OnlyKeyModel<>> {
#[inline(always)]
fn size() -> usize {
0
}

#[inline(always)]
fn layout(ref layout: Array<u8>) {

}

#[inline(always)]
fn ty() -> dojo::database::introspect::Ty {
dojo::database::introspect::Ty::Struct(dojo::database::introspect::Struct {
name: 'OnlyKeyModel',
attrs: array![].span(),
children: array![dojo::database::introspect::serialize_member(@dojo::database::introspect::Member {
name: 'id',
ty: dojo::database::introspect::Ty::Primitive('felt252'),
attrs: array!['key'].span()
})].span()
})
}
}


#[starknet::interface]
trait IOnlyKeyModel<T> {
fn name(self: @T) -> felt252;
}

#[starknet::contract]
mod only_key_model {
use super::OnlyKeyModel;

#[storage]
struct Storage {}

#[external(v0)]
fn name(self: @ContractState) -> felt252 {
'OnlyKeyModel'
}

#[external(v0)]
fn unpacked_size(self: @ContractState) -> usize {
dojo::database::introspect::Introspect::<OnlyKeyModel>::size()
}

#[external(v0)]
fn packed_size(self: @ContractState) -> usize {
let mut layout = core::array::ArrayTrait::new();
dojo::database::introspect::Introspect::<OnlyKeyModel>::layout(ref layout);
let mut layout_span = layout.span();
dojo::packing::calculate_packed_size(ref layout_span)
}

#[external(v0)]
fn layout(self: @ContractState) -> Span<u8> {
let mut layout = core::array::ArrayTrait::new();
dojo::database::introspect::Introspect::<OnlyKeyModel>::layout(ref layout);
core::array::ArrayTrait::span(@layout)
}

#[external(v0)]
fn schema(self: @ContractState) -> dojo::database::introspect::Ty {
dojo::database::introspect::Introspect::<OnlyKeyModel>::ty()
}
}
impl PlayerCopy of core::traits::Copy::<Player>;
impl PlayerDrop of core::traits::Drop::<Player>;
impl PlayerSerde of core::serde::Serde::<Player> {
Expand Down
2 changes: 1 addition & 1 deletion crates/dojo-world/src/contracts/model_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ async fn test_model() {
assert_eq!(
position.class_hash(),
FieldElement::from_hex_be(
"0x02b233bba9a232a5e891c85eca9f67beedca7a12f9768729ff017bcb62d25c9d"
"0x004cd20d231b04405a77b184c115dc60637e186504fad7f0929bd76cbd09c10b"
)
.unwrap()
);
Expand Down
2 changes: 1 addition & 1 deletion examples/spawn-and-move/Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ dependencies = [

[[package]]
name = "dojo_examples"
version = "0.4.1"
version = "0.4.2"
dependencies = [
"dojo",
]
Expand Down

0 comments on commit 3c55d86

Please sign in to comment.