Skip to content

Instantly share code, notes, and snippets.

@Ruin0x11
Last active September 6, 2017 10:06
Show Gist options
  • Save Ruin0x11/77bd93921e895f59dfd929a77be0f3ad to your computer and use it in GitHub Desktop.
Save Ruin0x11/77bd93921e895f59dfd929a77be0f3ad to your computer and use it in GitHub Desktop.
Reading back lua userdata by copy with hlua
#[macro_use] extern crate hlua;
mod point;
use std::fmt::{self, Display};
use hlua::Lua;
use point::Point;
struct State<'a> {
pub lua: Lua<'a>,
pub world: World,
}
pub fn make_grid_from_str<M, F, T>(text: &str, mut constructor: M, mut callback: F) -> T
where M: FnMut(Point) -> T,
F: FnMut(&Point, char, &mut T) {
let mut x = 0;
let mut y = 0;
let lines = text.split('\n').filter(|l| l.len() > 0).collect::<Vec<_>>();
let height = lines.len();
assert!(height > 0);
let width = lines[0].len();
assert!(width > 0);
assert!(lines.iter().all(|line| line.chars().count() == width));
let mut thing = constructor(Point::new(height as i32, width as i32));
for line in lines {
for ch_at_point in line.chars() {
let grid_pos = Point { x: x as i32, y: y as i32 };
callback(&grid_pos, ch_at_point, &mut thing);
x += 1;
}
y += 1;
x = 0;
}
thing
}
#[derive(Clone)]
pub struct World {
pub dim: Point,
tiles: Vec<char>,
}
impl World {
fn new(p: Point) -> Self {
let mut tiles = Vec::new();
for _ in 0..p.x {
for _ in 0..p.y {
tiles.push(' ');
}
}
World {
dim: p,
tiles: tiles,
}
}
pub fn in_bounds(&self, pt: &Point) -> bool {
*pt >= Point::new(0, 0) && *pt < self.dim
}
pub fn width(&self) -> i32 {
self.dim.x
}
pub fn height(&self) -> i32 {
self.dim.y
}
pub fn set(&mut self, pt: &Point, val: char) {
if self.in_bounds(pt) {
let idx = (pt.y * self.dim.x + pt.x) as usize;
let mut v = self.tiles.get_mut(idx).unwrap();
*v = val;
}
}
pub fn get(&self, pt: &Point) -> char {
if self.in_bounds(pt) {
let idx = (pt.y * self.dim.x + pt.x) as usize;
self.tiles.get(idx).unwrap().clone()
} else {
' '
}
}
}
implement_lua_read!(World);
implement_lua_push!(World, |mut metatable| {
let mut index = metatable.empty_array("__index");
// index.set("__call", hlua::function4(|w: &mut World, x: i32, y: i32, c: char| w.set(&Point::new(x, y), c)))
index.set("width", hlua::function1(|w: &mut World| w.width() ));
index.set("height", hlua::function1(|w: &mut World| w.height() ));
index.set("set", hlua::function4(|w: &mut World, x: i32, y: i32, c: u8) w.set(&Point::new(x,y), c as char))
});
pub fn get_world(s: &str) -> World {
let make = |p: Point| World::new(p);
let cb = |p: &Point, c: char, world: &mut World| {
world.set(p, c)
};
make_grid_from_str(s, make, cb)
}
impl Display for World {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in 0..self.dim.x {
for j in 0..self.dim.y {
write!(f, "{}", self.get(&Point::new(i, j)))?;
}
write!(f, "\n")?;
}
Ok(())
}
}
fn main() {
let mut lua = Lua::new();
lua.openlibs();
let mut world = get_world("
.....
.....
..@..
.....
.....");
let mut state = State {
lua: lua,
world: world,
};
println!("{}", state.lua.execute::<u32>("return 6 * 4;").unwrap());
// we create a fill an array named `Sound` which will be used as a class-like interface
{
let mut world_namespace = state.lua.empty_array("World");
// creating the `World.new` function
world_namespace.set("new", hlua::function2(|x: i32, y: i32| World::new(Point::new(x, y))));
}
state.lua.set("w", state.world);
state.lua.execute::<()>(r#"
print("hello world from within lua!");
print("width", w:width());
print("height", w:height());
w:set(1, 1, 36)
"#).unwrap();
impl<'lua, L> hlua::LuaRead<L> for World
where L: hlua::AsMutLua<'lua>
{
fn lua_read_at_position(lua: L, index: i32) -> Result<World, L> {
let val: Result<hlua::UserdataOnStack<World, _>, _> =
hlua::LuaRead::lua_read_at_position(lua, index);
val.map(|d| d.clone())
}
}
let w: World = state.lua.get("w").unwrap();
println!("{}", w);
}
@surajprak
Copy link

how do i do this, when my struct has a Type field?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment