Background
After PR #336, `ProtocolRustBinding` has 18 fields including three `BTreeMap<String, String>` / `BTreeMap<String, Vec>` maps keyed on feedback input variants:
```rust
pub handle_method_names: BTreeMap<String, String>,
// Keys: feedback.input_variant → handle-trait method name
pub handle_arg_accessors: BTreeMap<String, String>,
// Keys: "{input_variant}.{obligation_field}" → Rust suffix text (".0", ".clone()", ".into()")
pub handle_method_forwarded_fields: BTreeMap<String, Vec>,
// Keys: feedback.input_variant → ordered list of obligation field names
```
Problems flagged by review:
- Inconsistent composite key schemes — `handle_arg_accessors` uses dotted composite keys while the other two use bare input_variant keys.
- `handle_arg_accessors` is effectively a raw Rust suffix text escape hatch (".iter().map(ToString::to_string).collect()" in one concrete case) — this is stringly-typed transformation logic that should live in code, not data.
- No compile-time guarantee that every feedback input has all required entries across the three maps.
Proposed refactor
Introduce a typed container that groups all HandleBridge bindings for one feedback input:
```rust
pub struct HandleBridgeFeedbackBinding {
/// Handle trait method to call.
pub method: String,
/// Positional arguments (in order) with per-arg conversion.
pub args: Vec,
}
pub enum HandleBridgeArg {
/// Pass `obligation.` through the specified accessor.
Obligation {
field: String,
access: HandleBridgeAccess,
},
/// Pass an owner-supplied value at call time (String / Into).
OwnerContext { name: String },
}
pub enum HandleBridgeAccess {
/// Pass `obligation.` directly.
Direct,
/// Pass `obligation..0` (unwrap typed newtype to its inner value).
NewtypeInner,
/// Pass `obligation..clone()`.
Clone,
/// Pass `obligation..iter().map(ToString::to_string).collect()`
/// (typed ID set to BTreeSet).
StringifySet,
}
```
Replace all three maps on `ProtocolRustBinding` with:
```rust
pub handle_bridge_bindings: BTreeMap<String, HandleBridgeFeedbackBinding>,
// Keys: feedback.input_variant
```
Validation then becomes a single "every HandleBridge feedback input has a binding entry" check, and the codegen emits real typed logic instead of gluing Rust suffix text.
Estimated size
~60 lines of schema changes, ~30 lines of codegen refactor, plus migration of the three existing compositions to the new shape. Not a large change; mostly data-layout work.
References
Background
After PR #336, `ProtocolRustBinding` has 18 fields including three `BTreeMap<String, String>` / `BTreeMap<String, Vec>` maps keyed on feedback input variants:
```rust
pub handle_method_names: BTreeMap<String, String>,
// Keys: feedback.input_variant → handle-trait method name
pub handle_arg_accessors: BTreeMap<String, String>,
// Keys: "{input_variant}.{obligation_field}" → Rust suffix text (".0", ".clone()", ".into()")
pub handle_method_forwarded_fields: BTreeMap<String, Vec>,
// Keys: feedback.input_variant → ordered list of obligation field names
```
Problems flagged by review:
Proposed refactor
Introduce a typed container that groups all HandleBridge bindings for one feedback input:
```rust
pub struct HandleBridgeFeedbackBinding {
/// Handle trait method to call.
pub method: String,
/// Positional arguments (in order) with per-arg conversion.
pub args: Vec,
}
pub enum HandleBridgeArg {
/// Pass `obligation.` through the specified accessor.
Obligation {
field: String,
access: HandleBridgeAccess,
},
/// Pass an owner-supplied value at call time (String / Into).
OwnerContext { name: String },
}
pub enum HandleBridgeAccess {
/// Pass `obligation.` directly.
Direct,
/// Pass `obligation..0` (unwrap typed newtype to its inner value).
NewtypeInner,
/// Pass `obligation..clone()`.
Clone,
/// Pass `obligation..iter().map(ToString::to_string).collect()`
/// (typed ID set to BTreeSet).
StringifySet,
}
```
Replace all three maps on `ProtocolRustBinding` with:
```rust
pub handle_bridge_bindings: BTreeMap<String, HandleBridgeFeedbackBinding>,
// Keys: feedback.input_variant
```
Validation then becomes a single "every HandleBridge feedback input has a binding entry" check, and the codegen emits real typed logic instead of gluing Rust suffix text.
Estimated size
~60 lines of schema changes, ~30 lines of codegen refactor, plus migration of the three existing compositions to the new shape. Not a large change; mostly data-layout work.
References