Skip to main content

ember_protocol/command/
mod.rs

1//! Command parsing from RESP3 frames.
2//!
3//! Converts a parsed [`Frame`] (expected to be an array) into a typed
4//! [`Command`] enum. This keeps protocol-level concerns separate from
5//! the engine that actually executes commands.
6
7use bytes::Bytes;
8
9/// Expiration option for the SET and GETEX commands.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum SetExpire {
12    /// EX seconds — expire after N seconds.
13    Ex(u64),
14    /// PX milliseconds — expire after N milliseconds.
15    Px(u64),
16    /// EXAT unix-seconds — expire at an absolute unix timestamp (seconds).
17    ExAt(u64),
18    /// PXAT unix-milliseconds — expire at an absolute unix timestamp (milliseconds).
19    PxAt(u64),
20}
21
22/// A parsed client command, ready for execution.
23#[derive(Debug, Clone, PartialEq)]
24pub enum Command {
25    /// PING with an optional message. Returns PONG or echoes the message.
26    Ping(Option<Bytes>),
27
28    /// ECHO `message`. Returns the message back to the client.
29    Echo(Bytes),
30
31    /// GET `key`. Returns the value or nil.
32    Get { key: String },
33
34    /// SET `key` `value` \[EX seconds | PX milliseconds\] \[NX | XX\].
35    Set {
36        key: String,
37        value: Bytes,
38        expire: Option<SetExpire>,
39        /// Only set the key if it does not already exist.
40        nx: bool,
41        /// Only set the key if it already exists.
42        xx: bool,
43    },
44
45    /// INCR `key`. Increments the integer value of a key by 1.
46    Incr { key: String },
47
48    /// DECR `key`. Decrements the integer value of a key by 1.
49    Decr { key: String },
50
51    /// INCRBY `key` `increment`. Increments the integer value of a key by the given amount.
52    IncrBy { key: String, delta: i64 },
53
54    /// DECRBY `key` `decrement`. Decrements the integer value of a key by the given amount.
55    DecrBy { key: String, delta: i64 },
56
57    /// INCRBYFLOAT `key` `increment`. Increments the float value of a key by the given amount.
58    IncrByFloat { key: String, delta: f64 },
59
60    /// APPEND `key` `value`. Appends a value to a string key. Returns the new length.
61    Append { key: String, value: Bytes },
62
63    /// STRLEN `key`. Returns the length of the string value stored at key.
64    Strlen { key: String },
65
66    /// GETRANGE `key` `start` `end`. Returns a substring of the string at key.
67    GetRange { key: String, start: i64, end: i64 },
68
69    /// SETRANGE `key` `offset` `value`. Overwrites part of the string at key.
70    SetRange {
71        key: String,
72        offset: usize,
73        value: Bytes,
74    },
75
76    /// GETBIT `key` `offset`. Returns the bit at `offset` in the string stored at key.
77    ///
78    /// Bit ordering is big-endian (Redis compatible): byte 0 holds bits 0–7, MSB first.
79    /// Returns 0 if the key does not exist.
80    GetBit { key: String, offset: u64 },
81
82    /// SETBIT `key` `offset` `value`. Sets or clears the bit at `offset`.
83    ///
84    /// The string is automatically grown to accommodate the offset.
85    /// Returns the original bit value.
86    SetBit { key: String, offset: u64, value: u8 },
87
88    /// BITCOUNT `key` \[start end \[BYTE\|BIT\]\]. Counts set bits in the string,
89    /// optionally restricted to a byte or bit range.
90    BitCount {
91        key: String,
92        range: Option<BitRange>,
93    },
94
95    /// BITPOS `key` `bit` \[start \[end \[BYTE\|BIT\]\]\]. Returns the position of the
96    /// first set (`bit=1`) or clear (`bit=0`) bit in the string.
97    BitPos {
98        key: String,
99        bit: u8,
100        range: Option<BitRange>,
101    },
102
103    /// BITOP `operation` `destkey` `key` \[key ...\]. Performs a bitwise operation
104    /// across source strings and stores the result in `destkey`.
105    BitOp {
106        op: BitOpKind,
107        dest: String,
108        keys: Vec<String>,
109    },
110
111    /// KEYS `pattern`. Returns all keys matching a glob pattern.
112    Keys { pattern: String },
113
114    /// RENAME `key` `newkey`. Renames a key.
115    Rename { key: String, newkey: String },
116
117    /// DEL `key` \[key ...\]. Returns the number of keys removed.
118    Del { keys: Vec<String> },
119
120    /// UNLINK `key` \[key ...\]. Like DEL but frees memory in the background.
121    Unlink { keys: Vec<String> },
122
123    /// EXISTS `key` \[key ...\]. Returns the number of keys that exist.
124    Exists { keys: Vec<String> },
125
126    /// MGET `key` \[key ...\]. Returns the values for all specified keys.
127    MGet { keys: Vec<String> },
128
129    /// MSET `key` `value` \[key value ...\]. Sets multiple key-value pairs.
130    MSet { pairs: Vec<(String, Bytes)> },
131
132    /// MSETNX `key` `value` \[key value ...\]. Sets multiple keys only if none already exist.
133    /// Returns 1 if all keys were set, 0 if any key already existed (atomic: all-or-nothing).
134    MSetNx { pairs: Vec<(String, Bytes)> },
135
136    /// GETSET `key` `value`. Atomically sets `key` to `value` and returns the old value.
137    /// Deprecated in Redis 6.2 but widely used; kept for compatibility.
138    GetSet { key: String, value: Bytes },
139
140    /// EXPIRE `key` `seconds`. Sets a TTL on an existing key.
141    Expire { key: String, seconds: u64 },
142
143    /// EXPIREAT `key` `timestamp`. Sets expiry at an absolute Unix timestamp (seconds).
144    Expireat { key: String, timestamp: u64 },
145
146    /// TTL `key`. Returns remaining time-to-live in seconds.
147    Ttl { key: String },
148
149    /// PERSIST `key`. Removes the expiration from a key.
150    Persist { key: String },
151
152    /// PTTL `key`. Returns remaining time-to-live in milliseconds.
153    Pttl { key: String },
154
155    /// PEXPIRE `key` `milliseconds`. Sets a TTL in milliseconds on an existing key.
156    Pexpire { key: String, milliseconds: u64 },
157
158    /// PEXPIREAT `key` `timestamp-ms`. Sets expiry at an absolute Unix timestamp (milliseconds).
159    Pexpireat { key: String, timestamp_ms: u64 },
160
161    /// DBSIZE. Returns the number of keys in the database.
162    DbSize,
163
164    /// INFO \[section\]. Returns server info. Currently only supports "keyspace".
165    Info { section: Option<String> },
166
167    /// BGSAVE. Triggers a background snapshot.
168    BgSave,
169
170    /// BGREWRITEAOF. Triggers an AOF rewrite (snapshot + truncate).
171    BgRewriteAof,
172
173    /// FLUSHDB \[ASYNC\]. Removes all keys from the database.
174    FlushDb { async_mode: bool },
175
176    /// FLUSHALL \[ASYNC\]. Removes all keys (alias for FLUSHDB — Ember is single-database).
177    FlushAll { async_mode: bool },
178
179    /// MEMORY USAGE key \[SAMPLES count\]. Returns estimated memory usage in bytes.
180    MemoryUsage { key: String },
181
182    /// CONFIG GET `pattern`. Returns matching server configuration parameters.
183    ConfigGet { pattern: String },
184
185    /// CONFIG SET `param` `value`. Sets a server configuration parameter at runtime.
186    ConfigSet { param: String, value: String },
187
188    /// CONFIG REWRITE. Writes the current config to the file loaded at startup.
189    ConfigRewrite,
190
191    /// MULTI. Starts a transaction — subsequent commands are queued until EXEC.
192    Multi,
193
194    /// EXEC. Executes all queued commands atomically, returning an array of results.
195    Exec,
196
197    /// DISCARD. Aborts a transaction, discarding all queued commands.
198    Discard,
199
200    /// SCAN `cursor` \[MATCH pattern\] \[COUNT count\]. Iterates keys.
201    Scan {
202        cursor: u64,
203        pattern: Option<String>,
204        count: Option<usize>,
205    },
206
207    /// SSCAN `key` `cursor` \[MATCH pattern\] \[COUNT count\]. Iterates set members.
208    SScan {
209        key: String,
210        cursor: u64,
211        pattern: Option<String>,
212        count: Option<usize>,
213    },
214
215    /// HSCAN `key` `cursor` \[MATCH pattern\] \[COUNT count\]. Iterates hash fields.
216    HScan {
217        key: String,
218        cursor: u64,
219        pattern: Option<String>,
220        count: Option<usize>,
221    },
222
223    /// ZSCAN `key` `cursor` \[MATCH pattern\] \[COUNT count\]. Iterates sorted set members.
224    ZScan {
225        key: String,
226        cursor: u64,
227        pattern: Option<String>,
228        count: Option<usize>,
229    },
230
231    /// LPUSH `key` `value` \[value ...\]. Pushes values to the head of a list.
232    LPush { key: String, values: Vec<Bytes> },
233
234    /// RPUSH `key` `value` \[value ...\]. Pushes values to the tail of a list.
235    RPush { key: String, values: Vec<Bytes> },
236
237    /// LPOP `key` \[count\]. Pops one or more values from the head of a list.
238    ///
239    /// Without `count`: returns a bulk string (or nil). With `count`: returns
240    /// an array of up to `count` elements (Redis 6.2+ semantics).
241    LPop { key: String, count: Option<usize> },
242
243    /// RPOP `key` \[count\]. Pops one or more values from the tail of a list.
244    ///
245    /// Without `count`: returns a bulk string (or nil). With `count`: returns
246    /// an array of up to `count` elements (Redis 6.2+ semantics).
247    RPop { key: String, count: Option<usize> },
248
249    /// LRANGE `key` `start` `stop`. Returns a range of elements by index.
250    LRange { key: String, start: i64, stop: i64 },
251
252    /// LLEN `key`. Returns the length of a list.
253    LLen { key: String },
254
255    /// BLPOP `key` \[key ...\] `timeout`. Blocks until an element is available
256    /// at the head of one of the given lists, or the timeout expires.
257    BLPop {
258        keys: Vec<String>,
259        timeout_secs: f64,
260    },
261
262    /// BRPOP `key` \[key ...\] `timeout`. Blocks until an element is available
263    /// at the tail of one of the given lists, or the timeout expires.
264    BRPop {
265        keys: Vec<String>,
266        timeout_secs: f64,
267    },
268
269    /// LINDEX `key` `index`. Returns the element at `index` in the list.
270    LIndex { key: String, index: i64 },
271
272    /// LSET `key` `index` `element`. Sets the element at `index`.
273    LSet {
274        key: String,
275        index: i64,
276        value: Bytes,
277    },
278
279    /// LTRIM `key` `start` `stop`. Trims the list to the specified range.
280    LTrim { key: String, start: i64, stop: i64 },
281
282    /// LINSERT `key` BEFORE|AFTER `pivot` `element`. Inserts before or after pivot.
283    LInsert {
284        key: String,
285        before: bool,
286        pivot: Bytes,
287        value: Bytes,
288    },
289
290    /// LREM `key` `count` `element`. Removes elements equal to value.
291    LRem {
292        key: String,
293        count: i64,
294        value: Bytes,
295    },
296
297    /// LPOS `key` `element` \[RANK rank\] \[COUNT count\] \[MAXLEN maxlen\].
298    LPos {
299        key: String,
300        element: Bytes,
301        rank: i64,
302        count: Option<usize>,
303        maxlen: usize,
304    },
305
306    /// LMOVE `source` `destination` LEFT|RIGHT LEFT|RIGHT.
307    /// Atomically pops from the source list and pushes to the destination list.
308    LMove {
309        source: String,
310        destination: String,
311        /// Pop from the left (head) if true, right (tail) if false.
312        src_left: bool,
313        /// Push to the left (head) if true, right (tail) if false.
314        dst_left: bool,
315    },
316
317    /// GETDEL `key`. Returns the value of a key and deletes it atomically.
318    GetDel { key: String },
319
320    /// GETEX `key` \[EX seconds | PX ms | EXAT timestamp | PXAT timestamp-ms | PERSIST\].
321    /// Returns the value of a key and optionally updates its expiry.
322    GetEx {
323        key: String,
324        /// `None` — no change; `Some(None)` — remove TTL (PERSIST); `Some(Some(_))` — set TTL.
325        expire: Option<Option<SetExpire>>,
326    },
327
328    /// ZDIFF `numkeys` `key` \[key ...\] \[WITHSCORES\].
329    /// Returns members in the first sorted set not present in the others.
330    ZDiff {
331        keys: Vec<String>,
332        with_scores: bool,
333    },
334
335    /// ZINTER `numkeys` `key` \[key ...\] \[WITHSCORES\].
336    /// Returns members present in all of the given sorted sets.
337    ZInter {
338        keys: Vec<String>,
339        with_scores: bool,
340    },
341
342    /// ZUNION `numkeys` `key` \[key ...\] \[WITHSCORES\].
343    /// Returns the union of all given sorted sets.
344    ZUnion {
345        keys: Vec<String>,
346        with_scores: bool,
347    },
348
349    /// ZDIFFSTORE `destkey` `numkeys` `key` \[key ...\].
350    /// Stores the diff of sorted sets in destkey. Returns the cardinality.
351    ZDiffStore { dest: String, keys: Vec<String> },
352
353    /// ZINTERSTORE `destkey` `numkeys` `key` \[key ...\].
354    /// Stores the intersection of sorted sets in destkey. Returns the cardinality.
355    ZInterStore { dest: String, keys: Vec<String> },
356
357    /// ZUNIONSTORE `destkey` `numkeys` `key` \[key ...\].
358    /// Stores the union of sorted sets in destkey. Returns the cardinality.
359    ZUnionStore { dest: String, keys: Vec<String> },
360
361    /// TYPE `key`. Returns the type of the value stored at key.
362    Type { key: String },
363
364    /// ZADD `key` \[NX|XX\] \[GT|LT\] \[CH\] `score` `member` \[score member ...\].
365    ZAdd {
366        key: String,
367        flags: ZAddFlags,
368        members: Vec<(f64, String)>,
369    },
370
371    /// ZREM `key` `member` \[member ...\]. Removes members from a sorted set.
372    ZRem { key: String, members: Vec<String> },
373
374    /// ZSCORE `key` `member`. Returns the score of a member.
375    ZScore { key: String, member: String },
376
377    /// ZRANK `key` `member`. Returns the rank of a member (0-based).
378    ZRank { key: String, member: String },
379
380    /// ZCARD `key`. Returns the cardinality (number of members) of a sorted set.
381    ZCard { key: String },
382
383    /// ZRANGE `key` `start` `stop` \[WITHSCORES\]. Returns a range by rank.
384    ZRange {
385        key: String,
386        start: i64,
387        stop: i64,
388        with_scores: bool,
389    },
390
391    /// ZREVRANGE `key` `start` `stop` \[WITHSCORES\]. Returns a range by rank in reverse order.
392    ZRevRange {
393        key: String,
394        start: i64,
395        stop: i64,
396        with_scores: bool,
397    },
398
399    /// ZREVRANK `key` `member`. Returns the reverse rank of a member.
400    ZRevRank { key: String, member: String },
401
402    /// ZCOUNT `key` `min` `max`. Counts members with scores in the given range.
403    ZCount {
404        key: String,
405        min: ScoreBound,
406        max: ScoreBound,
407    },
408
409    /// ZINCRBY `key` `increment` `member`. Increments the score of a member.
410    ZIncrBy {
411        key: String,
412        increment: f64,
413        member: String,
414    },
415
416    /// ZRANGEBYSCORE `key` `min` `max` \[WITHSCORES\] \[LIMIT offset count\].
417    ZRangeByScore {
418        key: String,
419        min: ScoreBound,
420        max: ScoreBound,
421        with_scores: bool,
422        offset: usize,
423        count: Option<usize>,
424    },
425
426    /// ZREVRANGEBYSCORE `key` `max` `min` \[WITHSCORES\] \[LIMIT offset count\].
427    ZRevRangeByScore {
428        key: String,
429        min: ScoreBound,
430        max: ScoreBound,
431        with_scores: bool,
432        offset: usize,
433        count: Option<usize>,
434    },
435
436    /// ZPOPMIN `key` \[count\]. Removes and returns the lowest scored members.
437    ZPopMin { key: String, count: usize },
438
439    /// ZPOPMAX `key` \[count\]. Removes and returns the highest scored members.
440    ZPopMax { key: String, count: usize },
441
442    /// LMPOP `numkeys` `key` \[key ...\] LEFT|RIGHT \[COUNT n\].
443    /// Tries keys left-to-right, popping up to `count` elements from the first
444    /// non-empty list. Returns `[key_name, [elem, ...]]` or nil if all empty.
445    Lmpop {
446        keys: Vec<String>,
447        left: bool,
448        count: usize,
449    },
450
451    /// ZMPOP `numkeys` `key` \[key ...\] MIN|MAX \[COUNT n\].
452    /// Tries keys left-to-right, popping up to `count` elements from the first
453    /// non-empty sorted set. Returns `[key_name, [[member, score], ...]]` or nil.
454    Zmpop {
455        keys: Vec<String>,
456        min: bool,
457        count: usize,
458    },
459
460    /// HSET `key` `field` `value` \[field value ...\]. Sets field-value pairs in a hash.
461    HSet {
462        key: String,
463        fields: Vec<(String, Bytes)>,
464    },
465
466    /// HGET `key` `field`. Gets a field's value from a hash.
467    HGet { key: String, field: String },
468
469    /// HGETALL `key`. Gets all field-value pairs from a hash.
470    HGetAll { key: String },
471
472    /// HDEL `key` `field` \[field ...\]. Deletes fields from a hash.
473    HDel { key: String, fields: Vec<String> },
474
475    /// HEXISTS `key` `field`. Checks if a field exists in a hash.
476    HExists { key: String, field: String },
477
478    /// HLEN `key`. Returns the number of fields in a hash.
479    HLen { key: String },
480
481    /// HINCRBY `key` `field` `increment`. Increments a hash field's integer value.
482    HIncrBy {
483        key: String,
484        field: String,
485        delta: i64,
486    },
487
488    /// HKEYS `key`. Returns all field names in a hash.
489    HKeys { key: String },
490
491    /// HVALS `key`. Returns all values in a hash.
492    HVals { key: String },
493
494    /// HMGET `key` `field` \[field ...\]. Gets multiple field values from a hash.
495    HMGet { key: String, fields: Vec<String> },
496
497    /// HRANDFIELD `key` \[count \[WITHVALUES\]\].
498    /// Returns random field(s) from a hash. Positive count returns distinct fields;
499    /// negative allows duplicates. With WITHVALUES, returns interleaved field-value pairs.
500    HRandField {
501        key: String,
502        count: Option<i64>,
503        with_values: bool,
504    },
505
506    /// SADD `key` `member` \[member ...\]. Adds members to a set.
507    SAdd { key: String, members: Vec<String> },
508
509    /// SREM `key` `member` \[member ...\]. Removes members from a set.
510    SRem { key: String, members: Vec<String> },
511
512    /// SMEMBERS `key`. Returns all members of a set.
513    SMembers { key: String },
514
515    /// SISMEMBER `key` `member`. Checks if a member exists in a set.
516    SIsMember { key: String, member: String },
517
518    /// SCARD `key`. Returns the cardinality (number of members) of a set.
519    SCard { key: String },
520
521    /// SUNION `key` \[key ...\]. Returns the union of all given sets.
522    SUnion { keys: Vec<String> },
523
524    /// SINTER `key` \[key ...\]. Returns the intersection of all given sets.
525    SInter { keys: Vec<String> },
526
527    /// SDIFF `key` \[key ...\]. Returns members of the first set not in the others.
528    SDiff { keys: Vec<String> },
529
530    /// SUNIONSTORE `destination` `key` \[key ...\]. Stores the union into `destination`.
531    SUnionStore { dest: String, keys: Vec<String> },
532
533    /// SINTERSTORE `destination` `key` \[key ...\]. Stores the intersection into `destination`.
534    SInterStore { dest: String, keys: Vec<String> },
535
536    /// SDIFFSTORE `destination` `key` \[key ...\]. Stores the difference into `destination`.
537    SDiffStore { dest: String, keys: Vec<String> },
538
539    /// SRANDMEMBER `key` \[count\]. Returns random members without removing them.
540    SRandMember { key: String, count: Option<i64> },
541
542    /// ZRANDMEMBER `key` \[count \[WITHSCORES\]\].
543    /// Returns random member(s) from a sorted set. Positive count returns distinct members;
544    /// negative allows duplicates. With WITHSCORES, returns interleaved member-score pairs.
545    ZRandMember {
546        key: String,
547        count: Option<i64>,
548        with_scores: bool,
549    },
550
551    /// SPOP `key` \[count\]. Removes and returns random members.
552    SPop { key: String, count: usize },
553
554    /// SMISMEMBER `key` `member` \[member ...\]. Checks multiple members at once.
555    SMisMember { key: String, members: Vec<String> },
556
557    /// SMOVE `source` `destination` `member`. Atomically moves a member from one set to another.
558    /// Returns 1 if moved, 0 if the member was not in the source set.
559    SMove {
560        source: String,
561        destination: String,
562        member: String,
563    },
564
565    /// SINTERCARD `numkeys` `key` \[key ...\] \[LIMIT count\]. Returns the cardinality of the set
566    /// intersection. If LIMIT is given and nonzero, the result is capped at that value.
567    SInterCard { keys: Vec<String>, limit: usize },
568
569    /// EXPIRETIME `key`. Returns the absolute Unix timestamp (seconds) when the key expires.
570    /// Returns -1 if the key has no expiry, -2 if the key does not exist.
571    Expiretime { key: String },
572
573    /// PEXPIRETIME `key`. Returns the absolute Unix timestamp (milliseconds) when the key expires.
574    /// Returns -1 if the key has no expiry, -2 if the key does not exist.
575    Pexpiretime { key: String },
576
577    // --- cluster commands ---
578    /// CLUSTER INFO. Returns cluster state and configuration information.
579    ClusterInfo,
580
581    /// CLUSTER NODES. Returns the list of cluster nodes.
582    ClusterNodes,
583
584    /// CLUSTER SLOTS. Returns the slot distribution across nodes.
585    ClusterSlots,
586
587    /// CLUSTER KEYSLOT `key`. Returns the hash slot for a key.
588    ClusterKeySlot { key: String },
589
590    /// CLUSTER MYID. Returns the node's ID.
591    ClusterMyId,
592
593    /// CLUSTER SETSLOT `slot` IMPORTING `node-id`. Mark slot as importing from node.
594    ClusterSetSlotImporting { slot: u16, node_id: String },
595
596    /// CLUSTER SETSLOT `slot` MIGRATING `node-id`. Mark slot as migrating to node.
597    ClusterSetSlotMigrating { slot: u16, node_id: String },
598
599    /// CLUSTER SETSLOT `slot` NODE `node-id`. Assign slot to node.
600    ClusterSetSlotNode { slot: u16, node_id: String },
601
602    /// CLUSTER SETSLOT `slot` STABLE. Clear importing/migrating state.
603    ClusterSetSlotStable { slot: u16 },
604
605    /// CLUSTER MEET `ip` `port`. Add a node to the cluster.
606    ClusterMeet { ip: String, port: u16 },
607
608    /// CLUSTER ADDSLOTS `slot` \[slot...\]. Assign slots to the local node.
609    ClusterAddSlots { slots: Vec<u16> },
610
611    /// CLUSTER ADDSLOTSRANGE `start` `end` \[start end ...\]. Assign a contiguous range of hash slots.
612    ClusterAddSlotsRange { ranges: Vec<(u16, u16)> },
613
614    /// CLUSTER DELSLOTS `slot` \[slot...\]. Remove slots from the local node.
615    ClusterDelSlots { slots: Vec<u16> },
616
617    /// CLUSTER FORGET `node-id`. Remove a node from the cluster.
618    ClusterForget { node_id: String },
619
620    /// CLUSTER REPLICATE `node-id`. Make this node a replica of another.
621    ClusterReplicate { node_id: String },
622
623    /// CLUSTER FAILOVER [FORCE|TAKEOVER]. Trigger a manual failover.
624    ClusterFailover { force: bool, takeover: bool },
625
626    /// CLUSTER COUNTKEYSINSLOT `slot`. Return the number of keys in a slot.
627    ClusterCountKeysInSlot { slot: u16 },
628
629    /// CLUSTER GETKEYSINSLOT `slot` `count`. Return keys in a slot.
630    ClusterGetKeysInSlot { slot: u16, count: u32 },
631
632    /// MIGRATE `host` `port` `key` `db` `timeout` \[COPY\] \[REPLACE\] \[KEYS key...\].
633    /// Migrate a key to another node.
634    Migrate {
635        host: String,
636        port: u16,
637        key: String,
638        db: u32,
639        timeout_ms: u64,
640        copy: bool,
641        replace: bool,
642    },
643
644    /// RESTORE `key` `ttl` `serialized-value` \[REPLACE\].
645    /// Insert a key from serialized data (used by MIGRATE).
646    Restore {
647        key: String,
648        ttl_ms: u64,
649        data: Bytes,
650        replace: bool,
651    },
652
653    /// ASKING. Signals that the next command is for a migrating slot.
654    Asking,
655
656    /// SLOWLOG GET [count]. Returns recent slow log entries.
657    SlowLogGet { count: Option<usize> },
658
659    /// SLOWLOG LEN. Returns the number of entries in the slow log.
660    SlowLogLen,
661
662    /// SLOWLOG RESET. Clears the slow log.
663    SlowLogReset,
664
665    // --- pub/sub commands ---
666    /// SUBSCRIBE `channel` \[channel ...\]. Subscribe to one or more channels.
667    Subscribe { channels: Vec<String> },
668
669    /// UNSUBSCRIBE \[channel ...\]. Unsubscribe from channels (all if none given).
670    Unsubscribe { channels: Vec<String> },
671
672    /// PSUBSCRIBE `pattern` \[pattern ...\]. Subscribe to channels matching patterns.
673    PSubscribe { patterns: Vec<String> },
674
675    /// PUNSUBSCRIBE \[pattern ...\]. Unsubscribe from patterns (all if none given).
676    PUnsubscribe { patterns: Vec<String> },
677
678    /// PUBLISH `channel` `message`. Publish a message to a channel.
679    Publish { channel: String, message: Bytes },
680
681    /// PUBSUB CHANNELS \[pattern\]. List active channels, optionally matching a glob.
682    PubSubChannels { pattern: Option<String> },
683
684    /// PUBSUB NUMSUB \[channel ...\]. Returns subscriber counts for given channels.
685    PubSubNumSub { channels: Vec<String> },
686
687    /// PUBSUB NUMPAT. Returns the number of active pattern subscriptions.
688    PubSubNumPat,
689
690    // --- vector commands ---
691    /// VADD key element f32 [f32 ...] [METRIC COSINE|L2|IP] [QUANT F32|F16|I8]
692    /// [M n] [EF n]. Adds a vector to a vector set.
693    VAdd {
694        key: String,
695        element: String,
696        vector: Vec<f32>,
697        /// 0 = cosine (default), 1 = l2, 2 = inner product
698        metric: u8,
699        /// 0 = f32 (default), 1 = f16, 2 = i8
700        quantization: u8,
701        /// HNSW connectivity parameter (default 16)
702        connectivity: u32,
703        /// HNSW construction beam width (default 64)
704        expansion_add: u32,
705    },
706
707    /// VADD_BATCH key DIM n element1 f32... element2 f32... [METRIC COSINE|L2|IP]
708    /// [QUANT F32|F16|I8] [M n] [EF n]. Adds multiple vectors in a single command.
709    VAddBatch {
710        key: String,
711        entries: Vec<(String, Vec<f32>)>,
712        dim: usize,
713        /// 0 = cosine (default), 1 = l2, 2 = inner product
714        metric: u8,
715        /// 0 = f32 (default), 1 = f16, 2 = i8
716        quantization: u8,
717        /// HNSW connectivity parameter (default 16)
718        connectivity: u32,
719        /// HNSW construction beam width (default 64)
720        expansion_add: u32,
721    },
722
723    /// VSIM key f32 [f32 ...] COUNT k [EF n] [WITHSCORES].
724    /// Searches for k nearest neighbors.
725    VSim {
726        key: String,
727        query: Vec<f32>,
728        count: usize,
729        ef_search: usize,
730        with_scores: bool,
731    },
732
733    /// VREM key element. Removes a vector from a vector set.
734    VRem { key: String, element: String },
735
736    /// VGET key element. Retrieves the stored vector for an element.
737    VGet { key: String, element: String },
738
739    /// VCARD key. Returns the number of elements in a vector set.
740    VCard { key: String },
741
742    /// VDIM key. Returns the dimensionality of a vector set.
743    VDim { key: String },
744
745    /// VINFO key. Returns metadata about a vector set.
746    VInfo { key: String },
747
748    // --- protobuf commands ---
749    /// PROTO.REGISTER `name` `descriptor_bytes`. Registers a protobuf schema
750    /// (pre-compiled FileDescriptorSet) under the given name.
751    ProtoRegister { name: String, descriptor: Bytes },
752
753    /// PROTO.SET `key` `type_name` `data` \[EX s | PX ms\] \[NX | XX\].
754    /// Stores a validated protobuf value.
755    ProtoSet {
756        key: String,
757        type_name: String,
758        data: Bytes,
759        expire: Option<SetExpire>,
760        /// Only set the key if it does not already exist.
761        nx: bool,
762        /// Only set the key if it already exists.
763        xx: bool,
764    },
765
766    /// PROTO.GET `key`. Returns \[type_name, data\] or nil.
767    ProtoGet { key: String },
768
769    /// PROTO.TYPE `key`. Returns the message type name or nil.
770    ProtoType { key: String },
771
772    /// PROTO.SCHEMAS. Lists all registered schema names.
773    ProtoSchemas,
774
775    /// PROTO.DESCRIBE `name`. Lists message types in a registered schema.
776    ProtoDescribe { name: String },
777
778    /// PROTO.GETFIELD `key` `field_path`. Reads a single field from a
779    /// protobuf value, returning it as a native RESP3 type.
780    ProtoGetField { key: String, field_path: String },
781
782    /// PROTO.SETFIELD `key` `field_path` `value`. Updates a single scalar
783    /// field in a stored protobuf value.
784    ProtoSetField {
785        key: String,
786        field_path: String,
787        value: String,
788    },
789
790    /// PROTO.DELFIELD `key` `field_path`. Clears a field to its default value.
791    ProtoDelField { key: String, field_path: String },
792
793    // --- client commands ---
794    /// CLIENT ID. Returns the unique ID of the current connection.
795    ClientId,
796
797    /// CLIENT SETNAME `name`. Sets a human-readable name for the connection.
798    ClientSetName { name: String },
799
800    /// CLIENT GETNAME. Returns the name set by CLIENT SETNAME, or nil.
801    ClientGetName,
802
803    /// CLIENT LIST. Returns info about all connected clients.
804    ClientList,
805
806    /// AUTH \[username\] password. Authenticate the connection.
807    Auth {
808        /// Username for ACL-style auth. None for legacy AUTH.
809        username: Option<String>,
810        /// The password to validate.
811        password: String,
812    },
813
814    // --- ACL commands ---
815    /// ACL WHOAMI. Returns the username of the current connection.
816    AclWhoAmI,
817
818    /// ACL LIST. Returns all users and their ACL rules.
819    AclList,
820
821    /// ACL USERS. Returns all usernames.
822    AclUsers,
823
824    /// ACL GETUSER `username`. Returns detailed info about a user.
825    AclGetUser { username: String },
826
827    /// ACL DELUSER `username` \[username ...\]. Deletes users.
828    AclDelUser { usernames: Vec<String> },
829
830    /// ACL SETUSER `username` \[rule ...\]. Creates or modifies a user.
831    AclSetUser {
832        username: String,
833        rules: Vec<String>,
834    },
835
836    /// ACL CAT \[category\]. Lists categories, or commands in a category.
837    AclCat { category: Option<String> },
838
839    /// WATCH `key` \[key ...\]. Marks keys for optimistic locking.
840    /// If any watched key is modified before EXEC, the transaction aborts.
841    Watch { keys: Vec<String> },
842
843    /// UNWATCH. Clears all watched keys for the current connection.
844    Unwatch,
845
846    /// TIME. Returns the current server time as \[unix_seconds, microseconds\].
847    Time,
848
849    /// LASTSAVE. Returns the unix timestamp of the last successful save.
850    LastSave,
851
852    /// ROLE. Returns the replication role of the server.
853    Role,
854
855    /// WAIT numreplicas timeout-ms
856    ///
857    /// Blocks until `numreplicas` replicas have acknowledged all write
858    /// commands processed before this WAIT, or until `timeout_ms`
859    /// milliseconds elapse. Returns the count of replicas that
860    /// acknowledged in time.
861    Wait { numreplicas: u64, timeout_ms: u64 },
862
863    /// OBJECT ENCODING `key`. Returns the internal encoding of the value.
864    ObjectEncoding { key: String },
865
866    /// OBJECT REFCOUNT `key`. Returns the reference count of the value (always 1).
867    ObjectRefcount { key: String },
868
869    /// COPY `source` `destination` \[DB db\] \[REPLACE\]. Copies the value at source to destination.
870    Copy {
871        source: String,
872        destination: String,
873        replace: bool,
874    },
875
876    /// QUIT. Requests the server to close the connection.
877    Quit,
878
879    /// MONITOR. Streams all commands processed by the server.
880    Monitor,
881
882    /// RANDOMKEY. Returns a random key from the database, or nil if empty.
883    RandomKey,
884
885    /// TOUCH `key` \[key ...\]. Updates last access time, returns count of existing keys.
886    Touch { keys: Vec<String> },
887
888    /// SORT `key` \[ASC|DESC\] \[ALPHA\] \[LIMIT offset count\] \[STORE dest\].
889    /// Sorts a list, set, or sorted set and returns the sorted elements.
890    Sort {
891        key: String,
892        desc: bool,
893        alpha: bool,
894        limit: Option<(i64, i64)>,
895        store: Option<String>,
896    },
897
898    /// COMMAND \[COUNT | INFO name \[name ...\] | DOCS name \[name ...\]\]
899    ///
900    /// Returns metadata about supported commands. Used by client libraries
901    /// for capability discovery on connect.
902    Command {
903        /// Optional subcommand: COUNT, INFO, DOCS, LIST. None = list all commands.
904        subcommand: Option<String>,
905        /// Arguments to the subcommand (command names for INFO/DOCS).
906        args: Vec<String>,
907    },
908
909    /// HINCRBYFLOAT `key` `field` `increment`. Increments the float value of a hash field.
910    ///
911    /// If the field doesn't exist it is set to 0 before the operation.
912    /// Returns the new value as a bulk string.
913    HIncrByFloat {
914        key: String,
915        field: String,
916        delta: f64,
917    },
918
919    /// A command we don't recognize (yet).
920    Unknown(String),
921}
922
923/// Unit for BITCOUNT and BITPOS range arguments.
924#[derive(Debug, Clone, Copy, PartialEq, Eq)]
925pub enum BitRangeUnit {
926    /// Byte-granularity range (default for Redis).
927    Byte,
928    /// Bit-granularity range (Redis 7.0+).
929    Bit,
930}
931
932/// Range argument for BITCOUNT and BITPOS.
933#[derive(Debug, Clone, Copy, PartialEq, Eq)]
934pub struct BitRange {
935    pub start: i64,
936    pub end: i64,
937    pub unit: BitRangeUnit,
938}
939
940/// Operation kind for BITOP.
941#[derive(Debug, Clone, Copy, PartialEq, Eq)]
942pub enum BitOpKind {
943    And,
944    Or,
945    Xor,
946    Not,
947}
948
949/// A score bound for sorted set range queries (ZRANGEBYSCORE, ZCOUNT, etc.).
950///
951/// Redis supports `-inf`, `+inf`, inclusive (default), and exclusive
952/// bounds (prefixed with `(`).
953#[derive(Debug, Clone, Copy, PartialEq)]
954pub enum ScoreBound {
955    /// Negative infinity — matches all scores from the bottom.
956    NegInf,
957    /// Positive infinity — matches all scores to the top.
958    PosInf,
959    /// Inclusive bound: score >= value (for min) or score <= value (for max).
960    Inclusive(f64),
961    /// Exclusive bound: score > value (for min) or score < value (for max).
962    Exclusive(f64),
963}
964
965/// Flags for the ZADD command.
966#[derive(Debug, Clone, Default, PartialEq)]
967pub struct ZAddFlags {
968    /// Only add new members, don't update existing scores.
969    pub nx: bool,
970    /// Only update existing members, don't add new ones.
971    pub xx: bool,
972    /// Only update when new score > current score.
973    pub gt: bool,
974    /// Only update when new score < current score.
975    pub lt: bool,
976    /// Return count of changed members (added + updated) instead of just added.
977    pub ch: bool,
978}
979
980impl Eq for ZAddFlags {}
981
982mod attributes;
983mod parse;
984#[cfg(test)]
985mod tests;