perspective_client/utils/
mod.rs1mod clone;
16mod logging;
17
18#[cfg(test)]
19mod tests;
20
21use std::sync::Arc;
22
23use rand_unique::{RandomSequence, RandomSequenceBuilder};
24use thiserror::*;
25
26use crate::proto;
27
28#[derive(Clone, Error, Debug)]
29pub enum ClientError {
30 #[error("View not found")]
31 ViewNotFound,
32
33 #[error("Abort(): {0}")]
34 Internal(String),
35
36 #[error("Transport error: {0}")]
37 TransportError(String),
38
39 #[error("Client not yet initialized")]
40 NotInitialized,
41
42 #[error("Unknown error: {0}")]
43 Unknown(String),
44
45 #[error("Unwrapped option")]
46 Option,
47
48 #[error("Bad string")]
49 Utf8(#[from] std::str::Utf8Error),
50
51 #[error("Undecipherable server message {0:?}")]
52 DecodeError(#[from] prost::DecodeError),
53
54 #[error("Response aborted")]
55 ResponseAborted,
56
57 #[error("Unexpected response {0:?}")]
58 ResponseFailed(Box<proto::response::ClientResp>),
59
60 #[error("Not yet implemented {0:?}")]
61 NotImplemented(&'static str),
62
63 #[error("Can't use both `limit` and `index` arguments")]
64 BadTableOptions,
65
66 #[error("External error: {0}")]
67 ExternalError(Arc<Box<dyn std::error::Error + Send + Sync>>),
68
69 #[error("Undecipherable proto message")]
70 ProtoError(#[from] prost::EncodeError),
71
72 #[error("Duplicate name {0}")]
73 DuplicateNameError(String),
74}
75
76pub type ClientResult<T> = Result<T, ClientError>;
77
78impl From<Box<dyn std::error::Error + Send + Sync>> for ClientError {
79 fn from(value: Box<dyn std::error::Error + Send + Sync>) -> Self {
80 ClientError::ExternalError(Arc::new(value))
81 }
82}
83
84impl<'a, A> From<std::sync::PoisonError<std::sync::MutexGuard<'a, A>>> for ClientError {
85 fn from(_: std::sync::PoisonError<std::sync::MutexGuard<'a, A>>) -> Self {
86 ClientError::Internal("Lock Error".to_owned())
87 }
88}
89
90impl From<Option<proto::response::ClientResp>> for ClientError {
91 fn from(value: Option<proto::response::ClientResp>) -> Self {
92 match value {
93 Some(proto::response::ClientResp::ServerError(x)) => match x.status_code() {
94 proto::StatusCode::ServerError => ClientError::Internal(x.message),
95 proto::StatusCode::ViewNotFound => ClientError::ViewNotFound,
96 proto::StatusCode::TransportError => ClientError::TransportError(x.message),
97 },
98 Some(x) => ClientError::ResponseFailed(Box::new(x)),
99 None => ClientError::ResponseAborted,
100 }
101 }
102}
103
104impl From<proto::response::ClientResp> for ClientError {
105 fn from(value: proto::response::ClientResp) -> Self {
106 match value {
107 proto::response::ClientResp::ServerError(x) => match x.status_code() {
108 proto::StatusCode::ServerError => ClientError::Internal(x.message),
109 proto::StatusCode::ViewNotFound => ClientError::ViewNotFound,
110 proto::StatusCode::TransportError => ClientError::TransportError(x.message),
111 },
112 x => ClientError::ResponseFailed(Box::new(x)),
113 }
114 }
115}
116
117pub trait PerspectiveResultExt {
118 fn unwrap_or_log(&self);
119}
120
121impl<T, E> PerspectiveResultExt for Result<T, E>
122where
123 E: std::error::Error,
124{
125 fn unwrap_or_log(&self) {
126 if let Err(e) = self {
127 tracing::warn!("{}", e);
128 }
129 }
130}
131
132#[derive(Clone)]
134pub struct IDGen(Arc<std::sync::Mutex<RandomSequence<u32>>>);
135
136impl Default for IDGen {
137 fn default() -> Self {
138 Self(Arc::new(std::sync::Mutex::new(Self::new_seq())))
139 }
140}
141
142impl IDGen {
143 fn new_seq() -> RandomSequence<u32> {
144 let mut rng = rand::rngs::ThreadRng::default();
145 let config = RandomSequenceBuilder::<u32>::rand(&mut rng);
146 config.into_iter()
147 }
148
149 pub fn next(&self) -> u32 {
150 let mut idgen = self.0.lock().unwrap();
151 if let Some(x) = idgen.next() {
152 x
153 } else {
154 *idgen = Self::new_seq();
155 idgen.next().unwrap()
156 }
157 }
158}