use crate::identity::{ExecutionId, IdentityError, ProducerId};
use crate::bus::abi::{CodecError, EncodingError};
use crate::bus::topic::WildcardPublish;
#[derive(Debug, thiserror::Error)]
pub enum BusError {
#[error("invalid bus key '{key}': {problem}")]
InvalidKey {
key: String,
problem: KeyProblem,
},
#[error(
"a second timeline authority was requested; exactly one participant may own a timeline"
)]
DuplicateTimelineAuthority,
#[error("this session's sample sequence is exhausted")]
SequenceExhausted,
#[error("bus session identity mismatch: expected producer {expected}, observed {observed}")]
SessionIdentityMismatch {
expected: ProducerId,
observed: ProducerId,
},
#[error("router execution identity mismatch: expected {expected}, observed {observed}")]
ExecutionIdentityMismatch {
expected: ExecutionId,
observed: ExecutionId,
},
#[error(transparent)]
Codec(#[from] CodecError),
#[error("unsupported codec id {codec} on '{topic}'")]
UnsupportedCodec {
codec: u8,
topic: String,
},
#[error("invalid bus metadata on '{topic}': {problem}")]
Metadata {
topic: String,
problem: MetadataProblem,
},
#[error("outbound {bound} bound on '{topic}'; value was not accepted")]
Saturated {
topic: String,
bound: OutboundBound,
},
#[error("stream would block on '{topic}'")]
WouldBlock {
topic: String,
},
#[error(
"stream gap on '{topic}' from producer {producer}: expected position {expected}, observed {observed}"
)]
StreamGap {
topic: String,
producer: ProducerId,
expected: u64,
observed: u64,
},
#[error("stream sample on '{topic}' has no stream position")]
MissingStreamPosition { topic: String },
#[error(
"stream position regressed on '{topic}' from producer {producer}: expected at least {expected}, observed {observed}"
)]
StreamPositionRegressed {
topic: String,
producer: ProducerId,
expected: u64,
observed: u64,
},
#[error("stream receiver on '{topic}' exceeded its {limit}-source position-history bound")]
TooManyStreamSources { topic: String, limit: usize },
#[error("setpoint receiver on '{topic}' exceeded its {limit}-source bound")]
TooManySetpointSources { topic: String, limit: usize },
#[error("session id '{zid}' is not a phoxal {role}: {source}")]
ForeignSessionId {
zid: String,
role: SessionIdRole,
source: IdentityError,
},
#[error("bus transport error: {0}")]
Transport(String),
#[error(transparent)]
WildcardPublish(#[from] WildcardPublish),
#[error("subscriber closed")]
Closed,
}
#[derive(Debug, thiserror::Error)]
pub enum KeyProblem {
#[error("not a legal Zenoh key expression: {0}")]
NotAKeyExpression(String),
#[error("must be a non-empty path with no empty segment")]
Empty,
#[error("must be one concrete key segment, with no '/'")]
NotOneSegment,
#[error("must be concrete: a wildcard is not a key")]
Wildcard,
#[error("uses an authority-reserved key prefix")]
ReservedPrefix,
#[error("exceeds the {limit}-byte limit")]
TooLong {
limit: usize,
},
}
#[derive(Debug, thiserror::Error)]
pub enum MetadataProblem {
#[error("missing a request payload")]
MissingPayload,
#[error("missing an encoding string")]
MissingEncoding,
#[error("malformed encoding string: {0}")]
MalformedEncoding(#[from] EncodingError),
#[error("missing a BusMetadata attachment")]
MissingAttachment,
#[error("malformed BusMetadata: {0}")]
MalformedAttachment(#[from] rmp_serde::decode::Error),
#[error(
"encoding/BusMetadata codec mismatch: encoding codec={encoding}, metadata codec={attachment}"
)]
CodecMismatch {
encoding: u8,
attachment: u8,
},
#[error("failed to encode BusMetadata: {0}")]
Encode(#[from] rmp_serde::encode::Error),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum OutboundBound {
Sample,
Byte,
}
impl std::fmt::Display for OutboundBound {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
OutboundBound::Sample => formatter.write_str("sample"),
OutboundBound::Byte => formatter.write_str("byte"),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SessionIdRole {
Execution,
Producer,
}
impl std::fmt::Display for SessionIdRole {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SessionIdRole::Execution => formatter.write_str("execution"),
SessionIdRole::Producer => formatter.write_str("producer"),
}
}
}
impl BusError {
pub(crate) fn not_a_key_expression(
key: impl Into<String>,
error: impl std::fmt::Display,
) -> Self {
BusError::InvalidKey {
key: key.into(),
problem: KeyProblem::NotAKeyExpression(error.to_string()),
}
}
pub(crate) fn invalid_key(key: impl Into<String>, problem: KeyProblem) -> Self {
BusError::InvalidKey {
key: key.into(),
problem,
}
}
pub(crate) fn metadata(topic: impl Into<String>, problem: impl Into<MetadataProblem>) -> Self {
BusError::Metadata {
topic: topic.into(),
problem: problem.into(),
}
}
}
pub type Result<T> = std::result::Result<T, BusError>;