neige-lua 0.1.3

一个简单的lua运行时
Documentation
use std::rc::Rc;

use neige_infra::LuaType;

use crate::{
    state::LuaState,
    value::{closure::RustFn, table::LuaTable, value::LuaValue},
};

use super::CallApi;

pub trait AccessApi {
    fn tp_name(&self, tp: LuaType) -> String;
    fn ty_id(&self, idx: isize) -> LuaType;
    fn is_none(&self, idx: isize) -> bool;
    fn is_nil(&self, idx: isize) -> bool;
    fn is_none_or_nil(&self, idx: isize) -> bool;
    fn is_boolean(&self, idx: isize) -> bool;
    fn is_integer(&self, idx: isize) -> bool;
    fn is_number(&self, idx: isize) -> bool;
    fn is_string(&self, idx: isize) -> bool;
    fn is_rust_fn(&self, idx: isize) -> bool;
    fn is_lua_tbl(&self, idx: isize) -> bool;
    fn to_boolean(&self, idx: isize) -> bool;
    fn to_integer(&self, idx: isize) -> i64;
    fn to_integer_x(&self, idx: isize) -> Option<i64>;
    fn to_number(&self, idx: isize) -> f64;
    fn to_number_x(&self, idx: isize) -> Option<f64>;
    fn to_string(&mut self, idx: isize) -> String;
    fn to_string_x(&mut self, idx: isize) -> Option<String>;
    fn to_rust_fn(&self, idx: isize) -> Option<RustFn>;
    fn to_lua_tbl(&self, idx: isize) -> Option<Rc<LuaTable>>;
    fn raw_len(&self, idx: isize) -> usize;
}

impl AccessApi for LuaState {
    /// 获取类型名
    fn tp_name(&self, tp: LuaType) -> String {
        let name = match tp {
            LuaType::None => "no value",
            LuaType::Nil => "nil",
            LuaType::Boolean => "boolean",
            LuaType::LightUserData => "light user data",
            LuaType::Number => "number",
            LuaType::String => "string",
            LuaType::Table => "table",
            LuaType::Function => "function",
            LuaType::UserData => "user data",
            LuaType::Thread => "thread",
            LuaType::Integer => "integer",
        };
        name.into()
    }

    fn ty_id(&self, idx: isize) -> neige_infra::LuaType {
        if self.stack_is_valid(idx) {
            self.stack_get(idx).type_of()
        } else {
            LuaType::None
        }
    }

    fn is_none(&self, idx: isize) -> bool {
        self.ty_id(idx) == LuaType::None
    }

    fn is_nil(&self, idx: isize) -> bool {
        self.ty_id(idx) == LuaType::Nil
    }

    fn is_none_or_nil(&self, idx: isize) -> bool {
        self.is_nil(idx) || self.is_none(idx)
    }

    fn is_boolean(&self, idx: isize) -> bool {
        self.ty_id(idx) == LuaType::Boolean
    }

    fn is_integer(&self, idx: isize) -> bool {
        self.ty_id(idx) == LuaType::Integer
    }

    fn is_number(&self, idx: isize) -> bool {
        self.ty_id(idx) == LuaType::Number
    }

    fn is_string(&self, idx: isize) -> bool {
        let t = self.ty_id(idx);
        t == LuaType::String || t == LuaType::Number
    }

    fn is_rust_fn(&self, idx: isize) -> bool {
        let val = self.stack_get(idx);
        if let LuaValue::Function(f) = val {
            if let Some(_) = f.rust_fn {
                return true;
            }
        }
        return false;
    }

    fn is_lua_tbl(&self, idx: isize) -> bool {
        self.ty_id(idx) == LuaType::Table
    }

    fn to_boolean(&self, idx: isize) -> bool {
        self.stack_get(idx).convert_to_boolean()
    }

    fn to_integer(&self, idx: isize) -> i64 {
        self.to_integer_x(idx).unwrap_or(0)
    }

    fn to_integer_x(&self, idx: isize) -> Option<i64> {
        self.stack_get(idx).convert_to_integer()
    }

    fn to_number(&self, idx: isize) -> f64 {
        self.to_number_x(idx).unwrap_or(0.0)
    }

    fn to_number_x(&self, idx: isize) -> Option<f64> {
        self.stack_get(idx).convert_to_float()
    }

    fn to_string(&mut self, idx: isize) -> String {
        self.to_string_x(idx).unwrap_or(format!(""))
    }

    fn to_string_x(&mut self, idx: isize) -> Option<String> {
        let val = self.stack_get(idx);
        match val {
            LuaValue::Integer(i) => {
                let s = format!("{}", i);
                self.stack_set(idx, LuaValue::Str(s.clone()));
                Some(s)
            }
            LuaValue::Number(f) => {
                let s = format!("{}", f);
                self.stack_set(idx, LuaValue::Str(s.clone()));
                Some(s)
            }
            LuaValue::Str(s) => Some(s),
            LuaValue::Table(_) => {
                if let LuaValue::Function(c) = self.inline_get_meta_field(&val, "__tostring") {
                    self.stack_push(LuaValue::Function(c));
                    self.stack_push(val);
                    self.call(1, 1);
                    if let LuaValue::Str(s) = self.stack_get(-1) {
                        return Some(s);
                    }
                }
                None
            }
            _ => None,
        }
    }

    fn to_rust_fn(&self, idx: isize) -> Option<RustFn> {
        let val = self.stack_get(idx);
        if let LuaValue::Function(f) = val {
            if let Some(f) = &f.rust_fn {
                return Some(*f);
            }
        }
        None
    }

    fn to_lua_tbl(&self, idx: isize) -> Option<Rc<LuaTable>> {
        let val = self.stack_get(idx);
        if let LuaValue::Table(tbl) = val {
            Some(tbl)
        } else {
            None
        }
    }

    fn raw_len(&self, idx: isize) -> usize {
        let val = self.stack_get(idx);
        match val {
            LuaValue::Str(s) => s.len(),
            LuaValue::Table(t) => t.as_ref().arr.borrow().len(),
            _ => 0,
        }
    }
}