Skip to content

491: fix!: Remove unused fields in RecordField (order, position)#59

Open
martin-augment wants to merge 1 commit intomainfrom
pr-491-2026-03-02-08-17-25
Open

491: fix!: Remove unused fields in RecordField (order, position)#59
martin-augment wants to merge 1 commit intomainfrom
pr-491-2026-03-02-08-17-25

Conversation

@martin-augment
Copy link
Copy Markdown
Owner

491: To review by AI

Also changes the type of `aliases` from `Option<Vec<String>>` to `Vec<String>`.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 2, 2026

Walkthrough

This pull request refactors field position and order handling in record schema structures. The RecordField struct is simplified by removing the order and position fields, and the RecordFieldOrder enum is removed from the public API. Position tracking is deferred from field parsing to enumeration-based computation. The aliases field changes from Option<Vec<String>> to Vec<String>. Function signatures throughout the codebase, including get_record_fields_in_ctxt, are updated to remove position parameters. Test code is updated to use the builder pattern for constructing record fields, and serialization logic is modified to accept position as a parameter instead of accessing it from field structures.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch pr-491-2026-03-02-08-17-25

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant refactoring of the RecordField structure within the Avro schema implementation. The primary goal is to simplify the schema definition by removing unused and redundant fields like order and position. These contextual properties are now managed dynamically during schema processing, leading to a cleaner and more efficient representation. Additionally, the handling of field aliases has been streamlined for improved consistency. These changes enhance the maintainability and clarity of the Avro schema components.

Highlights

  • Refactored RecordField Structure: The RecordField struct has been significantly refactored by removing the order and position fields, which were previously noted as having no functional effect. This simplifies the core data structure for record fields.
  • Dynamic Field Positioning: Field positioning is now handled dynamically during schema parsing and serialization processes, rather than being stored as an inherent property within each RecordField. This change streamlines the schema representation and reduces redundancy.
  • Simplified Alias Handling: The aliases field within RecordField has been changed from an Option<Vec<String>> to a Vec<String>, ensuring that aliases are always represented as a vector, even if empty. This simplifies access and removes the need for Option unwrapping.
  • Updated Schema Derivation and Serialization: The AvroSchemaComponent trait and its implementations, along with the avro_derive macro, have been updated to reflect the removal of position arguments and the new aliases structure, ensuring compatibility with the revised RecordField.
  • Test Case Adjustments and Removals: Numerous test cases across the codebase have been updated to align with the RecordField changes, removing references to order and position. A specific test for field.position was removed entirely, and a test assertion for documentation serialization was corrected.
Changelog
  • avro/src/encode.rs
    • Simplified alias lookup logic by removing unnecessary if let Some block.
  • avro/src/schema/mod.rs
    • Removed RecordFieldOrder from public exports.
    • Updated test cases to use RecordField::builder() and remove order and position fields.
    • Corrected a test assertion for documentation serialization from 'is not serialized' to 'is serialized'.
  • avro/src/schema/parser.rs
    • Modified RecordField parsing to dynamically assign field positions using enumerate().
    • Updated alias handling to work with Vec<String> instead of Option<Vec<String>>.
  • avro/src/schema/record/field.rs
    • Removed order and position fields from the RecordField struct.
    • Changed aliases field type from Option<Vec<String>> to Vec<String> with a default builder attribute.
    • Removed the RecordFieldOrder enum.
    • Updated Debug implementation for RecordField to reflect removed fields.
    • Adjusted RecordField::parse method signature and logic to no longer accept position and handle the new aliases type.
    • Updated get_field_custom_attributes to exclude order from ignored keys.
  • avro/src/schema/record/mod.rs
    • Removed RecordFieldOrder from public exports.
  • avro/src/schema_compatibility.rs
    • Updated alias iteration to directly use r_field.aliases.iter() as aliases is now a Vec<String>.
  • avro/src/schema_equality.rs
    • Removed RecordFieldOrder import.
    • Updated test cases to use RecordField::builder() and remove order and position fields.
  • avro/src/serde/derive.rs
    • Updated get_record_fields_in_ctxt trait method signature to remove first_field_position argument.
    • Removed position assignment logic from generated RecordField instances.
    • Adjusted calls to get_record_fields_in_ctxt to remove the field_position argument.
  • avro/src/serde/ser_schema/mod.rs
    • Modified serialize_next_field to accept position as an argument.
    • Updated serialization logic to use the passed position instead of field.position for field lookup and caching.
  • avro/src/types.rs
    • Removed RecordFieldOrder import.
    • Updated test cases to use RecordField::builder() and remove order and position fields from RecordField instantiations and expected error messages.
  • avro/src/writer.rs
    • Updated an error message in a test to reflect the removal of position from RecordField debug output.
  • avro/tests/get_record_fields.rs
    • Updated calls to get_record_fields_in_ctxt to remove the first_field_position argument.
    • Removed the avro_rs_448_default_get_record_fields_position test case, as the position field was removed.
  • avro/tests/schema.rs
    • Updated a test case to remove order and position from RecordField destructuring.
  • avro_derive/src/lib.rs
    • Updated get_record_fields_in_ctxt macro generation to remove field_position argument.
    • Removed field_position increment logic in generated code.
    • Modified alias generation to produce Vec<String> directly instead of Option<Vec<String>>.
    • Adjusted lookup map creation to use enumerate() for dynamic position assignment.
    • Updated type_to_get_record_fields_expr and get_field_get_record_fields_expr to remove field_position argument.
  • avro_derive/tests/derive.rs
    • Updated calls to get_record_fields_in_ctxt in tests to remove the first_field_position argument.
    • Removed the avro_rs_448_flatten_field_positions test case.
Activity
  • The pull request was created with a title indicating the removal of unused fields in RecordField.
  • The author provided a minimal description, stating 'To review by AI'.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request is a nice refactoring that removes the unused order and position fields from RecordField. This simplification has been correctly propagated throughout the codebase, including parsing, serialization, derive macros, and tests. The change of RecordField.aliases from an Option<Vec<String>> to Vec<String> is also a welcome simplification. Additionally, this PR fixes an issue where the doc field of a RecordField was not being serialized. The changes are well-executed and improve the codebase. I've found one minor issue in the Debug implementation for RecordField which I've commented on.

// As we are always skipping self.order, always show the ..
debug.finish_non_exhaustive()
if self.doc.is_none()
|| !self.aliases.is_empty()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The condition !self.aliases.is_empty() seems incorrect for determining whether to use finish_non_exhaustive. finish_non_exhaustive should be used when a field is not displayed. The aliases field is not displayed when it's empty (self.aliases.is_empty()). Therefore, the condition should be self.aliases.is_empty() to correctly indicate that the debug output is incomplete.

Suggested change
|| !self.aliases.is_empty()
|| self.aliases.is_empty()

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

value:useful; category:bug; feedback: The Gemini AI reviewer is correct! The check for the aliases should be inverted, otherwise the Debug formatting will look like complete instead of as incomplete.

@claude
Copy link
Copy Markdown

claude bot commented Mar 2, 2026

PR Review: Remove unused fields in RecordField (order, position)

This PR cleans up RecordField by removing unused order/position fields, changing aliases from Option<Vec<String>> to Vec<String>, fixing doc serialization, and simplifying related APIs. The overall direction is good, but there are a few issues worth addressing.


Bug: Incorrect condition in Debug impl (avro/src/schema/record/field.rs:71-79)

The condition for choosing between finish_non_exhaustive() and finish() has a logic error:

if self.doc.is_none()
    || !self.aliases.is_empty()  // <-- BUG: should be self.aliases.is_empty()
    || self.default.is_none()
    || self.custom_attributes.is_empty()
{
    debug.finish_non_exhaustive()
} else {
    debug.finish()
}

finish_non_exhaustive() (which appends .. ) should be used when any field is not displayed. The condition for each term should fire when the field was skipped:

  • self.doc.is_none() → doc skipped ✓
  • !self.aliases.is_empty() → aliases are non-empty (shown), not skipped ✗ (should be self.aliases.is_empty())
  • self.default.is_none() → default skipped ✓
  • self.custom_attributes.is_empty() → custom_attributes skipped ✓

The current code has two concrete problems:

  1. When aliases is non-empty, !self.aliases.is_empty() is always true, so we always fall into finish_non_exhaustive() even when all fields are displayed — the else branch is unreachable whenever aliases are present.
  2. When aliases is empty (not displayed) but all other optional fields are Some/non-empty, the condition is false, so we call finish() without the .. marker — incorrect, since aliases were skipped.

Fix:

if self.doc.is_none()
    || self.aliases.is_empty()
    || self.default.is_none()
    || self.custom_attributes.is_empty()
{
    debug.finish_non_exhaustive()
} else {
    debug.finish()
}

Good fix: doc now serialized for record fields

Previously doc was never included in the JSON output of RecordField. The test comment change from "The documentation is not serialized" to "The documentation is serialized" confirms this was a silent bug — it's now correctly serialized per the Avro spec. Good catch.


Breaking change: RecordFieldOrder removed

The Avro spec defines order as a valid field attribute ("ascending", "descending", or "ignore"), and this was a publicly exported type. Removing it is a breaking change for users who relied on RecordField.order or matched on RecordFieldOrder variants.

The current handling — letting "order" fall through to custom_attributes — is pragmatic and does preserve round-trip fidelity. However, there are behavioral differences:

  1. custom_attributes is a BTreeMap, so "order" will appear alphabetically among other custom keys at the end of the serialized JSON, rather than as a first-class recognized field.
  2. There is no longer a typed, structured way to inspect a field's ordering intent. Users who relied on it for application-level sorting now have no typed accessor.

If the library plans to re-implement sorting in the future, removing this now creates more churn. It might be worth a deprecation cycle rather than immediate removal.


Breaking change: aliases type change (Option<Vec<String>>Vec<String>)

This is the right design — empty vec is semantically equivalent to None here — but it is a breaking API change. Any user code doing:

if let Some(aliases) = &field.aliases { ... }

will fail to compile. Since the PR title already uses fix! to signal a breaking change, this should be called out explicitly in the changelog/CHANGELOG entry.


Breaking change: position removed from RecordField

The removal itself is sound — position is inherently derivable from the field's index in RecordSchema.fields — but it is a public field removal. The serializer now correctly uses the lookup table index. One minor point: the lookup table and fields vec can still be inconsistently constructed by hand (this was already possible with inconsistent position values, so no regression here).


Simplification: get_record_fields_in_ctxt signature

Removing first_field_position is a clean API simplification. All the call sites and the derive macro are correctly updated. The test avro_rs_448_default_get_record_fields_position that verified position offset behavior was also appropriately removed.


Minor: aliases in derive macro uses struct literal, not builder

In avro_derive/src/lib.rs, the generated code still uses the struct literal syntax to construct RecordField rather than RecordField::builder():

schema_fields.push(::apache_avro::schema::RecordField {
    name: ...,
    aliases: ::std::vec::Vec::new(),
    schema: ...,
    ...
});

This is technically fine since the struct fields are public and there's no #[non_exhaustive], but if RecordField gains new fields in the future, every code path in the derive macro will need updating. Switching to the builder would be more resilient.


Summary

Issue Severity
Debug condition bug (!aliases.is_empty() instead of aliases.is_empty()) Bug
RecordFieldOrder removal (breaking public API, Avro spec item) Breaking change
aliases Option<Vec>→Vec (breaking public API) Breaking change
position removal (breaking public API) Breaking change
Doc serialization fix Good fix
Struct literal in derive macro (not using builder) Minor concern

The Debug condition bug should be fixed before merging. The breaking changes are acknowledged in the PR title (fix!) but should be documented in a CHANGELOG entry.

Copy link
Copy Markdown

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
avro/src/serde/derive.rs (1)

193-195: ⚠️ Potential issue | 🟡 Minor

Update stale docs for #[serde(with = "...")] helper signature.

Line 194 still documents the removed usize parameter. That now conflicts with the current trait API and examples.

Suggested doc fix
-///    and `fn get_record_fields_in_ctxt(usize, &mut HashSet<Name>, &Namespace) -> Option<Vec<RecordField>>` in the module provided
+///    and `fn get_record_fields_in_ctxt(&mut HashSet<Name>, &Namespace) -> Option<Vec<RecordField>>` in the module provided
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@avro/src/serde/derive.rs` around lines 193 - 195, The docs for the serde
helper are out of date: update the example/signature that mentions `fn
get_record_fields_in_ctxt(usize, &mut HashSet<Name>, &Namespace) ->
Option<Vec<RecordField>>` to remove the removed `usize` parameter so it matches
the current trait API; ensure both function signatures in the comments read `fn
get_schema_in_ctxt(&mut HashSet<Name>, &Namespace) -> Schema` and `fn
get_record_fields_in_ctxt(&mut HashSet<Name>, &Namespace) ->
Option<Vec<RecordField>>`, and adjust any example text in the same comment block
to reflect the new signature and parameter ordering so it no longer conflicts
with `AvroSchemaComponent`.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@avro/src/schema/parser.rs`:
- Around line 572-574: The loop that inserts field aliases into the lookup map
(the for alias in &field.aliases { lookup.insert(alias.clone(), position); }
block) can silently overwrite existing entries; modify it to detect collisions
before inserting: check lookup.get(alias) or use lookup.entry(alias.clone()) and
if an entry exists, return an error (or otherwise report) that includes the
conflicting alias and both indices (existing and new position) so callers can
handle duplicate alias/name conflicts; ensure you reference the same symbols
(field.aliases, lookup.insert/lookup.entry, position) when implementing the
check and error path.

In `@avro/src/schema/record/field.rs`:
- Around line 71-75: The Debug exhaustiveness check incorrectly treats present
aliases as "omitted" because the condition uses !self.aliases.is_empty(); change
that to self.aliases.is_empty() inside the same if (the block that calls
finish_non_exhaustive()) so the check becomes: self.doc.is_none() ||
self.aliases.is_empty() || self.default.is_none() ||
self.custom_attributes.is_empty(), ensuring finish_non_exhaustive() is only
invoked when aliases are actually absent.

---

Outside diff comments:
In `@avro/src/serde/derive.rs`:
- Around line 193-195: The docs for the serde helper are out of date: update the
example/signature that mentions `fn get_record_fields_in_ctxt(usize, &mut
HashSet<Name>, &Namespace) -> Option<Vec<RecordField>>` to remove the removed
`usize` parameter so it matches the current trait API; ensure both function
signatures in the comments read `fn get_schema_in_ctxt(&mut HashSet<Name>,
&Namespace) -> Schema` and `fn get_record_fields_in_ctxt(&mut HashSet<Name>,
&Namespace) -> Option<Vec<RecordField>>`, and adjust any example text in the
same comment block to reflect the new signature and parameter ordering so it no
longer conflicts with `AvroSchemaComponent`.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 682a3e3 and 0860320.

📒 Files selected for processing (15)
  • avro/src/encode.rs
  • avro/src/schema/mod.rs
  • avro/src/schema/parser.rs
  • avro/src/schema/record/field.rs
  • avro/src/schema/record/mod.rs
  • avro/src/schema_compatibility.rs
  • avro/src/schema_equality.rs
  • avro/src/serde/derive.rs
  • avro/src/serde/ser_schema/mod.rs
  • avro/src/types.rs
  • avro/src/writer.rs
  • avro/tests/get_record_fields.rs
  • avro/tests/schema.rs
  • avro_derive/src/lib.rs
  • avro_derive/tests/derive.rs
💤 Files with no reviewable changes (1)
  • avro/tests/schema.rs

Comment on lines +572 to 574
for alias in &field.aliases {
lookup.insert(alias.clone(), position);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Prevent silent lookup overwrites for colliding aliases.

Line 573 inserts aliases without collision checks. If an alias matches an existing field name/alias, the previous index is silently replaced, which can corrupt field resolution.

💡 Proposed fix
-            for alias in &field.aliases {
-                lookup.insert(alias.clone(), position);
-            }
+            for alias in &field.aliases {
+                if let Some(old_position) = lookup.insert(alias.clone(), position)
+                    && old_position != position
+                {
+                    return Err(Details::FieldNameDuplicate(alias.clone()).into());
+                }
+            }
📝 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
for alias in &field.aliases {
lookup.insert(alias.clone(), position);
}
for alias in &field.aliases {
if let Some(old_position) = lookup.insert(alias.clone(), position)
&& old_position != position
{
return Err(Details::FieldNameDuplicate(alias.clone()).into());
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@avro/src/schema/parser.rs` around lines 572 - 574, The loop that inserts
field aliases into the lookup map (the for alias in &field.aliases {
lookup.insert(alias.clone(), position); } block) can silently overwrite existing
entries; modify it to detect collisions before inserting: check
lookup.get(alias) or use lookup.entry(alias.clone()) and if an entry exists,
return an error (or otherwise report) that includes the conflicting alias and
both indices (existing and new position) so callers can handle duplicate
alias/name conflicts; ensure you reference the same symbols (field.aliases,
lookup.insert/lookup.entry, position) when implementing the check and error
path.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

value:good-to-have; category:bug; feedback: The CodeRabbit AI reviewer is correct! The previous version of the code didn't check that the aliases are unique. It would be good the new version to add such check and report this kind of problem to the application developer.

Comment on lines +71 to +75
if self.doc.is_none()
|| !self.aliases.is_empty()
|| self.default.is_none()
|| self.custom_attributes.is_empty()
{
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix inverted alias condition in Debug exhaustiveness check.

Line 72 is inverted. It currently treats present aliases as “omitted,” which makes finish_non_exhaustive() behavior incorrect.

💡 Proposed fix
-        if self.doc.is_none()
-            || !self.aliases.is_empty()
+        if self.doc.is_none()
+            || self.aliases.is_empty()
             || self.default.is_none()
             || self.custom_attributes.is_empty()
         {
📝 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 self.doc.is_none()
|| !self.aliases.is_empty()
|| self.default.is_none()
|| self.custom_attributes.is_empty()
{
if self.doc.is_none()
|| self.aliases.is_empty()
|| self.default.is_none()
|| self.custom_attributes.is_empty()
{
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@avro/src/schema/record/field.rs` around lines 71 - 75, The Debug
exhaustiveness check incorrectly treats present aliases as "omitted" because the
condition uses !self.aliases.is_empty(); change that to self.aliases.is_empty()
inside the same if (the block that calls finish_non_exhaustive()) so the check
becomes: self.doc.is_none() || self.aliases.is_empty() || self.default.is_none()
|| self.custom_attributes.is_empty(), ensuring finish_non_exhaustive() is only
invoked when aliases are actually absent.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

value:useful; category:bug; feedback: The CodeRabbit AI reviewer is correct! The check for the aliases should be inverted, otherwise the Debug formatting will look like complete instead of as incomplete.

@augmentcode
Copy link
Copy Markdown

augmentcode bot commented Mar 2, 2026

🤖 Augment PR Summary

Summary: This PR makes a breaking cleanup to record-field handling by removing unused RecordField metadata and simplifying how field ordering is tracked.

Changes:

  • Removes `RecordFieldOrder` and the `RecordField.order` / `RecordField.position` fields from the public schema model.
  • Switches `RecordField.aliases` from Option<Vec<String>> to a default-empty Vec<String>, simplifying call sites.
  • Updates schema parsing to derive field positions via enumeration when building the record lookup table.
  • Refactors schema-aware serde serialization to use lookup-derived positions rather than per-field stored positions.
  • Updates derive macro output and tests to reflect the new `RecordField` shape and the updated record-field lookup logic.
  • Adjusts schema JSON serialization expectations and various test fixtures accordingly.

Technical Notes: Because position is no longer stored in RecordField, all ordering/lookup behavior now depends on the record’s fields vector order and the computed lookup table.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode bot left a comment

Choose a reason for hiding this comment

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

Review completed. 1 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

}),
None => Err(Details::FieldName(String::from(key)).into()),
if let Some(position) = self.record_schema.lookup.get(key).copied() {
let field = &self.record_schema.fields[position];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

position comes from record_schema.lookup, but indexing with self.record_schema.fields[position] will panic if the lookup table is ever inconsistent/out-of-bounds (previously this path used .get() and returned a structured error). Consider keeping this path panic-free since RecordSchema can be constructed manually and lookup can also include aliases.

Severity: medium

Other Locations
  • avro/src/serde/ser_schema/mod.rs:399
  • avro/src/serde/ser_schema/mod.rs:455

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

value:useful; category:bug; feedback: The Augment AI reviewer is correct! Using array indexing may lead to a panic if the lookup table becomes invalid for any reason. Using HashMap::get() would be safer since it will lead to returning an error instead of panicking.

@martin-augment
Copy link
Copy Markdown
Owner Author

193-195: ⚠️ Potential issue | 🟡 Minor

Update stale docs for #[serde(with = "...")] helper signature.

Line 194 still documents the removed usize parameter. That now conflicts with the current trait API and examples.

value:useful; category:bug; feedback: The CodeRabbit AI reviewer is correct! The signature of the AvroSchema:: get_record_fields_in_ctxt() has changed and the docstring has to be updated. Prevents generating wrong rustdoc

@martin-augment
Copy link
Copy Markdown
Owner Author

The condition for choosing between finish_non_exhaustive() and finish() has a logic error:

if self.doc.is_none()
    || !self.aliases.is_empty()  // <-- BUG: should be self.aliases.is_empty()
    || self.default.is_none()
    || self.custom_attributes.is_empty()
{
    debug.finish_non_exhaustive()
} else {
    debug.finish()
}

finish_non_exhaustive() (which appends .. ) should be used when any field is not displayed. The condition for each term should fire when the field was skipped:

  • self.doc.is_none() → doc skipped ✓
  • !self.aliases.is_empty() → aliases are non-empty (shown), not skipped ✗ (should be self.aliases.is_empty())
  • self.default.is_none() → default skipped ✓
  • self.custom_attributes.is_empty() → custom_attributes skipped ✓

The current code has two concrete problems:

  1. When aliases is non-empty, !self.aliases.is_empty() is always true, so we always fall into finish_non_exhaustive() even when all fields are displayed — the else branch is unreachable whenever aliases are present.
  2. When aliases is empty (not displayed) but all other optional fields are Some/non-empty, the condition is false, so we call finish() without the .. marker — incorrect, since aliases were skipped.

value:useful; category:bug; feedback: The Claude AI reviewer is correct! The check for the aliases should be inverted, otherwise the Debug formatting will look like complete instead of as incomplete.

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