1#![forbid(unsafe_code)]
45#![warn(missing_docs)]
46
47use std::time::Duration;
48
49use kevy_embedded::Store;
50use kevy_resp_client::RespClient;
51
52mod blocking;
53mod cluster;
54mod cluster_coll;
55mod collections;
56mod feed;
57mod hash_ttl;
58mod index;
59mod pipeline;
60mod reply;
61mod scan;
62mod subscribe;
63mod subscribe_io;
64mod transaction;
65mod url;
66mod zalgebra;
67
68pub use blocking::ZPopHit;
69pub use cluster::ClusterClient;
70pub use feed::{FeedBatch, FeedFrame};
71pub use index::{IdxInfo, IdxPage, IdxRow, IdxType};
72pub use pipeline::PipelineBuf;
73pub use subscribe::{PubsubEvent, Subscriber, SubscriberEvents, SubscriberMessages};
74pub use transaction::{Transaction, TransactionReplies};
75
76pub use kevy_embedded::{HExpireCode, HExpireCond, KevyError, KevyResult, StoreError, ZAggregate};
79pub use kevy_resp::Reply;
80
81pub(crate) use reply::{array_to_bulks, num_f64, num_u64, store_err, string, unexpected, vec2, vec3};
82pub(crate) use url::{Target, parse_url, resolve_store};
83
84pub enum Connection {
87 Embedded(Box<Store>),
91 Remote(RespClient),
93}
94
95impl Connection {
96 pub fn connect(url: &str) -> KevyResult<Self> {
104 let parsed = parse_url(url)?;
105 match parsed {
106 Target::Remote(remote_url) => Ok(Self::Remote(RespClient::connect_url(&remote_url)?)),
107 embed => Ok(Self::Embedded(Box::new(resolve_store(&embed)?))),
108 }
109 }
110
111 pub(crate) fn remote(&mut self, feature: &str) -> KevyResult<&mut RespClient> {
115 match self {
116 Self::Embedded(_) => Err(KevyError::Unsupported(format!(
117 "{feature} is remote-only; on the embedded backend match \
118 Connection::Embedded and use kevy_embedded::Store's typed API"
119 ))),
120 Self::Remote(c) => Ok(c),
121 }
122 }
123
124 pub fn ping(&mut self) -> KevyResult<()> {
127 match self {
128 Self::Embedded(_) => Ok(()),
129 Self::Remote(c) => match c.request_borrowed(&[b"PING"])? {
130 Reply::Simple(s) if s == b"PONG" => Ok(()),
131 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
132 other => Err(unexpected(other)),
133 },
134 }
135 }
136
137 pub fn set(&mut self, key: &[u8], value: &[u8]) -> KevyResult<()> {
139 match self {
140 Self::Embedded(s) => s.set(key, value).map(|_| ()),
141 Self::Remote(c) => match c.request_borrowed(&[b"SET", key, value])? {
142 Reply::Simple(s) if s == b"OK" => Ok(()),
143 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
144 other => Err(unexpected(other)),
145 },
146 }
147 }
148
149 pub fn get(&mut self, key: &[u8]) -> KevyResult<Option<Vec<u8>>> {
151 match self {
152 Self::Embedded(s) => s.get(key),
153 Self::Remote(c) => match c.request_borrowed(&[b"GET", key])? {
154 Reply::Bulk(v) => Ok(Some(v)),
155 Reply::Nil => Ok(None),
156 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
157 other => Err(unexpected(other)),
158 },
159 }
160 }
161
162 pub fn del(&mut self, keys: &[&[u8]]) -> KevyResult<usize> {
165 match self {
166 Self::Embedded(s) => s.del(keys),
167 Self::Remote(c) => {
168 let mut args: Vec<&[u8]> = Vec::with_capacity(keys.len() + 1);
169 args.push(b"DEL");
170 args.extend_from_slice(keys);
171 match c.request_borrowed(&args)? {
172 Reply::Int(n) if n >= 0 => Ok(n as usize),
173 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
174 other => Err(unexpected(other)),
175 }
176 }
177 }
178 }
179
180 pub fn exists(&mut self, keys: &[&[u8]]) -> KevyResult<usize> {
183 match self {
184 Self::Embedded(s) => s.exists(keys),
185 Self::Remote(c) => {
186 let mut args: Vec<&[u8]> = Vec::with_capacity(keys.len() + 1);
187 args.push(b"EXISTS");
188 args.extend_from_slice(keys);
189 match c.request_borrowed(&args)? {
190 Reply::Int(n) if n >= 0 => Ok(n as usize),
191 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
192 other => Err(unexpected(other)),
193 }
194 }
195 }
196 }
197
198 pub fn incr(&mut self, key: &[u8]) -> KevyResult<i64> {
201 match self {
202 Self::Embedded(s) => s.incr(key),
203 Self::Remote(c) => match c.request_borrowed(&[b"INCR", key])? {
204 Reply::Int(n) => Ok(n),
205 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
206 other => Err(unexpected(other)),
207 },
208 }
209 }
210
211 pub fn incr_by(&mut self, key: &[u8], delta: i64) -> KevyResult<i64> {
213 match self {
214 Self::Embedded(s) => s.incr_by(key, delta),
215 Self::Remote(c) => {
216 let delta_s = delta.to_string();
217 match c.request_borrowed(&[b"INCRBY", key, delta_s.as_bytes()])? {
218 Reply::Int(n) => Ok(n),
219 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
220 other => Err(unexpected(other)),
221 }
222 }
223 }
224 }
225
226 pub fn expire(&mut self, key: &[u8], ttl: Duration) -> KevyResult<bool> {
228 match self {
229 Self::Embedded(s) => s.expire(key, ttl),
230 Self::Remote(c) => {
231 let ms = ttl.as_millis().min(i64::MAX as u128) as i64;
232 let ms_s = ms.to_string();
233 match c.request_borrowed(&[b"PEXPIRE", key, ms_s.as_bytes()])? {
234 Reply::Int(1) => Ok(true),
235 Reply::Int(0) => Ok(false),
236 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
237 other => Err(unexpected(other)),
238 }
239 }
240 }
241 }
242
243 pub fn persist(&mut self, key: &[u8]) -> KevyResult<bool> {
245 match self {
246 Self::Embedded(s) => s.persist(key),
247 Self::Remote(c) => match c.request_borrowed(&[b"PERSIST", key])? {
248 Reply::Int(1) => Ok(true),
249 Reply::Int(0) => Ok(false),
250 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
251 other => Err(unexpected(other)),
252 },
253 }
254 }
255
256 pub fn ttl_ms(&mut self, key: &[u8]) -> KevyResult<i64> {
258 match self {
259 Self::Embedded(s) => Ok(s.ttl_ms(key)),
260 Self::Remote(c) => match c.request_borrowed(&[b"PTTL", key])? {
261 Reply::Int(n) => Ok(n),
262 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
263 other => Err(unexpected(other)),
264 },
265 }
266 }
267
268 pub fn type_of(&mut self, key: &[u8]) -> KevyResult<String> {
272 match self {
273 Self::Embedded(s) => Ok(s.type_of(key).to_string()),
274 Self::Remote(c) => match c.request_borrowed(&[b"TYPE", key])? {
275 Reply::Simple(s) => Ok(string(s)),
276 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
277 other => Err(unexpected(other)),
278 },
279 }
280 }
281
282 pub fn dbsize(&mut self) -> KevyResult<usize> {
284 match self {
285 Self::Embedded(s) => Ok(s.dbsize()),
286 Self::Remote(c) => match c.request_borrowed(&[b"DBSIZE"])? {
287 Reply::Int(n) if n >= 0 => Ok(n as usize),
288 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
289 other => Err(unexpected(other)),
290 },
291 }
292 }
293
294 pub fn flushall(&mut self) -> KevyResult<()> {
301 match self {
302 Self::Embedded(s) => s.flushall(),
303 Self::Remote(c) => match c.request_borrowed(&[b"FLUSHALL"])? {
304 Reply::Simple(s) if s == b"OK" => Ok(()),
305 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
306 other => Err(unexpected(other)),
307 },
308 }
309 }
310
311 pub fn set_with_ttl(&mut self, key: &[u8], value: &[u8], ttl: Duration) -> KevyResult<()> {
315 match self {
316 Self::Embedded(s) => s.set_with_ttl(key, value, ttl).map(|_| ()),
317 Self::Remote(c) => {
318 let ms = ttl.as_millis().min(i64::MAX as u128) as i64;
319 let ms_s = ms.to_string();
320 match c.request_borrowed(&[b"SET", key, value, b"PX", ms_s.as_bytes()])? {
321 Reply::Simple(s) if s == b"OK" => Ok(()),
322 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
323 other => Err(unexpected(other)),
324 }
325 }
326 }
327 }
328
329 pub fn mget(&mut self, keys: &[&[u8]]) -> KevyResult<Vec<Option<Vec<u8>>>> {
332 match self {
333 Self::Embedded(s) => keys.iter().map(|k| s.get(k)).collect(),
334 Self::Remote(c) => {
335 let mut args: Vec<&[u8]> = Vec::with_capacity(keys.len() + 1);
336 args.push(b"MGET");
337 args.extend_from_slice(keys);
338 match c.request_borrowed(&args)? {
339 Reply::Array(items) => items
340 .into_iter()
341 .map(|r| match r {
342 Reply::Bulk(v) => Ok(Some(v)),
343 Reply::Nil => Ok(None),
344 other => Err(unexpected(other)),
345 })
346 .collect(),
347 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
348 other => Err(unexpected(other)),
349 }
350 }
351 }
352 }
353
354 pub fn mset(&mut self, pairs: &[(&[u8], &[u8])]) -> KevyResult<()> {
356 match self {
357 Self::Embedded(s) => {
358 for (k, v) in pairs {
359 s.set(k, v)?;
360 }
361 Ok(())
362 }
363 Self::Remote(c) => {
364 let mut args: Vec<&[u8]> = Vec::with_capacity(pairs.len() * 2 + 1);
365 args.push(b"MSET");
366 for &(k, v) in pairs {
367 args.push(k);
368 args.push(v);
369 }
370 match c.request_borrowed(&args)? {
371 Reply::Simple(s) if s == b"OK" => Ok(()),
372 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
373 other => Err(unexpected(other)),
374 }
375 }
376 }
377 }
378
379 pub fn publish(&mut self, channel: &[u8], message: &[u8]) -> KevyResult<usize> {
393 match self {
394 Self::Embedded(s) => Ok(s.publish(channel, message)),
395 Self::Remote(c) => match c.request_borrowed(&[b"PUBLISH", channel, message])? {
396 Reply::Int(n) if n >= 0 => Ok(n as usize),
397 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
398 other => Err(unexpected(other)),
399 },
400 }
401 }
402}
403
404
405#[cfg(test)]
406#[path = "lib_tests.rs"]
407mod tests;