Skip to content

[BUG] Bindgen - Array issue when an array of struct is set as a parameter for a smart contract method #3097

Open
@caillef

Description

@caillef

Describe the bug
While working on sozo build --unrealengine, I encountered an error for the Array type.

Here is the method in my smart contract:

        fn move(ref self: ContractState, direction: Direction, positions: Array<Vec2>)

I want to generate the .h and .cpp files for unrealengine. Here is more context:

    async fn generate_code(&self, data: &DojoData) -> BindgenResult<HashMap<PathBuf, Vec<u8>>> {
...
        let mut contracts = data.contracts.iter().collect::<Vec<_>>();
...
// Here going through each contract to build the args, the issue is when I map_type(&arg.1) that is an array of Vec2
        let mut functions_calls: String = String::new();
        for (_, contract) in contracts {
            for system_token in contract.systems.iter().filter(|s| {
                s.to_function().unwrap().get_output_kind() as u8
                    == FunctionOutputKind::NoOutput as u8
                    && s.to_function().unwrap().name != "upgrade"
            }) {
                let args = system_token
                    .to_function()
                    .unwrap()
                    .inputs
                    .iter()
                    .map(|arg| format!("{} {}", UnrealEnginePlugin::map_type(&arg.1), &arg.0))
                    .collect::<Vec<String>>()
                    .join(", ");

my rust code handling the types

"array" => {
                if let Token::Array(array) = token {
                    println!("Processing array inner type: {:?}", array.inner);
                    println!("Inner type_name: {}", array.inner.type_name());
                    let mapped = UnrealEnginePlugin::map_type(&array.inner);
                    println!("Mapped inner type: {}", mapped);
                    format!("TArray<{}>", mapped)
                } else {
                    panic!("Invalid array token: {:?}", token);
                }
            }
...
_ => {
                println!("Processing default case");
                let mut type_name = token.type_name().to_string();

                if let Token::Composite(composite) = token {
                    println!("Found composite type: {:?}", composite);
                    println!("Composite type: {:?}", composite.r#type);

                    if !composite.generic_args.is_empty() {
                        type_name += &format!(
                            "<{}>",
                            composite
                                .generic_args
                                .iter()
                                .map(|(_, t)| UnrealEnginePlugin::map_type(t))
                                .collect::<Vec<_>>()
                                .join(", ")
                        )
                    }

                    match composite.r#type {
                        CompositeType::Struct => {
                            println!("Returning struct type: F{}", type_name);
                            return "F".to_owned() + &type_name;
                        }
                        CompositeType::Enum => {
                            println!("Returning enum type: E{}", type_name);
                            return "E".to_owned() + &type_name;
                        }
                        _ => {
                            println!("Returning composite type: {}", type_name);
                            return type_name;
                        }
                    }
                }
                println!("Returning default type: {}", type_name);
                type_name
            }

and the resulting logs:

# entering the "array" in the match
Processing array inner type: Composite(Composite { type_path: "dojo_starter::models::Vec2", inners: [], generic_args: [], type: Unknown, is_event: false, alias: None })
Inner type_name: Vec2
# then calling recursively UnrealEnginePlugin::map_type(&array.inner);
Processing default case
Found composite type: Composite { type_path: "dojo_starter::models::Vec2", inners: [], generic_args: [], type: Unknown, is_event: false, alias: None }
Composite type: Unknown
Returning composite type: Vec2
Mapped inner type: Vec2

whereas when I have a Vec2 in a struct, so when it is not an inner type of an array, it works like this:

Processing default case
Found composite type: Composite { type_path: "dojo_starter::models::Vec2", inners: [CompositeInner { index: 0, name: "x", kind: NotUsed, token: CoreBasic(CoreBasic { type_path: "core::integer::u32" }) }, CompositeInner { index: 1, name: "y", kind: NotUsed, token: CoreBasic(CoreBasic { type_path: "core::integer::u32" }) }], generic_args: [], type: Struct, is_event: false, alias: None }
Composite type: Struct
Returning struct type: FVec2

this is the expected behavior, but it seems that inner type of arrays are not setup correctly, at least the type is Unknown where it should be Struct.

This bug can could have three origins:

  • issue with the build data but as it knows it is an array of Vec2, it's more likely that is comes from the second option
  • issue with the data sent to the generate_code function that is malformed. This data is generated in the PluginManager
let data = gather_dojo_data(
            &self.manifest_path,
            &self.root_package_name,
            &self.profile_name,
            skip_migration,
        )?;
  • maybe an issue with cainome when creating the Token::Function part.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions