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::{
82 array_to_bulks, num_f64, num_u64, store_err, string, unexpected, vec2, vec3,
83};
84pub(crate) use url::{Target, parse_url, resolve_store};
85
86pub enum Connection {
89 Embedded(Box<Store>),
93 Remote(RespClient),
95}
96
97impl Connection {
98 pub fn connect(url: &str) -> KevyResult<Self> {
106 let parsed = parse_url(url)?;
107 match parsed {
108 Target::Remote(remote_url) => Ok(Self::Remote(RespClient::connect_url(&remote_url)?)),
109 embed => Ok(Self::Embedded(Box::new(resolve_store(&embed)?))),
110 }
111 }
112
113 pub(crate) fn remote(&mut self, feature: &str) -> KevyResult<&mut RespClient> {
117 match self {
118 Self::Embedded(_) => Err(KevyError::Unsupported(format!(
119 "{feature} is remote-only; on the embedded backend match \
120 Connection::Embedded and use kevy_embedded::Store's typed API"
121 ))),
122 Self::Remote(c) => Ok(c),
123 }
124 }
125
126 pub fn ping(&mut self) -> KevyResult<()> {
129 match self {
130 Self::Embedded(_) => Ok(()),
131 Self::Remote(c) => match c.request_borrowed(&[b"PING"])? {
132 Reply::Simple(s) if s == b"PONG" => Ok(()),
133 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
134 other => Err(unexpected(other)),
135 },
136 }
137 }
138
139 pub fn set(&mut self, key: &[u8], value: &[u8]) -> KevyResult<()> {
141 match self {
142 Self::Embedded(s) => s.set(key, value).map(|_| ()),
143 Self::Remote(c) => match c.request_borrowed(&[b"SET", key, value])? {
144 Reply::Simple(s) if s == b"OK" => Ok(()),
145 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
146 other => Err(unexpected(other)),
147 },
148 }
149 }
150
151 pub fn get(&mut self, key: &[u8]) -> KevyResult<Option<Vec<u8>>> {
153 match self {
154 Self::Embedded(s) => s.get(key),
155 Self::Remote(c) => match c.request_borrowed(&[b"GET", key])? {
156 Reply::Bulk(v) => Ok(Some(v)),
157 Reply::Nil => Ok(None),
158 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
159 other => Err(unexpected(other)),
160 },
161 }
162 }
163
164 pub fn del(&mut self, keys: &[&[u8]]) -> KevyResult<usize> {
167 match self {
168 Self::Embedded(s) => s.del(keys),
169 Self::Remote(c) => {
170 let mut args: Vec<&[u8]> = Vec::with_capacity(keys.len() + 1);
171 args.push(b"DEL");
172 args.extend_from_slice(keys);
173 match c.request_borrowed(&args)? {
174 Reply::Int(n) if n >= 0 => Ok(n as usize),
175 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
176 other => Err(unexpected(other)),
177 }
178 }
179 }
180 }
181
182 pub fn exists(&mut self, keys: &[&[u8]]) -> KevyResult<usize> {
185 match self {
186 Self::Embedded(s) => s.exists(keys),
187 Self::Remote(c) => {
188 let mut args: Vec<&[u8]> = Vec::with_capacity(keys.len() + 1);
189 args.push(b"EXISTS");
190 args.extend_from_slice(keys);
191 match c.request_borrowed(&args)? {
192 Reply::Int(n) if n >= 0 => Ok(n as usize),
193 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
194 other => Err(unexpected(other)),
195 }
196 }
197 }
198 }
199
200 pub fn incr(&mut self, key: &[u8]) -> KevyResult<i64> {
203 match self {
204 Self::Embedded(s) => s.incr(key),
205 Self::Remote(c) => match c.request_borrowed(&[b"INCR", key])? {
206 Reply::Int(n) => Ok(n),
207 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
208 other => Err(unexpected(other)),
209 },
210 }
211 }
212
213 pub fn incr_by(&mut self, key: &[u8], delta: i64) -> KevyResult<i64> {
215 match self {
216 Self::Embedded(s) => s.incr_by(key, delta),
217 Self::Remote(c) => {
218 let delta_s = delta.to_string();
219 match c.request_borrowed(&[b"INCRBY", key, delta_s.as_bytes()])? {
220 Reply::Int(n) => Ok(n),
221 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
222 other => Err(unexpected(other)),
223 }
224 }
225 }
226 }
227
228 pub fn expire(&mut self, key: &[u8], ttl: Duration) -> KevyResult<bool> {
230 match self {
231 Self::Embedded(s) => s.expire(key, ttl),
232 Self::Remote(c) => {
233 let ms = ttl.as_millis().min(i64::MAX as u128) as i64;
234 let ms_s = ms.to_string();
235 match c.request_borrowed(&[b"PEXPIRE", key, ms_s.as_bytes()])? {
236 Reply::Int(1) => Ok(true),
237 Reply::Int(0) => Ok(false),
238 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
239 other => Err(unexpected(other)),
240 }
241 }
242 }
243 }
244
245 pub fn persist(&mut self, key: &[u8]) -> KevyResult<bool> {
247 match self {
248 Self::Embedded(s) => s.persist(key),
249 Self::Remote(c) => match c.request_borrowed(&[b"PERSIST", key])? {
250 Reply::Int(1) => Ok(true),
251 Reply::Int(0) => Ok(false),
252 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
253 other => Err(unexpected(other)),
254 },
255 }
256 }
257
258 pub fn ttl_ms(&mut self, key: &[u8]) -> KevyResult<i64> {
260 match self {
261 Self::Embedded(s) => Ok(s.ttl_ms(key)),
262 Self::Remote(c) => match c.request_borrowed(&[b"PTTL", key])? {
263 Reply::Int(n) => Ok(n),
264 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
265 other => Err(unexpected(other)),
266 },
267 }
268 }
269
270 pub fn type_of(&mut self, key: &[u8]) -> KevyResult<String> {
274 match self {
275 Self::Embedded(s) => Ok(s.type_of(key).to_string()),
276 Self::Remote(c) => match c.request_borrowed(&[b"TYPE", key])? {
277 Reply::Simple(s) => Ok(string(s)),
278 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
279 other => Err(unexpected(other)),
280 },
281 }
282 }
283
284 pub fn dbsize(&mut self) -> KevyResult<usize> {
286 match self {
287 Self::Embedded(s) => Ok(s.dbsize()),
288 Self::Remote(c) => match c.request_borrowed(&[b"DBSIZE"])? {
289 Reply::Int(n) if n >= 0 => Ok(n as usize),
290 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
291 other => Err(unexpected(other)),
292 },
293 }
294 }
295
296 pub fn flushall(&mut self) -> KevyResult<()> {
303 match self {
304 Self::Embedded(s) => s.flushall(),
305 Self::Remote(c) => match c.request_borrowed(&[b"FLUSHALL"])? {
306 Reply::Simple(s) if s == b"OK" => Ok(()),
307 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
308 other => Err(unexpected(other)),
309 },
310 }
311 }
312
313 pub fn set_with_ttl(&mut self, key: &[u8], value: &[u8], ttl: Duration) -> KevyResult<()> {
317 match self {
318 Self::Embedded(s) => s.set_with_ttl(key, value, ttl).map(|_| ()),
319 Self::Remote(c) => {
320 let ms = ttl.as_millis().min(i64::MAX as u128) as i64;
321 let ms_s = ms.to_string();
322 match c.request_borrowed(&[b"SET", key, value, b"PX", ms_s.as_bytes()])? {
323 Reply::Simple(s) if s == b"OK" => Ok(()),
324 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
325 other => Err(unexpected(other)),
326 }
327 }
328 }
329 }
330
331 pub fn mget(&mut self, keys: &[&[u8]]) -> KevyResult<Vec<Option<Vec<u8>>>> {
334 match self {
335 Self::Embedded(s) => keys.iter().map(|k| s.get(k)).collect(),
336 Self::Remote(c) => {
337 let mut args: Vec<&[u8]> = Vec::with_capacity(keys.len() + 1);
338 args.push(b"MGET");
339 args.extend_from_slice(keys);
340 match c.request_borrowed(&args)? {
341 Reply::Array(items) => items
342 .into_iter()
343 .map(|r| match r {
344 Reply::Bulk(v) => Ok(Some(v)),
345 Reply::Nil => Ok(None),
346 other => Err(unexpected(other)),
347 })
348 .collect(),
349 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
350 other => Err(unexpected(other)),
351 }
352 }
353 }
354 }
355
356 pub fn mset(&mut self, pairs: &[(&[u8], &[u8])]) -> KevyResult<()> {
358 match self {
359 Self::Embedded(s) => {
360 for (k, v) in pairs {
361 s.set(k, v)?;
362 }
363 Ok(())
364 }
365 Self::Remote(c) => {
366 let mut args: Vec<&[u8]> = Vec::with_capacity(pairs.len() * 2 + 1);
367 args.push(b"MSET");
368 for &(k, v) in pairs {
369 args.push(k);
370 args.push(v);
371 }
372 match c.request_borrowed(&args)? {
373 Reply::Simple(s) if s == b"OK" => Ok(()),
374 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
375 other => Err(unexpected(other)),
376 }
377 }
378 }
379 }
380
381 pub fn publish(&mut self, channel: &[u8], message: &[u8]) -> KevyResult<usize> {
395 match self {
396 Self::Embedded(s) => Ok(s.publish(channel, message)),
397 Self::Remote(c) => match c.request_borrowed(&[b"PUBLISH", channel, message])? {
398 Reply::Int(n) if n >= 0 => Ok(n as usize),
399 Reply::Error(e) => Err(KevyError::Protocol(string(e))),
400 other => Err(unexpected(other)),
401 },
402 }
403 }
404}
405
406#[cfg(test)]
407#[path = "lib_tests.rs"]
408mod tests;