Repository navigation
refactor(s3s): move the POST Object form parsing into a handwritten module - #994
Conversation
…odule PostObject::deserialize_http and serialize_http were emitted as function bodies into crates/s3s/src/ops/generated/post_object.rs. Move both verbatim into crates/s3s/src/ops/post_object.rs and emit thin delegates instead, so the POST-specific parsing and response serialization live in hand-written code. The struct, the Operation impl and the call glue stay generated, and the wrapper methods keep their public signatures. No behavior change. Assisted-by: DeepSeek Harness:deepseek-flash
The wire suite covers the client-visible shapes, but it cannot reach the control-character rejection or the URL parse failure of the redirect, nor pin the status mapping in isolation. Call serialize_http directly for the default, 200, 201 and unrecognized statuses, for a redirect with a control character and for an unparsable redirect. Assisted-by: DeepSeek Harness:deepseek-flash
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
🟢 Approval recommended
It is a faithful, verifiable code move with matching idempotent codegen output, all references resolving, and added unit tests covering the extracted logic.
0 open findings
What changed in this PR
This PR refactors the PostObject operation in the s3s crate by extracting its POST-specific form-parsing (deserialize_http) and response-serialization (serialize_http) logic out of the generated operation file and into a new hand-written module crates/s3s/src/ops/post_object.rs. The generated file (ops/generated/post_object.rs) and the codegen emitter (codegen/src/v2/post_object.rs) are reduced to thin delegations. This establishes a clean generated-vs-hand-written boundary so that future changes to the POST-specific semantics (part of the broader #982 effort to stop modeling POST Object as a fork of PutObject) can be made without touching the generator. Observable wire behavior is unchanged.
Changes:
- Move
deserialize_http/serialize_httpinto hand-writtenops/post_object.rs(aspub(crate)fns) and register the module inops/mod.rs. - Thin the codegen emitter and the generated file so
PostObject's methods delegate to the new module; drop the now-unusedPutObjectimport from the generated file. - Add six unit tests covering the serialize branches (200 / 201 / unrecognized / default status, control-character rejection, unparsable redirect) that the wire suite cannot reach.
| File | Description |
|---|---|
| crates/s3s/src/ops/post_object.rs | New hand-written module holding the moved parse/serialize functions plus six unit tests. |
| crates/s3s/src/ops/mod.rs | Registers the new post_object module. |
| crates/s3s/src/ops/generated/post_object.rs | Generated PostObject methods now delegate to the hand-written module; unused PutObject import removed. |
| codegen/src/v2/post_object.rs | Emitter updated to produce the thin delegations and the trimmed import set. |
I verified that the emitter output exactly matches the committed generated file (idempotent), all imports in both files remain used (the removed PutObject import is no longer referenced), the invalid_request!/s3_error! macros stay in scope via #[macro_use] on utils/error before ops, and all delegated paths resolve through pub use self::generated::*;. The new tests exercise the serialize branches not reachable by the wire suite. No issues were found.
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The patch coverage of the moved module left the missing multipart form, the legacy redirect fallback, a malformed success_action_status and the XML body error path unexercised. Cover each directly; the moved functions stay byte for byte unchanged. Assisted-by: DeepSeek Harness:deepseek-flash
parse_field_value is infallible for String, and a non-UTF-8 field is rejected by the multipart parser before the operation sees it, so the two redirect lookups have no reachable error path. Call them with a text value and show the rejection happens when the response is serialized instead. Assisted-by: DeepSeek Harness:deepseek-flash
Summary
POST Object's form parsing and its success responses used to be emitted straight into the generated operation file, so changing them meant changing the generator and the generated artifact together. This moves both functions into a hand-written module,crates/s3s/src/ops/post_object.rs, and leaves the generated file a wrapper that delegates to it. The generated file drops from 157 to 91 lines while the behaviour stays put: the wire suite passes in both feature sets, and a red control on the moved status mapping fails it.Changes
crates/s3s/src/ops/post_object.rsholdingdeserialize_httpandserialize_http, moved verbatim from the generated file (only paths, imports and visibility changed), and register the module inops/mod.rs.codegen/src/v2/post_object.rs, so the generatedPostObjectkeeps itspub fnmethods and theOperation::callglue is untouched.Behavior
None for callers: the wrappers keep their signatures and the response construction is the same code, so the recorded wire behaviour is unchanged in both feature sets.
Tests
cargo test -p s3s --all-features --lib→ exit 0, 1048 passed, 0 failed;cargo test -p s3s --all-features --test post_object_wireand the default feature set → 12 passed each.just codegentwice → exit 0 and 0, with 0 dirty files after each run, so the wrapper the generator emits is the committed one.compare_move.py --selftest). The generated file's diff is the two delegations and its imports; theOperation::callglue is unchanged.just dev→ exit 0;cargo +nightly clippy --workspace --all-targets --all-features -- -D warnings→ exit 0;just ci-rust→ exit 0, withassert_unchangedreporting a clean tree.200with201, each fail the suite with exit 101; restoring them returns to green. The status-mapping control was also reproduced during review by making the200branch answer201.?on the redirect lookups (T = Stringmakes the parse infallible) and the header-value conversion after a parsed URL (ASCII by construction). A test pins the observable half of that: the redirect value is validated when the response is serialized, not while parsing.References
Part of #982.
Dependencies
Based on
mainafter the codegen v2 change merged (#993). No dependency or manifest changes.AI
Written with DeepSeek Harness (
deepseek-flash): it moved the functions, thinned the emitter, wrote the unit tests and ran the gates and red controls above; the review re-ran the acceptance checks on the rebased stack. A human reviewed the diff and owns the change.