1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
use thiserror::Error;
#[derive(Debug, Error)]
pub enum StationError {
#[error("station not yet built")]
NotBuilt,
#[error("subscription failed: {0}")]
Subscribe(String),
/// The exchange does not expose this stream on the WS wire. Subscribe
/// MUST NOT spawn a forwarder for this combination — heal/resub would
/// loop forever. Surfaced from `subscribe_frame` returning either
/// `WebSocketError::WireAbsent` or `WebSocketError::NotImplemented`.
/// Consumers should treat this as a quiet "skip" rather than a hard
/// failure: it's an architectural fact about the venue, not a runtime fault.
#[error("stream not supported by exchange: {0}")]
StreamNotSupported(String),
#[error("core error: {0}")]
Core(String),
#[error("io error: {0}")]
Io(#[from] std::io::Error),
/// `Station::rewarm_derived` was asked to deepen a `SeriesKey.kind`
/// whose fold state cannot be reconstructed from the already-emitted
/// output alone (tick/volume imbalance bars and run bars carry EMA
/// state accumulated over the ENTIRE history — there is no
/// seed-from-output for that). Callers must fall back to the old
/// teardown + resubscribe-at-depth path for these three kinds.
#[error("kind does not support prepend-fold rewarm: {0}")]
RewarmUnsupported(String),
}
impl StationError {
/// True when this error originates from the venue not exposing the
/// requested stream (wire-not-present), as opposed to a transient
/// runtime failure. Used by `Station::subscribe(set)` to bucket
/// per-stream outcomes in the returned `SubscribeReport`.
pub fn is_not_supported(&self) -> bool {
matches!(self, StationError::StreamNotSupported(_))
}
}
pub type Result<T> = std::result::Result<T, StationError>;