mlua-periphery 1.2.4

A Rust-native implementation of lua-periphery for mlua.
use super::Gpio;
use super::configure::{configure_event_request_flags, configure_line_request_flags};
use gpio_cdev::{Chip, LineEventHandle};
use mlua::{Error, FromLua, Lua, Table, Value};
use std::sync::{Arc, Mutex};

pub(super) fn handle(lua: &Lua, args: mlua::MultiValue) -> Result<Gpio, Error> {
    // Establish defaults
    let mut bias = String::default();
    let mut drive = String::default();
    let mut edge = String::default();
    let mut inverted = false;
    let mut label = String::default();

    let args: Vec<Value> = args.into_iter().collect();
    let (path, line_num, direction): (String, u32, String) = match args.len() {
        2 => {
            let table: Table = Table::from_lua(args[1].clone(), lua)?;

            // Required keys
            let path: String = table.get("path")?;
            let line = table.get("line")?;
            let direction: String = table.get("direction")?;

            // Optional keys
            if table.contains_key("bias")? {
                bias = table.get("bias")?;
            }
            if table.contains_key("drive")? {
                drive = table.get("drive")?;
            }
            if table.contains_key("edge")? {
                edge = table.get("edge")?;
            }
            if table.contains_key("inverted")? {
                inverted = table.get("inverted")?;
            }
            if table.contains_key("label")? {
                label = table.get("label")?;
            }

            Ok((path, line, direction))
        }
        4 => {
            let path = String::from_lua(args[1].clone(), lua)?;
            let line = u32::from_lua(args[2].clone(), lua)?;
            let direction = String::from_lua(args[3].clone(), lua)?;
            Ok((path, line, direction))
        }
        _ => Err(Error::RuntimeError("Unsupported args".to_string())),
    }?;

    // Get chip
    let chip = Arc::new(Mutex::new(
        Chip::new(path).map_err(|err| Error::RuntimeError(err.to_string()))?,
    ));

    // Get line
    let line = chip
        .lock()
        .map_err(|err| Error::RuntimeError(err.to_string()))?
        .get_line(line_num)
        .map_err(|err| Error::RuntimeError(err.to_string()))?;

    // Get line event handle, when appropriate
    let line_events: Option<LineEventHandle> = {
        match configure_line_request_flags(&direction) {
            Err(_e) => None,
            Ok(line_request_flags) => match configure_event_request_flags(&edge) {
                Err(_e) => None,
                Ok(event_request_flags) => Some(
                    line.events(line_request_flags, event_request_flags, "periphery:read_event()")
                        .map_err(|err| Error::RuntimeError(err.to_string()))?,
                ),
            },
        }
    };

    Ok(Gpio {
        bias: Arc::new(Mutex::new(bias)),
        chip,
        direction: Arc::new(Mutex::new(direction)),
        drive: Arc::new(Mutex::new(drive)),
        edge: Arc::new(Mutex::new(edge)),
        inverted: Arc::new(Mutex::new(inverted)),
        label: Arc::new(Mutex::new(label)),
        line: Arc::new(Mutex::new(line)),
        line_events: Arc::new(Mutex::new(line_events)),
        line_num,
    })
}