torchbear 0.11.5

Lua programming environment in Rust
use rlua::prelude::*;
use std::{
    mem,
    io::{Cursor, SeekFrom, prelude::*}
};
use serde_json;
use rlua_serde;

//TODO: Move to having a common interface so IO can share the same binding
pub struct LuaMemory(Cursor<Vec<u8>>);

impl LuaUserData for LuaMemory {
    fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
        methods.add_method_mut("read", |_, this: &mut LuaMemory, len: Option<usize>|{
            let bytes = match len {
                Some(len) => {
                    let mut bytes = vec![0u8; len];
                    this.0.read(&mut bytes).map_err(LuaError::external)?;
                    bytes
                },
                None => {
                    let mut bytes = vec![];
                    this.0.read_to_end(&mut bytes).map_err(LuaError::external)?;
                    bytes
                }
            };
            Ok(bytes)
        });
        methods.add_method_mut("read_to_string", |_, this: &mut LuaMemory, _: ()|{
            let mut data = String::new();
            this.0.read_to_string(&mut data).map_err(LuaError::external)?;
            Ok(data)
        });
        methods.add_method_mut("write", |_, this: &mut LuaMemory, bytes: Vec<u8>|{
            Ok(this.0.write(bytes.as_slice()).map_err(LuaError::external)?)
        });
        methods.add_method_mut("write", |_, this: &mut LuaMemory, str: String|{
            Ok(this.0.write(str.as_bytes()).map_err(LuaError::external)?)
        });
        methods.add_method_mut("flush", |_, this: &mut LuaMemory, _: ()|{
            Ok(this.0.flush().map_err(LuaError::external)?)
        });
        methods.add_method_mut("clear", |_, this: &mut LuaMemory, _: ()|{
            mem::replace(&mut this.0, Cursor::new(Vec::new()));
            Ok(())
        });
        methods.add_method_mut("seek", |_, this: &mut LuaMemory, (pos, size): (Option<String>, Option<usize>)| {
            let size = size.unwrap_or(0);

            let seekfrom = pos.and_then(|s_pos| {
                Some(match s_pos.as_ref() {
                    "start" => SeekFrom::Start(size as u64),
                    "end" => SeekFrom::End(size as i64),
                    "current" | _ => SeekFrom::Current(size as i64),
                })
            }).unwrap_or(SeekFrom::Current(size as i64));
            Ok(this.0.seek(seekfrom).map_err(LuaError::external)?)
        });
        methods.add_method_mut("dump", |_, this: &mut LuaMemory, _: ()|{
            Ok(this.0.clone().into_inner())
        });
    }
}

pub fn init(lua: &Lua) -> crate::Result<()> {

    let module = lua.create_table()?;

    module.set("new", lua.create_function( |_, _: ()| {
        Ok(LuaMemory(Cursor::new(Vec::new())))
    })?  )?;

    lua.globals().set("memory", module)?;

    Ok(())
}