1#![forbid(unsafe_code)]
45#![warn(missing_docs)]
46
47use std::io;
48use std::time::Duration;
49
50use kevy_embedded::Store;
51use kevy_resp_client::RespClient;
52
53mod blocking;
54mod cluster;
55mod cluster_coll;
56mod collections;
57mod feed;
58mod hash_ttl;
59mod index;
60mod pipeline;
61mod reply;
62mod scan;
63mod subscribe;
64mod subscribe_io;
65mod transaction;
66mod url;
67mod zalgebra;
68
69pub use blocking::ZPopHit;
70pub use cluster::ClusterClient;
71pub use feed::{FeedBatch, FeedFrame};
72pub use index::{IdxInfo, IdxPage, IdxRow, IdxType};
73pub use pipeline::PipelineBuf;
74pub use subscribe::{PubsubEvent, Subscriber, SubscriberEvents, SubscriberMessages};
75pub use transaction::{Transaction, TransactionReplies};
76
77pub use kevy_embedded::{HExpireCode, HExpireCond, ZAggregate};
80pub use kevy_resp::Reply;
81
82pub(crate) use reply::{array_to_bulks, num_f64, num_u64, store_err, string, unexpected, vec2, vec3};
83pub(crate) use url::{Target, parse_url, resolve_store};
84
85pub enum Connection {
88 Embedded(Box<Store>),
92 Remote(RespClient),
94}
95
96impl Connection {
97 pub fn open(url: &str) -> io::Result<Self> {
105 let parsed = parse_url(url)?;
106 match parsed {
107 Target::Remote(remote_url) => Ok(Self::Remote(RespClient::from_url(&remote_url)?)),
108 embed => Ok(Self::Embedded(Box::new(resolve_store(&embed)?))),
109 }
110 }
111
112 pub(crate) fn remote(&mut self, feature: &str) -> io::Result<&mut RespClient> {
116 match self {
117 Self::Embedded(_) => Err(io::Error::new(
118 io::ErrorKind::Unsupported,
119 format!(
120 "{feature} is remote-only; on the embedded backend match \
121 Connection::Embedded and use kevy_embedded::Store's typed API"
122 ),
123 )),
124 Self::Remote(c) => Ok(c),
125 }
126 }
127
128 pub fn ping(&mut self) -> io::Result<()> {
131 match self {
132 Self::Embedded(_) => Ok(()),
133 Self::Remote(c) => match c.request_borrowed(&[b"PING"])? {
134 Reply::Simple(s) if s == b"PONG" => Ok(()),
135 Reply::Error(e) => Err(io::Error::other(string(e))),
136 other => Err(unexpected(other)),
137 },
138 }
139 }
140
141 pub fn set(&mut self, key: &[u8], value: &[u8]) -> io::Result<()> {
143 match self {
144 Self::Embedded(s) => s.set(key, value).map(|_| ()),
145 Self::Remote(c) => match c.request_borrowed(&[b"SET", key, value])? {
146 Reply::Simple(s) if s == b"OK" => Ok(()),
147 Reply::Error(e) => Err(io::Error::other(string(e))),
148 other => Err(unexpected(other)),
149 },
150 }
151 }
152
153 pub fn get(&mut self, key: &[u8]) -> io::Result<Option<Vec<u8>>> {
155 match self {
156 Self::Embedded(s) => s.get(key),
157 Self::Remote(c) => match c.request_borrowed(&[b"GET", key])? {
158 Reply::Bulk(v) => Ok(Some(v)),
159 Reply::Nil => Ok(None),
160 Reply::Error(e) => Err(io::Error::other(string(e))),
161 other => Err(unexpected(other)),
162 },
163 }
164 }
165
166 pub fn del(&mut self, keys: &[&[u8]]) -> io::Result<usize> {
169 match self {
170 Self::Embedded(s) => s.del(keys),
171 Self::Remote(c) => {
172 let mut args = Vec::with_capacity(keys.len() + 1);
173 args.push(b"DEL".to_vec());
174 args.extend(keys.iter().map(|k| k.to_vec()));
175 match c.request(&args)? {
176 Reply::Int(n) if n >= 0 => Ok(n as usize),
177 Reply::Error(e) => Err(io::Error::other(string(e))),
178 other => Err(unexpected(other)),
179 }
180 }
181 }
182 }
183
184 pub fn exists(&mut self, keys: &[&[u8]]) -> io::Result<usize> {
187 match self {
188 Self::Embedded(s) => s.exists(keys),
189 Self::Remote(c) => {
190 let mut args = Vec::with_capacity(keys.len() + 1);
191 args.push(b"EXISTS".to_vec());
192 args.extend(keys.iter().map(|k| k.to_vec()));
193 match c.request(&args)? {
194 Reply::Int(n) if n >= 0 => Ok(n as usize),
195 Reply::Error(e) => Err(io::Error::other(string(e))),
196 other => Err(unexpected(other)),
197 }
198 }
199 }
200 }
201
202 pub fn incr(&mut self, key: &[u8]) -> io::Result<i64> {
205 match self {
206 Self::Embedded(s) => s.incr(key),
207 Self::Remote(c) => match c.request_borrowed(&[b"INCR", key])? {
208 Reply::Int(n) => Ok(n),
209 Reply::Error(e) => Err(io::Error::other(string(e))),
210 other => Err(unexpected(other)),
211 },
212 }
213 }
214
215 pub fn incr_by(&mut self, key: &[u8], delta: i64) -> io::Result<i64> {
217 match self {
218 Self::Embedded(s) => s.incr_by(key, delta),
219 Self::Remote(c) => {
220 let args = vec![
221 b"INCRBY".to_vec(),
222 key.to_vec(),
223 delta.to_string().into_bytes(),
224 ];
225 match c.request(&args)? {
226 Reply::Int(n) => Ok(n),
227 Reply::Error(e) => Err(io::Error::other(string(e))),
228 other => Err(unexpected(other)),
229 }
230 }
231 }
232 }
233
234 pub fn expire(&mut self, key: &[u8], ttl: Duration) -> io::Result<bool> {
236 match self {
237 Self::Embedded(s) => s.expire(key, ttl),
238 Self::Remote(c) => {
239 let ms = ttl.as_millis().min(i64::MAX as u128) as i64;
240 let args = vec![b"PEXPIRE".to_vec(), key.to_vec(), ms.to_string().into_bytes()];
241 match c.request(&args)? {
242 Reply::Int(1) => Ok(true),
243 Reply::Int(0) => Ok(false),
244 Reply::Error(e) => Err(io::Error::other(string(e))),
245 other => Err(unexpected(other)),
246 }
247 }
248 }
249 }
250
251 pub fn persist(&mut self, key: &[u8]) -> io::Result<bool> {
253 match self {
254 Self::Embedded(s) => s.persist(key),
255 Self::Remote(c) => match c.request_borrowed(&[b"PERSIST", key])? {
256 Reply::Int(1) => Ok(true),
257 Reply::Int(0) => Ok(false),
258 Reply::Error(e) => Err(io::Error::other(string(e))),
259 other => Err(unexpected(other)),
260 },
261 }
262 }
263
264 pub fn ttl_ms(&mut self, key: &[u8]) -> io::Result<i64> {
266 match self {
267 Self::Embedded(s) => Ok(s.ttl_ms(key)),
268 Self::Remote(c) => match c.request_borrowed(&[b"PTTL", key])? {
269 Reply::Int(n) => Ok(n),
270 Reply::Error(e) => Err(io::Error::other(string(e))),
271 other => Err(unexpected(other)),
272 },
273 }
274 }
275
276 pub fn type_of(&mut self, key: &[u8]) -> io::Result<String> {
280 match self {
281 Self::Embedded(s) => Ok(s.type_of(key).to_string()),
282 Self::Remote(c) => match c.request_borrowed(&[b"TYPE", key])? {
283 Reply::Simple(s) => Ok(string(s)),
284 Reply::Error(e) => Err(io::Error::other(string(e))),
285 other => Err(unexpected(other)),
286 },
287 }
288 }
289
290 pub fn dbsize(&mut self) -> io::Result<usize> {
292 match self {
293 Self::Embedded(s) => Ok(s.dbsize()),
294 Self::Remote(c) => match c.request_borrowed(&[b"DBSIZE"])? {
295 Reply::Int(n) if n >= 0 => Ok(n as usize),
296 Reply::Error(e) => Err(io::Error::other(string(e))),
297 other => Err(unexpected(other)),
298 },
299 }
300 }
301
302 pub fn flushall(&mut self) -> io::Result<()> {
309 match self {
310 Self::Embedded(s) => s.flushall(),
311 Self::Remote(c) => match c.request_borrowed(&[b"FLUSHALL"])? {
312 Reply::Simple(s) if s == b"OK" => Ok(()),
313 Reply::Error(e) => Err(io::Error::other(string(e))),
314 other => Err(unexpected(other)),
315 },
316 }
317 }
318
319 #[deprecated(
322 since = "1.8.0",
323 note = "renamed to `flushall`: `flush` collides with Write::flush (sync-to-disk); this WIPES the store"
324 )]
325 pub fn flush(&mut self) -> io::Result<()> {
326 self.flushall()
327 }
328
329 pub fn set_with_ttl(&mut self, key: &[u8], value: &[u8], ttl: Duration) -> io::Result<()> {
333 match self {
334 Self::Embedded(s) => s.set_with_ttl(key, value, ttl).map(|_| ()),
335 Self::Remote(c) => {
336 let ms = ttl.as_millis().min(i64::MAX as u128) as i64;
337 let args = vec![
338 b"SET".to_vec(),
339 key.to_vec(),
340 value.to_vec(),
341 b"PX".to_vec(),
342 ms.to_string().into_bytes(),
343 ];
344 match c.request(&args)? {
345 Reply::Simple(s) if s == b"OK" => Ok(()),
346 Reply::Error(e) => Err(io::Error::other(string(e))),
347 other => Err(unexpected(other)),
348 }
349 }
350 }
351 }
352
353 pub fn mget(&mut self, keys: &[&[u8]]) -> io::Result<Vec<Option<Vec<u8>>>> {
356 match self {
357 Self::Embedded(s) => keys.iter().map(|k| s.get(k)).collect(),
358 Self::Remote(c) => {
359 let mut args = Vec::with_capacity(keys.len() + 1);
360 args.push(b"MGET".to_vec());
361 args.extend(keys.iter().map(|k| k.to_vec()));
362 match c.request(&args)? {
363 Reply::Array(items) => items
364 .into_iter()
365 .map(|r| match r {
366 Reply::Bulk(v) => Ok(Some(v)),
367 Reply::Nil => Ok(None),
368 other => Err(unexpected(other)),
369 })
370 .collect(),
371 Reply::Error(e) => Err(io::Error::other(string(e))),
372 other => Err(unexpected(other)),
373 }
374 }
375 }
376 }
377
378 pub fn mset(&mut self, pairs: &[(&[u8], &[u8])]) -> io::Result<()> {
380 match self {
381 Self::Embedded(s) => {
382 for (k, v) in pairs {
383 s.set(k, v)?;
384 }
385 Ok(())
386 }
387 Self::Remote(c) => {
388 let mut args = Vec::with_capacity(pairs.len() * 2 + 1);
389 args.push(b"MSET".to_vec());
390 for (k, v) in pairs {
391 args.push(k.to_vec());
392 args.push(v.to_vec());
393 }
394 match c.request(&args)? {
395 Reply::Simple(s) if s == b"OK" => Ok(()),
396 Reply::Error(e) => Err(io::Error::other(string(e))),
397 other => Err(unexpected(other)),
398 }
399 }
400 }
401 }
402
403 pub fn publish(&mut self, channel: &[u8], message: &[u8]) -> io::Result<usize> {
417 match self {
418 Self::Embedded(s) => Ok(s.publish(channel, message)),
419 Self::Remote(c) => match c.request_borrowed(&[b"PUBLISH", channel, message])? {
420 Reply::Int(n) if n >= 0 => Ok(n as usize),
421 Reply::Error(e) => Err(io::Error::other(string(e))),
422 other => Err(unexpected(other)),
423 },
424 }
425 }
426}
427
428
429#[cfg(test)]
430#[path = "lib_tests.rs"]
431mod tests;