1use ffi;
2
3use AsLua;
4use AsMutLua;
5
6use Push;
7use PushGuard;
8use PushOne;
9use LuaRead;
10use LuaTable;
11use Void;
12
13#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
14pub struct AnyLuaString(pub Vec<u8>);
15
16#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
18pub enum AnyHashableLuaValue {
19 LuaString(String),
20 LuaAnyString(AnyLuaString),
21 LuaNumber(i32),
22 LuaBoolean(bool),
23 LuaArray(Vec<(AnyHashableLuaValue, AnyHashableLuaValue)>),
24 LuaNil,
25
26 LuaOther,
29}
30
31#[derive(Clone, Debug, PartialEq)]
33pub enum AnyLuaValue {
34 LuaString(String),
35 LuaAnyString(AnyLuaString),
36 LuaNumber(f64),
37 LuaBoolean(bool),
38 LuaArray(Vec<(AnyLuaValue, AnyLuaValue)>),
39 LuaNil,
40
41 LuaOther,
44}
45
46impl<'lua, L> Push<L> for AnyLuaValue
47 where L: AsMutLua<'lua>
48{
49 type Err = Void; #[inline]
52 fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
53 let raw_lua = lua.as_lua();
54 match self {
55 AnyLuaValue::LuaString(val) => val.push_to_lua(lua),
56 AnyLuaValue::LuaAnyString(val) => val.push_to_lua(lua),
57 AnyLuaValue::LuaNumber(val) => val.push_to_lua(lua),
58 AnyLuaValue::LuaBoolean(val) => val.push_to_lua(lua),
59 AnyLuaValue::LuaArray(val) => {
60 let size = val.push_no_err(&mut lua as &mut AsMutLua<'lua>).forget_internal();
69
70 Ok(PushGuard {
71 lua: lua,
72 size: size,
73 raw_lua: raw_lua,
74 })
75 }
76 AnyLuaValue::LuaNil => {
77 unsafe {
78 ffi::lua_pushnil(lua.as_mut_lua().0);
79 }
80 Ok(PushGuard {
81 lua: lua,
82 size: 1,
83 raw_lua: raw_lua,
84 })
85 } AnyLuaValue::LuaOther => panic!("can't push a AnyLuaValue of type Other"),
87 }
88 }
89}
90
91impl<'lua, L> PushOne<L> for AnyLuaValue where L: AsMutLua<'lua> {}
92
93impl<'lua, L> LuaRead<L> for AnyLuaValue
94 where L: AsMutLua<'lua>
95{
96 #[inline]
97 fn lua_read_at_position(mut lua: L, index: i32) -> Result<AnyLuaValue, L> {
98
99 let data_type = unsafe { ffi::lua_type(lua.as_lua().0, index) };
103 if data_type == ffi::LUA_TSTRING {
104
105 let mut lua = match LuaRead::lua_read_at_position(&mut lua as &mut AsMutLua<'lua>, index) {
106 Ok(v) => return Ok(AnyLuaValue::LuaString(v)),
107 Err(lua) => lua,
108 };
109
110 let _lua = match LuaRead::lua_read_at_position(&mut lua as &mut AsMutLua<'lua>, index) {
111 Ok(v) => return Ok(AnyLuaValue::LuaAnyString(v)),
112 Err(lua) => lua,
113 };
114
115 Ok(AnyLuaValue::LuaOther)
116
117 } else {
118
119 let mut lua = match LuaRead::lua_read_at_position(&mut lua as &mut AsMutLua<'lua>, index) {
120 Ok(v) => return Ok(AnyLuaValue::LuaNumber(v)),
121 Err(lua) => lua,
122 };
123
124 let mut lua = match LuaRead::lua_read_at_position(&mut lua as &mut AsMutLua<'lua>, index) {
125 Ok(v) => return Ok(AnyLuaValue::LuaBoolean(v)),
126 Err(lua) => lua,
127 };
128
129 let mut lua = match LuaRead::lua_read_at_position(&mut lua as &mut AsMutLua<'lua>, index) {
130 Ok(v) => return Ok(AnyLuaValue::LuaString(v)),
131 Err(lua) => lua,
132 };
133
134 let lua = match LuaRead::lua_read_at_position(&mut lua as &mut AsMutLua<'lua>, index) {
135 Ok(v) => return Ok(AnyLuaValue::LuaAnyString(v)),
136 Err(lua) => lua,
137 };
138
139 if unsafe { ffi::lua_isnil(lua.as_lua().0, index) } {
140 return Ok(AnyLuaValue::LuaNil);
141 }
142
143 let table: Result<LuaTable<_>, _> = LuaRead::lua_read_at_position(lua, index);
144 let _lua = match table {
145 Ok(mut v) => return Ok(AnyLuaValue::LuaArray(v.iter::<AnyLuaValue, AnyLuaValue>()
146 .filter_map(|e| e).collect())),
147 Err(lua) => lua,
148 };
149
150 Ok(AnyLuaValue::LuaOther)
151 }
152 }
153}
154
155impl<'lua, L> Push<L> for AnyHashableLuaValue
156 where L: AsMutLua<'lua>
157{
158 type Err = Void; #[inline]
161 fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
162 let raw_lua = lua.as_lua();
163 match self {
164 AnyHashableLuaValue::LuaString(val) => val.push_to_lua(lua),
165 AnyHashableLuaValue::LuaAnyString(val) => val.push_to_lua(lua),
166 AnyHashableLuaValue::LuaNumber(val) => val.push_to_lua(lua),
167 AnyHashableLuaValue::LuaBoolean(val) => val.push_to_lua(lua),
168 AnyHashableLuaValue::LuaArray(val) => {
169 let size = val.push_no_err(&mut lua as &mut AsMutLua<'lua>).forget_internal();
178
179 Ok(PushGuard {
180 lua: lua,
181 size: size,
182 raw_lua: raw_lua,
183 })
184 }
185 AnyHashableLuaValue::LuaNil => {
186 unsafe {
187 ffi::lua_pushnil(lua.as_mut_lua().0);
188 }
189 Ok(PushGuard {
190 lua: lua,
191 size: 1,
192 raw_lua: raw_lua,
193 })
194 } AnyHashableLuaValue::LuaOther => panic!("can't push a AnyHashableLuaValue of type Other"),
196 }
197 }
198}
199
200impl<'lua, L> PushOne<L> for AnyHashableLuaValue where L: AsMutLua<'lua> {}
201
202impl<'lua, L> LuaRead<L> for AnyHashableLuaValue
203 where L: AsMutLua<'lua>
204{
205 #[inline]
206 fn lua_read_at_position(mut lua: L, index: i32) -> Result<AnyHashableLuaValue, L> {
207 let data_type = unsafe { ffi::lua_type(lua.as_lua().0, index) };
208 if data_type == ffi::LUA_TSTRING {
209
210 let mut lua = match LuaRead::lua_read_at_position(&mut lua as &mut AsMutLua<'lua>, index) {
211 Ok(v) => return Ok(AnyHashableLuaValue::LuaString(v)),
212 Err(lua) => lua,
213 };
214
215 let _lua = match LuaRead::lua_read_at_position(&mut lua as &mut AsMutLua<'lua>, index) {
216 Ok(v) => return Ok(AnyHashableLuaValue::LuaAnyString(v)),
217 Err(lua) => lua,
218 };
219
220 Ok(AnyHashableLuaValue::LuaOther)
221
222 } else {
223
224 let mut lua = match LuaRead::lua_read_at_position(&mut lua as &mut AsMutLua<'lua>, index) {
225 Ok(v) => return Ok(AnyHashableLuaValue::LuaNumber(v)),
226 Err(lua) => lua,
227 };
228
229 let mut lua = match LuaRead::lua_read_at_position(&mut lua as &mut AsMutLua<'lua>, index) {
230 Ok(v) => return Ok(AnyHashableLuaValue::LuaBoolean(v)),
231 Err(lua) => lua,
232 };
233
234 let mut lua = match LuaRead::lua_read_at_position(&mut lua as &mut AsMutLua<'lua>, index) {
235 Ok(v) => return Ok(AnyHashableLuaValue::LuaString(v)),
236 Err(lua) => lua,
237 };
238
239 let mut lua = match LuaRead::lua_read_at_position(&mut lua as &mut AsMutLua<'lua>, index) {
240 Ok(v) => return Ok(AnyHashableLuaValue::LuaAnyString(v)),
241 Err(lua) => lua,
242 };
243
244 if unsafe { ffi::lua_isnil(lua.as_lua().0, index) } {
245 return Ok(AnyHashableLuaValue::LuaNil);
246 }
247
248 let table: Result<LuaTable<_>, _> = LuaRead::lua_read_at_position(&mut lua as &mut AsMutLua<'lua>, index);
249 let _lua = match table {
250 Ok(mut v) => return Ok(AnyHashableLuaValue::LuaArray(v
251 .iter::<AnyHashableLuaValue, AnyHashableLuaValue>()
252 .filter_map(|e| e).collect())),
253 Err(lua) => lua,
254 };
255
256 Ok(AnyHashableLuaValue::LuaOther)
257 }
258 }
259}
260
261#[cfg(test)]
262mod tests {
263 use Lua;
264 use AnyLuaValue;
265 use AnyHashableLuaValue;
266 use AnyLuaString;
267
268 #[test]
269 fn read_numbers() {
270 let mut lua = Lua::new();
271
272 lua.set("a", "-2");
273 lua.set("b", 3.5f32);
274 lua.set("c", -2.0f32);
275
276 let x: AnyLuaValue = lua.get("a").unwrap();
277 assert_eq!(x, AnyLuaValue::LuaString("-2".to_owned()));
278
279 let y: AnyLuaValue = lua.get("b").unwrap();
280 assert_eq!(y, AnyLuaValue::LuaNumber(3.5));
281
282 let z: AnyLuaValue = lua.get("c").unwrap();
283 assert_eq!(z, AnyLuaValue::LuaNumber(-2.0));
284 }
285
286 #[test]
287 fn read_hashable_numbers() {
288 let mut lua = Lua::new();
289
290 lua.set("a", -2.0f32);
291 lua.set("b", 4.0f32);
292 lua.set("c", "4");
293
294 let x: AnyHashableLuaValue = lua.get("a").unwrap();
295 assert_eq!(x, AnyHashableLuaValue::LuaNumber(-2));
296
297 let y: AnyHashableLuaValue = lua.get("b").unwrap();
298 assert_eq!(y, AnyHashableLuaValue::LuaNumber(4));
299
300 let z: AnyHashableLuaValue = lua.get("c").unwrap();
301 assert_eq!(z, AnyHashableLuaValue::LuaString("4".to_owned()));
302 }
303
304 #[test]
305 fn read_strings() {
306 let mut lua = Lua::new();
307
308 lua.set("a", "hello");
309 lua.set("b", "3x");
310 lua.set("c", "false");
311
312 let x: AnyLuaValue = lua.get("a").unwrap();
313 assert_eq!(x, AnyLuaValue::LuaString("hello".to_string()));
314
315 let y: AnyLuaValue = lua.get("b").unwrap();
316 assert_eq!(y, AnyLuaValue::LuaString("3x".to_string()));
317
318 let z: AnyLuaValue = lua.get("c").unwrap();
319 assert_eq!(z, AnyLuaValue::LuaString("false".to_string()));
320 }
321
322 #[test]
323 fn read_hashable_strings() {
324 let mut lua = Lua::new();
325
326 lua.set("a", "hello");
327 lua.set("b", "3x");
328 lua.set("c", "false");
329
330 let x: AnyHashableLuaValue = lua.get("a").unwrap();
331 assert_eq!(x, AnyHashableLuaValue::LuaString("hello".to_string()));
332
333 let y: AnyHashableLuaValue = lua.get("b").unwrap();
334 assert_eq!(y, AnyHashableLuaValue::LuaString("3x".to_string()));
335
336 let z: AnyHashableLuaValue = lua.get("c").unwrap();
337 assert_eq!(z, AnyHashableLuaValue::LuaString("false".to_string()));
338 }
339
340 #[test]
341 fn read_booleans() {
342 let mut lua = Lua::new();
343
344 lua.set("a", true);
345 lua.set("b", false);
346
347 let x: AnyLuaValue = lua.get("a").unwrap();
348 assert_eq!(x, AnyLuaValue::LuaBoolean(true));
349
350 let y: AnyLuaValue = lua.get("b").unwrap();
351 assert_eq!(y, AnyLuaValue::LuaBoolean(false));
352 }
353
354 #[test]
355 fn read_hashable_booleans() {
356 let mut lua = Lua::new();
357
358 lua.set("a", true);
359 lua.set("b", false);
360
361 let x: AnyHashableLuaValue = lua.get("a").unwrap();
362 assert_eq!(x, AnyHashableLuaValue::LuaBoolean(true));
363
364 let y: AnyHashableLuaValue = lua.get("b").unwrap();
365 assert_eq!(y, AnyHashableLuaValue::LuaBoolean(false));
366 }
367
368 #[test]
369 fn read_tables() {
370 let mut lua = Lua::new();
371 lua.execute::<()>("
372 a = {x = 12, y = 19}
373 b = {z = a, w = 'test string'}
374 c = {'first', 'second'}
375 ").unwrap();
376
377 fn get<'a>(table: &'a AnyLuaValue, key: &str) -> &'a AnyLuaValue {
378 let test_key = AnyLuaValue::LuaString(key.to_owned());
379 match table {
380 &AnyLuaValue::LuaArray(ref vec) => {
381 let &(_, ref value) = vec.iter().find(|&&(ref key, _)| key == &test_key).expect("key not found");
382 value
383 },
384 _ => panic!("not a table")
385 }
386 }
387
388 fn get_numeric<'a>(table: &'a AnyLuaValue, key: usize) -> &'a AnyLuaValue {
389 let test_key = AnyLuaValue::LuaNumber(key as f64);
390 match table {
391 &AnyLuaValue::LuaArray(ref vec) => {
392 let &(_, ref value) = vec.iter().find(|&&(ref key, _)| key == &test_key).expect("key not found");
393 value
394 },
395 _ => panic!("not a table")
396 }
397 }
398
399 let a: AnyLuaValue = lua.get("a").unwrap();
400 assert_eq!(get(&a, "x"), &AnyLuaValue::LuaNumber(12.0));
401 assert_eq!(get(&a, "y"), &AnyLuaValue::LuaNumber(19.0));
402
403 let b: AnyLuaValue = lua.get("b").unwrap();
404 assert_eq!(get(&get(&b, "z"), "x"), get(&a, "x"));
405 assert_eq!(get(&get(&b, "z"), "y"), get(&a, "y"));
406
407 let c: AnyLuaValue = lua.get("c").unwrap();
408 assert_eq!(get_numeric(&c, 1), &AnyLuaValue::LuaString("first".to_owned()));
409 assert_eq!(get_numeric(&c, 2), &AnyLuaValue::LuaString("second".to_owned()));
410 }
411
412 #[test]
413 fn read_hashable_tables() {
414 let mut lua = Lua::new();
415 lua.execute::<()>("
416 a = {x = 12, y = 19}
417 b = {z = a, w = 'test string'}
418 c = {'first', 'second'}
419 ").unwrap();
420
421 fn get<'a>(table: &'a AnyHashableLuaValue, key: &str) -> &'a AnyHashableLuaValue {
422 let test_key = AnyHashableLuaValue::LuaString(key.to_owned());
423 match table {
424 &AnyHashableLuaValue::LuaArray(ref vec) => {
425 let &(_, ref value) = vec.iter().find(|&&(ref key, _)| key == &test_key).expect("key not found");
426 value
427 },
428 _ => panic!("not a table")
429 }
430 }
431
432 fn get_numeric<'a>(table: &'a AnyHashableLuaValue, key: usize) -> &'a AnyHashableLuaValue {
433 let test_key = AnyHashableLuaValue::LuaNumber(key as i32);
434 match table {
435 &AnyHashableLuaValue::LuaArray(ref vec) => {
436 let &(_, ref value) = vec.iter().find(|&&(ref key, _)| key == &test_key).expect("key not found");
437 value
438 },
439 _ => panic!("not a table")
440 }
441 }
442
443 let a: AnyHashableLuaValue = lua.get("a").unwrap();
444 assert_eq!(get(&a, "x"), &AnyHashableLuaValue::LuaNumber(12));
445 assert_eq!(get(&a, "y"), &AnyHashableLuaValue::LuaNumber(19));
446
447 let b: AnyHashableLuaValue = lua.get("b").unwrap();
448 assert_eq!(get(&get(&b, "z"), "x"), get(&a, "x"));
449 assert_eq!(get(&get(&b, "z"), "y"), get(&a, "y"));
450
451 let c: AnyHashableLuaValue = lua.get("c").unwrap();
452 assert_eq!(get_numeric(&c, 1), &AnyHashableLuaValue::LuaString("first".to_owned()));
453 assert_eq!(get_numeric(&c, 2), &AnyHashableLuaValue::LuaString("second".to_owned()));
454 }
455
456 #[test]
457 fn push_numbers() {
458 let mut lua = Lua::new();
459
460 lua.set("a", AnyLuaValue::LuaNumber(3.0));
461
462 let x: i32 = lua.get("a").unwrap();
463 assert_eq!(x, 3);
464 }
465
466 #[test]
467 fn push_hashable_numbers() {
468 let mut lua = Lua::new();
469
470 lua.set("a", AnyHashableLuaValue::LuaNumber(3));
471
472 let x: i32 = lua.get("a").unwrap();
473 assert_eq!(x, 3);
474 }
475
476 #[test]
477 fn push_strings() {
478 let mut lua = Lua::new();
479
480 lua.set("a", AnyLuaValue::LuaString("hello".to_string()));
481
482 let x: String = lua.get("a").unwrap();
483 assert_eq!(x, "hello");
484 }
485
486 #[test]
487 fn push_hashable_strings() {
488 let mut lua = Lua::new();
489
490 lua.set("a", AnyHashableLuaValue::LuaString("hello".to_string()));
491
492 let x: String = lua.get("a").unwrap();
493 assert_eq!(x, "hello");
494 }
495
496 #[test]
497 fn push_booleans() {
498 let mut lua = Lua::new();
499
500 lua.set("a", AnyLuaValue::LuaBoolean(true));
501
502 let x: bool = lua.get("a").unwrap();
503 assert_eq!(x, true);
504 }
505
506 #[test]
507 fn push_hashable_booleans() {
508 let mut lua = Lua::new();
509
510 lua.set("a", AnyHashableLuaValue::LuaBoolean(true));
511
512 let x: bool = lua.get("a").unwrap();
513 assert_eq!(x, true);
514 }
515
516 #[test]
517 fn push_nil() {
518 let mut lua = Lua::new();
519
520 lua.set("a", AnyLuaValue::LuaNil);
521
522 let x: Option<i32> = lua.get("a");
523 assert!(x.is_none(),
524 "x is a Some value when it should be a None value. X: {:?}",
525 x);
526 }
527
528 #[test]
529 fn push_hashable_nil() {
530 let mut lua = Lua::new();
531
532 lua.set("a", AnyHashableLuaValue::LuaNil);
533
534 let x: Option<i32> = lua.get("a");
535 assert!(x.is_none(),
536 "x is a Some value when it should be a None value. X: {:?}",
537 x);
538 }
539
540 #[test]
541 fn non_utf_8_string() {
542 let mut lua = Lua::new();
543 let a = lua.execute::<AnyLuaValue>(r"return '\xff\xfe\xff\xfe'").unwrap();
544 match a {
545 AnyLuaValue::LuaAnyString(AnyLuaString(v)) => {
546 assert_eq!(Vec::from(&b"\xff\xfe\xff\xfe"[..]), v);
547 },
548 _ => panic!("Decoded to wrong variant"),
549 }
550 }
551}