redis_driver/commands/string_commands.rs
1use std::collections::HashMap;
2
3use crate::{
4 prepare_command,
5 resp::{
6 cmd, CommandArg, CommandArgs, FromSingleValueArray, FromValue, HashMapExt, IntoArgs,
7 KeyValueArgOrCollection, SingleArgOrCollection, Value,
8 },
9 Error, PreparedCommand, Result,
10};
11
12/// A group of Redis commands related to [`Strings`](https://redis.io/docs/data-types/strings/)
13/// # See Also
14/// [Redis Generic Commands](https://redis.io/commands/?group=string)
15pub trait StringCommands {
16 /// If key already exists and is a string,
17 /// this command appends the value at the end of the string.
18 /// If key does not exist it is created and set as an empty string,
19 /// so APPEND will be similar to SET in this special case.
20 ///
21 /// # Return
22 /// the length of the string after the append operation.
23 ///
24 /// # See Also
25 /// [<https://redis.io/commands/append/>](https://redis.io/commands/append/)
26 #[must_use]
27 fn append<K, V>(&mut self, key: K, value: V) -> PreparedCommand<Self, usize>
28 where
29 Self: Sized,
30 K: Into<CommandArg>,
31 V: Into<CommandArg>,
32 {
33 prepare_command(self, cmd("APPEND").arg(key).arg(value))
34 }
35
36 /// Decrements the number stored at key by one.
37 ///
38 /// If the key does not exist, it is set to 0 before performing the operation.
39 /// An error is returned if the key contains a value of the wrong type or contains
40 /// a string that can not be represented as integer.
41 /// This operation is limited to 64 bit signed integers.
42 ///
43 /// # Return
44 /// the value of key after the decrement
45 ///
46 /// # See Also
47 /// [<https://redis.io/commands/decr/>](https://redis.io/commands/decr/)
48 #[must_use]
49 fn decr<K>(&mut self, key: K) -> PreparedCommand<Self, i64>
50 where
51 Self: Sized,
52 K: Into<CommandArg>,
53 {
54 prepare_command(self, cmd("DECR").arg(key))
55 }
56
57 /// Decrements the number stored at key by one.
58 ///
59 /// If the key does not exist, it is set to 0 before performing the operation.
60 /// An error is returned if the key contains a value of the wrong type or contains
61 /// a string that can not be represented as integer.
62 /// This operation is limited to 64 bit signed integers.
63 ///
64 /// # Return
65 /// the value of key after the decrement
66 ///
67 /// # See Also
68 /// [<https://redis.io/commands/decrby/>](https://redis.io/commands/decrby/)
69 #[must_use]
70 fn decrby<K>(&mut self, key: K, decrement: i64) -> PreparedCommand<Self, i64>
71 where
72 Self: Sized,
73 K: Into<CommandArg>,
74 {
75 prepare_command(self, cmd("DECRBY").arg(key).arg(decrement))
76 }
77
78 /// Get the value of key.
79 ///
80 /// Decrements the number stored at key by decrement.
81 /// If the key does not exist, it is set to 0 before performing the operation.
82 /// An error is returned if the key contains a value of the wrong type
83 /// or contains a string that can not be represented as integer.
84 /// This operation is limited to 64 bit signed integers.
85 ///
86 /// # Return
87 /// the value of key, or `nil` when key does not exist.
88 ///
89 /// # Example
90 /// ```
91 /// use redis_driver::{
92 /// resp::{cmd}, Client, ClientPreparedCommand, FlushingMode,
93 /// ServerCommands, StringCommands, Result
94 /// };
95 ///
96 /// #[tokio::main]
97 /// async fn main() -> Result<()> {
98 /// let mut client = Client::connect("127.0.0.1:6379").await?;
99 /// client.flushdb(FlushingMode::Sync).await?;
100 ///
101 /// // return value can be an Option<String>...
102 /// let value: Option<String> = client.get("key").await?;
103 /// assert_eq!(None, value);
104 ///
105 /// // ... or it can be directly a String.
106 /// // In this cas a `nil` value will result in an empty String
107 /// let value: String = client.get("key").await?;
108 /// assert_eq!("", &value);
109 ///
110 /// client.set("key", "value").await?;
111 /// let value: String = client.get("key").await?;
112 /// assert_eq!("value", value);
113 ///
114 /// Ok(())
115 /// }
116 /// ```
117 ///
118 /// # See Also
119 /// [<https://redis.io/commands/get/>](https://redis.io/commands/get/)
120 #[must_use]
121 fn get<K, V>(&mut self, key: K) -> PreparedCommand<Self, V>
122 where
123 Self: Sized,
124 K: Into<CommandArg>,
125 V: FromValue,
126 Self: Sized,
127 {
128 prepare_command(self, cmd("GET").arg(key))
129 }
130
131 /// Get the value of key and delete the key.
132 ///
133 /// This command is similar to GET, except for the fact that it also deletes the key on success
134 /// (if and only if the key's value type is a string).
135 ///
136 /// # Return
137 /// the value of key, `nil` when key does not exist, or an error if the key's value type isn't a string.
138 ///
139 /// # See Also
140 /// [<https://redis.io/commands/getdel/>](https://redis.io/commands/getdel/)
141 #[must_use]
142 fn getdel<K, V>(&mut self, key: K) -> PreparedCommand<Self, V>
143 where
144 Self: Sized,
145 K: Into<CommandArg>,
146 V: FromValue,
147 {
148 prepare_command(self, cmd("GETDEL").arg(key))
149 }
150
151 /// Get the value of key and optionally set its expiration. GETEX is similar to GET, but is a write command with additional options.
152 ///
153 /// Decrements the number stored at key by decrement.
154 /// If the key does not exist, it is set to 0 before performing the operation.
155 /// An error is returned if the key contains a value of the wrong type
156 /// or contains a string that can not be represented as integer.
157 /// This operation is limited to 64 bit signed integers.
158 ///
159 /// # Return
160 /// the value of key, or `nil` when key does not exist.
161 ///
162 /// # Example
163 /// ```
164 /// use redis_driver::{
165 /// resp::cmd, Client, ClientPreparedCommand, FlushingMode,
166 /// GetExOptions, GenericCommands, ServerCommands, StringCommands, Result
167 /// };
168 ///
169 /// #[tokio::main]
170 /// async fn main() -> Result<()> {
171 /// let mut client = Client::connect("127.0.0.1:6379").await?;
172 /// client.flushdb(FlushingMode::Sync).await?;
173 ///
174 /// client.set("key", "value").await?;
175 /// let value: String = client.getex("key", GetExOptions::Ex(60)).await?;
176 /// assert_eq!("value", value);
177 ///
178 /// let ttl = client.ttl("key").await?;
179 /// assert!(59 <= ttl && ttl <= 60);
180 ///
181 /// Ok(())
182 /// }
183 /// ```
184 ///
185 /// # See Also
186 /// [<https://redis.io/commands/getex/>](https://redis.io/commands/getex/)
187 #[must_use]
188 fn getex<K, V>(&mut self, key: K, options: GetExOptions) -> PreparedCommand<Self, V>
189 where
190 Self: Sized,
191 K: Into<CommandArg>,
192 V: FromValue,
193 {
194 prepare_command(self, cmd("GETEX").arg(key).arg(options))
195 }
196
197 /// Returns the substring of the string value stored at key, determined by the offsets start and end (both are inclusive).
198 ///
199 /// Negative offsets can be used in order to provide an offset starting from the end of the string.
200 /// So -1 means the last character, -2 the penultimate and so forth.
201 ///
202 /// The function handles out of range requests by limiting the resulting range to the actual length of the string.
203
204 /// # See Also
205 /// [<https://redis.io/commands/getrange/>](https://redis.io/commands/getrange/)
206 #[must_use]
207 fn getrange<K, V>(&mut self, key: K, start: usize, end: isize) -> PreparedCommand<Self, V>
208 where
209 Self: Sized,
210 K: Into<CommandArg>,
211 V: FromValue,
212 {
213 prepare_command(self, cmd("GETRANGE").arg(key).arg(start).arg(end))
214 }
215
216 /// Atomically sets key to value and returns the old value stored at key.
217 /// Returns an error when key exists but does not hold a string value.
218 /// Any previous time to live associated with the key is discarded on successful SET operation.
219 ///
220 /// # Return
221 /// the old value stored at key, or nil when key did not exist.
222 ///
223 /// # See Also
224 /// [<https://redis.io/commands/getset/>](https://redis.io/commands/getset/)
225 #[must_use]
226 fn getset<K, V, R>(&mut self, key: K, value: V) -> PreparedCommand<Self, R>
227 where
228 Self: Sized,
229 K: Into<CommandArg>,
230 V: Into<CommandArg>,
231 R: FromValue,
232 {
233 prepare_command(self, cmd("GETSET").arg(key).arg(value))
234 }
235
236 /// Increments the number stored at key by one.
237 ///
238 /// If the key does not exist, it is set to 0 before performing the operation.
239 /// An error is returned if the key contains a value of the wrong type
240 /// or contains a string that can not be represented as integer.
241 /// This operation is limited to 64 bit signed integers.
242 ///
243 /// Note: this is a string operation because Redis does not have a dedicated integer type.
244 /// The string stored at the key is interpreted as a base-10 64 bit signed integer to execute the operation.
245 ///
246 /// Redis stores integers in their integer representation, so for string values that actually hold an integer,
247 /// there is no overhead for storing the string representation of the integer.
248 ///
249 /// # Return
250 /// the value of key after the increment
251 ///
252 /// # See Also
253 /// [<https://redis.io/commands/incr/>](https://redis.io/commands/incr/)
254 #[must_use]
255 fn incr<K>(&mut self, key: K) -> PreparedCommand<Self, i64>
256 where
257 Self: Sized,
258 K: Into<CommandArg>,
259 {
260 prepare_command(self, cmd("INCR").arg(key))
261 }
262
263 /// Increments the number stored at key by increment.
264 ///
265 /// If the key does not exist, it is set to 0 before performing the operation.
266 /// An error is returned if the key contains a value of the wrong type
267 /// or contains a string that can not be represented as integer.
268 /// This operation is limited to 64 bit signed integers.
269 ///
270 /// See [incr](crate::StringCommands::incr) for extra information on increment/decrement operations.
271 ///
272 /// # Return
273 /// the value of key after the increment
274 ///
275 /// # See Also
276 /// [<https://redis.io/commands/incrby/>](https://redis.io/commands/incrby/)
277 #[must_use]
278 fn incrby<K>(&mut self, key: K, increment: i64) -> PreparedCommand<Self, i64>
279 where
280 Self: Sized,
281 K: Into<CommandArg>,
282 {
283 prepare_command(self, cmd("INCRBY").arg(key).arg(increment))
284 }
285
286 ///Increment the string representing a floating point number stored at key by the specified increment.
287 /// By using a negative increment value, the result is that the value stored at the key is decremented (by the obvious properties of addition).
288 /// If the key does not exist, it is set to 0 before performing the operation.
289 /// An error is returned if one of the following conditions occur:
290 ///
291 /// - The key contains a value of the wrong type (not a string).
292 ///
293 /// - The current key content or the specified increment are not parsable as a double precision floating point number.
294 ///
295 /// If the command is successful the new incremented value is stored as the new value of the key (replacing the old one),
296 /// and returned to the caller as a string.
297 ///
298 /// Both the value already contained in the string key and the increment argument can be optionally provided in exponential notation,
299 /// however the value computed after the increment is stored consistently in the same format, that is,
300 /// an integer number followed (if needed) by a dot, and a variable number of digits representing the decimal part of the number.
301 /// Trailing zeroes are always removed.
302 ///
303 /// The precision of the output is fixed at 17 digits after the decimal point
304 /// regardless of the actual internal precision of the computation.
305 ///
306 /// # Return
307 /// the value of key after the increment
308 ///
309 /// # See Also
310 /// [<https://redis.io/commands/incrbyfloat/>](https://redis.io/commands/incrbyfloat/)
311 #[must_use]
312 fn incrbyfloat<K>(&mut self, key: K, increment: f64) -> PreparedCommand<Self, f64>
313 where
314 Self: Sized,
315 K: Into<CommandArg>,
316 {
317 prepare_command(self, cmd("INCRBYFLOAT").arg(key).arg(increment))
318 }
319
320 /// The LCS command implements the longest common subsequence algorithm
321 ///
322 /// # Return
323 /// The string representing the longest common substring.
324 ///
325 /// # See Also
326 /// [<https://redis.io/commands/lcs/>](https://redis.io/commands/lcs/)
327 #[must_use]
328 fn lcs<K, V>(&mut self, key1: K, key2: K) -> PreparedCommand<Self, V>
329 where
330 Self: Sized,
331 K: Into<CommandArg>,
332 V: FromValue,
333 {
334 prepare_command(self, cmd("LCS").arg(key1).arg(key2))
335 }
336
337 /// The LCS command implements the longest common subsequence algorithm
338 ///
339 /// # Return
340 /// The length of the longest common substring.
341 ///
342 /// # See Also
343 /// [<https://redis.io/commands/lcs/>](https://redis.io/commands/lcs/)
344 #[must_use]
345 fn lcs_len<K>(&mut self, key1: K, key2: K) -> PreparedCommand<Self, usize>
346 where
347 Self: Sized,
348 K: Into<CommandArg>,
349 {
350 prepare_command(self, cmd("LCS").arg(key1).arg(key2).arg("LEN"))
351 }
352
353 /// The LCS command implements the longest common subsequence algorithm
354 ///
355 /// # Return
356 /// An array with the LCS length and all the ranges in both the strings,
357 /// start and end offset for each string, where there are matches.
358 /// When `with_match_len` is given each match will also have the length of the match
359 ///
360 /// # See Also
361 /// [<https://redis.io/commands/lcs/>](https://redis.io/commands/lcs/)
362 #[must_use]
363 fn lcs_idx<K>(
364 &mut self,
365 key1: K,
366 key2: K,
367 min_match_len: Option<usize>,
368 with_match_len: bool,
369 ) -> PreparedCommand<Self, LcsResult>
370 where
371 Self: Sized,
372 K: Into<CommandArg>,
373 {
374 prepare_command(
375 self,
376 cmd("LCS")
377 .arg(key1)
378 .arg(key2)
379 .arg("IDX")
380 .arg(min_match_len.map(|len| ("MINMATCHLEN", len)))
381 .arg_if(with_match_len, "WITHMATCHLEN"),
382 )
383 }
384
385 /// Returns the values of all specified keys.
386 ///
387 /// For every key that does not hold a string value or does not exist,
388 /// the special value nil is returned. Because of this, the operation never fails.
389 ///
390 /// # Return
391 /// Array reply: list of values at the specified keys.
392 ///
393 /// # See Also
394 /// [<https://redis.io/commands/mget/>](https://redis.io/commands/mget/)
395 #[must_use]
396 fn mget<K, KK, V, VV>(&mut self, keys: KK) -> PreparedCommand<Self, VV>
397 where
398 Self: Sized,
399 K: Into<CommandArg>,
400 KK: SingleArgOrCollection<K>,
401 V: FromValue,
402 VV: FromSingleValueArray<V>,
403 {
404 prepare_command(self, cmd("MGET").arg(keys))
405 }
406
407 /// Sets the given keys to their respective values.
408 ///
409 /// # Return
410 /// always OK since MSET can't fail.
411 ///
412 /// # See Also
413 /// [<https://redis.io/commands/mset/>](https://redis.io/commands/mset/)
414 #[must_use]
415 fn mset<K, V, C>(&mut self, items: C) -> PreparedCommand<Self, ()>
416 where
417 Self: Sized,
418 C: KeyValueArgOrCollection<K, V>,
419 K: Into<CommandArg>,
420 V: Into<CommandArg>,
421 {
422 prepare_command(self, cmd("MSET").arg(items))
423 }
424
425 /// Sets the given keys to their respective values.
426 /// MSETNX will not perform any operation at all even if just a single key already exists.
427 ///
428 /// Because of this semantic MSETNX can be used in order to set different keys representing
429 /// different fields of a unique logic object in a way that ensures that either
430 /// all the fields or none at all are set.
431 ///
432 /// MSETNX is atomic, so all given keys are set at once. It is not possible for
433 /// clients to see that some of the keys were updated while others are unchanged.
434 ///
435 /// # Return
436 /// specifically:
437 /// - 1 if the all the keys were set.
438 /// - 0 if no key was set (at least one key already existed).
439 ///
440 /// # See Also
441 /// [<https://redis.io/commands/msetnx/>](https://redis.io/commands/msetnx/)
442 #[must_use]
443 fn msetnx<K, V, C>(&mut self, items: C) -> PreparedCommand<Self, bool>
444 where
445 Self: Sized,
446 C: KeyValueArgOrCollection<K, V>,
447 K: Into<CommandArg>,
448 V: Into<CommandArg>,
449 {
450 prepare_command(self, cmd("MSETNX").arg(items))
451 }
452
453 /// Works exactly like [setex](crate::StringCommands::setex) with the sole
454 /// difference that the expire time is specified in milliseconds instead of seconds.
455 ///
456 /// If key already holds a value, it is overwritten, regardless of its type.
457 /// Any previous time to live associated with the key is discarded on successful SET operation.
458 ///
459 /// # See Also
460 /// [<https://redis.io/commands/psetex/>](https://redis.io/commands/psetex/)
461 #[must_use]
462 fn psetex<K, V>(&mut self, key: K, milliseconds: u64, value: V) -> PreparedCommand<Self, ()>
463 where
464 Self: Sized,
465 K: Into<CommandArg>,
466 V: Into<CommandArg>,
467 {
468 prepare_command(self, cmd("PSETEX").arg(key).arg(milliseconds).arg(value))
469 }
470
471 ///Set key to hold the string value.
472 ///
473 /// If key already holds a value, it is overwritten, regardless of its type.
474 /// Any previous time to live associated with the key is discarded on successful SET operation.
475 ///
476 /// # See Also
477 /// [<https://redis.io/commands/set/>](https://redis.io/commands/set/)
478 #[must_use]
479 fn set<K, V>(&mut self, key: K, value: V) -> PreparedCommand<Self, ()>
480 where
481 Self: Sized,
482 K: Into<CommandArg>,
483 V: Into<CommandArg>,
484 Self: Sized,
485 {
486 prepare_command(self, cmd("SET").arg(key).arg(value))
487 }
488
489 ///Set key to hold the string value.
490 ///
491 /// # Return
492 /// * `true` if SET was executed correctly.
493 /// * `false` if the SET operation was not performed because the user
494 /// specified the NX or XX option but the condition was not met.
495 ///
496 /// # See Also
497 /// [<https://redis.io/commands/set/>](https://redis.io/commands/set/)
498 #[must_use]
499 fn set_with_options<K, V>(
500 &mut self,
501 key: K,
502 value: V,
503 condition: SetCondition,
504 expiration: SetExpiration,
505 keep_ttl: bool,
506 ) -> PreparedCommand<Self, bool>
507 where
508 Self: Sized,
509 K: Into<CommandArg>,
510 V: Into<CommandArg>,
511 {
512 prepare_command(
513 self,
514 cmd("SET")
515 .arg(key)
516 .arg(value)
517 .arg(condition)
518 .arg(expiration)
519 .arg_if(keep_ttl, "KEEPTTL"),
520 )
521 }
522
523 /// Set key to hold the string value wit GET option enforced
524 ///
525 /// # See Also
526 /// [<https://redis.io/commands/set/>](https://redis.io/commands/set/)
527 #[must_use]
528 fn set_get_with_options<K, V1, V2>(
529 &mut self,
530 key: K,
531 value: V1,
532 condition: SetCondition,
533 expiration: SetExpiration,
534 keep_ttl: bool,
535 ) -> PreparedCommand<Self, V2>
536 where
537 Self: Sized,
538 K: Into<CommandArg>,
539 V1: Into<CommandArg>,
540 V2: FromValue,
541 {
542 prepare_command(
543 self,
544 cmd("SET")
545 .arg(key)
546 .arg(value)
547 .arg(condition)
548 .arg("GET")
549 .arg(expiration)
550 .arg_if(keep_ttl, "KEEPTTL"),
551 )
552 }
553
554 /// Set key to hold the string value and set key to timeout after a given number of seconds.
555 ///
556 /// # See Also
557 /// [<https://redis.io/commands/setex/>](https://redis.io/commands/setex/)
558 #[must_use]
559 fn setex<K, V>(&mut self, key: K, seconds: u64, value: V) -> PreparedCommand<Self, ()>
560 where
561 Self: Sized,
562 K: Into<CommandArg>,
563 V: Into<CommandArg>,
564 {
565 prepare_command(self, cmd("SETEX").arg(key).arg(seconds).arg(value))
566 }
567
568 /// Set key to hold string value if key does not exist.
569 ///
570 /// In that case, it is equal to SET.
571 /// When key already holds a value, no operation is performed.
572 /// SETNX is short for "SET if Not eXists".
573 ///
574 /// # Return
575 /// specifically:
576 /// * `true` - if the key was set
577 /// * `false` - if the key was not set
578 ///
579 /// # See Also
580 /// [<https://redis.io/commands/setnx/>](https://redis.io/commands/setnx/)
581 #[must_use]
582 fn setnx<K, V>(&mut self, key: K, value: V) -> PreparedCommand<Self, bool>
583 where
584 Self: Sized,
585 K: Into<CommandArg>,
586 V: Into<CommandArg>,
587 {
588 prepare_command(self, cmd("SETNX").arg(key).arg(value))
589 }
590
591 /// Overwrites part of the string stored at key,
592 /// starting at the specified offset,
593 /// for the entire length of value.
594 ///
595 /// # Return
596 /// the length of the string after it was modified by the command.
597 ///
598 /// # See Also
599 /// [<https://redis.io/commands/setrange/>](https://redis.io/commands/setrange/)
600 #[must_use]
601 fn setrange<K, V>(&mut self, key: K, offset: usize, value: V) -> PreparedCommand<Self, usize>
602 where
603 Self: Sized,
604 K: Into<CommandArg>,
605 V: Into<CommandArg>,
606 {
607 prepare_command(self, cmd("SETRANGE").arg(key).arg(offset).arg(value))
608 }
609
610 /// Returns the length of the string value stored at key.
611 ///
612 /// An error is returned when key holds a non-string value.
613 ///
614 /// # Return
615 /// the length of the string at key, or 0 when key does not exist.
616 ///
617 /// # See Also
618 /// [<https://redis.io/commands/strlen/>](https://redis.io/commands/strlen/)
619 #[must_use]
620 fn strlen<K>(&mut self, key: K) -> PreparedCommand<Self, usize>
621 where
622 Self: Sized,
623 K: Into<CommandArg>,
624 {
625 prepare_command(self, cmd("STRLEN").arg(key))
626 }
627}
628
629/// Options for the [`getex`](crate::StringCommands::getex) command
630pub enum GetExOptions {
631 /// Set the specified expire time, in seconds.
632 Ex(u64),
633 /// Set the specified expire time, in milliseconds.
634 Px(u64),
635 /// Set the specified Unix time at which the key will expire, in seconds.
636 Exat(u64),
637 /// Set the specified Unix time at which the key will expire, in milliseconds.
638 Pxat(u64),
639 /// Remove the time to live associated with the key.
640 Persist,
641}
642
643impl IntoArgs for GetExOptions {
644 fn into_args(self, args: CommandArgs) -> CommandArgs {
645 match self {
646 GetExOptions::Ex(duration) => ("EX", duration).into_args(args),
647 GetExOptions::Px(duration) => ("PX", duration).into_args(args),
648 GetExOptions::Exat(timestamp) => ("EXAT", timestamp).into_args(args),
649 GetExOptions::Pxat(timestamp) => ("PXAT", timestamp).into_args(args),
650 GetExOptions::Persist => "PERSIST".into_args(args),
651 }
652 }
653}
654
655pub type LcsMatch = ((usize, usize), (usize, usize), Option<usize>);
656
657/// Result for the [`lcs`](crate::StringCommands::lcs) command
658#[derive(Debug)]
659pub struct LcsResult {
660 pub matches: Vec<LcsMatch>,
661 pub len: usize,
662}
663
664impl FromValue for LcsResult {
665 fn from_value(value: Value) -> Result<Self> {
666 let mut values: HashMap<String, Value> = value.into()?;
667
668 let matches: Result<Vec<LcsMatch>> = values
669 .remove_with_result("matches")?
670 .into::<Vec<Value>>()?
671 .into_iter()
672 .map(|m| {
673 let mut match_: Vec<Value> = m.into()?;
674
675 match (match_.pop(), match_.pop(), match_.pop(), match_.pop()) {
676 (Some(len), Some(pos2), Some(pos1), None) => {
677 let mut pos1: Vec<usize> = pos1.into()?;
678 let mut pos2: Vec<usize> = pos2.into()?;
679 let len: usize = len.into()?;
680
681 match (pos1.pop(), pos1.pop(), pos1.pop()) {
682 (Some(pos1_right), Some(pos1_left), None) => {
683 match (pos2.pop(), pos2.pop(), pos2.pop()) {
684 (Some(pos2_right), Some(pos2_left), None) => Ok((
685 (pos1_left, pos1_right),
686 (pos2_left, pos2_right),
687 Some(len),
688 )),
689 _ => Err(Error::Client("Cannot parse LCS result".to_owned())),
690 }
691 }
692 _ => Err(Error::Client("Cannot parse LCS result".to_owned())),
693 }
694 }
695 (Some(pos2), Some(pos1), None, None) => {
696 let mut pos1: Vec<usize> = pos1.into()?;
697 let mut pos2: Vec<usize> = pos2.into()?;
698
699 match (pos1.pop(), pos1.pop(), pos1.pop()) {
700 (Some(pos1_right), Some(pos1_left), None) => {
701 match (pos2.pop(), pos2.pop(), pos2.pop()) {
702 (Some(pos2_right), Some(pos2_left), None) => {
703 Ok(((pos1_left, pos1_right), (pos2_left, pos2_right), None))
704 }
705 _ => Err(Error::Client("Cannot parse LCS result".to_owned())),
706 }
707 }
708 _ => Err(Error::Client("Cannot parse LCS result".to_owned())),
709 }
710 }
711 _ => Err(Error::Client("Cannot parse LCS result".to_owned())),
712 }
713 })
714 .collect();
715
716 Ok(Self {
717 matches: matches?,
718 len: values.remove_with_result("len")?.into()?,
719 })
720 }
721}
722
723/// Expiration option for the [`set_with_options`](crate::StringCommands::set_with_options) command
724pub enum SetExpiration {
725 /// No expiration
726 None,
727 /// Set the specified expire time, in seconds.
728 Ex(u64),
729 /// Set the specified expire time, in milliseconds.
730 Px(u64),
731 /// Set the specified Unix time at which the key will expire, in seconds.
732 Exat(u64),
733 /// Set the specified Unix time at which the key will expire, in milliseconds.
734 Pxat(u64),
735}
736
737impl Default for SetExpiration {
738 fn default() -> Self {
739 SetExpiration::None
740 }
741}
742
743impl IntoArgs for SetExpiration {
744 fn into_args(self, args: CommandArgs) -> CommandArgs {
745 match self {
746 SetExpiration::None => args,
747 SetExpiration::Ex(duration) => ("EX", duration).into_args(args),
748 SetExpiration::Px(duration) => ("PX", duration).into_args(args),
749 SetExpiration::Exat(timestamp) => ("EXAT", timestamp).into_args(args),
750 SetExpiration::Pxat(timestamp) => ("PXAT", timestamp).into_args(args),
751 }
752 }
753}
754
755/// Condition option for the [`set_with_options`](crate::StringCommands::set_with_options) command
756pub enum SetCondition {
757 /// No condition
758 None,
759 /// Only set the key if it does not already exist.
760 NX,
761 /// Only set the key if it already exist.
762 XX,
763}
764
765impl Default for SetCondition {
766 fn default() -> Self {
767 SetCondition::None
768 }
769}
770
771impl IntoArgs for SetCondition {
772 fn into_args(self, args: CommandArgs) -> CommandArgs {
773 match self {
774 SetCondition::None => args,
775 SetCondition::NX => args.arg("NX"),
776 SetCondition::XX => args.arg("XX"),
777 }
778 }
779}