Skip to content

fix(rust/reflection): support vectors of tables, strings, and structs in "get_field_vector" #8960

Open
Desel72 wants to merge 2 commits intogoogle:masterfrom
Desel72:fix/issue-8550
Open

fix(rust/reflection): support vectors of tables, strings, and structs in "get_field_vector" #8960
Desel72 wants to merge 2 commits intogoogle:masterfrom
Desel72:fix/issue-8550

Conversation

@Desel72
Copy link

@Desel72 Desel72 commented Mar 6, 2026

Closes #8550

The existing get_field_vector() reflection API only works for vectors of primitive/scalar types (integers, floats, bools). It fails for vectors of tables, strings, and structs because Vector<T>::get() uses size_of::<T>() to step through elements, which only produces correct offsets when the Rust type's memory size matches the buffer element size. For non-primitive types this invariant doesn't hold:

  • Vector of tables: buffer elements are 4-byte UOffsetT offsets, but Table<'a> is 24 bytes in Rust
  • Vector of strings: buffer elements are 4-byte offsets, but &str is 16 bytes in Rust
  • Vector of structs: buffer elements are inline at their schema-defined byte size, but the reflection Struct<'a> wrapper is 16 bytes in Rust

Solution

Added three new dedicated functions alongside the existing get_field_vector:

Function Return type Notes
get_field_vector_of_tables Vector<ForwardsUOffset<Table>> ForwardsUOffset is 4 bytes, matching buffer layout. Requires Schema to reject struct vectors.
get_field_vector_of_strings Vector<ForwardsUOffset<&str>> ForwardsUOffset is 4 bytes, matching buffer layout.
get_field_vector_of_structs StructVector (new type) Custom type that steps by the schema-defined struct byte size. Requires Schema.

Both get_field_vector_of_tables and get_field_vector_of_structs use the Schema to look up the object's is_struct() flag, preventing misuse where a struct vector is read as table offsets (or vice versa), which would cause silent data corruption.

StructVector is a new type providing len(), is_empty(), and get(idx) -> Struct with correct element stride from the schema.

Safe buffer wrappers (SafeTable::get_field_vector_of_tables, etc.) are also added.

Changes

  • rust/reflection/src/lib.rs: 3 new public functions + StructVector type + updated docs on get_field_vector pointing to the new functions
  • rust/reflection/src/safe_buffer.rs: 3 corresponding SafeTable wrapper methods
  • tests/rust_reflection_test/src/lib.rs: 8 new tests (success cases, wrong-type rejection, and cross-validation between table/struct vectors)

Test plan

  • All 120 reflection tests pass (112 existing + 8 new)
  • rust_usage_test unaffected (no dependency on reflection crate)
  • Verify vectors of tables are correctly read with get_field_vector_of_tables
  • Verify vectors of strings are correctly read with get_field_vector_of_strings
  • Verify vectors of structs are correctly read with get_field_vector_of_structs
  • Verify struct/table cross-validation rejects mismatched types

@Desel72 Desel72 requested a review from dbaileychess as a code owner March 6, 2026 22:21
@github-actions github-actions bot added the rust label Mar 6, 2026
@google-cla
Copy link

google-cla bot commented Mar 6, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@jtdavis777
Copy link
Collaborator

are new api functions necessary to implement this functionality? is it not possible to fix the current API to be functional? I have not yet dived into the code to get full context.

@Desel72
Copy link
Author

Desel72 commented Mar 7, 2026

are new api functions necessary to implement this functionality? is it not possible to fix the current API to be functional? I have not yet dived into the code to get full context.

Hi @jtdavis777

The existing get_field_vector<T>() signature has two hard constraints that prevent a unified fix:

1. Trait bound: T: Follow<'a, Inner = T>

ForwardsUOffset<Table> has Inner = Table, not Inner = ForwardsUOffset<Table>, so it cannot satisfy this bound. The same applies to ForwardsUOffset<&str>. These types simply cannot be passed as the type parameter to the current function without changing the core flatbuffers crate.

2. Vector::get() uses size_of::<T>() as element stride

For tables and strings this isn't an issue (offsets are always 4 bytes), but for structs, the element size is schema-defined and only known at runtime. There is no Rust type with the right compile-time size to represent "a struct whose byte size I'll only know after reading the schema". This is why StructVector stores the stride as a runtime value.

Because each element category (offsets-to-tables, offsets-to-strings, inline-structs) requires a different return type and a different stride, a single generic fix to the existing function is not possible without modifying the core flatbuffers crate's Vector type. The three new functions are the minimal addition that covers all non-primitive cases.

@Desel72
Copy link
Author

Desel72 commented Mar 10, 2026

Hi @jtdavis777, sorry for the ping. Do you have any feedback on my PR? If there are any issues, please feel free to let me know and I’ll address them.

@jtdavis777
Copy link
Collaborator

Hey @Desel72 no worries thank you for the ping. I'm more than happy to look this over and provide feedback, just a heads up I am a 100% volunteer donating my time to help maintain this project so it sometimes takes me a bit to carve out enough time to do a proper review! I try to be fairly responsive but know you're on my list even if it takes me a bit to make progress!

@Desel72
Copy link
Author

Desel72 commented Mar 10, 2026

Thank you @jtdavis777. Once this is approved, I’m planning to open another PR. Looking forward to it!

@Desel72
Copy link
Author

Desel72 commented Mar 11, 2026

Hi @jtdavis777 , I know you’re busy and donating your time, so I really appreciate any time you can give to review this PR. It would be great to get it reviewed soon so I can proceed with the next steps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Rust] [Reflection] get_field_vector() only works for vectors of primitive types

2 participants