Skip to content

refactor(hyperlane): route field accessors through Data macros - #45

Merged
vshengbro merged 3 commits into
masterfrom
refactor/lombok-data-macros
Oct 12, 2026
Merged

vshengbro merged 3 commits into
masterfrom
refactor/lombok-data-macros

Conversation

@vshengbro

Copy link
Copy Markdown
Member

Summary

Adds multipart/form-data and URL-encoded body parsing to http-type, and
replaces every hand-written struct field accessor in the workspace with
lombok Data-generated accessors so field access has one source of truth.

Two request defects surfaced while wiring up the new body API and are
fixed here: repeated query keys silently lost every value but the last,
and header lookup failed for any key that was not already lowercase.

Changes

Body parsing (new):

  • type/src/body/struct.rs — BodyPart and MultipartFormData
  • type/src/body/impl.rs — multipart and URL-encoded parsing, plus
    part-level and form-value access
  • type/src/body/const.rs, type/src/body/type.rs — internal constants
    and the BodyFormValue / content-type aliases
  • type/tests/body/ — multipart and form tests

Request correctness:

  • type/src/request/type.rs — RequestQuerysValue becomes
    VecDeque<String> so a repeated key keeps all its values
  • type/src/request/impl.rs — query parser and accessors handle the
    multi-value case; header lookup is case-insensitive to match the
    lowercased keys the header parser stores
  • type/tests/request/fn.rs — multi-value query coverage

Accessors and visibility (workspace-wide):

  • 21 hand-written get_* / set_* accessors removed in favour of
    Data derives across RequestConfig, HttpRequest, WebSocket,
    WebSocketConfig, Body and RequestBuilder
  • request/src/request/config/impl.rs deleted outright once its accessors
    became generated
  • business code no longer reads struct fields directly, going through
    accessors instead
  • field visibility narrowed to the least each field needs: pub(super)
    inside a module tree, pub(crate) across sibling modules, pub only
    for cross-crate and integration-test consumers
  • RequestBuilder::request keeps its public mutable accessor because
    request/tests/builder consumes it

Verification

  • cargo test --workspace — 724 passed, 0 failed
  • cargo clippy --all-targets — 0 warnings
  • crate fmt --check — clean, idempotent
  • audit_rust_standards.py . — 51/51 PASS
  • Independent scan for hand-written field accessors — 21 before,
    0 after
  • git commit ran the real pre-commit gate (no --no-verify);
    0 new violations
  • Commit author is the global-config identity, vshengbro <root@ltpp.vip>

Notes

WebSocketConfig deliberately keeps its hand-written set_* methods.
They are fluent builders taking mut self and returning Self, not
field setters, so converting them to macro-generated setters would change
their meaning. Those fields are marked #[set(skip)]; their getters are
generated like everything else.

type(clone) is required rather than redundant on the 13 Option<T> and
Method fields that carry it. Checked against lombok 10.2.2 source:
ReturnType::Reference is the default, so a Clone field without the
attribute yields &T; and for Option<T> the default branch generates
self.field.clone().unwrap(), which would turn "unset" into a panic.
Removing the attribute from each of four representative fields was tried
and all four failed to compile, so it stays.

WebSocketConfig holds &mut references and therefore cannot derive
Clone, Debug or Default; it was previously carrying no derives at
all and nothing in the workspace depends on those traits for it.

Parser failures return Option, following the existing try_get_*
convention, rather than a bespoke error type.

🤖 Generated with Hermes

@ghfind-review ghfind-review Bot added the review: high ghfind author score; see https://ghfind.com label Oct 12, 2026
Minor version bump for the accessor refactor and the new body parser.

- 21.12.1 -> 21.13.0, minor bump as defined by `crate bump --minor`
- `[workspace.package].version` is the single source of truth: all eight
  members use `version.workspace = true`
- `crate sync` realigned the nine `[workspace.dependencies]`
  entries, and is idempotent on a second run

🤖 Generated with [Hermes](https://hermes-agent.nousresearch.com)
Add multipart/form-data and URL-encoded body parsing, and replace every
hand-written field accessor in the workspace with lombok `Data`
accessors, so field access has one source of truth.

Body parsing:
- new `type/src/body` module parsing multipart/form-data parts and
  URL-encoded forms, exposed through `Request` body entry points
- parser failures return `Option` instead of a bespoke `BodyError`,
  matching the existing `try_get_*` accessor convention in the project
- a multipart body without its closing boundary is rejected rather than
  silently accepted as a short upload

Request fixes found while wiring the new body API:
- `RequestQuerysValue` is now a `VecDeque<String>` so repeated query
  keys keep every value; the previous map silently dropped all but the
  last one
- header lookup is now case-insensitive, matching the lowercased keys
  the header parser stores

Accessor and visibility pass across the workspace:
- 21 hand-written `get_*` / `set_*` accessors removed and replaced by
  `Data` derives; `request/src/request/config/impl.rs` is deleted
  outright
- business code no longer touches struct fields directly, going through
  generated accessors instead
- field visibility reduced to the narrowest level each field actually
  needs: `pub(super)` within a module tree, `pub(crate)` across sibling
  modules, `pub` for cross-crate and integration-test consumers
- accessor visibility kept aligned with the visibility of its field

`WebSocketConfig` keeps its hand-written `set_*` methods: they are
fluent builders taking `mut self` and returning `Self`, not field
setters, so they are marked `#[set(skip)]` rather than converted.

🤖 Generated with [Hermes](https://hermes-agent.nousresearch.com)
The rebase onto master brought the workspace back to full scan coverage
and surfaced two audit failures. One was inherited debt; both are fixed
here so the branch passes all 51 checks.

Check 16 (R1.3a) — `impl Default for Tmp` lived in the keyword file
`request/src/request/tmp/struct.rs`. It now lives in a sibling
`impl.rs`, registered in `mod.rs` in the house declaration order.

Check 18 (R1.3c) — literals moved out of function bodies into
`const.rs`:
- `type/src/body/impl.rs`: the header separator, the URL-encoded
  space, plus and percent bytes, and the six hex digit bounds
- `request/src/request/http_request/impl.rs`: the header value separator
  and the CRLF pattern, which were pre-existing debt on master

🤖 Generated with [Hermes](https://hermes-agent.nousresearch.com)
@vshengbro
vshengbro force-pushed the refactor/lombok-data-macros branch from 84d69cc to 57b9aed Compare October 12, 2026 13:01
@vshengbro
vshengbro merged commit c39d666 into master Oct 12, 2026
8 checks passed
@vshengbro
vshengbro deleted the refactor/lombok-data-macros branch October 12, 2026 13:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review: high ghfind author score; see https://ghfind.com

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant