perspective_client/utils/
mod.rs1mod clone;
16mod logging;
17mod rand_sequence;
18
19#[cfg(feature = "talc-allocator")]
20mod talc_allocator;
21
22#[cfg(test)]
23mod tests;
24
25use std::sync::Arc;
26use std::time::SystemTimeError;
27
28use rand::prelude::*;
29use rand::rngs::StdRng;
30#[cfg(feature = "talc-allocator")]
31pub(crate) use talc_allocator::get_used;
32use thiserror::*;
33
34use crate::proto;
35use crate::utils::rand_sequence::RandomSequence;
36
37#[derive(Clone, Error, Debug)]
38pub enum ClientError {
39 #[error("View not found")]
40 ViewNotFound,
41
42 #[error("Abort(): {0}")]
43 Internal(String),
44
45 #[error("Transport error: {0}")]
46 TransportError(String),
47
48 #[error("Client not yet initialized")]
49 NotInitialized,
50
51 #[error("Unknown error: {0}")]
52 Unknown(String),
53
54 #[error("Unwrapped option")]
55 Option,
56
57 #[error("Bad string")]
58 Utf8(#[from] std::str::Utf8Error),
59
60 #[error("Undecipherable server message {0:?}")]
61 DecodeError(#[from] prost::DecodeError),
62
63 #[error("Response aborted")]
64 ResponseAborted,
65
66 #[error("Unexpected response {0:?}")]
67 ResponseFailed(Box<proto::response::ClientResp>),
68
69 #[error("Not yet implemented {0:?}")]
70 NotImplemented(&'static str),
71
72 #[error("Can't use both `limit` and `index` arguments")]
73 BadTableOptions,
74
75 #[error("External error: {0}")]
76 ExternalError(Arc<Box<dyn std::error::Error + Send + Sync>>),
77
78 #[error("Undecipherable proto message")]
79 ProtoError(#[from] prost::EncodeError),
80
81 #[error("Duplicate name {0}")]
82 DuplicateNameError(String),
83
84 #[error("{0}")]
85 TimeError(#[from] SystemTimeError),
86}
87
88pub type ClientResult<T> = Result<T, ClientError>;
89
90impl From<Box<dyn std::error::Error + Send + Sync>> for ClientError {
91 fn from(value: Box<dyn std::error::Error + Send + Sync>) -> Self {
92 ClientError::ExternalError(Arc::new(value))
93 }
94}
95
96impl<'a, A> From<std::sync::PoisonError<std::sync::MutexGuard<'a, A>>> for ClientError {
97 fn from(_: std::sync::PoisonError<std::sync::MutexGuard<'a, A>>) -> Self {
98 ClientError::Internal("Lock Error".to_owned())
99 }
100}
101
102impl From<Option<proto::response::ClientResp>> for ClientError {
103 fn from(value: Option<proto::response::ClientResp>) -> Self {
104 match value {
105 Some(proto::response::ClientResp::ServerError(x)) => match x.status_code() {
106 proto::StatusCode::ServerError => ClientError::Internal(x.message),
107 proto::StatusCode::ViewNotFound => ClientError::ViewNotFound,
108 proto::StatusCode::TransportError => ClientError::TransportError(x.message),
109 },
110 Some(x) => ClientError::ResponseFailed(Box::new(x)),
111 None => ClientError::ResponseAborted,
112 }
113 }
114}
115
116impl From<proto::response::ClientResp> for ClientError {
117 fn from(value: proto::response::ClientResp) -> Self {
118 match value {
119 proto::response::ClientResp::ServerError(x) => match x.status_code() {
120 proto::StatusCode::ServerError => ClientError::Internal(x.message),
121 proto::StatusCode::ViewNotFound => ClientError::ViewNotFound,
122 proto::StatusCode::TransportError => ClientError::TransportError(x.message),
123 },
124 x => ClientError::ResponseFailed(Box::new(x)),
125 }
126 }
127}
128
129pub trait PerspectiveResultExt {
130 fn unwrap_or_log(&self);
131}
132
133impl<T, E> PerspectiveResultExt for Result<T, E>
134where
135 E: std::error::Error,
136{
137 fn unwrap_or_log(&self) {
138 if let Err(e) = self {
139 tracing::warn!("{}", e);
140 }
141 }
142}
143
144#[derive(Clone)]
146pub struct IDGen(Arc<std::sync::Mutex<RandomSequence>>);
147
148impl Default for IDGen {
149 fn default() -> Self {
150 Self(Arc::new(std::sync::Mutex::new(Self::new_seq())))
151 }
152}
153
154impl IDGen {
155 fn new_seq() -> RandomSequence {
156 let mut rng = rand::rngs::ThreadRng::default();
157 let config = RandomSequence::new(rng.next_u32(), rng.next_u32());
158 config.into_iter()
159 }
160
161 pub fn next(&self) -> u32 {
162 let mut idgen = self.0.lock().unwrap();
163 if let Some(x) = idgen.next() {
164 x
165 } else {
166 *idgen = Self::new_seq();
167 idgen.next().unwrap()
168 }
169 }
170}
171
172const SIZE: usize = 21;
173
174const CHARACTERS: [char; 52] = [
175 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
176 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
177 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
178];
179
180pub fn randid() -> String {
182 let mask = CHARACTERS.len().next_power_of_two() - 1;
183 let step: usize = 8 * SIZE / 5;
184 let mut id = String::with_capacity(SIZE);
185 loop {
186 let mut rng = rand::rngs::ThreadRng::default();
187 let mut random = StdRng::from_rng(&mut rng);
188 let mut bytes: Vec<u8> = vec![0; step];
189 random.fill(&mut bytes[..]);
190 for &byte in &bytes {
191 let byte = byte as usize & mask;
192 if CHARACTERS.len() > byte {
193 id.push(CHARACTERS[byte]);
194 if id.len() == SIZE {
195 return id;
196 }
197 }
198 }
199 }
200}