mlua-periphery 1.2.4

A Rust-native implementation of lua-periphery for mlua.
mod transfer;

#[cfg(test)]
pub mod integration_tests;

use mlua::prelude::LuaError;
use mlua::{Error, IntoLua, Lua, MultiValue, Number, Table, UserData, UserDataFields, UserDataMethods, Value};

#[repr(u16)]
#[derive(Copy, Clone)]
enum Const {
    Ten = 0x0010,
    Rd = 0x0001,
    Stop = 0x8000,
    Nostart = 0x4000,
    RevDirAddr = 0x2000,
    IgnoreNak = 0x1000,
    NoRdAck = 0x0800,
    RecvLen = 0x0400,
}

impl IntoLua for Const {
    fn into_lua(self, _lua: &Lua) -> Result<Value, LuaError> {
        Ok(Value::Number(Number::from(self as u16)))
    }
}

#[derive(Clone)]
struct I2c {
    #[allow(dead_code)]
    device: String,
}

impl UserData for I2c {
    fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
        methods.add_method("close", |_, _i2c, ()| Ok(()));
        methods.add_method("transfer", transfer::handle);
    }
    fn add_fields<F: UserDataFields<Self>>(_fields: &mut F) {
        // fields.add_field_method_get("name", |_, led| Ok(led.device.clone()));
    }
}

pub fn preload(lua: &Lua) -> Result<(), Error> {
    // Configure module table
    let module = lua.create_table()?;
    module.raw_set("I2C_M_TEN", Const::Ten)?;
    module.raw_set("I2C_M_RD", Const::Rd)?;
    module.raw_set("I2C_M_STOP", Const::Stop)?;
    module.raw_set("I2C_M_NOSTART", Const::Nostart)?;
    module.raw_set("I2C_M_REV_DIR_ADDR", Const::RevDirAddr)?;
    module.raw_set("I2C_M_IGNORE_NAK", Const::IgnoreNak)?;
    module.raw_set("I2C_M_NO_RD_ACK", Const::NoRdAck)?;
    module.raw_set("I2C_M_RECV_LEN", Const::RecvLen)?;

    // Configure module metatable
    let metatable = lua.create_table()?;
    metatable.set(
        "__call",
        lua.create_function(|_, args: MultiValue| {
            let device = args[1].to_string()?;
            Ok(I2c { device })
        })?,
    )?;
    module.set_metatable(Some(metatable))?;

    // Preload module
    let globals = lua.globals();
    let package: Table = globals.get("package")?;
    let loaded: Table = package.get("loaded")?;
    loaded.set("periphery.I2C", module)?;

    Ok(())
}

#[cfg(test)]
mod tests {
    use mlua::Lua;
    use std::error::Error;

    #[test]
    fn preload() -> Result<(), Box<dyn Error>> {
        let lua = Lua::new();
        super::preload(&lua)?;
        lua.load("local I2C = require('periphery.I2C')").exec()?;
        Ok(())
    }
}