#[path = "ops_surface.rs"]
pub mod surface;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum NotifyKind {
String,
Hash,
List,
Set,
Zset,
Stream,
Generic,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct OpSpec {
pub name: &'static str,
pub write: bool,
pub growing: bool,
pub notify: Option<NotifyKind>,
pub wake_idx: Option<u8>,
pub surfaces: u16,
}
const fn op(
name: &'static str,
write: bool,
growing: bool,
notify: Option<NotifyKind>,
wake_idx: Option<u8>,
surfaces: u16,
) -> OpSpec {
OpSpec { name, write, growing, notify, wake_idx, surfaces }
}
use NotifyKind as N;
use surface::{ATOMIC, ESTORE, PIPE, REPLAY, REWRITE, SERVER};
const RD: bool = false; const WR: bool = true; const GROW: bool = true;
const NG: bool = false;
pub const CONSUMER_SEEN: &str = "XINTERNAL.CONSUMERSEEN";
pub const CATALOG: &str = "XINTERNAL.CATALOG";
pub const PENDING: &str = "XINTERNAL.PENDING";
#[rustfmt::skip]
pub const OP_TABLE: &[OpSpec] = &[
op("APPEND", WR, GROW, Some(N::String), None, SERVER | ESTORE | REPLAY),
op("DECR", WR, GROW, Some(N::String), None, SERVER | ESTORE | REPLAY),
op("DECRBY", WR, GROW, Some(N::String), None, SERVER | ESTORE | REPLAY),
op("GET", RD, NG, None, None, SERVER | ESTORE | ATOMIC),
op("GETDEL", WR, NG, Some(N::String), None, SERVER | ESTORE | REPLAY),
op("GETEX", WR, NG, None, None, SERVER | ESTORE | REPLAY),
op("GETRANGE", RD, NG, None, None, SERVER | ESTORE),
op("GETSET", WR, GROW, Some(N::String), None, SERVER | ESTORE | REPLAY),
op("INCR", WR, GROW, Some(N::String), None, SERVER | ESTORE | PIPE | ATOMIC | REPLAY),
op("INCRBY", WR, GROW, Some(N::String), None, SERVER | ESTORE | PIPE | ATOMIC | REPLAY),
op("INCRBYFLOAT", WR, GROW, Some(N::String), None, SERVER | ESTORE | REPLAY),
op("MGET", RD, NG, None, None, SERVER | ESTORE),
op("MSET", WR, GROW, None, None, SERVER | ESTORE | REPLAY),
op("PSETEX", WR, GROW, Some(N::String), None, SERVER | REPLAY),
op("SET", WR, GROW, Some(N::String), None, SERVER | ESTORE | PIPE | ATOMIC | REPLAY | REWRITE),
op("SETEX", WR, GROW, Some(N::String), None, SERVER | REPLAY),
op("SETNX", WR, GROW, Some(N::String), None, SERVER | ESTORE | REPLAY),
op("SETRANGE", WR, GROW, Some(N::String), None, SERVER | ESTORE | REPLAY),
op("STRLEN", RD, NG, None, None, SERVER | ESTORE),
op("BITCOUNT", RD, NG, None, None, SERVER | ESTORE),
op("BITOP", WR, GROW, None, None, SERVER | ESTORE),
op("BITPOS", RD, NG, None, None, SERVER | ESTORE),
op("GETBIT", RD, NG, None, None, SERVER | ESTORE),
op("SETBIT", WR, GROW, Some(N::String), None, SERVER | ESTORE | REPLAY),
op("HDEL", WR, NG, Some(N::Hash), None, SERVER | ESTORE | PIPE | ATOMIC | REPLAY),
op("HEXISTS", RD, NG, None, None, SERVER | ESTORE | ATOMIC),
op("HGET", RD, NG, None, None, SERVER | ESTORE | ATOMIC),
op("HGETALL", RD, NG, None, None, SERVER | ESTORE | ATOMIC),
op("HINCRBY", WR, GROW, Some(N::Hash), None, SERVER | ESTORE | PIPE | ATOMIC | REPLAY),
op("HINCRBYFLOAT", WR, GROW, Some(N::Hash), None, SERVER | ESTORE | REPLAY),
op("HRANDFIELD", RD, NG, None, None, SERVER | ESTORE),
op("HKEYS", RD, NG, None, None, SERVER | ESTORE),
op("HLEN", RD, NG, None, None, SERVER | ESTORE),
op("HMGET", RD, NG, None, None, SERVER | ESTORE | ATOMIC),
op("HMSET", WR, GROW, Some(N::Hash), None, SERVER | REPLAY),
op("HSCAN", RD, NG, None, None, SERVER | ESTORE),
op("HSET", WR, GROW, Some(N::Hash), None, SERVER | ESTORE | PIPE | ATOMIC | REPLAY | REWRITE),
op("HEXPIRE", WR, NG, Some(N::Hash), None, SERVER | ESTORE | REPLAY),
op("HPEXPIRE", WR, NG, Some(N::Hash), None, SERVER | ESTORE | REPLAY),
op("HPEXPIREAT", WR, NG, Some(N::Hash), None, SERVER | ESTORE | REPLAY | REWRITE),
op("HTTL", RD, NG, None, None, SERVER | ESTORE),
op("HPTTL", RD, NG, None, None, SERVER | ESTORE),
op("HPERSIST", WR, NG, Some(N::Hash), None, SERVER | ESTORE | REPLAY),
op("HSETNX", WR, GROW, Some(N::Hash), None, SERVER | ESTORE | REPLAY),
op("HVALS", RD, NG, None, None, SERVER | ESTORE),
op("BLPOP", WR, NG, None, None, SERVER | REPLAY),
op("BRPOP", WR, NG, None, None, SERVER | REPLAY),
op("BRPOPLPUSH", WR, GROW, None, None, SERVER | REPLAY),
op("LINDEX", RD, NG, None, None, SERVER | ESTORE),
op("LINSERT", WR, GROW, Some(N::List), None, SERVER | ESTORE | REPLAY),
op("LLEN", RD, NG, None, None, SERVER | ESTORE | ATOMIC),
op("LMOVE", WR, GROW, Some(N::List), None, SERVER | REPLAY),
op("LPOP", WR, NG, Some(N::List), None, SERVER | ESTORE | REPLAY),
op("LPOS", RD, NG, None, None, SERVER),
op("LPUSH", WR, GROW, Some(N::List), Some(1), SERVER | ESTORE | PIPE | ATOMIC | REPLAY),
op("LRANGE", RD, NG, None, None, SERVER | ESTORE | ATOMIC),
op("LREM", WR, NG, Some(N::List), None, SERVER | ESTORE | REPLAY),
op("LSET", WR, GROW, Some(N::List), None, SERVER | ESTORE | REPLAY),
op("LTRIM", WR, NG, Some(N::List), None, SERVER | ESTORE | REPLAY),
op("RPOP", WR, NG, Some(N::List), None, SERVER | ESTORE | REPLAY),
op("RPOPLPUSH", WR, GROW, Some(N::List), None, SERVER | REPLAY),
op("RPUSH", WR, GROW, Some(N::List), Some(1), SERVER | ESTORE | PIPE | ATOMIC | REPLAY | REWRITE),
op("SADD", WR, GROW, Some(N::Set), None, SERVER | ESTORE | PIPE | ATOMIC | REPLAY | REWRITE),
op("SCARD", RD, NG, None, None, SERVER | ESTORE | ATOMIC),
op("SDIFF", RD, NG, None, None, SERVER | ESTORE),
op("SINTER", RD, NG, None, None, SERVER | ESTORE),
op("SINTERSTORE", WR, GROW, Some(N::Set), None, SERVER | ESTORE),
op("SISMEMBER", RD, NG, None, None, SERVER | ESTORE | ATOMIC),
op("SMEMBERS", RD, NG, None, None, SERVER | ESTORE | ATOMIC),
op("SPOP", WR, NG, Some(N::Set), None, SERVER | ESTORE | REPLAY),
op("SRANDMEMBER", RD, NG, None, None, SERVER | ESTORE),
op("SREM", WR, NG, Some(N::Set), None, SERVER | ESTORE | PIPE | ATOMIC | REPLAY),
op("SSCAN", RD, NG, None, None, SERVER),
op("SUNION", RD, NG, None, None, SERVER | ESTORE),
op("SUNIONSTORE", WR, GROW, Some(N::Set), None, SERVER | ESTORE),
op("SDIFFSTORE", WR, GROW, Some(N::Set), None, SERVER | ESTORE),
op("BZPOPMIN", WR, NG, None, None, SERVER | REPLAY),
op("ZADD", WR, GROW, Some(N::Zset), Some(1), SERVER | ESTORE | PIPE | ATOMIC | REPLAY | REWRITE),
op("ZCARD", RD, NG, None, None, SERVER | ESTORE | ATOMIC),
op("ZCOUNT", RD, NG, None, None, SERVER | ESTORE),
op("ZINCRBY", WR, GROW, Some(N::Zset), Some(1), SERVER | ESTORE | PIPE | ATOMIC | REPLAY),
op("ZINTERSTORE", WR, GROW, Some(N::Zset), None, SERVER | ESTORE),
op("ZPOPMIN.BELOW", WR, NG, Some(N::Zset), None, SERVER | ESTORE | REPLAY),
op("ZUNIONSTORE", WR, GROW, Some(N::Zset), None, SERVER | ESTORE),
op("ZDIFFSTORE", WR, GROW, Some(N::Zset), None, SERVER | ESTORE),
op("ZINTERCARD", RD, NG, None, None, SERVER | ESTORE),
op("ZPOPMIN", WR, NG, Some(N::Zset), None, SERVER | ESTORE | REPLAY),
op("ZRANGE", RD, NG, None, None, SERVER | ESTORE),
op("ZRANGEBYSCORE", RD, NG, None, None, SERVER | ESTORE | ATOMIC),
op("ZRANK", RD, NG, None, None, SERVER | ESTORE),
op("ZREM", WR, NG, Some(N::Zset), None, SERVER | ESTORE | PIPE | ATOMIC | REPLAY),
op("ZREMRANGEBYRANK", WR, NG, Some(N::Zset), None, SERVER | ESTORE | REPLAY),
op("ZREMRANGEBYSCORE", WR, NG, Some(N::Zset), None, SERVER | ESTORE | REPLAY),
op("ZREVRANGE", RD, NG, None, None, SERVER | ESTORE),
op("ZREVRANGEBYSCORE", RD, NG, None, None, SERVER | ESTORE),
op("ZSCAN", RD, NG, None, None, SERVER | ESTORE),
op("ZSCORE", RD, NG, None, None, SERVER | ESTORE | ATOMIC),
op("XACK", WR, NG, Some(N::Stream), None, SERVER | REPLAY),
op("XADD", WR, GROW, Some(N::Stream), Some(1), SERVER | REPLAY | REWRITE),
op("XAUTOCLAIM", WR, GROW, Some(N::Stream), None, SERVER | REPLAY),
op("XCLAIM", WR, GROW, Some(N::Stream), None, SERVER | REPLAY | REWRITE),
op("XDEL", WR, NG, Some(N::Stream), None, SERVER | REPLAY),
op("XGROUP", WR, GROW, Some(N::Stream), None, SERVER | REPLAY | REWRITE),
op("XINFO", RD, NG, None, None, SERVER),
op("XLEN", RD, NG, None, None, SERVER),
op("XPENDING", RD, NG, None, None, SERVER),
op("XRANGE", RD, NG, None, None, SERVER),
op("XREAD", RD, NG, None, None, SERVER),
op("XREADGROUP", WR, GROW, Some(N::Stream), None, SERVER | REPLAY),
op("XREVRANGE", RD, NG, None, None, SERVER),
op("XSETID", WR, NG, Some(N::Stream), None, SERVER | REPLAY | REWRITE),
op("XTRIM", WR, NG, Some(N::Stream), None, SERVER | REPLAY),
op(CONSUMER_SEEN, WR, NG, None, None, REPLAY),
op(CATALOG, WR, NG, None, None, REPLAY),
op(PENDING, WR, NG, None, None, REPLAY),
op("GEOADD", WR, GROW, Some(N::Zset), None, SERVER | REPLAY),
op("GEODIST", RD, NG, None, None, SERVER),
op("GEOHASH", RD, NG, None, None, SERVER),
op("GEOPOS", RD, NG, None, None, SERVER),
op("GEORADIUS", WR, GROW, None, None, SERVER | REPLAY),
op("GEORADIUSBYMEMBER", WR, GROW, None, None, SERVER | REPLAY),
op("GEOSEARCH", RD, NG, None, None, SERVER),
op("GEOSEARCHSTORE", WR, GROW, None, None, SERVER | REPLAY),
op("COPY", WR, GROW, None, None, SERVER | ESTORE),
op("DBSIZE", RD, NG, None, None, SERVER | ESTORE),
op("IDX.CREATE", WR, NG, None, None, SERVER | ESTORE),
op("IDX.DROP", WR, NG, None, None, SERVER | ESTORE),
op("IDX.LIST", RD, NG, None, None, SERVER | ESTORE),
op("IDX.ADVISE", RD, NG, None, None, SERVER | ESTORE),
op("IDX.DESCRIBE", RD, NG, None, None, SERVER | ESTORE),
op("IDX.QUERY", RD, NG, None, None, SERVER | ESTORE),
op("IDX.COUNT", RD, NG, None, None, SERVER | ESTORE),
op("IDX.VERIFY", RD, NG, None, None, SERVER),
op("IDX.EXPLAIN", RD, NG, None, None, SERVER),
op("IDX.REBUILD", WR, NG, None, None, SERVER),
op("PREFIX.DIGEST", RD, NG, None, None, SERVER | ESTORE),
op("TABLE.DECLARE", WR, NG, None, None, SERVER | ESTORE),
op("TABLE.ENSURE", WR, NG, None, None, SERVER | ESTORE),
op("TABLE.REPLACE", WR, NG, None, None, SERVER | ESTORE),
op("TABLE.DROP", WR, NG, None, None, SERVER | ESTORE),
op("TABLE.LIST", RD, NG, None, None, SERVER | ESTORE),
op("TABLE.VERIFY", RD, NG, None, None, SERVER | ESTORE),
op("TABLE.DESCRIBE", RD, NG, None, None, SERVER | ESTORE),
op("VIEW.CREATE", WR, NG, None, None, SERVER | ESTORE),
op("VIEW.DROP", WR, NG, None, None, SERVER | ESTORE),
op("VIEW.LIST", RD, NG, None, None, SERVER | ESTORE),
op("VIEW.QUERY", RD, NG, None, None, SERVER | ESTORE),
op("VIEW.DESCRIBE", RD, NG, None, None, SERVER | ESTORE),
op("VIEW.VERIFY", RD, NG, None, None, SERVER),
op("VIEW.REBUILD", WR, NG, None, None, SERVER),
op("VIEW.EXPLAIN", RD, NG, None, None, SERVER),
op("FEED.READ", RD, NG, None, None, SERVER | ESTORE),
op("FEED.TAIL", RD, NG, None, None, SERVER | ESTORE),
op("FEED.SHARDS", RD, NG, None, None, SERVER | ESTORE),
op("PREFIX.STATS", RD, NG, None, None, SERVER | ESTORE),
op("DEL", WR, NG, Some(N::Generic), None, SERVER | ESTORE | PIPE | ATOMIC | REPLAY),
op("EXISTS", RD, NG, None, None, SERVER | ESTORE | ATOMIC),
op("EXPIRE", WR, NG, Some(N::Generic), None, SERVER | ESTORE | REPLAY),
op("EXPIREAT", WR, NG, None, None, SERVER | ESTORE | REPLAY),
op("FLUSHALL", WR, NG, None, None, SERVER | ESTORE | REPLAY),
op("FLUSHDB", WR, NG, None, None, SERVER | REPLAY),
op("KEYS", RD, NG, None, None, SERVER | ESTORE),
op("PERSIST", WR, NG, Some(N::Generic), None, SERVER | ESTORE | REPLAY),
op("PEXPIRE", WR, NG, Some(N::Generic), None, SERVER | ESTORE | REPLAY),
op("PEXPIREAT", WR, NG, None, None, SERVER | ESTORE | REPLAY | REWRITE),
op("PTTL", RD, NG, None, None, SERVER),
op("RANDOMKEY", RD, NG, None, None, SERVER | ESTORE),
op("RENAME", WR, NG, None, None, SERVER | ESTORE | REPLAY),
op("RENAMENX", WR, NG, None, None, SERVER | ESTORE | REPLAY),
op("SCAN", RD, NG, None, None, SERVER | ESTORE),
op("TIME", RD, NG, None, None, SERVER | ESTORE),
op("TOUCH", RD, NG, None, None, SERVER | ESTORE),
op("TTL", RD, NG, None, None, SERVER | ESTORE),
op("TYPE", RD, NG, None, None, SERVER | ESTORE),
op("UNLINK", WR, NG, Some(N::Generic), None, SERVER | ESTORE | REPLAY),
];
pub const KNOWN_GAPS: &[(&str, u16, &str)] = &[
(
"SSCAN",
surface::ESTORE,
"manifest sweep 2026-07-03: scan/hscan/zscan facades exist, sscan missing",
),
];
pub fn ops_with(flag: u16) -> Vec<&'static str> {
OP_TABLE.iter().filter(|o| o.surfaces & flag != 0).map(|o| o.name).collect()
}
pub fn spec(name: &str) -> Option<&'static OpSpec> {
OP_TABLE.iter().find(|o| o.name == name)
}
#[cfg(test)]
#[path = "ops_table_tests.rs"]
mod tests;