mlua-periphery 1.2.4

A Rust-native implementation of lua-periphery for mlua.
#![allow(dead_code)]

use log::warn;
use mlua::{Error, FromLua, Lua, Table};
use std::time::Duration;
use std::{env, thread};

const GPIO_CHIP: &str = "GPIO_CHIP";
const GPIO_LINE_IN: &str = "GPIO_LINE_IN";
const GPIO_LINE_OUT: &str = "GPIO_LINE_OUT";

const I2C_DEVICE: &str = "I2C_DEVICE";

const SERIAL_DEVICE: &str = "SERIAL_DEVICE";

pub fn preload(lua: &Lua) -> Result<(), Error> {
    // Configure module table
    let module = lua.create_table()?;
    module.raw_set(
        "sleep",
        lua.create_function(|lua, arg: mlua::Value| {
            let dur = Duration::from_secs_f64(f64::from_lua(arg, lua)?);
            thread::sleep(dur);
            Ok(())
        })?,
    )?;

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

    Ok(())
}

pub fn get_gpio_chip() -> Result<(bool, String), Box<dyn std::error::Error>> {
    let chip = match env::var(GPIO_CHIP) {
        Ok(ok) => ok,
        Err(_e) => {
            log::warn!("Skipping test because no {GPIO_CHIP} is set");
            return Ok((true, "".to_string()));
        }
    };
    Ok((false, chip))
}

pub fn get_gpio_line_in() -> Result<(bool, String), Box<dyn std::error::Error>> {
    let line_in = match env::var(GPIO_LINE_IN) {
        Ok(line) => line,
        Err(_e) => {
            log::warn!("Skipping test because no {GPIO_LINE_IN} is set");
            return Ok((true, "".to_string()));
        }
    };
    Ok((false, line_in))
}

pub fn get_gpio_line_out() -> Result<(bool, String), Box<dyn std::error::Error>> {
    let line_out = match env::var(GPIO_LINE_OUT) {
        Ok(line) => line,
        Err(_e) => {
            log::warn!("Skipping test because no {GPIO_LINE_OUT} is set");
            return Ok((true, "".to_string()));
        }
    };
    Ok((false, line_out))
}

pub fn get_i2c_device() -> Result<(bool, String), Box<dyn std::error::Error>> {
    let dev = match env::var(I2C_DEVICE) {
        Ok(dev) => dev,
        Err(_) => {
            warn!("Skipping test because no {I2C_DEVICE} is set");
            return Ok((true, "".to_string()));
        }
    };
    Ok((false, dev))
}

pub fn get_serial_device() -> Result<(bool, String), Box<dyn std::error::Error>> {
    let dev = match env::var(SERIAL_DEVICE) {
        Ok(dev) => dev,
        Err(_) => {
            warn!("Skipping test because no {SERIAL_DEVICE} is set");
            return Ok((true, "".to_string()));
        }
    };
    Ok((false, dev))
}

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

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

    #[test]
    fn sleep() -> Result<(), Box<dyn Error>> {
        let lua = Lua::new();
        super::preload(&lua)?;
        let start_time = Instant::now();
        lua.load(
            r#"
                local testsupport = require('testsupport')
                testsupport.sleep(0.2)
            "#,
        )
        .exec()?;
        let elapsed = start_time.elapsed();
        assert!(elapsed.as_millis() > 190);
        assert!(elapsed.as_millis() < 400);
        Ok(())
    }
}