macro_rules! if_redisresult {
((RedisResult<$type:ty>), strip_redisresult) => {
($type)
};
((RedisResult<$unused:ty>), try, $target:tt) => {
(($target)?)
};
((RedisResult<$unused:ty>), wrap_ok, $target:tt) => {
(Ok($target))
};
((RedisResult<$unused:ty>), wrap_redisresult, $target:tt) => {
(RedisResult<$target>)
};
($other_type:ty, $i:ident, $target:tt) => {
$target
};
($other_type:ty, $i:ident) => {
$other_type
};
}
macro_rules! convert_ret {
($ret_conv_fn:ident, { $($body:tt)* }) => {
Ok($ret_conv_fn({ $($body)* }?)?)
};
(, { $($body:tt)* }) => {
$($body)*
};
}
#[cfg(feature = "aio")]
macro_rules! implement_command_async {
(
$(#[$attr:meta])+
fn $name:ident<$($tyargs:ident : $ty:ident),*>(
$($argname:ident: $argty:ty),*) -> Generic $(via $ret_conv_fn:ident)?
) => {
implement_command_async!(
$(#[$attr])+
fn $name<$($tyargs : $ty,)* RV: FromRedisValue>(
$($argname: $argty),*) -> RV $(via $ret_conv_fn)?
);
};
(
$(#[$attr:meta])+
fn $name:ident<$($tyargs:ident : $ty:ident),*>(
$($argname:ident: $argty:ty),*) -> (RedisResult<Generic>) $(via $ret_conv_fn:ident)?
) => {
implement_command_async!(
$(#[$attr])+
fn $name<$($tyargs : $ty,)* RV: FromRedisValue>(
$($argname: $argty),*) -> (RedisResult<RV>) $(via $ret_conv_fn)?
);
};
(
$(#[$attr:meta])+
fn $name:ident<$($tyargs:ident : $ty:ident),*>(
$($argname:ident: $argty:ty),*) -> $rettype:tt $(via $ret_conv_fn:ident)?
) => {
$(#[$attr])*
#[inline]
#[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
fn $name<$($tyargs: $ty + Send + Sync,)*>(
&mut self
$(, $argname: $argty)*
) -> impl Future<Output = RedisResult<if_redisresult!($rettype, strip_redisresult)>> + Send
{
async move {
convert_ret!($($ret_conv_fn)?, {
if_redisresult!($rettype, try, (Cmd::$name($($argname),*)))
.query_async(self)
.await
})
}
}
};
}
macro_rules! implement_command_sync {
(
$(#[$attr:meta])+
fn $name:ident<$($tyargs:ident : $ty:ident),*>(
$($argname:ident: $argty:ty),*) -> Generic $(via $ret_conv_fn:ident)?
) => {
implement_command_sync!(
$(#[$attr])+
fn $name<$($tyargs : $ty,)* RV: FromRedisValue>(
$($argname: $argty),*) -> RV $(via $ret_conv_fn)?
);
};
(
$(#[$attr:meta])+
fn $name:ident<$($tyargs:ident : $ty:ident),*>(
$($argname:ident: $argty:ty),*) -> (RedisResult<Generic>) $(via $ret_conv_fn:ident)?
) => {
implement_command_sync!(
$(#[$attr])+
fn $name<$($tyargs : $ty,)* RV: FromRedisValue>(
$($argname: $argty),*) -> (RedisResult<RV>) $(via $ret_conv_fn)?
);
};
(
$(#[$attr:meta])+
fn $name:ident<$($tyargs:ident : $ty:ident),*>(
$($argname:ident: $argty:ty),*) -> $rettype:tt $(via $ret_conv_fn:ident)?
) => {
$(#[$attr])*
#[inline]
#[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
fn $name<$($tyargs: $ty + Send + Sync,)*>(
&mut self
$(, $argname: $argty)*
) -> RedisResult<if_redisresult!($rettype, strip_redisresult)>
{
convert_ret!($($ret_conv_fn)?, {
if_redisresult!($rettype, try, { (Cmd::$name($($argname),*)) })
.query(self)
})
}
};
}
macro_rules! ready_cmd {
($name:expr $(, $arg:expr)*) => {{
let name = $name;
let args_count = 1usize;
let args_size = name.len();
$(
let (next_args_count, next_args_size) = $arg.num_of_args_and_size();
let args_count = args_count + next_args_count;
let args_size = args_size + next_args_size;
)*
let mut cmd = Cmd::with_capacity(args_count, args_size);
cmd.arg(name);
$(cmd.arg($arg);)*
cmd
}};
}
macro_rules! write_pipeline_command {
($self:expr, { ready_cmd!($name:expr $(, $arg:expr)*).take() }) => {{
let name = $name;
let args_count = 1usize;
let args_size = name.len();
$(
let (next_args_count, next_args_size) = $arg.num_of_args_and_size();
let args_count = args_count + next_args_count;
let args_size = args_size + next_args_size;
)*
$self.reserve_for_args(args_count)
.reserve_for_data(args_size);
$self.start_command();
$crate::types::RedisWrite::write_arg($self, name.as_bytes());
$($self.arg($arg);)*
$self
}};
($self:expr, $cmd:expr) => {{
$self.add_command($cmd)
}};
}
macro_rules! implement_iterators {
($lifetime: lifetime, $iter:expr, $ret:ty) => {
#[inline]
fn scan<$lifetime, RV: FromRedisValue + $lifetime>(&$lifetime mut self) -> $ret {
let mut c = cmd("SCAN");
c.cursor_arg(0);
$iter(c, self)
}
#[inline]
fn scan_options<$lifetime, RV: FromRedisValue + $lifetime>(&$lifetime mut self, opts: ScanOptions) -> $ret {
let mut c = cmd("SCAN");
c.cursor_arg(0).arg(opts);
$iter(c, self)
}
#[inline]
fn scan_match<$lifetime, P: ToSingleRedisArg, RV: FromRedisValue + $lifetime>(&$lifetime mut self, pattern: P) -> $ret {
let mut c = cmd("SCAN");
c.cursor_arg(0).arg("MATCH").arg(pattern);
$iter(c, self)
}
#[inline]
fn hscan<$lifetime, K: ToSingleRedisArg, RV: FromRedisValue + $lifetime>(&$lifetime mut self, key: K) -> $ret {
let mut c = cmd("HSCAN");
c.arg(key).cursor_arg(0);
$iter(c, self)
}
#[inline]
fn hscan_match<$lifetime, K: ToSingleRedisArg, P: ToSingleRedisArg, RV: FromRedisValue + $lifetime>(
&$lifetime mut self,
key: K,
pattern: P,
) -> $ret {
let mut c = cmd("HSCAN");
c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
$iter(c, self)
}
#[inline]
fn sscan<$lifetime, K: ToSingleRedisArg, RV: FromRedisValue + $lifetime>(&$lifetime mut self, key: K) -> $ret {
let mut c = cmd("SSCAN");
c.arg(key).cursor_arg(0);
$iter(c, self)
}
#[inline]
fn sscan_match<$lifetime, K: ToSingleRedisArg, P: ToSingleRedisArg, RV: FromRedisValue + $lifetime>(
&$lifetime mut self,
key: K,
pattern: P,
) -> $ret {
let mut c = cmd("SSCAN");
c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
$iter(c, self)
}
#[inline]
fn zscan<$lifetime, K: ToSingleRedisArg, RV: FromRedisValue + $lifetime>(&$lifetime mut self, key: K) -> $ret {
let mut c = cmd("ZSCAN");
c.arg(key).cursor_arg(0);
$iter(c, self)
}
#[inline]
fn zscan_match<$lifetime, K: ToSingleRedisArg, P: ToSingleRedisArg, RV: FromRedisValue + $lifetime>(
&$lifetime mut self,
key: K,
pattern: P,
) -> $ret {
let mut c = cmd("ZSCAN");
c.arg(key).cursor_arg(0).arg("MATCH").arg(pattern);
$iter(c, self)
}
};
}
macro_rules! implement_commands {
(
$(
$(#[$attr:meta])+
fn $name:ident<$($tyargs:ident : $ty:ident),*>(
$($argname:ident: $argty:ty),*) -> $rettype:tt $(via $ret_conv_fn:ident)? { $($body:tt)* }
)*
) =>
(
pub trait Commands : ConnectionLike+Sized {
$(
$(#[$attr])*
#[inline]
#[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
fn $name<$($tyargs: $ty, )* RV: FromRedisValue>(
&mut self $(, $argname: $argty)*) -> RedisResult<RV>
{
if_redisresult!($rettype, try, (Cmd::$name($($argname),*)))
.query(self)
}
)*
implement_iterators! {
'a,
|c: Cmd, this| c.iter(this),
RedisResult<Iter<'a, RV>>
}
}
impl Cmd {
$(
$(#[$attr])*
#[inline]
#[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
pub fn $name<$($tyargs: $ty),*>($($argname: $argty),*) -> if_redisresult!($rettype, wrap_redisresult, Self) {
if_redisresult!($rettype, wrap_ok, { $($body)* })
}
)*
}
#[cfg(feature = "aio")]
pub trait AsyncCommands : crate::aio::ConnectionLike + Send + Sized {
$(
$(#[$attr])*
#[inline]
#[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
fn $name<$($tyargs: $ty + Send + Sync,)* RV>(
&mut self
$(, $argname: $argty)*
) -> impl Future<Output = RedisResult<RV>> + Send
where
RV: FromRedisValue,
{
async move {
if_redisresult!($rettype, try, (Cmd::$name($($argname),*)))
.query_async(self)
.await
}
}
)*
implement_iterators! {
'a,
|c: Cmd, this| async move { c.iter_async(this).await },
impl Future<Output = RedisResult<crate::cmd::AsyncIter<'a, RV>>> + Send
}
}
pub trait TypedCommands : ConnectionLike+Sized {
$(
implement_command_sync! {
$(#[$attr])*
fn $name<$($tyargs: $ty),*>(
$($argname: $argty),*
) -> $rettype $(via $ret_conv_fn)?
}
)*
implement_iterators! {
'a,
|c: Cmd, this| c.iter(this),
RedisResult<Iter<'a, RV>>
}
fn get_int<K: ToSingleRedisArg>(&mut self, key: K) -> RedisResult<Option<isize>> {
cmd("GET").arg(key).query(self)
}
fn mget_ints<K: ToRedisArgs>(&mut self, key: K) -> RedisResult<Vec<Option<isize>>> {
cmd("MGET").arg(key).query(self)
}
}
#[cfg(feature = "aio")]
pub trait AsyncTypedCommands : crate::aio::ConnectionLike + Send + Sized {
$(
implement_command_async! {
$(#[$attr])*
fn $name<$($tyargs: $ty),*>(
$($argname: $argty),*
) -> $rettype $(via $ret_conv_fn)?
}
)*
implement_iterators! {
'a,
|c: Cmd, this| async move { c.iter_async(this).await },
impl Future<Output = RedisResult<crate::cmd::AsyncIter<'a, RV>>>
}
fn get_int<K: ToSingleRedisArg + Send + Sync>(&mut self, key: K) -> impl Future<Output = RedisResult<Option<isize>>> + Send {
async move { cmd("GET").arg(key).query_async(self).await }
}
fn mget_ints<K: ToRedisArgs + Send + Sync>(&mut self, key: K) -> impl Future<Output = RedisResult<Vec<Option<isize>>>> + Send {
async move { cmd("MGET").arg(key).query_async(self).await }
}
}
impl Pipeline {
$(
$(#[$attr])*
#[inline]
#[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
pub fn $name<$($tyargs: $ty),*>(
&mut self $(, $argname: $argty)*
) -> if_redisresult!($rettype, wrap_redisresult, (&mut Self)) {
if_redisresult!($rettype, wrap_ok, (write_pipeline_command!(self, { $($body)* })))
}
)*
}
#[cfg(feature = "cluster")]
impl ClusterPipeline {
$(
$(#[$attr])*
#[inline]
#[allow(clippy::extra_unused_lifetimes, clippy::needless_lifetimes)]
pub fn $name<$($tyargs: $ty),*>(
&mut self $(, $argname: $argty)*
) -> if_redisresult!($rettype, wrap_redisresult, (&mut Self)) {
if_redisresult!($rettype, wrap_ok, (write_pipeline_command!(self, { $($body)* })))
}
)*
}
);
}