Skip to main content

zenobuf_core/
error.rs

1//! Error types for the Zenobuf framework
2
3use thiserror::Error;
4
5/// Result type for Zenobuf operations
6pub type Result<T> = std::result::Result<T, Error>;
7
8/// Error type for Zenobuf operations
9#[derive(Error, Debug)]
10pub enum Error {
11    /// Error from the Zenoh transport layer
12    #[error("Transport error in {context}")]
13    Transport {
14        #[source]
15        source: zenoh::Error,
16        context: String,
17    },
18
19    /// Error during message serialization
20    #[error("Message serialization failed for type {type_name}")]
21    MessageSerialization {
22        #[source]
23        source: prost::EncodeError,
24        type_name: &'static str,
25    },
26
27    /// Error during message deserialization
28    #[error("Message deserialization failed for type {type_name}")]
29    MessageDeserialization {
30        #[source]
31        source: prost::DecodeError,
32        type_name: &'static str,
33    },
34
35    /// Error during serialization or deserialization (legacy)
36    #[error("Serialization error: {0}")]
37    Serialization(String),
38
39    /// Error during message encoding (legacy)
40    #[error("Encoding error: {0}")]
41    Encoding(#[from] prost::EncodeError),
42
43    /// Error during message decoding (legacy)
44    #[error("Decoding error: {0}")]
45    Decoding(#[from] prost::DecodeError),
46
47    /// Error when a node with the same name already exists
48    #[error("Node '{name}' already exists")]
49    NodeAlreadyExists { name: String },
50
51    /// Error when a topic with the same name already exists
52    #[error("Topic '{topic}' already exists on node '{node}'")]
53    TopicAlreadyExists { topic: String, node: String },
54
55    /// Error when a service with the same name already exists
56    #[error("Service '{service}' already exists on node '{node}'")]
57    ServiceAlreadyExists { service: String, node: String },
58
59    /// Error when a service call times out
60    #[error("Service call to '{service}' timed out after {timeout_ms}ms")]
61    ServiceCallTimeout { service: String, timeout_ms: u64 },
62
63    /// Error when a service call fails
64    #[error("Service call to '{service}' failed: {reason}")]
65    ServiceCallFailed { service: String, reason: String },
66
67    /// Error when a parameter operation fails
68    #[error("Parameter '{name}' error: {reason}")]
69    Parameter { name: String, reason: String },
70
71    /// Error when a node operation fails
72    #[error("Node '{node}' error: {reason}")]
73    Node { node: String, reason: String },
74
75    /// Error when a publisher operation fails
76    #[error("Publisher for topic '{topic}' error: {reason}")]
77    Publisher { topic: String, reason: String },
78
79    /// Error when a subscriber operation fails
80    #[error("Subscriber for topic '{topic}' error: {reason}")]
81    Subscriber { topic: String, reason: String },
82
83    /// Error when a service operation fails
84    #[error("Service '{service}' error: {reason}")]
85    Service { service: String, reason: String },
86
87    /// Error when a client operation fails
88    #[error("Client for service '{service}' error: {reason}")]
89    Client { service: String, reason: String },
90
91    /// Error when an operation is not supported
92    #[error("Operation '{operation}' not supported: {reason}")]
93    NotSupported { operation: String, reason: String },
94
95    /// Error when an operation is not implemented
96    #[error("Operation '{operation}' not implemented: {reason}")]
97    NotImplemented { operation: String, reason: String },
98
99    /// Configuration error
100    #[error("Configuration error: {reason}")]
101    Configuration { reason: String },
102
103    /// Network error
104    #[error("Network error: {reason}")]
105    Network { reason: String },
106
107    /// Other errors
108    #[error("Error: {reason}")]
109    Other { reason: String },
110}
111
112impl From<zenoh::Error> for Error {
113    fn from(err: zenoh::Error) -> Self {
114        Error::Transport {
115            source: err,
116            context: "unknown".to_string(),
117        }
118    }
119}
120
121// Error context helpers
122pub trait ErrorContext<T> {
123    /// Add context to an error
124    fn with_context(self, context: &str) -> Result<T>;
125    /// Add context with format arguments
126    fn with_context_f<F>(self, f: F) -> Result<T>
127    where
128        F: FnOnce() -> String;
129}
130
131impl<T> ErrorContext<T> for Result<T> {
132    fn with_context(self, context: &str) -> Result<T> {
133        self.map_err(|err| match err {
134            Error::Transport { source, .. } => Error::Transport {
135                source,
136                context: context.to_string(),
137            },
138            other => other,
139        })
140    }
141
142    fn with_context_f<F>(self, f: F) -> Result<T>
143    where
144        F: FnOnce() -> String,
145    {
146        self.map_err(|err| match err {
147            Error::Transport { source, .. } => Error::Transport {
148                source,
149                context: f(),
150            },
151            other => other,
152        })
153    }
154}
155
156// Helper functions for creating structured errors
157impl Error {
158    /// Create a transport error with context
159    pub fn transport(source: zenoh::Error, context: impl Into<String>) -> Self {
160        Error::Transport {
161            source,
162            context: context.into(),
163        }
164    }
165
166    /// Create a message serialization error
167    pub fn message_serialization(source: prost::EncodeError, type_name: &'static str) -> Self {
168        Error::MessageSerialization { source, type_name }
169    }
170
171    /// Create a message deserialization error
172    pub fn message_deserialization(source: prost::DecodeError, type_name: &'static str) -> Self {
173        Error::MessageDeserialization { source, type_name }
174    }
175
176    /// Create a node already exists error
177    pub fn node_already_exists(name: impl Into<String>) -> Self {
178        Error::NodeAlreadyExists { name: name.into() }
179    }
180
181    /// Create a topic already exists error
182    pub fn topic_already_exists(topic: impl Into<String>, node: impl Into<String>) -> Self {
183        Error::TopicAlreadyExists {
184            topic: topic.into(),
185            node: node.into(),
186        }
187    }
188
189    /// Create a service already exists error
190    pub fn service_already_exists(service: impl Into<String>, node: impl Into<String>) -> Self {
191        Error::ServiceAlreadyExists {
192            service: service.into(),
193            node: node.into(),
194        }
195    }
196
197    /// Create a service call timeout error
198    pub fn service_call_timeout(service: impl Into<String>, timeout_ms: u64) -> Self {
199        Error::ServiceCallTimeout {
200            service: service.into(),
201            timeout_ms,
202        }
203    }
204
205    /// Create a service call failed error
206    pub fn service_call_failed(service: impl Into<String>, reason: impl Into<String>) -> Self {
207        Error::ServiceCallFailed {
208            service: service.into(),
209            reason: reason.into(),
210        }
211    }
212
213    /// Create a parameter error
214    pub fn parameter(name: impl Into<String>, reason: impl Into<String>) -> Self {
215        Error::Parameter {
216            name: name.into(),
217            reason: reason.into(),
218        }
219    }
220
221    /// Create a node error
222    pub fn node(node: impl Into<String>, reason: impl Into<String>) -> Self {
223        Error::Node {
224            node: node.into(),
225            reason: reason.into(),
226        }
227    }
228
229    /// Create a publisher error
230    pub fn publisher(topic: impl Into<String>, reason: impl Into<String>) -> Self {
231        Error::Publisher {
232            topic: topic.into(),
233            reason: reason.into(),
234        }
235    }
236
237    /// Create a subscriber error
238    pub fn subscriber(topic: impl Into<String>, reason: impl Into<String>) -> Self {
239        Error::Subscriber {
240            topic: topic.into(),
241            reason: reason.into(),
242        }
243    }
244
245    /// Create a service error
246    pub fn service(service: impl Into<String>, reason: impl Into<String>) -> Self {
247        Error::Service {
248            service: service.into(),
249            reason: reason.into(),
250        }
251    }
252
253    /// Create a client error
254    pub fn client(service: impl Into<String>, reason: impl Into<String>) -> Self {
255        Error::Client {
256            service: service.into(),
257            reason: reason.into(),
258        }
259    }
260
261    /// Create a configuration error
262    pub fn configuration(reason: impl Into<String>) -> Self {
263        Error::Configuration {
264            reason: reason.into(),
265        }
266    }
267
268    /// Create a network error
269    pub fn network(reason: impl Into<String>) -> Self {
270        Error::Network {
271            reason: reason.into(),
272        }
273    }
274
275    /// Create an other error
276    pub fn other(reason: impl Into<String>) -> Self {
277        Error::Other {
278            reason: reason.into(),
279        }
280    }
281}