redis_driver/commands/
server_commands.rs

1use std::{collections::HashMap, str::FromStr};
2
3use crate::{
4    prepare_command,
5    resp::{
6        cmd, CommandArg, CommandArgs, FromKeyValueValueArray, FromSingleValueArray, FromValue,
7        HashMapExt, IntoArgs, KeyValueArgOrCollection, SingleArgOrCollection, Value,
8    },
9    Error, PreparedCommand, Result,
10};
11
12/// A group of Redis commands related to Server Management
13/// # See Also
14/// [Redis Server Management Commands](https://redis.io/commands/?group=server)
15/// [ACL guide](https://redis.io/docs/manual/security/acl/)
16pub trait ServerCommands {
17    /// The command shows the available ACL categories if called without arguments.
18    /// If a category name is given, the command shows all the Redis commands in the specified category.
19    ///
20    /// # Return
21    /// A collection of ACL categories or a collection of commands inside a given category.
22    ///
23    /// # Errors
24    /// The command may return an error if an invalid category name is given as argument.
25    ///
26    /// # See Also
27    /// [<https://redis.io/commands/acl-cat/>](https://redis.io/commands/acl-cat/)
28    fn acl_cat<C, CC>(&mut self, options: AclCatOptions) -> PreparedCommand<Self, CC>
29    where
30        Self: Sized,
31        C: FromValue,
32        CC: FromSingleValueArray<C>,
33    {
34        prepare_command(self, cmd("ACL").arg("CAT").arg(options))
35    }
36
37    /// Delete all the specified ACL users and terminate all
38    /// the connections that are authenticated with such users.
39    ///
40    /// # Return
41    /// The number of users that were deleted.
42    /// This number will not always match the number of arguments since certain users may not exist.
43    ///
44    /// # See Also
45    /// [<https://redis.io/commands/acl-deluser/>](https://redis.io/commands/acl-deluser/)
46    fn acl_deluser<U, UU>(&mut self, usernames: UU) -> PreparedCommand<Self, usize>
47    where
48        Self: Sized,
49        U: Into<CommandArg>,
50        UU: SingleArgOrCollection<U>,
51    {
52        prepare_command(self, cmd("ACL").arg("DELUSER").arg(usernames))
53    }
54
55    /// Simulate the execution of a given command by a given user.
56    ///
57    /// # Return
58    /// OK on success.
59    /// An error describing why the user can't execute the command.
60    ///
61    /// # See Also
62    /// [<https://redis.io/commands/acl-dryrun/>](https://redis.io/commands/acl-dryrun/)
63    fn acl_dryrun<U, C, R>(
64        &mut self,
65        username: U,
66        command: C,
67        options: AclDryRunOptions,
68    ) -> PreparedCommand<Self, R>
69    where
70        Self: Sized,
71        U: Into<CommandArg>,
72        C: Into<CommandArg>,
73        R: FromValue,
74    {
75        prepare_command(
76            self,
77            cmd("ACL")
78                .arg("DRYRUN")
79                .arg(username)
80                .arg(command)
81                .arg(options),
82        )
83    }
84
85    /// Generates a password starting from /dev/urandom if available,
86    /// otherwise (in systems without /dev/urandom) it uses a weaker
87    /// system that is likely still better than picking a weak password by hand.
88    ///
89    /// # Return
90    /// by default 64 bytes string representing 256 bits of pseudorandom data.
91    /// Otherwise if an argument if needed, the output string length is the number
92    /// of specified bits (rounded to the next multiple of 4) divided by 4.
93    ///
94    /// # See Also
95    /// [<https://redis.io/commands/acl-genpass/>](https://redis.io/commands/acl-genpass/)
96    fn acl_genpass<R: FromValue>(&mut self, options: AclGenPassOptions) -> PreparedCommand<Self, R>
97    where
98        Self: Sized,
99    {
100        prepare_command(self, cmd("ACL").arg("GENPASS").arg(options))
101    }
102
103    /// The command returns all the rules defined for an existing ACL user.
104    ///
105    /// # Return
106    /// A collection of ACL rule definitions for the user.
107    ///
108    /// # See Also
109    /// [<https://redis.io/commands/acl-getuser/>](https://redis.io/commands/acl-getuser/)
110    fn acl_getuser<U, RR>(&mut self, username: U) -> PreparedCommand<Self, RR>
111    where
112        Self: Sized,
113        U: Into<CommandArg>,
114        RR: FromKeyValueValueArray<String, Value>,
115    {
116        prepare_command(self, cmd("ACL").arg("GETUSER").arg(username))
117    }
118
119    /// The command shows the currently active ACL rules in the Redis server.
120    ///
121    /// # Return
122    /// An array of strings.
123    /// Each line in the returned array defines a different user, and the
124    /// format is the same used in the redis.conf file or the external ACL file
125    ///
126    /// # See Also
127    /// [<https://redis.io/commands/acl-list/>](https://redis.io/commands/acl-list/)
128    fn acl_list(&mut self) -> PreparedCommand<Self, Vec<String>>
129    where
130        Self: Sized,
131    {
132        prepare_command(self, cmd("ACL").arg("LIST"))
133    }
134
135    /// When Redis is configured to use an ACL file (with the aclfile configuration option),
136    /// this command will reload the ACLs from the file, replacing all the current ACL rules
137    /// with the ones defined in the file.
138    ///
139    /// # Return
140    /// An array of strings.
141    /// Each line in the returned array defines a different user, and the
142    /// format is the same used in the redis.conf file or the external ACL file
143    ///
144    /// # Errors
145    /// The command may fail with an error for several reasons:
146    /// - if the file is not readable,
147    /// - if there is an error inside the file, and in such case the error will be reported to the user in the error.
148    /// - Finally the command will fail if the server is not configured to use an external ACL file.
149    ///
150    /// # See Also
151    /// [<https://redis.io/commands/acl-load/>](https://redis.io/commands/acl-load/)
152    fn acl_load(&mut self) -> PreparedCommand<Self, ()>
153    where
154        Self: Sized,
155    {
156        prepare_command(self, cmd("ACL").arg("LOAD"))
157    }
158
159    /// The command shows a list of recent ACL security events
160    ///
161    /// # Return
162    /// A key/value collection of ACL security events.
163    /// Empty collection when called with the [`reset`](crate::AclLogOptions::reset) option
164    ///
165    /// # See Also
166    /// [<https://redis.io/commands/acl-log/>](https://redis.io/commands/acl-log/)
167    fn acl_log<EE>(&mut self, options: AclLogOptions) -> PreparedCommand<Self, Vec<EE>>
168    where
169        Self: Sized,
170        EE: FromKeyValueValueArray<String, Value>,
171    {
172        prepare_command(self, cmd("ACL").arg("LOG").arg(options))
173    }
174
175    /// When Redis is configured to use an ACL file (with the aclfile configuration option),
176    /// this command will save the currently defined ACLs from the server memory to the ACL file.
177    ///
178    /// # Errors
179    /// The command may fail with an error for several reasons:
180    /// - if the file cannot be written
181    /// - if the server is not configured to use an external ACL file.
182    ///
183    /// # See Also
184    /// [<https://redis.io/commands/acl-save/>](https://redis.io/commands/acl-save/)
185    fn acl_save(&mut self) -> PreparedCommand<Self, ()>
186    where
187        Self: Sized,
188    {
189        prepare_command(self, cmd("ACL").arg("SAVE"))
190    }
191
192    /// Create an ACL user with the specified rules or modify the rules of an existing user.
193    ///
194    /// # Errors
195    /// If the rules contain errors, the error is returned.
196    ///
197    /// # See Also
198    /// [<https://redis.io/commands/acl-setuser/>](https://redis.io/commands/acl-setuser/)
199    fn acl_setuser<U, R, RR>(&mut self, username: U, rules: RR) -> PreparedCommand<Self, ()>
200    where
201        Self: Sized,
202        U: Into<CommandArg>,
203        R: Into<CommandArg>,
204        RR: SingleArgOrCollection<R>,
205    {
206        prepare_command(self, cmd("ACL").arg("SETUSER").arg(username).arg(rules))
207    }
208
209    /// The command shows a list of all the usernames of the currently configured users in the Redis ACL system.
210    ///
211    /// # Return
212    /// A collection of usernames
213    ///
214    /// # See Also
215    /// [<https://redis.io/commands/acl-users/>](https://redis.io/commands/acl-users/)
216    fn acl_users<U, UU>(&mut self) -> PreparedCommand<Self, UU>
217    where
218        Self: Sized,
219        U: FromValue,
220        UU: FromSingleValueArray<U>,
221    {
222        prepare_command(self, cmd("ACL").arg("USERS"))
223    }
224
225    /// Return the username the current connection is authenticated with.
226    ///
227    /// # Return
228    /// The username of the current connection.
229    ///
230    /// # See Also
231    /// [<https://redis.io/commands/acl-whoami/>](https://redis.io/commands/acl-whoami/)
232    fn acl_whoami<U: FromValue>(&mut self) -> PreparedCommand<Self, U>
233    where
234        Self: Sized,
235    {
236        prepare_command(self, cmd("ACL").arg("WHOAMI"))
237    }
238
239    /// Return an array with details about every Redis command.
240    ///
241    /// # Return
242    /// A nested list of command details.
243    /// The order of commands in the array is random.
244    ///
245    /// # See Also
246    /// [<https://redis.io/commands/command/>](https://redis.io/commands/command/)
247    fn command(&mut self) -> PreparedCommand<Self, Vec<CommandInfo>>
248    where
249        Self: Sized,
250    {
251        prepare_command(self, cmd("COMMAND"))
252    }
253
254    /// Number of total commands in this Redis server.
255    ///
256    /// # Return
257    /// number of commands returned by [`command`](crate::ServerCommands::command)
258    ///
259    /// # See Also
260    /// [<https://redis.io/commands/command-count/>](https://redis.io/commands/command-count/)
261    fn command_count(&mut self) -> PreparedCommand<Self, usize>
262    where
263        Self: Sized,
264    {
265        prepare_command(self, cmd("COMMAND").arg("COUNT"))
266    }
267
268    /// Number of total commands in this Redis server.
269    ///
270    /// # Return
271    /// map key=command name, value=command doc
272    ///
273    /// # See Also
274    /// [<https://redis.io/commands/command-docs/>](https://redis.io/commands/command-docs/)
275    fn command_docs<N, NN, DD>(&mut self, command_names: NN) -> PreparedCommand<Self, DD>
276    where
277        Self: Sized,
278        N: Into<CommandArg>,
279        NN: SingleArgOrCollection<N>,
280        DD: FromKeyValueValueArray<String, CommandDoc>,
281    {
282        prepare_command(self, cmd("COMMAND").arg("DOCS").arg(command_names))
283    }
284
285    /// A helper command to let you find the keys from a full Redis command.
286    ///
287    /// # Return
288    /// list of keys from your command.
289    ///
290    /// # See Also
291    /// [<https://redis.io/commands/command-_getkeys/>](https://redis.io/commands/command-_getkeys/)
292    fn command_getkeys<A, AA, KK>(&mut self, args: AA) -> PreparedCommand<Self, KK>
293    where
294        Self: Sized,
295        A: Into<CommandArg>,
296        AA: SingleArgOrCollection<A>,
297        KK: FromSingleValueArray<String>,
298    {
299        prepare_command(self, cmd("COMMAND").arg("GETKEYS").arg(args))
300    }
301
302    /// A helper command to let you find the keys from a full Redis command together with flags indicating what each key is used for.
303    ///
304    /// # Return
305    /// map of keys with their flags from your command.
306    ///
307    /// # See Also
308    /// [<https://redis.io/commands/command-getkeysandflags/>](https://redis.io/commands/command-getkeysandflags/)
309    fn command_getkeysandflags<A, AA, KK>(&mut self, args: AA) -> PreparedCommand<Self, KK>
310    where
311        Self: Sized,
312        A: Into<CommandArg>,
313        AA: SingleArgOrCollection<A>,
314        KK: FromKeyValueValueArray<String, Vec<String>>,
315    {
316        prepare_command(self, cmd("COMMAND").arg("GETKEYSANDFLAGS").arg(args))
317    }
318
319    /// Return an array with details about multiple Redis command.
320    ///
321    /// # Return
322    /// A nested list of command details.
323    ///
324    /// # See Also
325    /// [<https://redis.io/commands/command-info/>](https://redis.io/commands/command-info/)
326    fn command_info<N, NN>(&mut self, command_names: NN) -> PreparedCommand<Self, Vec<CommandInfo>>
327    where
328        Self: Sized,
329        N: Into<CommandArg>,
330        NN: SingleArgOrCollection<N>,
331    {
332        prepare_command(self, cmd("COMMAND").arg("INFO").arg(command_names))
333    }
334
335    /// Return an array of the server's command names based on optional filters
336    ///
337    /// # Return
338    /// an array of the server's command names.
339    ///
340    /// # See Also
341    /// [<https://redis.io/commands/command-list/>](https://redis.io/commands/command-list/)
342    fn command_list<CC>(&mut self, options: CommandListOptions) -> PreparedCommand<Self, CC>
343    where
344        Self: Sized,
345        CC: FromSingleValueArray<String>,
346    {
347        prepare_command(self, cmd("COMMAND").arg("LIST").arg(options))
348    }
349
350    /// Used to read the configuration parameters of a running Redis server.
351    ///
352    /// For every key that does not hold a string value or does not exist,
353    /// the special value nil is returned. Because of this, the operation never fails.
354    ///
355    /// # Return
356    /// Array reply: collection of the requested params with their matching values.
357    ///
358    /// # See Also
359    /// [<https://redis.io/commands/config-get/>](https://redis.io/commands/config-get/)
360    #[must_use]
361    fn config_get<P, PP, V, VV>(&mut self, params: PP) -> PreparedCommand<Self, VV>
362    where
363        Self: Sized,
364        P: Into<CommandArg>,
365        PP: SingleArgOrCollection<P>,
366        V: FromValue,
367        VV: FromKeyValueValueArray<String, V>,
368    {
369        prepare_command(self, cmd("CONFIG").arg("GET").arg(params))
370    }
371
372    /// Resets the statistics reported by Redis using the [`info`](crate::ServerCommands::info) command.
373    ///
374    /// # See Also
375    /// [<https://redis.io/commands/config-resetstat/>](https://redis.io/commands/config-resetstat/)
376    #[must_use]
377    fn config_resetstat(&mut self) -> PreparedCommand<Self, ()>
378    where
379        Self: Sized,
380    {
381        prepare_command(self, cmd("CONFIG").arg("RESETSTAT"))
382    }
383
384    /// Rewrites the redis.conf file the server was started with,
385    /// applying the minimal changes needed to make it reflect the configuration currently used by the server,
386    /// which may be different compared to the original one because of the use of the
387    /// [`config_set`](crate::ServerCommands::config_set) command.
388    ///
389    /// # See Also
390    /// [<https://redis.io/commands/config-rewrite/>](https://redis.io/commands/config-rewrite/)
391    #[must_use]
392    fn config_rewrite(&mut self) -> PreparedCommand<Self, ()>
393    where
394        Self: Sized,
395    {
396        prepare_command(self, cmd("CONFIG").arg("REWRITE"))
397    }
398
399    /// Used in order to reconfigure the server at run time without the need to restart Redis.
400    ///
401    /// # See Also
402    /// [<https://redis.io/commands/config-set/>](https://redis.io/commands/config-set/)
403    #[must_use]
404    fn config_set<P, V, C>(&mut self, configs: C) -> PreparedCommand<Self, ()>
405    where
406        Self: Sized,
407        P: Into<CommandArg>,
408        V: Into<CommandArg>,
409        C: KeyValueArgOrCollection<P, V>,
410    {
411        prepare_command(self, cmd("CONFIG").arg("SET").arg(configs))
412    }
413
414    /// Return the number of keys in the currently-selected database.
415    ///
416    /// # See Also
417    /// [<https://redis.io/commands/dbsize/>](https://redis.io/commands/dbsize/)
418    #[must_use]
419    fn dbsize(&mut self) -> PreparedCommand<Self, usize>
420    where
421        Self: Sized,
422    {
423        prepare_command(self, cmd("DBSIZE"))
424    }
425
426    /// This command will start a coordinated failover between
427    /// the currently-connected-to master and one of its replicas.
428    ///
429    /// # See Also
430    /// [<https://redis.io/commands/failover/>](https://redis.io/commands/failover/)
431    #[must_use]
432    fn failover(&mut self, options: FailOverOptions) -> PreparedCommand<Self, ()>
433    where
434        Self: Sized,
435    {
436        prepare_command(self, cmd("FAILOVER").arg(options))
437    }
438
439    /// Delete all the keys of the currently selected DB.
440    ///
441    /// # See Also
442    /// [<https://redis.io/commands/flushdb/>](https://redis.io/commands/flushdb/)
443    #[must_use]
444    fn flushdb(&mut self, flushing_mode: FlushingMode) -> PreparedCommand<Self, ()>
445    where
446        Self: Sized,
447    {
448        prepare_command(self, cmd("FLUSHDB").arg(flushing_mode))
449    }
450
451    /// Delete all the keys of all the existing databases, not just the currently selected one.
452    ///
453    /// # See Also
454    /// [<https://redis.io/commands/flushall/>](https://redis.io/commands/flushall/)
455    #[must_use]
456    fn flushall(&mut self, flushing_mode: FlushingMode) -> PreparedCommand<Self, ()>
457    where
458        Self: Sized,
459    {
460        prepare_command(self, cmd("FLUSHALL").arg(flushing_mode))
461    }
462
463    /// This command returns information and statistics about the server
464    /// in a format that is simple to parse by computers and easy to read by humans.
465    ///
466    /// # See Also
467    /// [<https://redis.io/commands/info/>](https://redis.io/commands/info/)
468    #[must_use]
469    fn info<SS>(&mut self, sections: SS) -> PreparedCommand<Self, String>
470    where
471        Self: Sized,
472        SS: SingleArgOrCollection<InfoSection>,
473    {
474        prepare_command(self, cmd("INFO").arg(sections))
475    }
476
477    /// Return the UNIX TIME of the last DB save executed with success.
478    ///
479    /// # See Also
480    /// [<https://redis.io/commands/lastsave/>](https://redis.io/commands/lastsave/)
481    #[must_use]
482    fn lastsave(&mut self) -> PreparedCommand<Self, u64>
483    where
484        Self: Sized,
485    {
486        prepare_command(self, cmd("LASTSAVE"))
487    }
488
489    /// This command reports about different latency-related issues and advises about possible remedies.
490    ///
491    /// # Return
492    /// String report
493    ///
494    /// # See Also
495    /// [<https://redis.io/commands/latency-doctor/>](https://redis.io/commands/latency-doctor/)
496    #[must_use]
497    fn latency_doctor(&mut self) -> PreparedCommand<Self, String>
498    where
499        Self: Sized,
500    {
501        prepare_command(self, cmd("LATENCY").arg("DOCTOR"))
502    }
503
504    /// Produces an ASCII-art style graph for the specified event.
505    ///
506    /// # Return
507    /// String graph
508    ///
509    /// # See Also
510    /// [<https://redis.io/commands/latency-graph/>](https://redis.io/commands/latency-graph/)
511    #[must_use]
512    fn latency_graph(&mut self, event: LatencyHistoryEvent) -> PreparedCommand<Self, String>
513    where
514        Self: Sized,
515    {
516        prepare_command(self, cmd("LATENCY").arg("GRAPH").arg(event))
517    }
518
519    /// This command reports a cumulative distribution of latencies
520    /// in the format of a histogram for each of the specified command names.
521    ///
522    /// # Return
523    /// The command returns a map where each key is a command name, and each value is a CommandHistogram instance.
524    ///
525    /// # See Also
526    /// [<https://redis.io/commands/latency-histogram/>](https://redis.io/commands/latency-histogram/)
527    #[must_use]
528    fn latency_histogram<C, CC, RR>(&mut self, commands: CC) -> PreparedCommand<Self, RR>
529    where
530        Self: Sized,
531        C: Into<CommandArg>,
532        CC: SingleArgOrCollection<C>,
533        RR: FromKeyValueValueArray<String, CommandHistogram>,
534    {
535        prepare_command(self, cmd("LATENCY").arg("HISTOGRAM").arg(commands))
536    }
537
538    /// This command returns the raw data of the event's latency spikes time series.
539    ///
540    /// # Return
541    /// The command returns a collection where each element is a two elements tuple representing
542    /// - the unix timestamp in seconds
543    /// - the latency of the event in milliseconds
544    ///
545    /// # See Also
546    /// [<https://redis.io/commands/latency-history/>](https://redis.io/commands/latency-history/)
547    #[must_use]
548    fn latency_history<RR>(&mut self, event: LatencyHistoryEvent) -> PreparedCommand<Self, RR>
549    where
550        Self: Sized,
551        RR: FromSingleValueArray<(u32, u32)>,
552    {
553        prepare_command(self, cmd("LATENCY").arg("HISTORY").arg(event))
554    }
555
556    /// This command reports the latest latency events logged.
557    ///
558    /// # Return
559    /// A collection of the latest latency events logged.
560    /// Each reported event has the following fields:
561    /// - Event name.
562    /// - Unix timestamp of the latest latency spike for the event.
563    /// - Latest event latency in millisecond.
564    /// - All-time maximum latency for this event.
565    ///
566    /// "All-time" means the maximum latency since the Redis instance was started,
567    /// or the time that events were [`reset`](crate::ConnectionCommands::reset).
568    ///
569    /// # See Also
570    /// [<https://redis.io/commands/latency-latest/>](https://redis.io/commands/latency-latest/)
571    #[must_use]
572    fn latency_latest<RR>(&mut self) -> PreparedCommand<Self, RR>
573    where
574        Self: Sized,
575        RR: FromSingleValueArray<(String, u32, u32, u32)>,
576    {
577        prepare_command(self, cmd("LATENCY").arg("LATEST"))
578    }
579
580    /// This command resets the latency spikes time series of all, or only some, events.
581    ///
582    /// # Return
583    /// the number of event time series that were reset.
584    ///
585    /// # See Also
586    /// [<https://redis.io/commands/latency-latest/>](https://redis.io/commands/latency-latest/)
587    #[must_use]
588    fn latency_reset<EE>(&mut self, events: EE) -> PreparedCommand<Self, usize>
589    where
590        Self: Sized,
591        EE: SingleArgOrCollection<LatencyHistoryEvent>,
592    {
593        prepare_command(self, cmd("LATENCY").arg("RESET").arg(events))
594    }
595
596    /// The LOLWUT command displays the Redis version: however as a side effect of doing so,
597    /// it also creates a piece of generative computer art that is different with each version of Redis.
598    ///
599    /// # Return
600    /// the string containing the generative computer art, and a text with the Redis version.
601    ///
602    /// # See Also
603    /// [<https://redis.io/commands/lolwut/>](https://redis.io/commands/lolwut/)
604    #[must_use]
605    fn lolwut(&mut self, options: LolWutOptions) -> PreparedCommand<Self, String>
606    where
607        Self: Sized,
608    {
609        prepare_command(self, cmd("LOLWUT").arg(options))
610    }
611
612    /// This command reports about different memory-related issues that
613    /// the Redis server experiences, and advises about possible remedies.
614    ///
615    /// # Return
616    /// the string report.
617    ///
618    /// # See Also
619    /// [<https://redis.io/commands/memory-doctor/>](https://redis.io/commands/memory-doctor/)
620    #[must_use]
621    fn memory_doctor(&mut self) -> PreparedCommand<Self, String>
622    where
623        Self: Sized,
624    {
625        prepare_command(self, cmd("MEMORY").arg("DOCTOR"))
626    }
627
628    /// This command provides an internal statistics report from the memory allocator.
629    ///
630    /// # Return
631    /// the memory allocator's internal statistics report.
632    ///
633    /// # See Also
634    /// [<https://redis.io/commands/memory-malloc-stats/>](https://redis.io/commands/memory-malloc-stats/)
635    #[must_use]
636    fn memory_malloc_stats(&mut self) -> PreparedCommand<Self, String>
637    where
638        Self: Sized,
639    {
640        prepare_command(self, cmd("MEMORY").arg("MALLOC-STATS"))
641    }
642
643    /// This command attempts to purge dirty pages so these can be reclaimed by the allocator.
644    ///
645    /// # See Also
646    /// [<https://redis.io/commands/memory-purge/>](https://redis.io/commands/memory-purge/)
647    #[must_use]
648    fn memory_purge(&mut self) -> PreparedCommand<Self, ()>
649    where
650        Self: Sized,
651    {
652        prepare_command(self, cmd("MEMORY").arg("PURGE"))
653    }
654
655    /// This command returns information about the memory usage of the server.
656    ///
657    /// # Return
658    /// the memory allocator's internal statistics report.
659    ///
660    /// # See Also
661    /// [<https://redis.io/commands/memory-stats/>](https://redis.io/commands/memory-stats/)
662    #[must_use]
663    fn memory_stats(&mut self) -> PreparedCommand<Self, MemoryStats>
664    where
665        Self: Sized,
666    {
667        prepare_command(self, cmd("MEMORY").arg("STATS"))
668    }
669
670    /// This command reports the number of bytes that a key and its value require to be stored in RAM.
671    ///
672    /// # Return
673    /// the memory usage in bytes, or None when the key does not exist.
674    ///
675    /// # See Also
676    /// [<https://redis.io/commands/memory-usage/>](https://redis.io/commands/memory-usage/)
677    #[must_use]
678    fn memory_usage<K>(
679        &mut self,
680        key: K,
681        options: MemoryUsageOptions,
682    ) -> PreparedCommand<Self, Option<usize>>
683    where
684        Self: Sized,
685        K: Into<CommandArg>,
686    {
687        prepare_command(self, cmd("MEMORY").arg("USAGE").arg(key).arg(options))
688    }
689
690    /// Returns information about the modules loaded to the server.
691    ///
692    /// # Return
693    /// list of loaded modules.
694    /// Each element in the list represents a module as an instance of [`ModuleInfo`](crate::ModuleInfo)
695    ///
696    /// # See Also
697    /// [<https://redis.io/commands/module-list/>](https://redis.io/commands/module-list/)
698    #[must_use]
699    fn module_list<MM>(&mut self) -> PreparedCommand<Self, MM>
700    where
701        Self: Sized,
702        MM: FromSingleValueArray<ModuleInfo>,
703    {
704        prepare_command(self, cmd("MODULE").arg("LIST"))
705    }
706
707    /// Loads a module from a dynamic library at runtime.
708    ///
709    /// # See Also
710    /// [<https://redis.io/commands/module-load/>](https://redis.io/commands/module-load/)
711    #[must_use]
712    fn module_load<P>(&mut self, path: P, options: ModuleLoadOptions) -> PreparedCommand<Self, ()>
713    where
714        Self: Sized,
715        P: Into<CommandArg>,
716    {
717        prepare_command(self, cmd("MODULE").arg("LOADEX").arg(path).arg(options))
718    }
719
720    /// Unloads a module.
721    ///
722    /// # See Also
723    /// [<https://redis.io/commands/module-unload/>](https://redis.io/commands/module-unload/)
724    #[must_use]
725    fn module_unload<N>(&mut self, name: N) -> PreparedCommand<Self, ()>
726    where
727        Self: Sized,
728        N: Into<CommandArg>,
729    {
730        prepare_command(self, cmd("MODULE").arg("UNLOAD").arg(name))
731    }
732
733    /// This command can change the replication settings of a replica on the fly.
734    ///
735    /// # See Also
736    /// [<https://redis.io/commands/replicaof/>](https://redis.io/commands/replicaof/)
737    #[must_use]
738    fn replicaof(&mut self, options: ReplicaOfOptions) -> PreparedCommand<Self, ()>
739    where
740        Self: Sized,
741    {
742        prepare_command(self, cmd("REPLICAOF").arg(options))
743    }
744
745    /// Provide information on the role of a Redis instance in the context of replication,
746    /// by returning if the instance is currently a `master`, `slave`, or `sentinel`.
747    ///
748    /// # See Also
749    /// [<https://redis.io/commands/role/>](https://redis.io/commands/role/)
750    #[must_use]
751    fn role(&mut self) -> PreparedCommand<Self, RoleResult>
752    where
753        Self: Sized,
754    {
755        prepare_command(self, cmd("ROLE"))
756    }
757
758    /// This command performs a synchronous save of the dataset producing a point in time snapshot
759    /// of all the data inside the Redis instance, in the form of an RDB file.
760    ///
761    /// # See Also
762    /// [<https://redis.io/commands/save/>](https://redis.io/commands/save/)
763    #[must_use]
764    fn save(&mut self) -> PreparedCommand<Self, ()>
765    where
766        Self: Sized,
767    {
768        prepare_command(self, cmd("SAVE"))
769    }
770
771    /// Shutdown the server
772    ///
773    /// # See Also
774    /// [<https://redis.io/commands/shutdown/>](https://redis.io/commands/shutdown/)
775    #[must_use]
776    fn shutdown(&mut self, options: ShutdownOptions) -> PreparedCommand<Self, ()>
777    where
778        Self: Sized,
779    {
780        prepare_command(self, cmd("SHUTDOWN").arg(options))
781    }
782
783    /// This command returns entries from the slow log in chronological order.
784    ///
785    /// # See Also
786    /// [<https://redis.io/commands/slowlog-get/>](https://redis.io/commands/slowlog-get/)
787    #[must_use]
788    fn slowlog_get(&mut self, options: SlowLogOptions) -> PreparedCommand<Self, Vec<SlowLogEntry>>
789    where
790        Self: Sized,
791    {
792        prepare_command(self, cmd("SLOWLOG").arg("GET").arg(options))
793    }
794
795    /// This command returns the current number of entries in the slow log.
796    ///
797    /// # See Also
798    /// [<https://redis.io/commands/slowlog-len/>](https://redis.io/commands/slowlog-len/)
799    #[must_use]
800    fn slowlog_len(&mut self) -> PreparedCommand<Self, usize>
801    where
802        Self: Sized,
803    {
804        prepare_command(self, cmd("SLOWLOG").arg("LEN"))
805    }
806
807    /// This command resets the slow log, clearing all entries in it.
808    ///
809    /// # See Also
810    /// [<https://redis.io/commands/slowlog-reset/>](https://redis.io/commands/slowlog-reset/)
811    #[must_use]
812    fn slowlog_reset(&mut self) -> PreparedCommand<Self, ()>
813    where
814        Self: Sized,
815    {
816        prepare_command(self, cmd("SLOWLOG").arg("RESET"))
817    }
818
819    /// This command swaps two Redis databases,
820    /// so that immediately all the clients connected to a given database
821    /// will see the data of the other database, and the other way around.
822    ///
823    /// # See Also
824    /// [<https://redis.io/commands/swapdb/>](https://redis.io/commands/swapdb/)
825    #[must_use]
826    fn swapdb(&mut self, index1: usize, index2: usize) -> PreparedCommand<Self, ()>
827    where
828        Self: Sized,
829    {
830        prepare_command(self, cmd("SWAPDB").arg(index1).arg(index2))
831    }
832
833    /// The TIME command returns the current server time as a two items lists:
834    /// a Unix timestamp and the amount of microseconds already elapsed in the current second.
835    ///
836    /// # See Also
837    /// [<https://redis.io/commands/time/>](https://redis.io/commands/time/)
838    #[must_use]
839    fn time(&mut self) -> PreparedCommand<Self, (u32, u32)>
840    where
841        Self: Sized,
842    {
843        prepare_command(self, cmd("TIME"))
844    }
845}
846
847/// Database flushing mode
848pub enum FlushingMode {
849    Default,
850    /// Flushes the database(s) asynchronously
851    Async,
852    /// Flushed the database(s) synchronously
853    Sync,
854}
855
856impl Default for FlushingMode {
857    fn default() -> Self {
858        FlushingMode::Default
859    }
860}
861
862impl IntoArgs for FlushingMode {
863    fn into_args(self, args: CommandArgs) -> CommandArgs {
864        match self {
865            FlushingMode::Default => args,
866            FlushingMode::Async => args.arg("ASYNC"),
867            FlushingMode::Sync => args.arg("SYNC"),
868        }
869    }
870}
871
872/// Options for the [`acl_cat`](crate::ServerCommands::acl_cat) command
873#[derive(Default)]
874pub struct AclCatOptions {
875    command_args: CommandArgs,
876}
877
878impl AclCatOptions {
879    #[must_use]
880    pub fn category_name<C: Into<CommandArg>>(self, category_name: C) -> Self {
881        Self {
882            command_args: self.command_args.arg(category_name),
883        }
884    }
885}
886
887impl IntoArgs for AclCatOptions {
888    fn into_args(self, args: CommandArgs) -> CommandArgs {
889        args.arg(self.command_args)
890    }
891}
892
893/// Options for the [`acl_dryrun`](crate::ServerCommands::acl_dryrun) command
894#[derive(Default)]
895pub struct AclDryRunOptions {
896    command_args: CommandArgs,
897}
898
899impl AclDryRunOptions {
900    #[must_use]
901    pub fn arg<A, AA>(self, args: AA) -> Self
902    where
903        A: Into<CommandArg>,
904        AA: SingleArgOrCollection<A>,
905    {
906        Self {
907            command_args: self.command_args.arg(args),
908        }
909    }
910}
911
912impl IntoArgs for AclDryRunOptions {
913    fn into_args(self, args: CommandArgs) -> CommandArgs {
914        args.arg(self.command_args)
915    }
916}
917
918/// Options for the [`acl_genpass`](crate::ServerCommands::acl_genpass) command
919#[derive(Default)]
920pub struct AclGenPassOptions {
921    command_args: CommandArgs,
922}
923
924impl AclGenPassOptions {
925    /// The command output is a hexadecimal representation of a binary string.
926    /// By default it emits 256 bits (so 64 hex characters).
927    /// The user can provide an argument in form of number of bits to emit from 1 to 1024 to change the output length.
928    /// Note that the number of bits provided is always rounded to the next multiple of 4.
929    /// So for instance asking for just 1 bit password will result in 4 bits to be emitted, in the form of a single hex character.
930    #[must_use]
931    pub fn bits(self, bits: usize) -> Self {
932        Self {
933            command_args: self.command_args.arg(bits),
934        }
935    }
936}
937
938impl IntoArgs for AclGenPassOptions {
939    fn into_args(self, args: CommandArgs) -> CommandArgs {
940        args.arg(self.command_args)
941    }
942}
943
944/// Options for the [`acl_log`](crate::ServerCommands::acl_log) command
945#[derive(Default)]
946pub struct AclLogOptions {
947    command_args: CommandArgs,
948}
949
950impl AclLogOptions {
951    /// This optional argument specifies how many entries to show.
952    /// By default up to ten failures are returned.
953    #[must_use]
954    pub fn count(self, count: usize) -> Self {
955        Self {
956            command_args: self.command_args.arg(count),
957        }
958    }
959
960    /// The special RESET argument clears the log.
961    #[must_use]
962    pub fn reset(self) -> Self {
963        Self {
964            command_args: self.command_args.arg("RESET"),
965        }
966    }
967}
968
969impl IntoArgs for AclLogOptions {
970    fn into_args(self, args: CommandArgs) -> CommandArgs {
971        args.arg(self.command_args)
972    }
973}
974
975/// Command info result for the [`command`](crate::ServerCommands::command) command.
976#[derive(Debug, Clone)]
977pub struct CommandInfo {
978    /// This is the command's name in lowercase.
979    pub name: String,
980    /// Arity is the number of arguments a command expects. It follows a simple pattern:
981    /// - A positive integer means a fixed number of arguments.
982    /// - A negative integer means a minimal number of arguments.
983    pub arity: isize,
984    /// Command flags are an array.
985    /// See [COMMAND documentation](https://redis.io/commands/command/) for the list of flags
986    pub flags: Vec<String>,
987    /// The position of the command's first key name argument.
988    /// For most commands, the first key's position is 1. Position 0 is always the command name itself.
989    pub first_key: usize,
990    /// The position of the command's last key name argument.
991    pub last_key: isize,
992    /// The step, or increment, between the first key and the position of the next key.
993    pub step: usize,
994    /// [From Redis 6.0] This is an array of simple strings that are the ACL categories to which the command belongs.
995    pub acl_categories: Vec<String>,
996    /// [From Redis 7.0] Helpful information about the command. To be used by clients/proxies.
997    /// See [<https://redis.io/docs/reference/command-tips/>](https://redis.io/docs/reference/command-tips/)
998    pub command_tips: Vec<CommandTip>,
999    /// [From Redis 7.0] This is an array consisting of the command's key specifications.
1000    /// See [<https://redis.io/docs/reference/key-specs/>](https://redis.io/docs/reference/key-specs/)
1001    pub key_specifications: Vec<KeySpecification>,
1002    pub sub_commands: Vec<CommandInfo>,
1003}
1004
1005impl FromValue for CommandInfo {
1006    fn from_value(value: Value) -> Result<Self> {
1007        let values: Vec<Value> = value.into()?;
1008        let mut iter = values.into_iter();
1009
1010        match (
1011            iter.next(),
1012            iter.next(),
1013            iter.next(),
1014            iter.next(),
1015            iter.next(),
1016            iter.next(),
1017            iter.next(),
1018            iter.next(),
1019            iter.next(),
1020            iter.next(),
1021        ) {
1022            (
1023                Some(name),
1024                Some(arity),
1025                Some(flags),
1026                Some(first_key),
1027                Some(last_key),
1028                Some(step),
1029                Some(acl_categories),
1030                Some(command_tips),
1031                Some(key_specifications),
1032                Some(sub_commands),
1033            ) => Ok(Self {
1034                name: name.into()?,
1035                arity: arity.into()?,
1036                flags: flags.into()?,
1037                first_key: first_key.into()?,
1038                last_key: last_key.into()?,
1039                step: step.into()?,
1040                acl_categories: acl_categories.into()?,
1041                command_tips: command_tips.into()?,
1042                key_specifications: key_specifications.into()?,
1043                sub_commands: sub_commands.into()?,
1044            }),
1045            (
1046                Some(name),
1047                Some(arity),
1048                Some(flags),
1049                Some(first_key),
1050                Some(last_key),
1051                Some(step),
1052                Some(acl_categories),
1053                None,
1054                None,
1055                None,
1056            ) => Ok(Self {
1057                name: name.into()?,
1058                arity: arity.into()?,
1059                flags: flags.into()?,
1060                first_key: first_key.into()?,
1061                last_key: last_key.into()?,
1062                step: step.into()?,
1063                acl_categories: acl_categories.into()?,
1064                command_tips: Vec::new(),
1065                key_specifications: Vec::new(),
1066                sub_commands: Vec::new(),
1067            }),
1068            (
1069                Some(name),
1070                Some(arity),
1071                Some(flags),
1072                Some(first_key),
1073                Some(last_key),
1074                Some(step),
1075                None,
1076                None,
1077                None,
1078                None,
1079            ) => Ok(Self {
1080                name: name.into()?,
1081                arity: arity.into()?,
1082                flags: flags.into()?,
1083                first_key: first_key.into()?,
1084                last_key: last_key.into()?,
1085                step: step.into()?,
1086                acl_categories: Vec::new(),
1087                command_tips: Vec::new(),
1088                key_specifications: Vec::new(),
1089                sub_commands: Vec::new(),
1090            }),
1091            _ => Err(Error::Client(
1092                "Cannot parse CommandInfo from result".to_owned(),
1093            )),
1094        }
1095
1096        //let (name, arity, flags, first_key, last_key, step, acl_categories, command_tips, key_specifications, sub_commands)
1097    }
1098}
1099
1100/// Get additional information about a command
1101/// 
1102/// See <https://redis.io/docs/reference/command-tips/>
1103#[derive(Debug, Clone)]
1104pub enum CommandTip {
1105    NonDeterministricOutput,
1106    NonDeterministricOutputOrder,
1107    RequestPolicy(RequestPolicy),
1108    ResponsePolicy(ResponsePolicy),
1109}
1110
1111impl FromValue for CommandTip {
1112    fn from_value(value: Value) -> Result<Self> {
1113        let tip: String = value.into()?;
1114        match tip.as_str() {
1115            "nondeterministic_output" => Ok(CommandTip::NonDeterministricOutput),
1116            "nondeterministic_output_order" => Ok(CommandTip::NonDeterministricOutputOrder),
1117            _ => {
1118                let mut parts = tip.split(':');
1119                match (parts.next(), parts.next(), parts.next()) {
1120                    (Some("request_policy"), Some(policy), None) => {
1121                        Ok(CommandTip::RequestPolicy(RequestPolicy::from_str(policy)?))
1122                    }
1123                    (Some("response_policy"), Some(policy), None) => Ok(
1124                        CommandTip::ResponsePolicy(ResponsePolicy::from_str(policy)?),
1125                    ),
1126                    _ => Err(Error::Client(
1127                        "Cannot parse CommandTip from result".to_owned(),
1128                    )),
1129                }
1130            }
1131        }
1132    }
1133}
1134
1135/// This tip can help clients determine the shards to send the command in clustering mode. 
1136/// 
1137/// The default behavior a client should implement for commands without the request_policy tip is as follows:
1138/// 1. The command doesn't accept key name arguments: the client can execute the command on an arbitrary shard.
1139/// 2. For commands that accept one or more key name arguments: the client should route the command to a single shard, 
1140/// as determined by the hash slot of the input keys.
1141#[derive(Debug, Clone)]
1142pub enum RequestPolicy {
1143    /// the client should execute the command on all nodes - masters and replicas alike. 
1144    /// 
1145    /// An example is the [`config_set`](crate::ServerCommands::config_set) command. 
1146    /// This tip is in-use by commands that don't accept key name arguments. The command operates atomically per shard.
1147    AllNodes,
1148    /// the client should execute the command on all master shards (e.g., the [`dbsize`](crate::ServerCommands::dbsize) command). 
1149    /// 
1150    /// This tip is in-use by commands that don't accept key name arguments. The command operates atomically per shard.
1151    AllShards,
1152    /// the client should execute the command on several shards. 
1153    /// 
1154    /// The shards that execute the command are determined by the hash slots of its input key name arguments. 
1155    /// Examples for such commands include [`mset`](crate::StringCommands::mset), [`mget`](crate::StringCommands::mget) 
1156    /// and [`del`](crate::GenericCommands::del). 
1157    /// However, note that [`sunionstore`](crate::SetCommands::sunionstore) isn't considered 
1158    /// as multi_shard because all of its keys must belong to the same hash slot.
1159    MultiShard,
1160    /// indicates a non-trivial form of the client's request policy, such as the [`scan`](crate::GenericCommands::scan) command.
1161    Special,
1162}
1163
1164impl FromStr for RequestPolicy {
1165    type Err = Error;
1166
1167    fn from_str(str: &str) -> Result<Self> {
1168        match str {
1169            "all_nodes" => Ok(RequestPolicy::AllNodes),
1170            "all_shards" => Ok(RequestPolicy::AllShards),
1171            "multi_shard" => Ok(RequestPolicy::MultiShard),
1172            "special" => Ok(RequestPolicy::Special),
1173            _ => Err(Error::Client(
1174                "Cannot parse RequestPolicy from result".to_owned(),
1175            )),
1176        }
1177    }
1178}
1179
1180/// This tip can help clients determine the aggregate they need to compute from the replies of multiple shards in a cluster. 
1181/// 
1182/// The default behavior for commands without a request_policy tip only applies to replies with of nested types 
1183/// (i.e., an array, a set, or a map). 
1184/// The client's implementation for the default behavior should be as follows:
1185/// 1. The command doesn't accept key name arguments: the client can aggregate all replies within a single nested data structure. 
1186/// For example, the array replies we get from calling [`keys`](crate::GenericCommands::keys) against all shards. 
1187/// These should be packed in a single in no particular order.
1188/// 2. For commands that accept one or more key name arguments: the client needs to retain the same order of replies as the input key names. 
1189/// For example, [`mget`](crate::StringCommands::mget)'s aggregated reply.
1190#[derive(Debug, Clone)]
1191pub enum ResponsePolicy {
1192    /// the clients should return success if at least one shard didn't reply with an error. 
1193    /// 
1194    /// The client should reply with the first non-error reply it obtains. 
1195    /// If all shards return an error, the client can reply with any one of these. 
1196    /// For example, consider a [`script_kill`](crate::ScriptingCommands::script_kill) command that's sent to all shards. 
1197    /// Although the script should be loaded in all of the cluster's shards, 
1198    /// the [`script_kill`](crate::ScriptingCommands::script_kill) will typically run only on one at a given time.
1199    OneSucceeded,
1200    /// the client should return successfully only if there are no error replies. 
1201    /// 
1202    /// Even a single error reply should disqualify the aggregate and be returned. 
1203    /// Otherwise, the client should return one of the non-error replies. 
1204    /// As an example, consider the [`config_set`](crate::ServerCommands::config_set), 
1205    /// [`script_flush`](crate::ScriptingCommands::script_flush) and 
1206    /// [`script_load`](crate::ScriptingCommands::script_load) commands.
1207    AllSucceeded,
1208    /// the client should return the result of a logical `AND` operation on all replies 
1209    /// (only applies to integer replies, usually from commands that return either 0 or 1). 
1210    /// 
1211    /// Consider the [`script_exists`](crate::ScriptingCommands::script_exists) command as an example. 
1212    /// It returns an array of 0's and 1's that denote the existence of its given SHA1 sums in the script cache. 
1213    /// The aggregated response should be 1 only when all shards had reported that a given script SHA1 sum is in their respective cache.
1214    AggLogicalAnd,
1215    /// the client should return the result of a logical `OR` operation on all replies 
1216    /// (only applies to integer replies, usually from commands that return either 0 or 1).
1217    AggLogicalOr,
1218    /// the client should return the minimal value from the replies (only applies to numerical replies). 
1219    /// 
1220    /// The aggregate reply from a cluster-wide [`wait`](crate::GenericCommands::wait) command, for example, 
1221    /// should be the minimal value (number of synchronized replicas) from all shards
1222    AggMin,
1223    /// the client should return the maximal value from the replies (only applies to numerical replies).
1224    AggMax,
1225    /// the client should return the sum of replies (only applies to numerical replies). 
1226    /// 
1227    /// Example: [`dbsize`](crate::ServerCommands::dbsize).
1228    AggSum,
1229    /// this type of tip indicates a non-trivial form of reply policy. 
1230    /// 
1231    /// [`info`](crate::ServerCommands::info) is an excellent example of that.
1232    Special,
1233}
1234
1235impl FromStr for ResponsePolicy {
1236    type Err = Error;
1237
1238    fn from_str(str: &str) -> Result<Self> {
1239        match str {
1240            "one_succeeded" => Ok(ResponsePolicy::OneSucceeded),
1241            "all_succeeded" => Ok(ResponsePolicy::AllSucceeded),
1242            "agg_logical_and" => Ok(ResponsePolicy::AggLogicalAnd),
1243            "agg_logical_or" => Ok(ResponsePolicy::AggLogicalOr),
1244            "agg_min" => Ok(ResponsePolicy::AggMin),
1245            "agg_max" => Ok(ResponsePolicy::AggMax),
1246            "agg_sum" => Ok(ResponsePolicy::AggSum),
1247            "special" => Ok(ResponsePolicy::Special),
1248            _ => Err(Error::Client(
1249                "Cannot parse ResponsePolicy from result".to_owned(),
1250            )),
1251        }
1252    }
1253}
1254
1255/// Key specifications of a command for the [`command`](crate::ServerCommands::command) command.
1256#[derive(Debug, Clone)]
1257pub struct KeySpecification {
1258    pub begin_search: BeginSearch,
1259    pub find_keys: FindKeys,
1260    pub flags: Vec<String>,
1261    pub notes: String,
1262}
1263
1264impl FromValue for KeySpecification {
1265    fn from_value(value: Value) -> Result<Self> {
1266        let mut values: HashMap<String, Value> = value.into()?;
1267
1268        let notes: String = match values.remove("notes") {
1269            Some(notes) => notes.into()?,
1270            None => "".to_owned(),
1271        };
1272
1273        Ok(Self {
1274            begin_search: values.remove_with_result("begin_search")?.into()?,
1275            find_keys: values.remove_with_result("find_keys")?.into()?,
1276            flags: values.remove_with_result("flags")?.into()?,
1277            notes,
1278        })
1279    }
1280}
1281
1282#[derive(Debug, Clone)]
1283pub enum BeginSearch {
1284    Index(usize),
1285    Keyword { keyword: String, start_from: isize },
1286    Unknown,
1287}
1288
1289impl FromValue for BeginSearch {
1290    fn from_value(value: Value) -> Result<Self> {
1291        let mut values: HashMap<String, Value> = value.into()?;
1292
1293        let type_: String = values.remove_with_result("type")?.into()?;
1294        match type_.as_str() {
1295            "index" => {
1296                let mut spec: HashMap<String, Value> = values.remove_with_result("spec")?.into()?;
1297                Ok(BeginSearch::Index(
1298                    spec.remove_with_result("index")?.into()?,
1299                ))
1300            }
1301            "keyword" => {
1302                let mut spec: HashMap<String, Value> = values.remove_with_result("spec")?.into()?;
1303                Ok(BeginSearch::Keyword {
1304                    keyword: spec.remove_with_result("keyword")?.into()?,
1305                    start_from: spec.remove_with_result("startfrom")?.into()?,
1306                })
1307            }
1308            "unknown" => Ok(BeginSearch::Unknown),
1309            _ => Err(Error::Client(
1310                "Cannot parse BeginSearch from result".to_owned(),
1311            )),
1312        }
1313    }
1314}
1315
1316#[derive(Debug, Clone)]
1317pub enum FindKeys {
1318    Range {
1319        last_key: isize,
1320        key_step: usize,
1321        limit: usize,
1322    },
1323    KeyEnum {
1324        key_num_idx: usize,
1325        first_key: usize,
1326        key_step: usize,
1327    },
1328    Unknown,
1329}
1330
1331impl FromValue for FindKeys {
1332    fn from_value(value: Value) -> Result<Self> {
1333        let mut values: HashMap<String, Value> = value.into()?;
1334
1335        let type_: String = values.remove_with_result("type")?.into()?;
1336        match type_.as_str() {
1337            "range" => {
1338                let mut spec: HashMap<String, Value> = values.remove_with_result("spec")?.into()?;
1339                Ok(FindKeys::Range {
1340                    last_key: spec.remove_with_result("lastkey")?.into()?,
1341                    key_step: spec.remove_with_result("keystep")?.into()?,
1342                    limit: spec.remove_with_result("limit")?.into()?,
1343                })
1344            }
1345            "keynum" => {
1346                let mut spec: HashMap<String, Value> = values.remove_with_result("spec")?.into()?;
1347                Ok(FindKeys::KeyEnum {
1348                    key_num_idx: spec.remove_with_result("keynumidx")?.into()?,
1349                    first_key: spec.remove_with_result("firstkey")?.into()?,
1350                    key_step: spec.remove_with_result("keystep")?.into()?,
1351                })
1352            }
1353            "unknown" => Ok(FindKeys::Unknown),
1354            _ => Err(Error::Client(
1355                "Cannot parse BeginSearch from result".to_owned(),
1356            )),
1357        }
1358    }
1359}
1360
1361/// Command doc result for the [`command_docs`](crate::ServerCommands::command_docs) command
1362#[derive(Debug, Default)]
1363pub struct CommandDoc {
1364    /// short command description.
1365    pub summary: String,
1366    /// the Redis version that added the command (or for module commands, the module version).
1367    pub since: String,
1368    /// he functional group to which the command belongs.
1369    pub group: String,
1370    /// a short explanation about the command's time complexity.
1371    pub complexity: String,
1372    /// an array of documentation flags. Possible values are:
1373    /// - `deprecated`: the command is deprecated.
1374    /// - `syscmd`: a system command that isn't meant to be called by users.
1375    pub doc_flags: Vec<CommandDocFlag>,
1376    /// the Redis version that deprecated the command (or for module commands, the module version).
1377    pub deprecated_since: String,
1378    /// the alternative for a deprecated command.
1379    pub replaced_by: String,
1380    /// an array of historical notes describing changes to the command's behavior or arguments.
1381    pub history: Vec<HistoricalNote>,
1382    /// an array of [`command arguments`](https://redis.io/docs/reference/command-arguments/)
1383    pub arguments: Vec<CommandArgument>,
1384}
1385
1386impl FromValue for CommandDoc {
1387    fn from_value(value: Value) -> Result<Self> {
1388        let mut values: HashMap<String, Value> = value.into()?;
1389
1390        Ok(Self {
1391            summary: values.remove_with_result("summary")?.into()?,
1392            since: values.remove_with_result("since")?.into()?,
1393            group: values.remove_with_result("group")?.into()?,
1394            complexity: values.remove_with_result("complexity")?.into()?,
1395            doc_flags: values.remove_or_default("doc_flags").into()?,
1396            deprecated_since: values.remove_or_default("deprecated_since").into()?,
1397            replaced_by: values.remove_or_default("replaced_by").into()?,
1398            history: values.remove_or_default("history").into()?,
1399            arguments: values.remove_with_result("arguments")?.into()?,
1400        })
1401    }
1402}
1403
1404/// Command documenation flag
1405#[derive(Debug)]
1406pub enum CommandDocFlag {
1407    /// the command is deprecated.
1408    Deprecated,
1409    /// a system command that isn't meant to be called by users.
1410    SystemCommand,
1411}
1412
1413impl FromValue for CommandDocFlag {
1414    fn from_value(value: Value) -> Result<Self> {
1415        let f: String = value.into()?;
1416
1417        match f.as_str() {
1418            "deprecated" => Ok(CommandDocFlag::Deprecated),
1419            "syscmd" => Ok(CommandDocFlag::SystemCommand),
1420            _ => Err(Error::Client(
1421                "Cannot parse CommandDocFlag from result".to_owned(),
1422            )),
1423        }
1424    }
1425}
1426
1427#[derive(Debug)]
1428pub struct HistoricalNote {
1429    pub version: String,
1430    pub description: String,
1431}
1432
1433impl FromValue for HistoricalNote {
1434    fn from_value(value: Value) -> Result<Self> {
1435        let (version, description): (String, String) = value.into()?;
1436
1437        Ok(Self {
1438            version,
1439            description,
1440        })
1441    }
1442}
1443
1444/// [`command argument`](https://redis.io/docs/reference/command-arguments/)
1445#[derive(Debug)]
1446pub struct CommandArgument {
1447    ///  the argument's name, always present.
1448    pub name: String,
1449    /// the argument's display string, present in arguments that have a displayable representation
1450    pub display_text: String,
1451    ///  the argument's type, always present.
1452    pub type_: CommandArgumentType,
1453    /// this value is available for every argument of the `key` type.
1454    /// t is a 0-based index of the specification in the command's [`key specifications`](https://redis.io/topics/key-specs)
1455    /// that corresponds to the argument.
1456    pub key_spec_index: usize,
1457    /// a constant literal that precedes the argument (user input) itself.
1458    pub token: String,
1459    /// a short description of the argument.
1460    pub summary: String,
1461    /// the debut Redis version of the argument (or for module commands, the module version).
1462    pub since: String,
1463    /// the Redis version that deprecated the command (or for module commands, the module version).
1464    pub deprecated_since: String,
1465    /// an array of argument flags.
1466    pub flags: Vec<ArgumentFlag>,
1467    /// the argument's value.
1468    pub value: Vec<String>,
1469}
1470
1471impl FromValue for CommandArgument {
1472    fn from_value(value: Value) -> Result<Self> {
1473        let mut values: HashMap<String, Value> = value.into()?;
1474
1475        Ok(Self {
1476            name: values.remove_with_result("name")?.into()?,
1477            display_text: values.remove_or_default("display_text").into()?,
1478            type_: values.remove_with_result("type")?.into()?,
1479            key_spec_index: values.remove_or_default("key_spec_index").into()?,
1480            token: values.remove_or_default("token").into()?,
1481            summary: values.remove_or_default("summary").into()?,
1482            since: values.remove_or_default("since").into()?,
1483            deprecated_since: values.remove_or_default("deprecated_since").into()?,
1484            flags: values.remove_or_default("flags").into()?,
1485            value: match values.remove_or_default("value") {
1486                value @ Value::BulkString(_) => vec![value.into()?],
1487                value @ Value::Array(_) => value.into()?,
1488                _ => {
1489                    return Err(Error::Client(
1490                        "Cannot parse CommandArgument from result".to_owned(),
1491                    ))
1492                }
1493            },
1494        })
1495    }
1496}
1497
1498/// An argument must have one of the following types:
1499#[derive(Debug)]
1500pub enum CommandArgumentType {
1501    /// a string argument.
1502    String,
1503    /// an integer argument.
1504    Integer,
1505    /// a double-precision argument.
1506    Double,
1507    /// a string that represents the name of a key.
1508    Key,
1509    /// a string that represents a glob-like pattern.
1510    Pattern,
1511    /// an integer that represents a Unix timestamp.
1512    UnixTime,
1513    /// a token, i.e. a reserved keyword, which may or may not be provided.
1514    /// Not to be confused with free-text user input.
1515    PureToken,
1516    /// the argument is a container for nested arguments.
1517    /// This type enables choice among several nested arguments
1518    OneOf,
1519    /// the argument is a container for nested arguments.
1520    /// This type enables grouping arguments and applying a property (such as optional) to all
1521    Block,
1522}
1523
1524impl FromValue for CommandArgumentType {
1525    fn from_value(value: Value) -> Result<Self> {
1526        let t: String = value.into()?;
1527
1528        match t.as_str() {
1529            "string" => Ok(CommandArgumentType::String),
1530            "integer" => Ok(CommandArgumentType::Integer),
1531            "double" => Ok(CommandArgumentType::Double),
1532            "key" => Ok(CommandArgumentType::Key),
1533            "pattern" => Ok(CommandArgumentType::Pattern),
1534            "unix-time" => Ok(CommandArgumentType::UnixTime),
1535            "pure-token" => Ok(CommandArgumentType::PureToken),
1536            "oneof" => Ok(CommandArgumentType::OneOf),
1537            "block" => Ok(CommandArgumentType::Block),
1538            _ => Err(Error::Client(
1539                "Cannot parse CommandArgumentType from result".to_owned(),
1540            )),
1541        }
1542    }
1543}
1544
1545/// Flag for a command argument
1546#[derive(Debug)]
1547pub enum ArgumentFlag {
1548    /// denotes that the argument is optional (for example, the GET clause of the SET command).
1549    Optional,
1550    /// denotes that the argument may be repeated (such as the key argument of DEL).
1551    Multiple,
1552    ///  denotes the possible repetition of the argument with its preceding token (see SORT's GET pattern clause).
1553    MultipleToken,
1554}
1555
1556impl FromValue for ArgumentFlag {
1557    fn from_value(value: Value) -> Result<Self> {
1558        let f: String = value.into()?;
1559
1560        match f.as_str() {
1561            "optional" => Ok(ArgumentFlag::Optional),
1562            "multiple" => Ok(ArgumentFlag::Multiple),
1563            "multiple-token" => Ok(ArgumentFlag::MultipleToken),
1564            _ => Err(Error::Client(
1565                "Cannot parse ArgumentFlag from result".to_owned(),
1566            )),
1567        }
1568    }
1569}
1570
1571/// Options for the [`command_list`](crate::ServerCommands::command_list) command.
1572#[derive(Default)]
1573pub struct CommandListOptions {
1574    command_args: CommandArgs,
1575}
1576
1577impl CommandListOptions {
1578    /// get the commands that belong to the module specified by `module-name`.
1579    #[must_use]
1580    pub fn filter_by_module_name<M: Into<CommandArg>>(self, module_name: M) -> Self {
1581        Self {
1582            command_args: self
1583                .command_args
1584                .arg("FILTERBY")
1585                .arg("MODULE")
1586                .arg(module_name),
1587        }
1588    }
1589
1590    /// get the commands in the [`ACL category`](https://redis.io/docs/manual/security/acl/#command-categories) specified by `category`.
1591    #[must_use]
1592    pub fn filter_by_acl_category<C: Into<CommandArg>>(self, category: C) -> Self {
1593        Self {
1594            command_args: self
1595                .command_args
1596                .arg("FILTERBY")
1597                .arg("ACLCAT")
1598                .arg(category),
1599        }
1600    }
1601
1602    /// get the commands that match the given glob-like `pattern`.
1603    #[must_use]
1604    pub fn filter_by_pattern<P: Into<CommandArg>>(self, pattern: P) -> Self {
1605        Self {
1606            command_args: self
1607                .command_args
1608                .arg("FILTERBY")
1609                .arg("PATTERN")
1610                .arg(pattern),
1611        }
1612    }
1613}
1614
1615impl IntoArgs for CommandListOptions {
1616    fn into_args(self, args: CommandArgs) -> CommandArgs {
1617        args.arg(self.command_args)
1618    }
1619}
1620
1621/// Options for the [`failover`](crate::ServerCommands::failover) command.
1622#[derive(Default)]
1623pub struct FailOverOptions {
1624    command_args: CommandArgs,
1625}
1626
1627impl FailOverOptions {
1628    /// This option allows designating a specific replica, by its host and port, to failover to.
1629    #[must_use]
1630    pub fn to<H: Into<CommandArg>>(self, host: H, port: u16) -> Self {
1631        Self {
1632            command_args: self.command_args.arg("TO").arg(host).arg(port),
1633        }
1634    }
1635
1636    /// This option allows specifying a maximum time a master will wait in the waiting-for-sync state
1637    /// before aborting the failover attempt and rolling back.
1638    #[must_use]
1639    pub fn timeout(self, milliseconds: u64) -> Self {
1640        Self {
1641            command_args: self.command_args.arg("TIMEOUT").arg(milliseconds),
1642        }
1643    }
1644
1645    /// If both the [`timeout`](crate::FailOverOptions::timeout) and [`to`](crate::FailOverOptions::to) options are set,
1646    /// the force flag can also be used to designate that that once the timeout has elapsed,
1647    /// the master should failover to the target replica instead of rolling back.
1648    #[must_use]
1649    pub fn force(self) -> Self {
1650        Self {
1651            command_args: self.command_args.arg("FORCE"),
1652        }
1653    }
1654
1655    /// This command will abort an ongoing failover and return the master to its normal state.
1656    #[must_use]
1657    pub fn abort(self) -> Self {
1658        Self {
1659            command_args: self.command_args.arg("ABORT"),
1660        }
1661    }
1662}
1663
1664impl IntoArgs for FailOverOptions {
1665    fn into_args(self, args: CommandArgs) -> CommandArgs {
1666        args.arg(self.command_args)
1667    }
1668}
1669
1670/// Section for the [`info`](crate::ServerCommands::info) command.
1671pub enum InfoSection {
1672    Server,
1673    Clients,
1674    Memory,
1675    Persistence,
1676    Stats,
1677    Replication,
1678    Cpu,
1679    Commandstats,
1680    Latencystats,
1681    Cluster,
1682    Keyspace,
1683    Modules,
1684    Errorstats,
1685    All,
1686    Default,
1687    Everything,
1688}
1689
1690impl From<InfoSection> for CommandArg {
1691    fn from(s: InfoSection) -> Self {
1692        match s {
1693            InfoSection::Server => CommandArg::Str("server"),
1694            InfoSection::Clients => CommandArg::Str("clients"),
1695            InfoSection::Memory => CommandArg::Str("memory"),
1696            InfoSection::Persistence => CommandArg::Str("persistence"),
1697            InfoSection::Stats => CommandArg::Str("stats"),
1698            InfoSection::Replication => CommandArg::Str("replication"),
1699            InfoSection::Cpu => CommandArg::Str("cpu"),
1700            InfoSection::Commandstats => CommandArg::Str("commandstats"),
1701            InfoSection::Latencystats => CommandArg::Str("latencystats"),
1702            InfoSection::Cluster => CommandArg::Str("cluster"),
1703            InfoSection::Keyspace => CommandArg::Str("keyspace"),
1704            InfoSection::Modules => CommandArg::Str("modules"),
1705            InfoSection::Errorstats => CommandArg::Str("errorstats"),
1706            InfoSection::All => CommandArg::Str("all"),
1707            InfoSection::Default => CommandArg::Str("default"),
1708            InfoSection::Everything => CommandArg::Str("everything"),
1709        }
1710    }
1711}
1712
1713/// Latency history event for the [`latency_graph`](crate::ServerCommands::latency_graph)
1714/// & [`latency_history`](crate::ServerCommands::latency_history) commands.
1715pub enum LatencyHistoryEvent {
1716    ActiveDefragCycle,
1717    AofFsyncAlways,
1718    AofStat,
1719    AofRewriteDiffWrite,
1720    AofRename,
1721    AofWrite,
1722    AofWriteActiveChild,
1723    AofWriteAlone,
1724    AofWritePendingFsync,
1725    Command,
1726    ExpireCycle,
1727    EvictionCycle,
1728    EvictionDel,
1729    FastCommand,
1730    Fork,
1731    RdbUnlinkTempFile,
1732}
1733
1734impl From<LatencyHistoryEvent> for CommandArg {
1735    fn from(e: LatencyHistoryEvent) -> Self {
1736        match e {
1737            LatencyHistoryEvent::ActiveDefragCycle => "active-defrag-cycle".into(),
1738            LatencyHistoryEvent::AofFsyncAlways => "aof-fsync-always".into(),
1739            LatencyHistoryEvent::AofStat => "aof-stat".into(),
1740            LatencyHistoryEvent::AofRewriteDiffWrite => "aof-rewrite-diff-write".into(),
1741            LatencyHistoryEvent::AofRename => "aof-rename".into(),
1742            LatencyHistoryEvent::AofWrite => "aof-write".into(),
1743            LatencyHistoryEvent::AofWriteActiveChild => "aof-write-active-child".into(),
1744            LatencyHistoryEvent::AofWriteAlone => "aof-write-alone".into(),
1745            LatencyHistoryEvent::AofWritePendingFsync => "aof-write-pending-fsync".into(),
1746            LatencyHistoryEvent::Command => "command".into(),
1747            LatencyHistoryEvent::ExpireCycle => "expire-cycle".into(),
1748            LatencyHistoryEvent::EvictionCycle => "eviction-cycle".into(),
1749            LatencyHistoryEvent::EvictionDel => "eviction-del".into(),
1750            LatencyHistoryEvent::FastCommand => "fast-command".into(),
1751            LatencyHistoryEvent::Fork => "fork".into(),
1752            LatencyHistoryEvent::RdbUnlinkTempFile => "rdb-unlink-temp-file".into(),
1753        }
1754    }
1755}
1756
1757/// Command Histogram for the [`latency_histogram`](crate::ServerCommands::latency_histogram) commands.
1758#[derive(Default)]
1759pub struct CommandHistogram {
1760    /// The total calls for that command.
1761    pub calls: usize,
1762
1763    /// A map of time buckets:
1764    /// - Each bucket represents a latency range.
1765    /// - Each bucket covers twice the previous bucket's range.
1766    /// - Empty buckets are not printed.
1767    /// - The tracked latencies are between 1 microsecond and roughly 1 second.
1768    /// - Everything above 1 sec is considered +Inf.
1769    /// - At max there will be log2(1000000000)=30 buckets.
1770    pub histogram_usec: HashMap<u32, u32>,
1771}
1772
1773impl FromValue for CommandHistogram {
1774    fn from_value(value: Value) -> Result<Self> {
1775        let mut values: HashMap<String, Value> = value.into()?;
1776
1777        Ok(Self {
1778            calls: values.remove_with_result("calls")?.into()?,
1779            histogram_usec: values.remove_with_result("histogram_usec")?.into()?,
1780        })
1781    }
1782}
1783
1784/// Options for the [`lolwut`](crate::ServerCommands::lolwut) command
1785#[derive(Default)]
1786pub struct LolWutOptions {
1787    command_args: CommandArgs,
1788}
1789
1790impl LolWutOptions {
1791    #[must_use]
1792    pub fn version(self, version: usize) -> Self {
1793        Self {
1794            command_args: self.command_args.arg("VERSION").arg(version),
1795        }
1796    }
1797
1798    #[must_use]
1799    pub fn optional_arg<A: Into<CommandArg>>(self, arg: A) -> Self {
1800        Self {
1801            command_args: self.command_args.arg(arg),
1802        }
1803    }
1804}
1805
1806impl IntoArgs for LolWutOptions {
1807    fn into_args(self, args: CommandArgs) -> CommandArgs {
1808        args.arg(self.command_args)
1809    }
1810}
1811
1812/// Result for the [`memory_stats`](crate::ServerCommands::memory_stats) command.
1813#[derive(Debug)]
1814pub struct MemoryStats {
1815    /// Peak memory consumed by Redis in bytes
1816    /// (see [`INFO`](https://redis.io/commands/info)'s used_memory_peak)
1817    pub peak_allocated: usize,
1818
1819    /// Total number of bytes allocated by Redis using its allocator
1820    /// (see [`INFO`](https://redis.io/commands/info)'s used_memory)
1821    pub total_allocated: usize,
1822
1823    /// Initial amount of memory consumed by Redis at startup in bytes
1824    /// (see [`INFO`](https://redis.io/commands/info)'s used_memory_startup)
1825    pub startup_allocated: usize,
1826
1827    /// Size in bytes of the replication backlog
1828    /// (see [`INFO`](https://redis.io/commands/info)'s repl_backlog_active)
1829    pub replication_backlog: usize,
1830
1831    /// The total size in bytes of all replicas overheads
1832    /// (output and query buffers, connection contexts)
1833    pub clients_slaves: usize,
1834
1835    /// The total size in bytes of all clients overheads
1836    /// (output and query buffers, connection contexts)
1837    pub clients_normal: usize,
1838
1839    /// Memory usage by cluster links
1840    /// (Added in Redis 7.0, see [`INFO`](https://redis.io/commands/info)'s mem_cluster_links).
1841    pub cluster_links: usize,
1842
1843    /// The summed size in bytes of AOF related buffers.
1844    pub aof_buffer: usize,
1845
1846    /// the summed size in bytes of the overheads of the Lua scripts' caches
1847    pub lua_caches: usize,
1848
1849    /// the summed size in bytes of the overheads of the functions' caches
1850    pub functions_caches: usize,
1851
1852    /// For each of the server's databases (key = db index),
1853    /// the overheads of the main and expiry dictionaries are reported in bytes
1854    pub databases: HashMap<usize, DatabaseOverhead>,
1855
1856    /// The sum of all overheads, i.e. `startup.allocated`, `replication.backlog`,
1857    /// `clients.slaves`, `clients.normal`, `aof.buffer` and those of the internal data structures
1858    /// that are used in managing the Redis keyspace (see [`INFO`](https://redis.io/commands/info)'s used_memory_overhead)
1859    pub overhead_total: usize,
1860
1861    /// The total number of keys stored across all databases in the server
1862    pub keys_count: usize,
1863
1864    /// The ratio between net memory usage (`total.allocated` minus `startup.allocated`) and `keys.count`
1865    pub keys_bytes_per_key: usize,
1866
1867    /// The size in bytes of the dataset, i.e. `overhead.total` subtracted from `total.allocated`
1868    ///  (see [`INFO`](https://redis.io/commands/info)'s used_memory_dataset)
1869    pub dataset_bytes: usize,
1870
1871    /// The percentage of `dataset.bytes` out of the net memory usage
1872    pub dataset_percentage: f64,
1873
1874    /// The percentage of `peak.allocated` out of `total.allocated`
1875    pub peak_percentage: f64,
1876
1877    pub allocator_allocated: usize,
1878
1879    pub allocator_active: usize,
1880
1881    pub allocator_resident: usize,
1882
1883    pub allocator_fragmentation_ratio: f64,
1884
1885    pub allocator_fragmentation_bytes: usize,
1886
1887    pub allocator_rss_ratio: f64,
1888
1889    pub allocator_rss_bytes: usize,
1890
1891    pub rss_overhead_ratio: f64,
1892
1893    pub rss_overhead_bytes: usize,
1894
1895    /// See [`INFO`](https://redis.io/commands/info)'s mem_fragmentation_ratio
1896    pub fragmentation: f64,
1897
1898    pub fragmentation_bytes: usize,
1899
1900    pub additional_stats: HashMap<String, Value>,
1901}
1902
1903impl FromValue for MemoryStats {
1904    fn from_value(value: Value) -> Result<Self> {
1905        let mut values: HashMap<String, Value> = value.into()?;
1906
1907        Ok(Self {
1908            peak_allocated: values.remove_or_default("peak.allocated").into()?,
1909            total_allocated: values.remove_or_default("total.allocated").into()?,
1910            startup_allocated: values.remove_or_default("startup.allocated").into()?,
1911            replication_backlog: values.remove_or_default("replication.backlog").into()?,
1912            clients_slaves: values.remove_or_default("clients.slaves").into()?,
1913            clients_normal: values.remove_or_default("clients.normal").into()?,
1914            cluster_links: values.remove_or_default("cluster.links").into()?,
1915            aof_buffer: values.remove_or_default("aof.buffer").into()?,
1916            lua_caches: values.remove_or_default("lua.caches").into()?,
1917            functions_caches: values.remove_or_default("functions.caches").into()?,
1918            databases: (0..16)
1919                .into_iter()
1920                .filter_map(|i| {
1921                    values
1922                        .remove(&format!("db.{i}"))
1923                        .map(|v| DatabaseOverhead::from_value(v).map(|o| (i, o)))
1924                })
1925                .collect::<Result<HashMap<usize, DatabaseOverhead>>>()?,
1926            overhead_total: values.remove_or_default("overhead.total").into()?,
1927            keys_count: values.remove_or_default("keys.count").into()?,
1928            keys_bytes_per_key: values.remove_or_default("keys.bytes-per-key").into()?,
1929            dataset_bytes: values.remove_or_default("dataset.bytes").into()?,
1930            dataset_percentage: values.remove_or_default("dataset.percentage").into()?,
1931            peak_percentage: values.remove_or_default("peak.percentage").into()?,
1932            allocator_allocated: values.remove_or_default("allocator.allocated").into()?,
1933            allocator_active: values.remove_or_default("allocator.active").into()?,
1934            allocator_resident: values.remove_or_default("allocator.resident").into()?,
1935            allocator_fragmentation_ratio: values
1936                .remove_or_default("allocator-fragmentation.ratio")
1937                .into()?,
1938            allocator_fragmentation_bytes: values
1939                .remove_or_default("allocator-fragmentation.bytes")
1940                .into()?,
1941            allocator_rss_ratio: values.remove_or_default("allocator-rss.ratio").into()?,
1942            allocator_rss_bytes: values.remove_or_default("allocator-rss.bytes").into()?,
1943            rss_overhead_ratio: values.remove_or_default("rss-overhead.ratio").into()?,
1944            rss_overhead_bytes: values.remove_or_default("rss-overhead.bytes").into()?,
1945            fragmentation: values.remove_or_default("fragmentation").into()?,
1946            fragmentation_bytes: values.remove_or_default("fragmentation.bytes").into()?,
1947            additional_stats: values,
1948        })
1949    }
1950}
1951
1952#[derive(Debug)]
1953pub struct DatabaseOverhead {
1954    pub overhead_hashtable_main: usize,
1955    pub overhead_hashtable_expires: usize,
1956    pub overhead_hashtable_slot_to_keys: usize,
1957}
1958
1959impl FromValue for DatabaseOverhead {
1960    fn from_value(value: Value) -> Result<Self> {
1961        let mut values: HashMap<String, Value> = value.into()?;
1962
1963        Ok(Self {
1964            overhead_hashtable_main: values.remove_or_default("overhead.hashtable.main").into()?,
1965            overhead_hashtable_expires: values
1966                .remove_or_default("overhead.hashtable.expires")
1967                .into()?,
1968            overhead_hashtable_slot_to_keys: values
1969                .remove_or_default("overhead.hashtable.slot-to-keys")
1970                .into()?,
1971        })
1972    }
1973}
1974
1975/// Options for the [`memory_usage`](crate::ServerCommands::memory_usage) command
1976#[derive(Default)]
1977pub struct MemoryUsageOptions {
1978    command_args: CommandArgs,
1979}
1980
1981impl MemoryUsageOptions {
1982    /// For nested data types, the optional `samples` option can be provided,
1983    /// where count is the number of sampled nested values.
1984    /// By default, this option is set to 5.
1985    /// To sample the all of the nested values, use samples(0).
1986    #[must_use]
1987    pub fn samples(self, count: usize) -> Self {
1988        Self {
1989            command_args: self.command_args.arg("SAMPLES").arg(count),
1990        }
1991    }
1992}
1993
1994impl IntoArgs for MemoryUsageOptions {
1995    fn into_args(self, args: CommandArgs) -> CommandArgs {
1996        args.arg(self.command_args)
1997    }
1998}
1999
2000/// Module information result for the [`module_list`](crate::ServerCommands::module_list) command.
2001pub struct ModuleInfo {
2002    /// Name of the module
2003    pub name: String,
2004    /// Version of the module
2005    pub version: String,
2006}
2007
2008impl FromValue for ModuleInfo {
2009    fn from_value(value: Value) -> Result<Self> {
2010        let mut values: HashMap<String, Value> = value.into()?;
2011
2012        Ok(Self {
2013            name: values.remove_or_default("name").into()?,
2014            version: values.remove_or_default("ver").into()?,
2015        })
2016    }
2017}
2018
2019/// Options for the [`module_load`](crate::ServerCommands::module_load) command
2020#[derive(Default)]
2021pub struct ModuleLoadOptions {
2022    command_args: CommandArgs,
2023    args_added: bool,
2024}
2025
2026impl ModuleLoadOptions {
2027    /// You can use this optional method to provide the module with configuration directives.
2028    /// This method can be called multiple times
2029    #[must_use]
2030    pub fn config<N, V>(self, name: N, value: V) -> Self
2031    where
2032        N: Into<CommandArg>,
2033        V: Into<CommandArg>,
2034    {
2035        if self.args_added {
2036            panic!("method config should be called before method arg");
2037        }
2038
2039        Self {
2040            command_args: self.command_args.arg("CONFIG").arg(name).arg(value),
2041            args_added: false,
2042        }
2043    }
2044
2045    /// Any additional arguments are passed unmodified to the module.
2046    /// This method can be called multiple times
2047    #[must_use]
2048    pub fn arg<A: Into<CommandArg>>(self, arg: A) -> Self {
2049        if !self.args_added {
2050            Self {
2051                command_args: self.command_args.arg("ARGS").arg(arg),
2052                args_added: true,
2053            }
2054        } else {
2055            Self {
2056                command_args: self.command_args.arg(arg),
2057                args_added: false,
2058            }
2059        }
2060    }
2061}
2062
2063impl IntoArgs for ModuleLoadOptions {
2064    fn into_args(self, args: CommandArgs) -> CommandArgs {
2065        args.arg(self.command_args)
2066    }
2067}
2068
2069/// options for the [`replicaof`](crate::ServerCommands::replicaof) command.
2070pub struct ReplicaOfOptions {
2071    command_args: CommandArgs,
2072}
2073
2074impl ReplicaOfOptions {
2075    /// If a Redis server is already acting as replica,
2076    /// the command REPLICAOF NO ONE will turn off the replication,
2077    /// turning the Redis server into a MASTER.
2078    #[must_use]
2079    pub fn no_one() -> Self {
2080        Self {
2081            command_args: CommandArgs::Empty.arg("NO").arg("ONE"),
2082        }
2083    }
2084
2085    /// In the proper form REPLICAOF hostname port will make the server
2086    /// a replica of another server listening at the specified hostname and port.
2087    #[must_use]
2088    pub fn master<H: Into<CommandArg>>(host: H, port: u16) -> Self {
2089        Self {
2090            command_args: CommandArgs::Empty.arg(host).arg(port),
2091        }
2092    }
2093}
2094
2095impl IntoArgs for ReplicaOfOptions {
2096    fn into_args(self, args: CommandArgs) -> CommandArgs {
2097        args.arg(self.command_args)
2098    }
2099}
2100
2101/// Result for the [`role`](crate::ServerCommands::role) command.
2102pub enum RoleResult {
2103    Master {
2104        /// The current master replication offset,
2105        /// which is an offset that masters and replicas share to understand,
2106        /// in partial resynchronizations,
2107        /// the part of the replication stream the replicas needs to fetch to continue.
2108        master_replication_offset: usize,
2109        /// information av=bout the connected replicas
2110        replica_infos: Vec<ReplicaInfo>,
2111    },
2112    Replica {
2113        /// The IP of the master.
2114        master_ip: String,
2115        /// The port number of the master.
2116        master_port: u16,
2117        /// The state of the replication from the point of view of the master
2118        state: ReplicationState,
2119        /// The amount of data received from the replica
2120        /// so far in terms of master replication offset.
2121        amount_data_received: isize,
2122    },
2123    Sentinel {
2124        /// An array of master names monitored by this Sentinel instance.
2125        master_names: Vec<String>,
2126    },
2127}
2128
2129impl FromValue for RoleResult {
2130    fn from_value(value: Value) -> Result<Self> {
2131        let values: Vec<Value> = value.into()?;
2132        let mut iter = values.into_iter();
2133
2134        match (
2135            iter.next(),
2136            iter.next(),
2137            iter.next(),
2138            iter.next(),
2139            iter.next(),
2140            iter.next(),
2141        ) {
2142            (
2143                Some(Value::BulkString(Some(s))),
2144                Some(master_replication_offset),
2145                Some(replica_infos),
2146                None,
2147                None,
2148                None,
2149            ) if s == b"master" => Ok(Self::Master {
2150                master_replication_offset: master_replication_offset.into()?,
2151                replica_infos: replica_infos.into()?,
2152            }),
2153            (
2154                Some(Value::BulkString(Some(s))),
2155                Some(master_ip),
2156                Some(master_port),
2157                Some(state),
2158                Some(amount_data_received),
2159                None,
2160            ) if s == b"slave" => Ok(Self::Replica {
2161                master_ip: master_ip.into()?,
2162                master_port: master_port.into()?,
2163                state: state.into()?,
2164                amount_data_received: amount_data_received.into()?,
2165            }),
2166            (
2167                Some(Value::BulkString(Some(s))),
2168                Some(master_names),
2169                None,
2170                None,
2171                None,
2172                None,
2173            ) if s == b"sentinel" => Ok(Self::Sentinel {
2174                master_names: master_names.into()?,
2175            }),
2176            _ => Err(Error::Client(
2177                "Cannot parse RoleResult from result".to_string(),
2178            )),
2179        }
2180    }
2181}
2182
2183/// Represents a connected replicas to a master
2184/// 
2185/// returned by the [`role`](crate::ServerCommands::role) command.
2186pub struct ReplicaInfo {
2187    /// the replica IP
2188    pub ip: String,
2189    /// the replica port
2190    pub port: u16,
2191    /// the last acknowledged replication offset.
2192    pub last_ack_offset: usize,
2193}
2194
2195impl FromValue for ReplicaInfo {
2196    fn from_value(value: Value) -> Result<Self> {
2197        let (ip, port, last_ack_offset) = value.into()?;
2198        Ok(Self {
2199            ip,
2200            port,
2201            last_ack_offset,
2202        })
2203    }
2204}
2205
2206/// The state of the replication from the point of view of the master, 
2207/// 
2208/// returned by the [`role`](crate::ServerCommands::role) command.
2209pub enum ReplicationState {
2210    /// the instance needs to connect to its master
2211    Connect,
2212    /// the master-replica connection is in progress
2213    Connecting,
2214    /// the master and replica are trying to perform the synchronization
2215    Sync,
2216    /// the replica is online
2217    Connected,
2218}
2219
2220impl FromValue for ReplicationState {
2221    fn from_value(value: Value) -> Result<Self> {
2222        let str: String = value.into()?;
2223
2224        match str.as_str() {
2225            "connect" => Ok(Self::Connect),
2226            "connecting" => Ok(Self::Connecting),
2227            "sync" => Ok(Self::Sync),
2228            "connected" => Ok(Self::Connected),
2229            _ => Err(Error::Client(format!(
2230                "Cannot parse {str} to ReplicationState"
2231            ))),
2232        }
2233    }
2234}
2235
2236/// options for the [`shutdown`](crate::ServerCommands::shutdown) command.
2237#[derive(Default)]
2238pub struct ShutdownOptions {
2239    command_args: CommandArgs,
2240}
2241
2242impl ShutdownOptions {
2243    /// - if save is true, will force a DB saving operation even if no save points are configured
2244    /// - if save is false, will prevent a DB saving operation even if one or more save points are configured.
2245    #[must_use]
2246    pub fn save(self, save: bool) -> Self {
2247        Self {
2248            command_args: self.command_args.arg(if save { "SAVE" } else { "NOSAVE" }),
2249        }
2250    }
2251
2252    /// skips waiting for lagging replicas, i.e. it bypasses the first step in the shutdown sequence.
2253    #[must_use]
2254    pub fn now(self) -> Self {
2255        Self {
2256            command_args: self.command_args.arg("NOW"),
2257        }
2258    }
2259
2260    /// ignores any errors that would normally prevent the server from exiting.
2261    #[must_use]
2262    pub fn force(self) -> Self {
2263        Self {
2264            command_args: self.command_args.arg("FORCE"),
2265        }
2266    }
2267
2268    /// cancels an ongoing shutdown and cannot be combined with other flags.
2269    #[must_use]
2270    pub fn abort(self) -> Self {
2271        Self {
2272            command_args: self.command_args.arg("ABORT"),
2273        }
2274    }
2275}
2276
2277impl IntoArgs for ShutdownOptions {
2278    fn into_args(self, args: CommandArgs) -> CommandArgs {
2279        args.arg(self.command_args)
2280    }
2281}
2282
2283/// options for the [`slowlog_get`](crate::ServerCommands::slowlog_get) command.
2284#[derive(Default)]
2285pub struct SlowLogOptions {
2286    command_args: CommandArgs,
2287}
2288
2289impl SlowLogOptions {
2290    /// limits the number of returned entries, so the command returns at most up to `count` entries.
2291    #[must_use]
2292    pub fn count(self, count: usize) -> Self {
2293        Self {
2294            command_args: self.command_args.arg(count),
2295        }
2296    }
2297}
2298
2299impl IntoArgs for SlowLogOptions {
2300    fn into_args(self, args: CommandArgs) -> CommandArgs {
2301        args.arg(self.command_args)
2302    }
2303}
2304
2305/// Result [`slowlog_get`](crate::ServerCommands::slowlog_get) for the command.
2306pub struct SlowLogEntry {
2307    /// A unique progressive identifier for every slow log entry.
2308    pub id: i64,
2309    /// A unique progressive identifier for every slow log entry.
2310    pub unix_timestamp: u32,
2311    /// The amount of time needed for its execution, in microseconds.
2312    pub execution_time_micros: u64,
2313    /// The array composing the arguments of the command.
2314    pub command: Vec<String>,
2315    /// Client IP address and port.
2316    pub client_address: String,
2317    /// Client name if set via the CLIENT SETNAME command.
2318    pub client_name: String,
2319}
2320
2321impl FromValue for SlowLogEntry {
2322    fn from_value(value: Value) -> Result<Self> {
2323        let (id, unix_timestamp, execution_time_micros, command, client_address, client_name) =
2324            value.into()?;
2325
2326        Ok(Self {
2327            id,
2328            unix_timestamp,
2329            execution_time_micros,
2330            command,
2331            client_address,
2332            client_name,
2333        })
2334    }
2335}