Ports `Variant` (cs:1170-1241), `AsbStatus` (cs:1109-1167), `RuntimeValue`
(cs:741-791), `AsbVariantFactory.From*` (cs:1310-1429), and
`MxAsbDataClient.DecodeVariant` (cs:713-825) into `mxaccess-codec::asb_variant`.
Three layers per `docs/ASB-Variant-Wire-Format.md`:
1. `AsbVariant` — raw 2/4/4/payload header + bytes; round-trips byte-identical.
2. `DecodedVariant` — typed view with one variant per proven ASB scalar / array
(`Bool`, `Int32`, `Float`, `Double`, `String`, `DateTime`, `Duration` plus
array forms). Type ids outside the proven matrix surface as
`Unsupported { type_id, payload }` — same fallback as .NET's `_ => payload`.
3. `from_*` factories — mirror `AsbVariantFactory.FromX` exactly, setting
`length` to `payload.len()` per `cs:1431-1438`.
`AsbStatus` and `RuntimeValue` round-trip the wire layout verbatim.
Status-element walking (marker bit 7 = implicit zero, etc., per
`docs/ASB-Variant-Wire-Format.md:180-205`) is deferred to a follow-up; the
codec exposes the raw status payload bytes for now, matching .NET's
`AsbStatus.Payload = byte[]` shape.
The lib.rs `AsbVariant` / `AsbStatus` / `RuntimeValue` stubs are replaced by
the real types via `pub use`. 25 new unit tests cover the proven matrix:
scalar + array round-trip, byte layout (2/4/4/payload), `Unsupported`
fallback for declared-but-unproven types, short-frame rejection,
malformed `string[]` partial-decode preservation matching .NET behavior.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Last codec-side prerequisite before F13 (NmxClient high-level write
wrappers) can land. Two small additions, both wire-byte-direct ports
of the .NET reference's MxDataType → MxValueKind lookup logic.
mxaccess-codec
- MxValueKind::for_data_type(MxDataType, is_array) -> Option<MxValueKind>:
fuses NmxWriteMessage.cs:58-86 (TryGetValueKind's 12 base mappings
for data types 1..=6 scalar+array) with the two scalar fallbacks the
.NET GalaxyTagMetadata.ProjectWriteValue layers on top
(GalaxyRepositoryTagResolver.cs:65-69): ElapsedTime → Int32,
InternationalizedString → String. Returns None for any other
combination — including arrays of those two types and unsupported
scalars (ReferenceType, StatusType, Enum, etc.).
- 6 new tests covering the base table, both fallbacks, the array-of-
unsupported rejection, and the no-mapping branch for ReferenceType /
StatusType / Enum / DataQualityType / BigString / Unknown / NoData /
End sentinels.
mxaccess-galaxy
- GalaxyTagMetadata::resolve_write_kind() -> Result<MxValueKind,
UnsupportedDataType>: pure delegation to MxValueKind::for_data_type
+ a typed error carrying (mx_data_type, is_array) for diagnostics.
- GalaxyTagMetadata::is_writable() — Ok-side accessor for browse UIs.
- UnsupportedDataType public error type (re-exported from lib.rs).
- 7 new tests: Double scalar → Float64, Boolean array → BoolArray,
ElapsedTime scalar → Int32 (the fallback path), array-of-ElapsedTime
rejected, InternationalizedString → String, ReferenceType rejected,
Unknown sentinel rejected.
Test count delta: 446 -> 459 (+13; codec 215 -> 221, galaxy 49 -> 56).
All four DoD gates green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>