Skip to content

Conversation

@Larkooo
Copy link
Collaborator

@Larkooo Larkooo commented Aug 18, 2025

Summary by CodeRabbit

  • New Features

    • Fixed-size arrays now serialize to an object with "elements" (the items) and "size" (the fixed length).
  • Bug Fixes / Compatibility

    • Deserialization accepts both the new object format and the legacy raw-array format, validating size to prevent mismatches; public APIs remain unchanged to minimize migration impact.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 18, 2025

ohayo sensei

Walkthrough

Serialization and deserialization for Ty::FixedSizeArray in crates/dojo/types/src/schema.rs now use an object {"elements": [...], "size": N}; deserialization validates size and supports a legacy bare-array fallback. Public APIs unchanged.

Changes

Cohort / File(s) Summary
Schema JSON (de)serialization
crates/dojo/types/src/schema.rs
to_json_value: emits {"elements": ..., "size": N} for Ty::FixedSizeArray. from_json_value: accepts and validates the new object form and retains backward-compatible parsing of legacy plain-array form. deserialize: iterates per-element types for fixed-size arrays. Unit test added for new format.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant Ty
  Caller->>Ty: to_json_value()
  alt Ty::FixedSizeArray
    Ty-->>Caller: {"elements": [...], "size": N}
  else Other Ty variants
    Ty-->>Caller: existing JSON format
  end

  Caller->>Ty: from_json_value(json)
  alt json is {"elements": ..., "size": N}
    Ty->>Ty: validate size matches
    Ty-->>Caller: construct FixedSizeArray (per-element)
  else json is legacy array
    Ty-->>Caller: construct FixedSizeArray (legacy path)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • glihm

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f229f9f and 982e925.

📒 Files selected for processing (1)
  • crates/dojo/types/src/schema.rs (1 hunks)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
crates/dojo/types/src/schema.rs (1)

446-456: Ohayo sensei — inline the JSON return; keep it tidy

Micro-nit: you can return the json! directly without the temporary binding. This was already raised in an earlier review; reiterating here for completeness.

Apply:

-                let value = json!(
-                    {
-                        "elements": values?,
-                        "size": size
-                    }
-                );
-                Ok(value)
+                Ok(json!({
+                    "elements": values?,
+                    "size": size
+                }))

Optional: consider asserting elements count vs declared size at serialization time to catch inconsistent states earlier (can be a debug_assert to avoid breaking prod paths).

🧹 Nitpick comments (1)
crates/dojo/types/src/schema.rs (1)

574-601: Ohayo sensei — add unit tests for new JSON shape and legacy fallback

To lock this in and prevent regressions:

  • FixedSizeArray.to_json_value outputs {"elements":[...], "size": N}.
  • from_json_value accepts the object form (happy path) and rejects when elements.len() != size.
  • from_json_value continues to accept the legacy bare array and enforces length == fixed size.

I can draft targeted tests in this module mirroring the existing style (serde_json round-trip for a small FixedSizeArray).

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 982e925 and 72eedf5.

📒 Files selected for processing (1)
  • crates/dojo/types/src/schema.rs (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
crates/dojo/types/src/schema.rs (1)
crates/dojo/world/src/contracts/model.rs (2)
  • values (270-270)
  • values (281-281)
🪛 GitHub Actions: test
crates/dojo/types/src/schema.rs

[error] 598-598: Cargo clippy failed with exit code 101. Rust type errors in crates/dojo/types/src/schema.rs:598: mismatched types (usize vs u32) (E0308); cannot compare usize with u32 (E0277).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
crates/dojo/types/src/schema.rs (1)

573-594: Ohayo sensei — enforce elements length and avoid potential panic when deserializing object form

Two robustness issues:

  • Missing check that "elements".len() equals the fixed size (could leave the type in an inconsistent state).
  • items[0] will panic if empty; use get(0).cloned().ok_or(...) to fail gracefully.

Apply this diff:

             (Ty::FixedSizeArray((items, size)), JsonValue::Object(obj)) => {
                 if let (Some(JsonValue::Array(values)), Some(JsonValue::Number(expected_size))) =
                     (obj.get("elements"), obj.get("size"))
                 {
                     if let Some(expected_size) = expected_size.as_u64() {
                         if expected_size != *size as u64 {
                             return Err(PrimitiveError::TypeMismatch);
                         }
-                        let template = items[0].clone();
+                        if values.len() as u64 != expected_size {
+                            return Err(PrimitiveError::TypeMismatch);
+                        }
+                        let template = items.get(0).cloned().ok_or(PrimitiveError::TypeMismatch)?;
                         items.clear();
                         for value in values {
                             let mut item = template.clone();
                             item.from_json_value(value.clone())?;
                             items.push(item);
                         }
                     } else {
                         return Err(PrimitiveError::TypeMismatch);
                     }
                 } else {
                     return Err(PrimitiveError::TypeMismatch);
                 }
             }

Optional migration tweak (if desired): allow omitting "size" in the object and validate only elements.len() == *size as usize. I can provide a minimal diff if you want that behavior.

🧹 Nitpick comments (2)
crates/dojo/types/src/schema.rs (2)

445-455: Ohayo sensei — simplify JSON construction and assert invariant for FixedSizeArray

You can avoid the temporary value and add a lightweight invariant check to catch inconsistent states early.

Apply this diff:

             Ty::FixedSizeArray((items, size)) => {
-                let values: Result<Vec<_>, _> = items.iter().map(|ty| ty.to_json_value()).collect();
-
-                let value = json!(
-                    {
-                        "elements": values?,
-                        "size": size
-                    }
-                );
-                Ok(value)
+                debug_assert_eq!(items.len(), *size as usize);
+                let values: Result<Vec<_>, _> = items.iter().map(|ty| ty.to_json_value()).collect();
+                Ok(json!({
+                    "elements": values?,
+                    "size": size
+                }))
             }

1149-1183: Ohayo sensei — add tests for from_json_value (new object and legacy forms) and mismatch cases

Great coverage for to_json_value and felts-based deserialize. Please add JSON-deserialization tests to lock the new behavior and BC path, including mismatched sizes.

Suggested tests:

#[test]
fn ty_from_json_fixed_size_array_object() {
    // template for elements
    let mut ty = Ty::FixedSizeArray((vec![Ty::Primitive(Primitive::Felt252(None))], 3));
    let json = json!({"size": 3, "elements": ["0x1", "0x2", "0x3"]});
    ty.from_json_value(json).expect("failed to from_json_value");

    assert_matches!(&ty, Ty::FixedSizeArray((elements, size)) => {
        assert_eq!(*size, 3);
        assert_eq!(elements.len(), 3);
    });
}

#[test]
fn ty_from_json_fixed_size_array_legacy_array() {
    let mut ty = Ty::FixedSizeArray((vec![Ty::Primitive(Primitive::Felt252(None))], 2));
    let json = json!(["0xA", "0xB"]);
    ty.from_json_value(json).expect("failed to from_json_value (legacy)");
    assert_matches!(&ty, Ty::FixedSizeArray((elements, size)) => {
        assert_eq!(*size, 2);
        assert_eq!(elements.len(), 2);
    });
}

#[test]
fn ty_from_json_fixed_size_array_mismatched_sizes_error() {
    // Provided JSON size mismatches type size
    let mut ty = Ty::FixedSizeArray((vec![Ty::Primitive(Primitive::Felt252(None))], 3));
    let json = json!({"size": 2, "elements": ["0x1", "0x2"]});
    let res = ty.from_json_value(json);
    assert_matches!(res, Err(PrimitiveError::TypeMismatch));
}

If you decide to allow omitting "size" in the object form, I can add a test for that variant too.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 72eedf5 and c29f56a.

📒 Files selected for processing (1)
  • crates/dojo/types/src/schema.rs (4 hunks)
🔇 Additional comments (1)
crates/dojo/types/src/schema.rs (1)

595-607: Ohayo sensei — legacy bare-array path looks solid

The backward-compat branch validates length (with proper usize/u32 cast) and clones from a template as expected. LGTM.

Comment on lines 283 to 287
Ty::FixedSizeArray((items_ty, size)) => {
let item_ty = &items_ty[0];
for _ in 0..*size {
let mut cur_item_ty = item_ty.clone();
cur_item_ty.deserialize(felts, legacy_storage)?;
debug_assert_eq!(items_ty.len(), *size as usize);
for elem in items_ty {
elem.deserialize(felts, legacy_storage)?;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Ohayo sensei — deserialize now assumes per-element entries; make serialize symmetric to prevent data corruption

This path asserts items_ty.len() == size and deserializes each element individually. However, serialize for FixedSizeArray (Lines 186–191) still repeats items_ty[0] size times, which risks emitting duplicated felts when elements differ. Consider iterating each element instead to keep round-trip symmetry.

Proposed change for the serialize arm (outside this hunk, shown as plain Rust for clarity):

// In Ty::serialize -> serialize_inner match arm for Ty::FixedSizeArray
Ty::FixedSizeArray((items_ty, size)) => {
    debug_assert_eq!(items_ty.len(), *size as usize);
    for item_ty in items_ty {
        serialize_inner(item_ty, felts)?;
    }
}

If you want, I can open a follow-up patch and add a unit test that exercises serialize→deserialize round-trips where element values differ (to catch this class of regressions).

🤖 Prompt for AI Agents
In crates/dojo/types/src/schema.rs around lines 283 to 287, the deserialize arm
for Ty::FixedSizeArray deserializes each element individually but serialize
currently repeats items_ty[0] size times; change the serialize match arm for
Ty::FixedSizeArray to iterate over items_ty and call serialize_inner on each
element (keeping the existing debug_assert_eq!(items_ty.len(), *size as usize))
so serialization mirrors deserialization and prevents duplicated felts when
elements differ.

Copy link
Collaborator Author

@Larkooo Larkooo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future, we could generalize to test the entire JSON serde of the Ty. We could have one big Ty containing all variants, to_json_value it and then assert parsing. But for now it looks good to me!

@kariy kariy merged commit 89e31b7 into dojoengine:main Aug 18, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants