[http-client-rust] Multi-inheritance for polymorphic types Implementation
- Dominant language
- Rust
- Stars
- 7
- Forks
- 11
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 5
Description
## Summary
Implement support for multi-level (nested) polymorphic discriminators, where a base type has a discriminator and a derived type introduces a second discriminator.
## Spector Test Coverage
**No spector test currently exists.** The `nested-discriminator` spec from `@typespec/http-specs` (`type/model/inheritance/nested-discriminator`) is not wired up in `tspcompile.js` and no test crate exists under `test/spector/`.
### Existing related tests:
- `type/model/inheritance/single-discriminator` ✅ (single-level discriminator)
- `type/model/inheritance/enum-discriminator` ✅ (enum-based discriminator)
- `type/model/inheritance/not-discriminated` ✅ (plain inheritance)
- `type/model/inheritance/recursive` — ✅
- **`type/model/inheritance/nested-discriminator`** — ❌ not wired up
## Scenario from `@typespec/http-specs`
The `nested-discriminator` TypeSpec spec defines:
```typespec
@discriminator("kind")
model Fish { age: int32; }
@discriminator("sharktype")
model Shark extends Fish { kind: "shark"; sharktype: string; }
model Salmon extends Fish { kind: "salmon"; friends?: Fish[]; hate?: Record; partner?: Fish; }
model SawShark extends Shark { sharktype: "saw"; }
model GoblinShark extends Shark { sharktype: "goblin"; }
```
Key challenge: `Fish` uses `"kind"` as its discriminator, and `Shark` (a subtype of `Fish`) introduces a second discriminator `"sharktype"` for its own subtypes.
### API operations in the spec:
1. `GET /model` — return a `GoblinShark` (`{"age": 1, "kind": "shark", "sharktype": "goblin"}`)
2. `PUT /model` — accept a `GoblinShark`
3. `GET /recursivemodel` — return a `Salmon` with nested polymorphic references (`Fish[]`, `Record`, `Fish`)
4. `PUT /recursivemodel` — accept recursive polymorphic input
5. `GET /missingdiscriminator` — return a `Fish` without the discriminator field
6. `GET /wrongdiscriminator` — return a `Fish` with an unknown discriminator value
## Implementation Plan
### 1. Emitter changes (`packages/typespec-rust/src/`)
The current `getDiscriminatedUnion()` in `src/tcgcadapter/adapter.ts` handles single-level discriminators. It needs to handle the case where a discriminated union member itself has `discriminatedSubtypes` (i.e., `Shark` is both a member of the `Fish` union and a base for the `Shark` union).
Key areas to investigate/modify:
- **`src/tcgcadapter/adapter.ts`** (lines ~235, 515-555): `getDiscriminatedUnion()` iterates `discriminatedSubtypes` but may not recursively handle subtypes that themselves define discriminators
- **`src/codegen/models.ts`**: Serde attribute generation needs to handle nested `#[serde(tag = ...)]` for multi-level discriminators
- **`src/codegen/unions.ts`**: Serialize implementation for nested discriminated unions
### 2. Add spector test
1. Add entry to `.scripts/tspcompile.js`:
```javascript
'spector_nesteddisc': {input: 'type/model/inheritance/nested-discriminator'},
```
2. Run `pnpm run tspcompile --filter=nesteddisc` to generate the test crate
3. Create integration tests in `test/spector/type/model/inheritance/nested-discriminator/tests/` covering:
- GET/PUT simple nested discriminator model
- GET/PUT recursive models with nested polymorphic references
- Missing discriminator handling
- Wrong/unknown discriminator handling
### 3. Verify Rust codegen output
The generated Rust types need to correctly represent the two-level discriminator hierarchy. Possible approaches:
- **Flatten**: A single `Fish` enum with variants for all leaf types (`Salmon`, `SawShark`, `GoblinShark`) with appropriate serde tagging
- **Nested enums**: A `Fish` enum containing a `Shark` enum variant that itself discriminates on `sharktype`
The approach should be consistent with how other Rust SDKs handle this pattern and should produce correct round-trip serialization.
### 4. Validation
- `pnpm build` — emitter compiles
- `pnpm test` — unit tests pass
- `cargo build` — generated Rust crates compile
- `cargo clippy` — no warnings
- `pnpm spector --start && cargo test` — integration tests pass
Contributor guide
Assessment
This issue has not been assessed yet.