use redis::{
Cmd, Direction, Expiry, FromRedisValue, LposOptions, RedisFuture, SetOptions, ToRedisArgs,
Value, from_owned_redis_value,
};
#[cfg(feature = "sync")]
use redis::RedisResult;
macro_rules! implement_glide_commands {
(
$lifetime:lifetime;
$(
$(#[$attr:meta])*
fn $name:ident $(<$($g:ident: $b:ident),+>)? ($($arg:ident: $ty:ty),*);
)*
) => {
pub trait AsyncCommands: Send + Sync + Sized {
fn glide_send_owned<'a>(&'a self, cmd: Cmd) -> RedisFuture<'a, Value>;
#[inline]
fn glide_send<'a, RV: FromRedisValue>(&'a self, cmd: Cmd) -> RedisFuture<'a, RV> {
Box::pin(async move { from_owned_redis_value(self.glide_send_owned(cmd).await?) })
}
$(
$(#[$attr])*
#[inline]
#[allow(deprecated)]
#[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
fn $name<$lifetime, $($($g: $b + Send + Sync + $lifetime,)+)? RV>(
&$lifetime self $(, $arg: $ty)*
) -> RedisFuture<$lifetime, RV>
where
RV: FromRedisValue,
{
let cmd = Cmd::$name($($arg),*);
Box::pin(async move { from_owned_redis_value(self.glide_send_owned(cmd).await?) })
}
)*
#[inline]
fn scan<'s, RV: FromRedisValue + Send + 's>(
&'s self,
) -> RedisFuture<'s, crate::commands::scan::ScanIter<'s, Self, RV>> {
Box::pin(crate::commands::scan::ScanIter::new(
self,
vec![b"SCAN".to_vec()],
Vec::new(),
))
}
#[inline]
fn scan_match<'s, P: ToRedisArgs, RV: FromRedisValue + Send + 's>(
&'s self,
pattern: P,
) -> RedisFuture<'s, crate::commands::scan::ScanIter<'s, Self, RV>> {
let mut suffix = vec![b"MATCH".to_vec()];
pattern.write_redis_args(&mut suffix);
Box::pin(crate::commands::scan::ScanIter::new(
self,
vec![b"SCAN".to_vec()],
suffix,
))
}
#[inline]
fn hscan<'s, K: ToRedisArgs, RV: FromRedisValue + Send + 's>(
&'s self,
key: K,
) -> RedisFuture<'s, crate::commands::scan::ScanIter<'s, Self, RV>> {
let mut prefix = vec![b"HSCAN".to_vec()];
key.write_redis_args(&mut prefix);
Box::pin(crate::commands::scan::ScanIter::new(self, prefix, Vec::new()))
}
#[inline]
fn hscan_match<'s, K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue + Send + 's>(
&'s self,
key: K,
pattern: P,
) -> RedisFuture<'s, crate::commands::scan::ScanIter<'s, Self, RV>> {
let mut prefix = vec![b"HSCAN".to_vec()];
key.write_redis_args(&mut prefix);
let mut suffix = vec![b"MATCH".to_vec()];
pattern.write_redis_args(&mut suffix);
Box::pin(crate::commands::scan::ScanIter::new(self, prefix, suffix))
}
#[inline]
fn sscan<'s, K: ToRedisArgs, RV: FromRedisValue + Send + 's>(
&'s self,
key: K,
) -> RedisFuture<'s, crate::commands::scan::ScanIter<'s, Self, RV>> {
let mut prefix = vec![b"SSCAN".to_vec()];
key.write_redis_args(&mut prefix);
Box::pin(crate::commands::scan::ScanIter::new(self, prefix, Vec::new()))
}
#[inline]
fn sscan_match<'s, K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue + Send + 's>(
&'s self,
key: K,
pattern: P,
) -> RedisFuture<'s, crate::commands::scan::ScanIter<'s, Self, RV>> {
let mut prefix = vec![b"SSCAN".to_vec()];
key.write_redis_args(&mut prefix);
let mut suffix = vec![b"MATCH".to_vec()];
pattern.write_redis_args(&mut suffix);
Box::pin(crate::commands::scan::ScanIter::new(self, prefix, suffix))
}
#[inline]
fn zscan<'s, K: ToRedisArgs, RV: FromRedisValue + Send + 's>(
&'s self,
key: K,
) -> RedisFuture<'s, crate::commands::scan::ScanIter<'s, Self, RV>> {
let mut prefix = vec![b"ZSCAN".to_vec()];
key.write_redis_args(&mut prefix);
Box::pin(crate::commands::scan::ScanIter::new(self, prefix, Vec::new()))
}
#[inline]
fn zscan_match<'s, K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue + Send + 's>(
&'s self,
key: K,
pattern: P,
) -> RedisFuture<'s, crate::commands::scan::ScanIter<'s, Self, RV>> {
let mut prefix = vec![b"ZSCAN".to_vec()];
key.write_redis_args(&mut prefix);
let mut suffix = vec![b"MATCH".to_vec()];
pattern.write_redis_args(&mut suffix);
Box::pin(crate::commands::scan::ScanIter::new(self, prefix, suffix))
} }
#[cfg(feature = "sync")]
pub trait Commands: Sized {
fn glide_send_owned_sync(&self, cmd: Cmd) -> RedisResult<Value>;
#[inline]
fn glide_send_sync<RV: FromRedisValue>(&self, cmd: Cmd) -> RedisResult<RV> {
from_owned_redis_value(self.glide_send_owned_sync(cmd)?)
}
$(
$(#[$attr])*
#[inline]
#[allow(deprecated)]
#[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
fn $name<$lifetime, $($($g: $b,)+)? RV: FromRedisValue>(
&self $(, $arg: $ty)*
) -> RedisResult<RV> {
from_owned_redis_value(self.glide_send_owned_sync(Cmd::$name($($arg),*))?)
}
)*
#[inline]
fn scan<RV: FromRedisValue>(
&self,
) -> RedisResult<crate::commands::scan::SyncScanIter<'_, Self, RV>> {
crate::commands::scan::SyncScanIter::new(self, vec![b"SCAN".to_vec()], Vec::new())
}
#[inline]
fn scan_match<P: ToRedisArgs, RV: FromRedisValue>(
&self,
pattern: P,
) -> RedisResult<crate::commands::scan::SyncScanIter<'_, Self, RV>> {
let mut suffix = vec![b"MATCH".to_vec()];
pattern.write_redis_args(&mut suffix);
crate::commands::scan::SyncScanIter::new(self, vec![b"SCAN".to_vec()], suffix)
}
#[inline]
fn hscan<K: ToRedisArgs, RV: FromRedisValue>(
&self,
key: K,
) -> RedisResult<crate::commands::scan::SyncScanIter<'_, Self, RV>> {
let mut prefix = vec![b"HSCAN".to_vec()];
key.write_redis_args(&mut prefix);
crate::commands::scan::SyncScanIter::new(self, prefix, Vec::new())
}
#[inline]
fn hscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>(
&self,
key: K,
pattern: P,
) -> RedisResult<crate::commands::scan::SyncScanIter<'_, Self, RV>> {
let mut prefix = vec![b"HSCAN".to_vec()];
key.write_redis_args(&mut prefix);
let mut suffix = vec![b"MATCH".to_vec()];
pattern.write_redis_args(&mut suffix);
crate::commands::scan::SyncScanIter::new(self, prefix, suffix)
}
#[inline]
fn sscan<K: ToRedisArgs, RV: FromRedisValue>(
&self,
key: K,
) -> RedisResult<crate::commands::scan::SyncScanIter<'_, Self, RV>> {
let mut prefix = vec![b"SSCAN".to_vec()];
key.write_redis_args(&mut prefix);
crate::commands::scan::SyncScanIter::new(self, prefix, Vec::new())
}
#[inline]
fn sscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>(
&self,
key: K,
pattern: P,
) -> RedisResult<crate::commands::scan::SyncScanIter<'_, Self, RV>> {
let mut prefix = vec![b"SSCAN".to_vec()];
key.write_redis_args(&mut prefix);
let mut suffix = vec![b"MATCH".to_vec()];
pattern.write_redis_args(&mut suffix);
crate::commands::scan::SyncScanIter::new(self, prefix, suffix)
}
#[inline]
fn zscan<K: ToRedisArgs, RV: FromRedisValue>(
&self,
key: K,
) -> RedisResult<crate::commands::scan::SyncScanIter<'_, Self, RV>> {
let mut prefix = vec![b"ZSCAN".to_vec()];
key.write_redis_args(&mut prefix);
crate::commands::scan::SyncScanIter::new(self, prefix, Vec::new())
}
#[inline]
fn zscan_match<K: ToRedisArgs, P: ToRedisArgs, RV: FromRedisValue>(
&self,
key: K,
pattern: P,
) -> RedisResult<crate::commands::scan::SyncScanIter<'_, Self, RV>> {
let mut prefix = vec![b"ZSCAN".to_vec()];
key.write_redis_args(&mut prefix);
let mut suffix = vec![b"MATCH".to_vec()];
pattern.write_redis_args(&mut suffix);
crate::commands::scan::SyncScanIter::new(self, prefix, suffix)
} }
};
}
implement_glide_commands! {
'a;
fn get<K: ToRedisArgs>(key: K);
fn mget<K: ToRedisArgs>(key: K);
fn set<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V);
fn set_options<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V, options: SetOptions);
#[allow(deprecated)]
#[deprecated(since = "0.2.0", note = "use mset() (same command)")]
fn set_multiple<K: ToRedisArgs, V: ToRedisArgs>(items: &'a [(K, V)]);
fn mset<K: ToRedisArgs, V: ToRedisArgs>(items: &'a [(K, V)]);
fn set_ex<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V, seconds: u64);
fn pset_ex<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V, milliseconds: u64);
fn set_nx<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V);
fn mset_nx<K: ToRedisArgs, V: ToRedisArgs>(items: &'a [(K, V)]);
fn getset<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V);
fn getrange<K: ToRedisArgs>(key: K, from: isize, to: isize);
fn setrange<K: ToRedisArgs, V: ToRedisArgs>(key: K, offset: isize, value: V);
fn get_ex<K: ToRedisArgs>(key: K, expire_at: Expiry);
fn get_del<K: ToRedisArgs>(key: K);
fn append<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V);
fn incr<K: ToRedisArgs, V: ToRedisArgs>(key: K, delta: V);
fn decr<K: ToRedisArgs, V: ToRedisArgs>(key: K, delta: V);
fn strlen<K: ToRedisArgs>(key: K);
fn keys<K: ToRedisArgs>(key: K);
fn del<K: ToRedisArgs>(key: K);
fn exists<K: ToRedisArgs>(key: K);
fn key_type<K: ToRedisArgs>(key: K);
fn expire<K: ToRedisArgs>(key: K, seconds: i64);
fn expire_at<K: ToRedisArgs>(key: K, ts: i64);
fn pexpire<K: ToRedisArgs>(key: K, ms: i64);
fn pexpire_at<K: ToRedisArgs>(key: K, ts: i64);
fn persist<K: ToRedisArgs>(key: K);
fn ttl<K: ToRedisArgs>(key: K);
fn pttl<K: ToRedisArgs>(key: K);
fn rename<K: ToRedisArgs, N: ToRedisArgs>(key: K, new_key: N);
fn rename_nx<K: ToRedisArgs, N: ToRedisArgs>(key: K, new_key: N);
fn unlink<K: ToRedisArgs>(key: K);
fn object_encoding<K: ToRedisArgs>(key: K);
fn object_idletime<K: ToRedisArgs>(key: K);
fn object_freq<K: ToRedisArgs>(key: K);
fn object_refcount<K: ToRedisArgs>(key: K);
fn blmove<S: ToRedisArgs, D: ToRedisArgs>(srckey: S, dstkey: D, src_dir: Direction, dst_dir: Direction, timeout: f64);
fn blmpop<K: ToRedisArgs>(timeout: f64, numkeys: usize, key: K, dir: Direction, count: usize);
fn blpop<K: ToRedisArgs>(key: K, timeout: f64);
fn brpop<K: ToRedisArgs>(key: K, timeout: f64);
fn brpoplpush<S: ToRedisArgs, D: ToRedisArgs>(srckey: S, dstkey: D, timeout: f64);
fn lindex<K: ToRedisArgs>(key: K, index: isize);
fn linsert_before<K: ToRedisArgs, P: ToRedisArgs, V: ToRedisArgs>(key: K, pivot: P, value: V);
fn linsert_after<K: ToRedisArgs, P: ToRedisArgs, V: ToRedisArgs>(key: K, pivot: P, value: V);
fn llen<K: ToRedisArgs>(key: K);
fn lmove<S: ToRedisArgs, D: ToRedisArgs>(srckey: S, dstkey: D, src_dir: Direction, dst_dir: Direction);
fn lmpop<K: ToRedisArgs>(numkeys: usize, key: K, dir: Direction, count: usize);
fn lpop<K: ToRedisArgs>(key: K, count: Option<core::num::NonZeroUsize>);
fn lpos<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V, options: LposOptions);
fn lpush<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V);
fn lpush_exists<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V);
fn lrange<K: ToRedisArgs>(key: K, start: isize, stop: isize);
fn lrem<K: ToRedisArgs, V: ToRedisArgs>(key: K, count: isize, value: V);
fn ltrim<K: ToRedisArgs>(key: K, start: isize, stop: isize);
fn lset<K: ToRedisArgs, V: ToRedisArgs>(key: K, index: isize, value: V);
fn rpop<K: ToRedisArgs>(key: K, count: Option<core::num::NonZeroUsize>);
fn rpoplpush<K: ToRedisArgs, D: ToRedisArgs>(key: K, dstkey: D);
fn rpush<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V);
fn rpush_exists<K: ToRedisArgs, V: ToRedisArgs>(key: K, value: V);
fn hget<K: ToRedisArgs, F: ToRedisArgs>(key: K, field: F);
fn hdel<K: ToRedisArgs, F: ToRedisArgs>(key: K, field: F);
fn hset<K: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(key: K, field: F, value: V);
fn hset_nx<K: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(key: K, field: F, value: V);
fn hset_multiple<K: ToRedisArgs, F: ToRedisArgs, V: ToRedisArgs>(key: K, items: &'a [(F, V)]);
fn hincr<K: ToRedisArgs, F: ToRedisArgs, D: ToRedisArgs>(key: K, field: F, delta: D);
fn hexists<K: ToRedisArgs, F: ToRedisArgs>(key: K, field: F);
fn hkeys<K: ToRedisArgs>(key: K);
fn hvals<K: ToRedisArgs>(key: K);
fn hgetall<K: ToRedisArgs>(key: K);
fn hlen<K: ToRedisArgs>(key: K);
fn sadd<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M);
fn scard<K: ToRedisArgs>(key: K);
fn sdiff<K: ToRedisArgs>(keys: K);
fn sdiffstore<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: K);
fn sinter<K: ToRedisArgs>(keys: K);
fn sinterstore<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: K);
fn sismember<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M);
fn smismember<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M);
fn smembers<K: ToRedisArgs>(key: K);
fn smove<S: ToRedisArgs, D: ToRedisArgs, M: ToRedisArgs>(srckey: S, dstkey: D, member: M);
fn spop<K: ToRedisArgs>(key: K);
fn srandmember<K: ToRedisArgs>(key: K);
fn srandmember_multiple<K: ToRedisArgs>(key: K, count: usize);
fn srem<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M);
fn sunion<K: ToRedisArgs>(keys: K);
fn sunionstore<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: K);
fn zadd<K: ToRedisArgs, S: ToRedisArgs, M: ToRedisArgs>(key: K, member: M, score: S);
fn zadd_multiple<K: ToRedisArgs, S: ToRedisArgs, M: ToRedisArgs>(key: K, items: &'a [(S, M)]);
fn zcard<K: ToRedisArgs>(key: K);
fn zcount<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM);
fn zincr<K: ToRedisArgs, M: ToRedisArgs, D: ToRedisArgs>(key: K, member: M, delta: D);
fn zinterstore<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: &'a [K]);
fn zinterstore_min<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: &'a [K]);
fn zinterstore_max<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: &'a [K]);
fn zinterstore_weights<D: ToRedisArgs, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]);
fn zinterstore_min_weights<D: ToRedisArgs, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]);
fn zinterstore_max_weights<D: ToRedisArgs, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]);
fn zlexcount<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM);
fn bzpopmax<K: ToRedisArgs>(key: K, timeout: f64);
fn zpopmax<K: ToRedisArgs>(key: K, count: isize);
fn bzpopmin<K: ToRedisArgs>(key: K, timeout: f64);
fn zpopmin<K: ToRedisArgs>(key: K, count: isize);
fn bzmpop_max<K: ToRedisArgs>(timeout: f64, keys: &'a [K], count: isize);
fn zmpop_max<K: ToRedisArgs>(keys: &'a [K], count: isize);
fn bzmpop_min<K: ToRedisArgs>(timeout: f64, keys: &'a [K], count: isize);
fn zmpop_min<K: ToRedisArgs>(keys: &'a [K], count: isize);
fn zrandmember<K: ToRedisArgs>(key: K, count: Option<isize>);
fn zrandmember_withscores<K: ToRedisArgs>(key: K, count: isize);
fn zrange<K: ToRedisArgs>(key: K, start: isize, stop: isize);
fn zrange_withscores<K: ToRedisArgs>(key: K, start: isize, stop: isize);
fn zrangebylex<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM);
fn zrangebylex_limit<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM, offset: isize, count: isize);
fn zrevrangebylex<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M);
fn zrevrangebylex_limit<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M, offset: isize, count: isize);
fn zrangebyscore<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM);
fn zrangebyscore_withscores<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM);
fn zrangebyscore_limit<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM, offset: isize, count: isize);
fn zrangebyscore_limit_withscores<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM, offset: isize, count: isize);
fn zrank<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M);
fn zrem<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: M);
fn zrembylex<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM);
fn zremrangebyrank<K: ToRedisArgs>(key: K, start: isize, stop: isize);
fn zrembyscore<K: ToRedisArgs, M: ToRedisArgs, MM: ToRedisArgs>(key: K, min: M, max: MM);
fn zrevrange<K: ToRedisArgs>(key: K, start: isize, stop: isize);
fn zrevrange_withscores<K: ToRedisArgs>(key: K, start: isize, stop: isize);
fn zrevrangebyscore<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M);
fn zrevrangebyscore_withscores<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M);
fn zrevrangebyscore_limit<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M, offset: isize, count: isize);
fn zrevrangebyscore_limit_withscores<K: ToRedisArgs, MM: ToRedisArgs, M: ToRedisArgs>(key: K, max: MM, min: M, offset: isize, count: isize);
fn zrevrank<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M);
fn zscore<K: ToRedisArgs, M: ToRedisArgs>(key: K, member: M);
fn zscore_multiple<K: ToRedisArgs, M: ToRedisArgs>(key: K, members: &'a [M]);
fn zunionstore<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: &'a [K]);
fn zunionstore_min<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: &'a [K]);
fn zunionstore_max<D: ToRedisArgs, K: ToRedisArgs>(dstkey: D, keys: &'a [K]);
fn zunionstore_weights<D: ToRedisArgs, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]);
fn zunionstore_min_weights<D: ToRedisArgs, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]);
fn zunionstore_max_weights<D: ToRedisArgs, K: ToRedisArgs, W: ToRedisArgs>(dstkey: D, keys: &'a [(K, W)]);
fn pfadd<K: ToRedisArgs, E: ToRedisArgs>(key: K, element: E);
fn pfcount<K: ToRedisArgs>(key: K);
fn pfmerge<D: ToRedisArgs, S: ToRedisArgs>(dstkey: D, srckeys: S);
fn setbit<K: ToRedisArgs>(key: K, offset: usize, value: bool);
fn getbit<K: ToRedisArgs>(key: K, offset: usize);
fn bitcount<K: ToRedisArgs>(key: K);
fn bitcount_range<K: ToRedisArgs>(key: K, start: usize, end: usize);
fn bit_and<D: ToRedisArgs, S: ToRedisArgs>(dstkey: D, srckeys: S);
fn bit_or<D: ToRedisArgs, S: ToRedisArgs>(dstkey: D, srckeys: S);
fn bit_xor<D: ToRedisArgs, S: ToRedisArgs>(dstkey: D, srckeys: S);
fn bit_not<D: ToRedisArgs, S: ToRedisArgs>(dstkey: D, srckey: S);
fn publish<K: ToRedisArgs, E: ToRedisArgs>(channel: K, message: E);
}