Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sozo): add model command back #2618

Merged
merged 2 commits into from
Nov 3, 2024
Merged

Conversation

glihm
Copy link
Collaborator

@glihm glihm commented Nov 3, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new Model command for inspecting models.
    • Added ResourceDescriptor enum for improved handling of resource identifiers.
  • Enhancements

    • Updated tag_or_address fields across various commands to use ResourceDescriptor, enhancing type safety and clarity.
  • Bug Fixes

    • Streamlined error handling for contract resolution and improved namespace management.
  • Chores

    • Updated dependencies in the Cargo.toml file for better integration.
    • Added new modules for model and resource_descriptor in the library structure.

Copy link

coderabbitai bot commented Nov 3, 2024

Walkthrough

Ohayo, sensei! This pull request introduces significant changes across several files, primarily focusing on the type safety and handling of contract identifiers by replacing String fields with a new ResourceDescriptor type. This affects the CallArgs, ExecuteArgs, and various commands in the model module. Additionally, a new command Model is added, and the Cargo.toml file reflects a shift in the dependency context for dojo-types. The overall structure is improved for clarity and consistency in managing resource descriptors.

Changes

File Change Summary
bin/sozo/src/commands/call.rs Updated tag_or_address type from String to ResourceDescriptor. Simplified contract descriptor logic.
bin/sozo/src/commands/execute.rs Updated tag_or_address type from String to ResourceDescriptor. Removed ContractDescriptor enum.
bin/sozo/src/commands/mod.rs Added new module model and new command Model to Commands enum.
bin/sozo/src/commands/model.rs Updated tag_or_name type from String to ResourceDescriptor in multiple commands. Modified run method.
bin/sozo/src/utils.rs Removed is_address function.
crates/sozo/ops/Cargo.toml Added dojo-types as a regular dependency; removed from [dev-dependencies].
crates/sozo/ops/src/lib.rs Added new public modules model and resource_descriptor.
crates/sozo/ops/src/model.rs Updated imports and function signatures to use new types. Removed check_tag_or_read_default_namespace.
crates/sozo/ops/src/resource_descriptor.rs Introduced ResourceDescriptor enum with methods for parsing and managing namespaces.

Possibly related PRs

Suggested reviewers

  • kariy

🪧 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.
    • Generate unit testing code for this file.
    • 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. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

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.

Documentation and Community

  • 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

@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: 4

🧹 Outside diff range and nitpick comments (8)
crates/sozo/ops/src/resource_descriptor.rs (3)

1-15: Ohayo! Consider enhancing documentation with examples, sensei!

The enum definition looks clean and well-structured! To make it even more helpful for other developers, consider adding usage examples in the documentation.

Add examples like:

/// Examples:
/// ```
/// use sozo_ops::ResourceDescriptor;
/// 
/// let address = ResourceDescriptor::from_string("0x1234")?;
/// let name = ResourceDescriptor::from_string("my_contract")?;
/// let tag = ResourceDescriptor::from_string("namespace-contract")?;
/// ```

23-31: Consider strengthening address validation, sensei!

While the current address parsing works, it might be good to add additional validation for the hex string format beyond just checking the "0x" prefix.

Here's a suggested improvement:

 pub fn from_string(s: &str) -> Result<Self> {
     if s.starts_with("0x") {
+        // Validate hex string format
+        if !s[2..].chars().all(|c| c.is_ascii_hexdigit()) {
+            anyhow::bail!("Invalid hex string format");
+        }
         Ok(ResourceDescriptor::Address(Felt::from_str(s)?))
     } else if naming::is_valid_tag(s) {
         Ok(ResourceDescriptor::Tag(s.to_string()))
     } else {
         Ok(ResourceDescriptor::Name(s.to_string()))
     }
 }

55-63: Extract magic number into a constant, sensei!

The Display implementation looks good, but the hex width (66) should be extracted into a named constant for better maintainability.

Consider this improvement:

+const ADDRESS_HEX_WIDTH: usize = 66;
+
 impl fmt::Display for ResourceDescriptor {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            ResourceDescriptor::Address(address) => write!(f, "{:#066x}", address),
+            ResourceDescriptor::Address(address) => write!(f, "{:#0width$x}", address, width = ADDRESS_HEX_WIDTH),
             ResourceDescriptor::Name(name) => write!(f, "{}", name),
             ResourceDescriptor::Tag(tag) => write!(f, "{}", tag),
         }
     }
 }
bin/sozo/src/commands/model.rs (1)

122-186: Consider refactoring repetitive code in command handlers

Sensei, the code for each command variant repeats similar logic:

  • Ensuring the namespace with tag_or_name.ensure_namespace(&default_ns)
  • Retrieving world_diff and provider using utils::get_world_diff_and_provider
  • Calling the respective model function with similar parameters

Refactoring this repetitive code into a common function or utility could improve maintainability and reduce duplication.

crates/sozo/ops/src/model.rs (4)

Line range hint 205-340: Ohayo, sensei! Consider refactoring to reduce code duplication

The functions get_printable_layout_list_from_struct, get_printable_layout_list_from_enum, get_printable_layout_list_from_tuple, and get_printable_layout_list_from_array share similar logic for processing layouts. Refactoring these into a generic function or utilizing traits can improve maintainability and reduce code duplication.


Line range hint 425-433: Ohayo, sensei! Add checks to prevent panics in format_array

In format_array, accessing values without ensuring it has sufficient elements can lead to panics. It's important to verify the length of values before removing elements or iterating over it.

Apply this diff to add necessary checks:

 fn format_array(item: &Ty, values: &mut Vec<Felt>, level: usize, start_indent: bool) -> String {
-    let length: u32 = values.remove(0).to_u32().unwrap();
+    if values.is_empty() {
+        return format!("{}Error: insufficient values for array length", _start_indent(level, start_indent));
+    }
+    let length = values.remove(0).to_u32().unwrap();
     let mut items = vec![];

     for _ in 0..length {
+        if values.is_empty() {
+            items.push(format!("{}Error: insufficient values for array item", INDENT.repeat(level + 1)));
+            break;
+        }
         items.push(format_record_value(item, values, level + 1, true));
     }

     format!(
         "{}[\n{}\n{}]",
         _start_indent(level, start_indent),
         items.join(",\n"),
         INDENT.repeat(level)
     )
 }

Line range hint 475-482: Ohayo, sensei! Add bounds checking in format_enum to prevent panics

Accessing schema.options[variant_index] without verifying that variant_index is within bounds can cause a panic if the index is invalid. Ensure that you check the bounds before accessing the array.

Apply this diff to include bounds checking:

 fn format_enum(schema: &Enum, values: &mut Vec<Felt>, level: usize, start_indent: bool) -> String {
     let variant_index: u8 = values.remove(0).to_u8().unwrap();
     let variant_index: usize = variant_index.into();
+    if variant_index >= schema.options.len() {
+        return format!("{}Error: invalid variant index {}", _start_indent(level, start_indent), variant_index);
+    }
     let variant_name = format!("{}::{}", schema.name, schema.options[variant_index].name);
     let variant_data =
         format_record_value(&schema.options[variant_index].ty, values, level + 1, true);

     if variant_data.is_empty() {
         format!("{}{variant_name}", _start_indent(level, start_indent),)
     } else {
         format!(
             "{}{variant_name}(\n{}\n{})",
             _start_indent(level, start_indent),
             variant_data,
             INDENT.repeat(level)
         )
     }
 }

Line range hint 402-408: Ohayo, sensei! Clarify cloning behavior in format_primitive

In format_primitive, cloning the primitive type with let mut _p = *p; may not be necessary if Primitive implements the Copy trait. Ensure that this cloning is intentional and consider using references to avoid unnecessary copies.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 2c97d56 and 0a72d48.

📒 Files selected for processing (9)
  • bin/sozo/src/commands/call.rs (4 hunks)
  • bin/sozo/src/commands/execute.rs (4 hunks)
  • bin/sozo/src/commands/mod.rs (5 hunks)
  • bin/sozo/src/commands/model.rs (7 hunks)
  • bin/sozo/src/utils.rs (0 hunks)
  • crates/sozo/ops/Cargo.toml (1 hunks)
  • crates/sozo/ops/src/lib.rs (1 hunks)
  • crates/sozo/ops/src/model.rs (14 hunks)
  • crates/sozo/ops/src/resource_descriptor.rs (1 hunks)
💤 Files with no reviewable changes (1)
  • bin/sozo/src/utils.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/sozo/ops/src/lib.rs
🔇 Additional comments (16)
crates/sozo/ops/Cargo.toml (1)

16-16: Ohayo! The dependency change looks good, sensei! ✨

Moving dojo-types to regular dependencies aligns perfectly with the introduction of the ResourceDescriptor type and the model command functionality.

crates/sozo/ops/src/resource_descriptor.rs (1)

1-63: Ohayo! Overall implementation looks solid, sensei!

The ResourceDescriptor implementation provides a robust and type-safe way to handle different types of resource identifiers. The code is well-structured, properly documented, and follows Rust best practices. The suggested improvements are minor and optional.

bin/sozo/src/commands/mod.rs (4)

17-17: LGTM! Module declaration follows consistent pattern.

Ohayo sensei! The new model module declaration is properly placed and follows the existing pattern.


29-29: LGTM! Import follows consistent pattern.

The ModelArgs import maintains consistency with other command argument imports.


53-54: LGTM! Command declaration follows best practices.

The Model command is properly documented and uses Box<ModelArgs> following the established pattern for complex command arguments.


69-69: LGTM! Command handling is properly implemented.

The new Model command is correctly integrated into both the Display implementation and command execution logic.

Let's verify that the new command follows the same pattern as other boxed commands:

Also applies to: 92-92

✅ Verification successful

The previous pattern might have been too specific. Let's look at the actual implementation to verify the command handling consistency.


Ohayo sensei! The Model command implementation is perfectly consistent

Looking at the output, the Model command follows the exact same pattern as all other commands in the codebase:

  • It's properly defined in the Commands enum
  • It has the same Display implementation format: Commands::Model(_) => write!(f, "Model")
  • It follows the same execution pattern: Commands::Model(args) => args.run(config)

This consistency ensures the command integrates seamlessly with the existing command infrastructure.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistency of command implementations
# Test: Check if all boxed commands follow the same pattern
ast-grep --pattern 'Commands::$_($_(Box<$_>))' 

Length of output: 48


Script:

#!/bin/bash
# Let's check the Commands enum definition and its variants
rg -A 5 "^pub enum Commands" 

# Also check all matches of Commands:: to see the pattern
rg "Commands::" -A 2

Length of output: 2979

bin/sozo/src/commands/execute.rs (1)

26-26: Ohayo, sensei! The refactoring to use ResourceDescriptor enhances type safety and clarity

Changing tag_or_address from a String to ResourceDescriptor and updating its usage with ensure_namespace improves type safety and makes the code more maintainable.

Also applies to: 63-63

bin/sozo/src/commands/call.rs (4)

5-5: Import ResourceDescriptor correctly introduced

Ohayo sensei! The ResourceDescriptor is properly imported from sozo_ops::resource_descriptor, which will enhance the clarity and manageability of resource descriptors in the codebase.


21-21: Update of tag_or_address to ResourceDescriptor improves type safety

Ohayo sensei! Changing the type of tag_or_address to ResourceDescriptor enhances type safety and clarity in the CallArgs struct.


57-57: Correct usage of ensure_namespace on tag_or_address

Ohayo sensei! The method ensure_namespace is appropriately called on tag_or_address to ensure the default namespace is applied when necessary.


70-71: Correct handling of ResourceDescriptor variants

Ohayo sensei! The match arms for ResourceDescriptor::Address and ResourceDescriptor::Tag are correctly implemented, ensuring proper retrieval of the contract address.

bin/sozo/src/commands/model.rs (3)

5-6: Ohayo sensei! Properly importing ResourceDescriptor

The addition of ResourceDescriptor import ensures that the new type is available for use, maintaining code integrity.


25-25: Consistent use of ResourceDescriptor for tag_or_name

Sensei, updating the tag_or_name parameter to use ResourceDescriptor across all commands enhances type safety and clarity.

Also applies to: 37-37, 68-68, 80-80, 96-96


115-117: Ohayo sensei! Correctly loading workspace and profile configuration

The workspace and profile configurations are properly loaded, ensuring access to the default namespace and necessary settings.

crates/sozo/ops/src/model.rs (2)

3-5: Ohayo, sensei! Imports updated appropriately

The new imports of Primitive, Enum, Member, Struct, and Ty are necessary for the updated type handling in the code. This enhances type safety and clarity.


495-506: Ohayo, sensei! Ensure all variants of Ty are handled

In format_record_value, consider handling all possible variants of Ty to prevent unexpected behavior. If new variants are added to the Ty enum in the future, the lack of a catch-all case may lead to unhandled cases.

Run the following script to check for unhandled Ty variants:

Comment on lines +91 to +93
ResourceDescriptor::Name(_) => {
unimplemented!("Expected to be a resolved tag with default namespace.")
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ohayo, sensei! Replace unimplemented!() with proper error handling

Using unimplemented!() will cause a panic at runtime if ResourceDescriptor::Name(_) is encountered. This is not ideal in production code as it can lead to unexpected crashes. Consider returning a descriptive error to handle this case gracefully.

Apply this diff to handle the error appropriately:

 ResourceDescriptor::Name(_) => {
-    unimplemented!("Expected to be a resolved tag with default namespace.")
+    return Err(anyhow!(
+        "Unresolved resource descriptor: expected a resolved tag with default namespace."
+    ));
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ResourceDescriptor::Name(_) => {
unimplemented!("Expected to be a resolved tag with default namespace.")
}
ResourceDescriptor::Name(_) => {
return Err(anyhow!(
"Unresolved resource descriptor: expected a resolved tag with default namespace."
));
}

Comment on lines +75 to +77
ResourceDescriptor::Name(_) => {
unimplemented!("Expected to be a resolved tag with default namespace.")
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle ResourceDescriptor::Name to prevent runtime panics

Ohayo sensei! Using unimplemented! for the ResourceDescriptor::Name variant will cause a panic if encountered at runtime. It's recommended to handle this variant properly or return a descriptive error to prevent unexpected crashes.

Apply this diff to handle the variant:

 ResourceDescriptor::Name(_) => {
-    unimplemented!("Expected to be a resolved tag with default namespace.")
+    return Err(anyhow!(
+        "Expected a resolved tag with default namespace for descriptor: {}",
+        descriptor
+    ));
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ResourceDescriptor::Name(_) => {
unimplemented!("Expected to be a resolved tag with default namespace.")
}
ResourceDescriptor::Name(_) => {
return Err(anyhow!(
"Expected a resolved tag with default namespace for descriptor: {}",
descriptor
));
}

Comment on lines +381 to 383
if let Layout::Fixed(lf) = layout {
println!("\n{} (packed)", name);
println!(" selector : {:#x}", get_selector_from_name(name).unwrap());
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ohayo, sensei! Avoid using unwrap() to prevent potential panics

Using unwrap() on get_selector_from_name(name) may cause a panic if the function returns an error. Consider handling the error gracefully to improve the robustness of the code.

Apply this diff to handle the potential error:

-    println!("    selector : {:#x}", get_selector_from_name(name).unwrap());
+    match get_selector_from_name(name) {
+        Ok(selector) => println!("    selector : {:#x}", selector),
+        Err(e) => println!("    selector : Error getting selector ({})", e),
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if let Layout::Fixed(lf) = layout {
println!("\n{} (packed)", name);
println!(" selector : {:#x}", get_selector_from_name(name).unwrap());
if let Layout::Fixed(lf) = layout {
println!("\n{} (packed)", name);
match get_selector_from_name(name) {
Ok(selector) => println!(" selector : {:#x}", selector),
Err(e) => println!(" selector : Error getting selector ({})", e),
}

Comment on lines +420 to 423
fn format_field_value(member: &Member, values: &mut Vec<Felt>, level: usize) -> String {
let field_repr = format_record_value(&member.ty, values, level, false);
format!("{}{:<16}: {field_repr}", INDENT.repeat(level), member.name)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ohayo, sensei! Ensure sufficient elements in values to prevent panics

In format_field_value, removing elements from values without checking its length can cause a panic if values is empty. Consider verifying that values has enough elements before proceeding.

Apply this diff to add a check:

 fn format_field_value(member: &Member, values: &mut Vec<Felt>, level: usize) -> String {
-    let field_repr = format_record_value(&member.ty, values, level, false);
+    let field_repr = if values.is_empty() {
+        format!("Error: insufficient values for field {}", member.name)
+    } else {
+        format_record_value(&member.ty, values, level, false)
+    };
     format!("{}{:<16}: {field_repr}", INDENT.repeat(level), member.name)
 }

Committable suggestion skipped: line range outside the PR's diff.

Copy link

codecov bot commented Nov 3, 2024

Codecov Report

Attention: Patch coverage is 0% with 145 lines in your changes missing coverage. Please review.

Project coverage is 57.24%. Comparing base (2c97d56) to head (0a72d48).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
crates/sozo/ops/src/model.rs 0.00% 58 Missing ⚠️
bin/sozo/src/commands/model.rs 0.00% 51 Missing ⚠️
crates/sozo/ops/src/resource_descriptor.rs 0.00% 24 Missing ⚠️
bin/sozo/src/commands/call.rs 0.00% 5 Missing ⚠️
bin/sozo/src/commands/execute.rs 0.00% 5 Missing ⚠️
bin/sozo/src/commands/mod.rs 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2618      +/-   ##
==========================================
- Coverage   57.92%   57.24%   -0.68%     
==========================================
  Files         393      396       +3     
  Lines       48587    49162     +575     
==========================================
  Hits        28144    28144              
- Misses      20443    21018     +575     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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.

1 participant