google / flatbuffers

FlatBuffers: Memory Efficient Serialization Library
https://flatbuffers.dev/
Apache License 2.0
23.39k stars 3.25k forks source link

Rust default for array #8436

Open DolajoCZ opened 2 weeks ago

DolajoCZ commented 2 weeks ago

Issue

Invalid generation of rust code with switch --gen-object-api and struct containing array of size 33 and more.

Reason

Generated object api struct implement Default trait by derive macro, but array implement Default trait only for size up to 32 (source).

Example of invalid fbs

Fbs file example.fbs

namespace example;

struct FooStruct {
    array_values: [double:81];
}

table FooTable {
    foo_struct: FooStruct;
}

root_type FooTable;

Command

flatc.exe --rust --gen-object-api example.fbs

Invalid code section

    #[derive(Debug, Clone, PartialEq, Default)]
    pub struct FooStructT {
        pub array_values: [f64; 81],
    }

Tool versions

flatc - 24.3.25 rustc - 1.82.0

Potential solution

For struct with array implement custom Default trait.

Example of solution from code above

    #[derive(Debug, Clone, PartialEq)]
    pub struct FooStructT {
        pub array_values: [f64; 81],
    }

    impl std::default::Default for FooStructT {
        fn default() -> Self {
            Self {
                array_values: [Default::default(); 81],
            }
        }
    }
DolajoCZ commented 2 weeks ago

For correction should be sufficient to replace this code:

https://github.com/google/flatbuffers/blob/595bf0007ab1929570c7671f091313c8fc20644e/src/idl_gen_rust.cpp#L2910-L2917

by this code:

      // Struct declaration
      code_ += "#[derive(Debug, Copy, Clone, PartialEq)]";
      code_ += "{{ACCESS_TYPE}} struct {{STRUCT_OTY}} {";
      ForAllStructFields(struct_def, [&](const FieldDef &field) {
        (void)field;  // unused.
        code_ += "pub {{FIELD}}: {{FIELD_OTY}},";
      });
      code_ += "}";

      // Struct default trait implementation
      code_ += "impl std::default::Default for {{STRUCT_OTY}} {";
      code_ += "    fn default() -> Self {";
      code_ += "      Self {";
      ForAllStructFields(struct_def, [&](const FieldDef &field) {
        const Type &type = field.value.type;
        if (IsArray(type)) {
          code_ += "      {{FIELD}}: [Default::default(); " + NumToString(type.fixed_length) + "],";
        } else {
          code_ += "      {{FIELD}}: Default::default(),";
        }
      });
      code_ += "    }";
      code_ += "  }";
      code_ += "}";

Base on some tests everything looks good but I am not C++ developer so it is necessary to review it by some expert.