1use std::mem;
2use std::slice;
3use std::str;
4use std::ops::Deref;
5
6use ffi;
7use libc;
8
9use AnyLuaValue;
10use AnyLuaString;
11use AsLua;
12use AsMutLua;
13use LuaRead;
14use Push;
15use PushGuard;
16use PushOne;
17use Void;
18
19macro_rules! integer_impl(
20 ($t:ident) => (
21 impl<'lua, L> Push<L> for $t where L: AsMutLua<'lua> {
22 type Err = Void; #[inline]
25 fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
26 unsafe { ffi::lua_pushinteger(lua.as_mut_lua().0, self as ffi::lua_Integer) };
27 let raw_lua = lua.as_lua();
28 Ok(PushGuard { lua: lua, size: 1, raw_lua: raw_lua })
29 }
30 }
31
32 impl<'lua, L> PushOne<L> for $t where L: AsMutLua<'lua> {
33 }
34
35 impl<'lua, L> LuaRead<L> for $t where L: AsLua<'lua> {
36 #[inline]
37 fn lua_read_at_position(lua: L, index: i32) -> Result<$t, L> {
38 let mut success = unsafe { mem::uninitialized() };
39 let val = unsafe { ffi::lua_tointegerx(lua.as_lua().0, index, &mut success) };
40 match success {
41 0 => Err(lua),
42 _ => Ok(val as $t)
43 }
44 }
45 }
46 );
47);
48
49integer_impl!(i8);
50integer_impl!(i16);
51integer_impl!(i32);
52macro_rules! unsigned_impl(
55 ($t:ident) => (
56 impl<'lua, L> Push<L> for $t where L: AsMutLua<'lua> {
57 type Err = Void; #[inline]
60 fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
61 unsafe { ffi::lua_pushunsigned(lua.as_mut_lua().0, self as ffi::lua_Unsigned) };
62 let raw_lua = lua.as_lua();
63 Ok(PushGuard { lua: lua, size: 1, raw_lua: raw_lua })
64 }
65 }
66
67 impl<'lua, L> PushOne<L> for $t where L: AsMutLua<'lua> {
68 }
69
70 impl<'lua, L> LuaRead<L> for $t where L: AsLua<'lua> {
71 #[inline]
72 fn lua_read_at_position(lua: L, index: i32) -> Result<$t, L> {
73 let mut success = unsafe { mem::uninitialized() };
74 let val = unsafe { ffi::lua_tounsignedx(lua.as_lua().0, index, &mut success) };
75 match success {
76 0 => Err(lua),
77 _ => Ok(val as $t)
78 }
79 }
80 }
81 );
82);
83
84unsigned_impl!(u8);
85unsigned_impl!(u16);
86unsigned_impl!(u32);
87macro_rules! numeric_impl(
90 ($t:ident) => (
91 impl<'lua, L> Push<L> for $t where L: AsMutLua<'lua> {
92 type Err = Void; #[inline]
95 fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
96 unsafe { ffi::lua_pushnumber(lua.as_mut_lua().0, self as f64) };
97 let raw_lua = lua.as_lua();
98 Ok(PushGuard { lua: lua, size: 1, raw_lua: raw_lua })
99 }
100 }
101
102 impl<'lua, L> PushOne<L> for $t where L: AsMutLua<'lua> {
103 }
104
105 impl<'lua, L> LuaRead<L> for $t where L: AsLua<'lua> {
106 #[inline]
107 fn lua_read_at_position(lua: L, index: i32) -> Result<$t, L> {
108 let mut success = unsafe { mem::uninitialized() };
109 let val = unsafe { ffi::lua_tonumberx(lua.as_lua().0, index, &mut success) };
110 match success {
111 0 => Err(lua),
112 _ => Ok(val as $t)
113 }
114 }
115 }
116 );
117);
118
119numeric_impl!(f32);
120numeric_impl!(f64);
121
122impl<'lua, L> Push<L> for String
123 where L: AsMutLua<'lua>
124{
125 type Err = Void; #[inline]
128 fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
129 unsafe {
130 ffi::lua_pushlstring(lua.as_mut_lua().0,
131 self.as_bytes().as_ptr() as *const _,
132 self.as_bytes().len() as libc::size_t);
133
134 let raw_lua = lua.as_lua();
135 Ok(PushGuard {
136 lua: lua,
137 size: 1,
138 raw_lua: raw_lua,
139 })
140 }
141 }
142}
143
144impl<'lua, L> PushOne<L> for String where L: AsMutLua<'lua> {}
145
146impl<'lua, L> LuaRead<L> for String
147 where L: AsLua<'lua>
148{
149 #[inline]
150 fn lua_read_at_position(lua: L, index: i32) -> Result<String, L> {
151 let mut size: libc::size_t = unsafe { mem::uninitialized() };
152 let c_str_raw = unsafe { ffi::lua_tolstring(lua.as_lua().0, index, &mut size) };
153 if c_str_raw.is_null() {
154 return Err(lua);
155 }
156
157 let c_slice = unsafe { slice::from_raw_parts(c_str_raw as *const u8, size) };
158 let maybe_string = String::from_utf8(c_slice.to_vec());
159 match maybe_string {
160 Ok(string) => Ok(string),
161 Err(_) => Err(lua),
162 }
163 }
164}
165
166impl<'lua, L> Push<L> for AnyLuaString
167 where L: AsMutLua<'lua>
168{
169 type Err = Void; #[inline]
172 fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
173 let AnyLuaString(v) = self;
174 unsafe {
175 ffi::lua_pushlstring(lua.as_mut_lua().0,
176 v[..].as_ptr() as *const _,
177 v[..].len() as libc::size_t);
178
179 let raw_lua = lua.as_lua();
180 Ok(PushGuard {
181 lua: lua,
182 size: 1,
183 raw_lua: raw_lua,
184 })
185 }
186 }
187}
188
189impl<'lua, L> LuaRead<L> for AnyLuaString
190 where L: AsLua<'lua>
191{
192 #[inline]
193 fn lua_read_at_position(lua: L, index: i32) -> Result<AnyLuaString, L> {
194 let mut size: libc::size_t = unsafe { mem::uninitialized() };
195 let c_str_raw = unsafe { ffi::lua_tolstring(lua.as_lua().0, index, &mut size) };
196 if c_str_raw.is_null() {
197 return Err(lua);
198 }
199
200 let c_slice = unsafe { slice::from_raw_parts(c_str_raw as *const u8, size) };
201 Ok(AnyLuaString(c_slice.to_vec()))
202 }
203}
204
205impl<'lua, 's, L> Push<L> for &'s str
206 where L: AsMutLua<'lua>
207{
208 type Err = Void; #[inline]
211 fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
212 unsafe {
213 ffi::lua_pushlstring(lua.as_mut_lua().0,
214 self.as_bytes().as_ptr() as *const _,
215 self.as_bytes().len() as libc::size_t);
216
217 let raw_lua = lua.as_lua();
218 Ok(PushGuard {
219 lua: lua,
220 size: 1,
221 raw_lua: raw_lua,
222 })
223 }
224 }
225}
226
227impl<'lua, 's, L> PushOne<L> for &'s str where L: AsMutLua<'lua> {}
228
229#[derive(Debug)]
246pub struct StringInLua<L> {
247 lua: L,
248 c_str_raw: *const libc::c_char,
249 size: libc::size_t,
250}
251
252impl<'lua, L> LuaRead<L> for StringInLua<L>
253 where L: AsLua<'lua>
254{
255 #[inline]
256 fn lua_read_at_position(lua: L, index: i32) -> Result<StringInLua<L>, L> {
257 let mut size: libc::size_t = unsafe { mem::uninitialized() };
258 let c_str_raw = unsafe { ffi::lua_tolstring(lua.as_lua().0, index, &mut size) };
259 if c_str_raw.is_null() {
260 return Err(lua);
261 }
262
263 let c_slice = unsafe { slice::from_raw_parts(c_str_raw as *const u8, size) };
264 match str::from_utf8(c_slice) {
265 Ok(_) => (),
266 Err(_) => return Err(lua)
267 };
268
269 Ok(StringInLua {
270 lua: lua,
271 c_str_raw: c_str_raw,
272 size: size,
273 })
274 }
275}
276
277impl<L> Deref for StringInLua<L> {
278 type Target = str;
279
280 #[inline]
281 fn deref(&self) -> &str {
282 let c_slice = unsafe { slice::from_raw_parts(self.c_str_raw as *const u8, self.size) };
283 match str::from_utf8(c_slice) {
284 Ok(s) => s,
285 Err(_) => unreachable!() }
287 }
288}
289
290impl<'lua, L> Push<L> for bool
291 where L: AsMutLua<'lua>
292{
293 type Err = Void; #[inline]
296 fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
297 unsafe { ffi::lua_pushboolean(lua.as_mut_lua().0, self.clone() as libc::c_int) };
298 let raw_lua = lua.as_lua();
299 Ok(PushGuard {
300 lua: lua,
301 size: 1,
302 raw_lua: raw_lua,
303 })
304 }
305}
306
307impl<'lua, L> PushOne<L> for bool where L: AsMutLua<'lua> {}
308
309impl<'lua, L> LuaRead<L> for bool
310 where L: AsLua<'lua>
311{
312 #[inline]
313 fn lua_read_at_position(lua: L, index: i32) -> Result<bool, L> {
314 if unsafe { ffi::lua_isboolean(lua.as_lua().0, index) } != true {
315 return Err(lua);
316 }
317
318 Ok(unsafe { ffi::lua_toboolean(lua.as_lua().0, index) != 0 })
319 }
320}
321
322impl<'lua, L> Push<L> for ()
323 where L: AsMutLua<'lua>
324{
325 type Err = Void; #[inline]
328 fn push_to_lua(self, lua: L) -> Result<PushGuard<L>, (Void, L)> {
329 let raw_lua = lua.as_lua();
330
331 Ok(PushGuard {
332 lua: lua,
333 size: 0,
334 raw_lua: raw_lua,
335 })
336 }
337}
338
339impl<'lua, L> LuaRead<L> for ()
340 where L: AsLua<'lua>
341{
342 #[inline]
343 fn lua_read_at_position(_: L, _: i32) -> Result<(), L> {
344 Ok(())
345 }
346}
347
348impl<'lua, L, T, E> Push<L> for Option<T>
349where T: Push<L, Err = E>,
350 L: AsMutLua<'lua>
351{
352 type Err = E;
353
354 #[inline]
355 fn push_to_lua(self, lua: L) -> Result<PushGuard<L>, (E, L)> {
356 match self {
357 Some(val) => val.push_to_lua(lua),
358 None => Ok(AnyLuaValue::LuaNil.push_no_err(lua)),
359 }
360 }
361}
362
363impl<'lua, L, T, E> PushOne<L> for Option<T>
364where T: PushOne<L, Err = E>,
365 L: AsMutLua<'lua>
366{
367}
368
369#[cfg(test)]
370mod tests {
371 use AnyLuaValue;
372 use AnyLuaString;
373 use Lua;
374 use StringInLua;
375
376 #[test]
377 fn read_i32s() {
378 let mut lua = Lua::new();
379
380 lua.set("a", 2);
381
382 let x: i32 = lua.get("a").unwrap();
383 assert_eq!(x, 2);
384
385 let y: i8 = lua.get("a").unwrap();
386 assert_eq!(y, 2);
387
388 let z: i16 = lua.get("a").unwrap();
389 assert_eq!(z, 2);
390
391 let w: i32 = lua.get("a").unwrap();
392 assert_eq!(w, 2);
393
394 let a: u32 = lua.get("a").unwrap();
395 assert_eq!(a, 2);
396
397 let b: u8 = lua.get("a").unwrap();
398 assert_eq!(b, 2);
399
400 let c: u16 = lua.get("a").unwrap();
401 assert_eq!(c, 2);
402
403 let d: u32 = lua.get("a").unwrap();
404 assert_eq!(d, 2);
405 }
406
407 #[test]
408 fn write_i32s() {
409 let mut lua = Lua::new();
412
413 lua.set("a", 2);
414 let x: i32 = lua.get("a").unwrap();
415 assert_eq!(x, 2);
416 }
417
418 #[test]
419 fn readwrite_floats() {
420 let mut lua = Lua::new();
421
422 lua.set("a", 2.51234 as f32);
423 lua.set("b", 3.4123456789 as f64);
424
425 let x: f32 = lua.get("a").unwrap();
426 assert!(x - 2.51234 < 0.000001);
427
428 let y: f64 = lua.get("a").unwrap();
429 assert!(y - 2.51234 < 0.000001);
430
431 let z: f32 = lua.get("b").unwrap();
432 assert!(z - 3.4123456789 < 0.000001);
433
434 let w: f64 = lua.get("b").unwrap();
435 assert!(w - 3.4123456789 < 0.000001);
436 }
437
438 #[test]
439 fn readwrite_bools() {
440 let mut lua = Lua::new();
441
442 lua.set("a", true);
443 lua.set("b", false);
444
445 let x: bool = lua.get("a").unwrap();
446 assert_eq!(x, true);
447
448 let y: bool = lua.get("b").unwrap();
449 assert_eq!(y, false);
450 }
451
452 #[test]
453 fn readwrite_strings() {
454 let mut lua = Lua::new();
455
456 lua.set("a", "hello");
457 lua.set("b", "hello".to_string());
458
459 let x: String = lua.get("a").unwrap();
460 assert_eq!(x, "hello");
461
462 let y: String = lua.get("b").unwrap();
463 assert_eq!(y, "hello");
464
465 assert_eq!(lua.execute::<String>("return 'abc'").unwrap(), "abc");
466 assert_eq!(lua.execute::<u32>("return #'abc'").unwrap(), 3);
467 assert_eq!(lua.execute::<u32>("return #'a\\x00c'").unwrap(), 3);
468 assert_eq!(lua.execute::<AnyLuaString>("return 'a\\x00c'").unwrap().0, vec!(97, 0, 99));
469 assert_eq!(lua.execute::<AnyLuaString>("return 'a\\x00c'").unwrap().0.len(), 3);
470 assert_eq!(lua.execute::<AnyLuaString>("return '\\x01\\xff'").unwrap().0, vec!(1, 255));
471 lua.execute::<String>("return 'a\\x00\\xc0'").unwrap_err();
472 }
473
474 #[test]
475 fn i32_to_string() {
476 let mut lua = Lua::new();
477
478 lua.set("a", 2);
479
480 let x: String = lua.get("a").unwrap();
481 assert_eq!(x, "2");
482 }
483
484 #[test]
485 fn string_to_i32() {
486 let mut lua = Lua::new();
487
488 lua.set("a", "2");
489 lua.set("b", "aaa");
490
491 let x: i32 = lua.get("a").unwrap();
492 assert_eq!(x, 2);
493
494 let y: Option<i32> = lua.get("b");
495 assert!(y.is_none());
496 }
497
498 #[test]
499 fn string_on_lua() {
500 let mut lua = Lua::new();
501
502 lua.set("a", "aaa");
503 {
504 let x: StringInLua<_> = lua.get("a").unwrap();
505 assert_eq!(&*x, "aaa");
506 }
507
508 lua.set("a", 18);
509 {
510 let x: StringInLua<_> = lua.get("a").unwrap();
511 assert_eq!(&*x, "18");
512 }
513 }
514
515 #[test]
516 fn push_opt() {
517 let mut lua = Lua::new();
518
519 lua.set("some", ::function0(|| Some(123)));
520 lua.set("none", ::function0(|| Option::None::<i32>));
521
522 match lua.execute::<i32>("return some()") {
523 Ok(123) => {}
524 unexpected => panic!("{:?}", unexpected),
525 }
526
527 match lua.execute::<AnyLuaValue>("return none()") {
528 Ok(AnyLuaValue::LuaNil) => {}
529 unexpected => panic!("{:?}", unexpected),
530 }
531
532 lua.set("no_value", None::<i32>);
533 lua.set("some_value", Some("Hello!"));
534
535 assert_eq!(lua.get("no_value"), None::<String>);
536 assert_eq!(lua.get("some_value"), Some("Hello!".to_string()));
537 }
538}