2dc091d0be
Now that Subscription impls Stream<Item = Result<DataChange, Error>>,
the read-as-subscribe pattern is a thin wrapper over subscribe +
timeout + best-effort unsubscribe.
New
- Session::read(reference, timeout) -> Result<DataChange, Error> —
port of MxNativeSession.ReadAsync (cs:312-359). Validates timeout
> 0, subscribes, awaits the first DataChange under
tokio::time::timeout, then issues UnAdvise (best-effort, mirrors
the .NET finally block at cs:351-358 which discards the
unsubscribe return).
Error mapping
- timeout=0: Configuration::InvalidArgument ("Read timeout must be
positive") matching ArgumentOutOfRangeException at cs:318-321.
- timeout elapsed: Error::Timeout(timeout).
- subscribe failure (resolver / transport): propagated unchanged.
- stream ends before any value: Connection::EngineNotRegistered
(broadcast sender dropped during shutdown).
- unsubscribe failure: tracing::warn! with the error; doesn't
override the read result.
Removed the placeholder stub in lib.rs that returned
Error::Unsupported.
Tests (4 new in mxaccess; total 44)
- read_returns_first_data_change_within_timeout: spawn read,
inject a 0x33 DataUpdate via test_inject_sender (which fans out
to all subscriptions), assert the DataChange comes back with the
right value.
- read_returns_timeout_when_no_data_arrives: read times out cleanly
with Error::Timeout when no callback fires.
- read_zero_timeout_returns_invalid_argument_without_subscribing:
validates the early-reject path before any RPC is issued.
- read_propagates_resolver_not_found: subscribe-side error
surfaces through read unchanged.
Test count delta: 516 -> 520 (+4). All four DoD gates green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>