1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use crate::types::ScriptArg;
use futures::prelude::*;
#[derive(Clone, Debug)]
pub struct Info {
script: &'static str,
body: &'static str,
args: &'static [&'static str],
}
impl Info {
pub fn new(script: &'static str, body: &'static str, args: &'static [&'static str]) -> Self {
Self { script, body, args }
}
}
fn _object_safe(_: &dyn Script) {}
pub trait Script {
fn info(&self, _: &mut Vec<Info>, _: &mut Vec<ScriptArg>);
fn join<T: Script>(self, other: T) -> ScriptJoin<Self, T>
where
Self: Sized,
{
ScriptJoin(self, other)
}
fn invoke<T>(self, con: &mut dyn redis::ConnectionLike) -> redis::RedisResult<T>
where
T: redis::FromRedisValue,
Self: Sized,
{
let mut info = vec![];
let mut args = vec![];
self.info(&mut info, &mut args);
let script = gen_script(&info, &args);
let mut invoke = script.prepare_invoke();
for wr in args {
invoke.arg(wr);
}
invoke.invoke(con)
}
fn invoke_async<'a, C, T>(self, con: &'a mut C) -> redis::RedisFuture<'a, T>
where
C: redis::aio::ConnectionLike + Send,
T: redis::FromRedisValue + Send,
Self: Sized + Send + 'a,
{
async move {
let mut info = vec![];
let mut args = vec![];
self.info(&mut info, &mut args);
let script = gen_script(&info, &args);
let mut invoke = script.prepare_invoke();
for wr in args {
invoke.arg(wr);
}
invoke.invoke_async(con).await
}
.boxed()
}
}
impl<S: Script + ?Sized> Script for Box<S> {
fn info(&self, infos: &mut Vec<Info>, args: &mut Vec<ScriptArg>) {
(**self).info(infos, args);
}
}
impl Script for () {
fn info(&self, _: &mut Vec<Info>, _: &mut Vec<ScriptArg>) {}
}
pub struct ScriptJoin<S, T>(S, T);
impl<S, T> Script for ScriptJoin<S, T>
where
S: Script,
T: Script,
{
fn info(&self, info: &mut Vec<Info>, args: &mut Vec<ScriptArg>) {
self.0.info(info, args);
self.1.info(info, args);
}
}
pub trait TakeScript<I> {
type Item;
fn take(self, inner: I) -> Self::Item;
}
pub fn gen_script(info: &[Info], args: &[ScriptArg]) -> redis::Script {
assert!(info.len() > 0, "No script information");
let mut arg_index = 0;
let mut script = String::new();
let last = info.len() - 1;
for (index, info) in info.iter().enumerate() {
let prefix = if index == last { "return " } else { "" };
let mut init = String::new();
for arg in info.args {
let pack = args[arg_index].pack();
arg_index += 1;
if pack {
init += &format!("local {} = cmsgpack.unpack(ARGV[{}]) ", arg, arg_index);
} else {
init += &format!("local {} = ARGV[{}] ", arg, arg_index);
}
}
script += &format!("{}(function() {} {} end)();\n", prefix, init, info.body);
}
redis::Script::new(&script)
}