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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
//!
//! redis-lua is a Lua scripting helper for [`redis-rs`](https://github.com/mitsuhiko/redis-rs)
//!
//! redis-lua allows to insert Redis Lua scripts in Rust code in safer manner. The key features of redis-lua are:
//!
//! * Compile-time lint for Redis Lua scripts.
//! * Capturing Rust variables in Lua scripts.
//! * Safe argument substitution.
//! * Safely joining multiple Lua scripts.
//!
//! # Invoke a Lua script
//!
//! [`lua`][] macro allows to create the Lua script. The script object implements [`Script`][] trait.
//! The return value from the script can be converted to any types which implement [`redis::FromRedisValue`][].
//!
//! ```rust
//! use redis_lua::lua;
//!
//! # fn main() {
//! let mut cli = redis::Client::open("redis://localhost").unwrap();
//!
//! let script = lua!(return 1 + 2);
//! let num: usize = script.invoke(&mut cli).unwrap();
//! assert_eq!(num, 3);
//! # }
//! ```
//!
//! Any Lua syntax supported by Redis Lua is usable.
//!
//! * if-else
//!
//! ```rust
//! # use redis_lua::lua;
//! #
//! # fn main() {
//! # let mut cli = redis::Client::open("redis://localhost").unwrap();
//! #
//! # let script =
//! lua!(
//!   if 3 > 1 then
//!     return 3
//!   else
//!     return 1
//!   end
//! );
//! # let num: usize = script.invoke(&mut cli).unwrap();
//! # assert_eq!(num, 3);
//! # }
//! ```
//!
//! * for-loop
//!
//! ```rust
//! # use redis_lua::lua;
//! #
//! # fn main() {
//! # let mut cli = redis::Client::open("redis://localhost").unwrap();
//! #
//! # let script =
//! lua!(
//!   local sum = 0
//!   for i=1,10 do
//!      sum = sum + i
//!   end
//!   return sum
//! );
//! # let num: usize = script.invoke(&mut cli).unwrap();
//! # assert_eq!(num, 55);
//! # }
//! ```
//!
//! # Error reporting
//!
//! Errors in Lua scripts (such as undefined variables) are detected at compile time.
//!
//! ```rust,ignore
//! # use redis_lua::lua;
//! #
//! # fn main() {
//! # let mut cli = redis::Client::open("redis://localhost").unwrap();
//! #
//! # let script =
//! lua!(
//!   return a + 1
//! );
//! # let num: usize = script.invoke(&mut cli).unwrap();
//! # assert_eq!(num, 55);
//! # }
//! ```
//!
//! ```text,ignore
//! error: in lua: `a` is not defined (undefined_variable)
//!    --> src/lib.rs:80:10
//!    |
//! 10 |   return a + 1
//!    |          ^
//!
//!    error: aborting due to previous error
//! ```
//!
//! # Capturing a variable
//!
//! `@` with an identifier allows to capture a Rust variable in the script. It allows to capture any types which implement [`serde::Serialize`][].
//!
//! ```rust
//! # use redis_lua::lua;
//! #
//! # fn main() {
//! # let mut cli = redis::Client::open("redis://localhost").unwrap();
//! #
//! let x = 10;
//!
//! let script = lua!(return @x + 2);
//! let num: usize = script.invoke(&mut cli).unwrap();
//! assert_eq!(num, 12);
//! # }
//! ```
//!
//! # Argument substitution
//!
//! `$` with an identifier allows to substitute a variable before actually running the script. Same as `@`, any types which implement [`serde::Serialize`][] can be substituted.
//!
//! ```rust
//! # use redis_lua::lua;
//! #
//! # fn main() {
//! # let mut cli = redis::Client::open("redis://localhost").unwrap();
//! #
//! let script = lua!(return $x + 2);
//! let num: usize = script.x(30).invoke(&mut cli).unwrap();
//! assert_eq!(num, 32);
//! # }
//! ```
//!
//! The difference from `@` is that the same script can be called multiple times with different values.
//!
//! ```rust
//! # use redis_lua::lua;
//! #
//! # fn main() {
//! # let mut cli = redis::Client::open("redis://localhost").unwrap();
//! #
//! let script = lua!(return $x + 2);
//!
//! for i in 0..10 {
//!     let num: usize = script.clone().x(i).invoke(&mut cli).unwrap();
//!     assert_eq!(num, i + 2);
//! }
//! # }
//! ```
//!
//! The script object is clonable if all the variables it captures are clonable or it captures no variables.
//!
//! # Type conversion
//!
//! `@` and `$` allow to pass Rust variables to Lua scripts. Primitive types and strings are converted to
//! the corresponding primitive types/strings in Lua scripts.
//! Non-empty byte sequences (e.g. `Vec<u8>`, `&[u8]`) are converted to a Lua string.
//! If the sequence is empty, it's converted to an empty table.
//!
//! Complicated types such as structs, tuples, maps and non-u8 vectors are converted to Lua tables.
//! The name of struct members become the key of tables.
//!
//! # Limitation
//!
//! * The comment `--` is available only in nightly.
//! * The warnings are available only in nightly. All the warnings are treated as errors in stable.
//!

use proc_macro_hack::proc_macro_hack;

mod script;
mod types;

pub use futures;
pub use redis;
pub use serde;

/// Macro to embed Lua script in Rust code.
#[proc_macro_hack]
pub use redis_lua_macro::lua;

/// Macro to convert Lua script to string.
#[proc_macro_hack]
pub use redis_lua_macro::lua_s;

pub use script::{gen_script, Info, Script, ScriptJoin, TakeScript};

pub use types::{script_arg, ScriptArg};