use thiserror::Error;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Error, Debug)]
pub enum Error {
#[error("Transport error in {context}")]
Transport {
#[source]
source: zenoh::Error,
context: String,
},
#[error("Message serialization failed for type {type_name}")]
MessageSerialization {
#[source]
source: prost::EncodeError,
type_name: &'static str,
},
#[error("Message deserialization failed for type {type_name}")]
MessageDeserialization {
#[source]
source: prost::DecodeError,
type_name: &'static str,
},
#[error("Serialization error: {0}")]
Serialization(String),
#[error("Encoding error: {0}")]
Encoding(#[from] prost::EncodeError),
#[error("Decoding error: {0}")]
Decoding(#[from] prost::DecodeError),
#[error("Node '{name}' already exists")]
NodeAlreadyExists { name: String },
#[error("Topic '{topic}' already exists on node '{node}'")]
TopicAlreadyExists { topic: String, node: String },
#[error("Service '{service}' already exists on node '{node}'")]
ServiceAlreadyExists { service: String, node: String },
#[error("Service call to '{service}' timed out after {timeout_ms}ms")]
ServiceCallTimeout { service: String, timeout_ms: u64 },
#[error("Service call to '{service}' failed: {reason}")]
ServiceCallFailed { service: String, reason: String },
#[error("Parameter '{name}' error: {reason}")]
Parameter { name: String, reason: String },
#[error("Node '{node}' error: {reason}")]
Node { node: String, reason: String },
#[error("Publisher for topic '{topic}' error: {reason}")]
Publisher { topic: String, reason: String },
#[error("Subscriber for topic '{topic}' error: {reason}")]
Subscriber { topic: String, reason: String },
#[error("Service '{service}' error: {reason}")]
Service { service: String, reason: String },
#[error("Client for service '{service}' error: {reason}")]
Client { service: String, reason: String },
#[error("Operation '{operation}' not supported: {reason}")]
NotSupported { operation: String, reason: String },
#[error("Operation '{operation}' not implemented: {reason}")]
NotImplemented { operation: String, reason: String },
#[error("Configuration error: {reason}")]
Configuration { reason: String },
#[error("Network error: {reason}")]
Network { reason: String },
#[error("Error: {reason}")]
Other { reason: String },
}
impl From<zenoh::Error> for Error {
fn from(err: zenoh::Error) -> Self {
Error::Transport {
source: err,
context: "unknown".to_string(),
}
}
}
pub trait ErrorContext<T> {
fn with_context(self, context: &str) -> Result<T>;
fn with_context_f<F>(self, f: F) -> Result<T>
where
F: FnOnce() -> String;
}
impl<T> ErrorContext<T> for Result<T> {
fn with_context(self, context: &str) -> Result<T> {
self.map_err(|err| match err {
Error::Transport { source, .. } => Error::Transport {
source,
context: context.to_string(),
},
other => other,
})
}
fn with_context_f<F>(self, f: F) -> Result<T>
where
F: FnOnce() -> String,
{
self.map_err(|err| match err {
Error::Transport { source, .. } => Error::Transport {
source,
context: f(),
},
other => other,
})
}
}
impl Error {
pub fn transport(source: zenoh::Error, context: impl Into<String>) -> Self {
Error::Transport {
source,
context: context.into(),
}
}
pub fn message_serialization(source: prost::EncodeError, type_name: &'static str) -> Self {
Error::MessageSerialization { source, type_name }
}
pub fn message_deserialization(source: prost::DecodeError, type_name: &'static str) -> Self {
Error::MessageDeserialization { source, type_name }
}
pub fn node_already_exists(name: impl Into<String>) -> Self {
Error::NodeAlreadyExists { name: name.into() }
}
pub fn topic_already_exists(topic: impl Into<String>, node: impl Into<String>) -> Self {
Error::TopicAlreadyExists {
topic: topic.into(),
node: node.into(),
}
}
pub fn service_already_exists(service: impl Into<String>, node: impl Into<String>) -> Self {
Error::ServiceAlreadyExists {
service: service.into(),
node: node.into(),
}
}
pub fn service_call_timeout(service: impl Into<String>, timeout_ms: u64) -> Self {
Error::ServiceCallTimeout {
service: service.into(),
timeout_ms,
}
}
pub fn service_call_failed(service: impl Into<String>, reason: impl Into<String>) -> Self {
Error::ServiceCallFailed {
service: service.into(),
reason: reason.into(),
}
}
pub fn parameter(name: impl Into<String>, reason: impl Into<String>) -> Self {
Error::Parameter {
name: name.into(),
reason: reason.into(),
}
}
pub fn node(node: impl Into<String>, reason: impl Into<String>) -> Self {
Error::Node {
node: node.into(),
reason: reason.into(),
}
}
pub fn publisher(topic: impl Into<String>, reason: impl Into<String>) -> Self {
Error::Publisher {
topic: topic.into(),
reason: reason.into(),
}
}
pub fn subscriber(topic: impl Into<String>, reason: impl Into<String>) -> Self {
Error::Subscriber {
topic: topic.into(),
reason: reason.into(),
}
}
pub fn service(service: impl Into<String>, reason: impl Into<String>) -> Self {
Error::Service {
service: service.into(),
reason: reason.into(),
}
}
pub fn client(service: impl Into<String>, reason: impl Into<String>) -> Self {
Error::Client {
service: service.into(),
reason: reason.into(),
}
}
pub fn configuration(reason: impl Into<String>) -> Self {
Error::Configuration {
reason: reason.into(),
}
}
pub fn network(reason: impl Into<String>) -> Self {
Error::Network {
reason: reason.into(),
}
}
pub fn other(reason: impl Into<String>) -> Self {
Error::Other {
reason: reason.into(),
}
}
}