1use std::sync::Arc;
2
3use thiserror::Error;
4
5#[derive(Error, Debug, Clone)]
6#[non_exhaustive]
7pub enum Error {
8 #[error("Connection is already disconnected or has terminated normally")]
9 Disconnected,
10
11 #[error("Failed to connect: {source}")]
12 FailedToConnect {
13 #[source]
14 source: InternalError,
15 },
16
17 #[error("Host returned error when processing subscription query: {error}")]
18 SubscriptionError { error: String },
19
20 #[error("Subscription has already ended")]
21 AlreadyEnded,
22
23 #[error("Unsubscribe already called on subscription")]
24 AlreadyUnsubscribed,
25
26 #[error(transparent)]
27 Internal(#[from] InternalError),
28}
29
30#[derive(Debug, Clone)]
31pub struct InternalError {
32 message: String,
33 cause: Option<Arc<dyn std::error::Error + Send + Sync>>,
34}
35
36impl InternalError {
37 pub(crate) fn new(message: impl Into<String>) -> Self {
38 Self {
39 message: message.into(),
40 cause: None,
41 }
42 }
43
44 #[doc(hidden)]
45 pub fn with_cause(self, cause: impl std::error::Error + Send + Sync + 'static) -> Self {
47 Self {
48 cause: Some(Arc::new(cause)),
49 ..self
50 }
51 }
52
53 #[doc(hidden)]
54 pub fn failed_parse(ty: &'static str, container: &'static str) -> Self {
56 Self::new(format!(
57 "Failed to parse {ty} from {container}.
58
59This is often caused by outdated bindings; try re-running `spacetime generate`."
60 ))
61 }
62
63 #[doc(hidden)]
64 pub fn unknown_name(category: &'static str, name: impl std::fmt::Display, container: &'static str) -> Self {
66 Self::new(format!(
67 "Unknown {category} {name} in {container}
68
69This is often caused by outdated bindings; try re-running `spacetime generate`."
70 ))
71 }
72}
73
74impl std::fmt::Display for InternalError {
75 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
76 f.write_str(&self.message)?;
77 if let Some(cause) = &self.cause {
78 write!(f, ": {cause}")?;
79 }
80 Ok(())
81 }
82}
83
84impl std::error::Error for InternalError {
85 fn cause(&self) -> Option<&dyn std::error::Error> {
86 if let Some(cause) = &self.cause {
91 Some(cause)
92 } else {
93 None
94 }
95 }
96 fn description(&self) -> &str {
97 &self.message
98 }
99 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
100 None
101 }
102}
103
104pub type Result<T> = std::result::Result<T, Error>;