use std::{
collections::{VecDeque, vec_deque},
fmt,
ops::{Deref, DerefMut},
};
use crate::lua::{
self, FromLuaMulti, Result, ToLuaMulti, ffi,
traits::{FromLua, ToLua},
value_ref::ValueRef,
};
#[derive(Clone, Debug)]
pub struct Value {
pub(crate) inner: ValueRef,
}
#[repr(i32)]
#[non_exhaustive]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ValueKind {
None = -1,
Nil = 0,
Bool,
LightUserData,
Number,
String,
Table,
Function,
UserData,
Thread,
Entity,
Vector,
Angle,
PhysObj,
Save,
Restore,
DamageInfo,
EffectData,
MoveData,
RecipientFilter,
UserCmd,
ScriptedVehicle,
Material,
Panel,
Particle,
ParticleEmitter,
Texture,
UserMsg,
ConVar,
IMesh,
Matrix,
Sound,
PixelVisHandle,
DLight,
Video,
File,
Locomotion,
Path,
NavArea,
SoundHandle,
NavLadder,
ParticleSystem,
ProjectedTexture,
PhysCollide,
SurfaceInfo,
TypeCount,
}
impl ValueKind {
#[must_use]
#[inline]
pub fn from_i32(id: i32) -> Self {
assert!(
id >= Self::None as i32 && id < Self::TypeCount as i32,
"Invalid lua type id: {id}"
);
unsafe { std::mem::transmute(id) }
}
#[must_use]
pub const fn as_str(&self) -> &'static str {
match self {
Self::None => "none",
Self::Nil => "nil",
Self::Bool => "boolean",
Self::LightUserData => "lightuserdata",
Self::Number => "number",
Self::String => "string",
Self::Table => "table",
Self::Function => "function",
Self::UserData => "userdata",
Self::Thread => "thread",
Self::Entity => "entity",
Self::Vector => "vector",
Self::Angle => "angle",
Self::PhysObj => "physobj",
Self::Save => "save",
Self::Restore => "restore",
Self::DamageInfo => "damageinfo",
Self::EffectData => "effectdata",
Self::MoveData => "movedata",
Self::RecipientFilter => "recipientfilter",
Self::UserCmd => "usercmd",
Self::ScriptedVehicle => "scriptedvehicle",
Self::Material => "material",
Self::Panel => "panel",
Self::Particle => "particle",
Self::ParticleEmitter => "particleemitter",
Self::Texture => "texture",
Self::UserMsg => "usermsg",
Self::ConVar => "convar",
Self::IMesh => "imesh",
Self::Matrix => "matrix",
Self::Sound => "sound",
Self::PixelVisHandle => "pixelvishandle",
Self::DLight => "dlight",
Self::Video => "video",
Self::File => "file",
Self::Locomotion => "locomotion",
Self::Path => "path",
Self::NavArea => "navarea",
Self::SoundHandle => "soundhandle",
Self::NavLadder => "navladder",
Self::ParticleSystem => "particlesystem",
Self::ProjectedTexture => "projectedtexture",
Self::PhysCollide => "physcollide",
Self::SurfaceInfo => "surfaceinfo",
_ => "unknown",
}
}
}
impl fmt::Display for ValueKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Value {
#[must_use]
pub fn from_stack(l: &lua::State, index: i32) -> Self {
ffi::lua_pushvalue(l.0, index);
Self::pop_from_stack(l)
}
#[must_use]
pub fn pop_from_stack(l: &lua::State) -> Self {
let type_id = ffi::lua_type(l.0, -1);
Self {
inner: ValueRef::pop_from(l, type_id),
}
}
#[must_use]
pub fn type_id(&self) -> i32 {
self.inner.type_id()
}
#[must_use]
pub fn type_kind(&self) -> ValueKind {
ValueKind::from_i32(self.type_id())
}
#[must_use]
pub fn type_name(&self) -> &'static str {
self.type_kind().as_str()
}
pub fn to<T: FromLua>(self, l: &lua::State) -> Result<T> {
T::try_from_value(self, l)
}
pub fn push_to_stack(&self, l: &lua::State) {
self.inner.push(l);
}
pub(crate) fn index(&self) -> i32 {
self.inner.index()
}
pub(crate) fn ref_state(&self) -> lua::State {
self.inner.ref_state()
}
pub(crate) fn leak_index(self) -> i32 {
self.inner.leak_index()
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Value of type {} ({})", self.type_name(), self.type_id())
}
}
impl ToLua for Value {
fn push_to_stack(self, l: &lua::State) {
Self::push_to_stack(&self, l);
}
fn to_value(self, _: &lua::State) -> Self {
self
}
}
impl ToLua for &Value {
fn push_to_stack(self, l: &lua::State) {
Value::push_to_stack(self, l);
}
fn to_value(self, _: &lua::State) -> Value {
self.clone()
}
}
impl FromLua for Value {
fn try_from_stack(l: &lua::State, index: i32) -> Result<Self> {
Ok(Self::from_stack(l, index))
}
fn try_from_value(value: Value, _: &lua::State) -> Result<Self> {
Ok(value)
}
}
#[derive(Default, Debug, Clone)]
pub struct MultiValue(VecDeque<Value>);
impl Deref for MultiValue {
type Target = VecDeque<Value>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for MultiValue {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl MultiValue {
#[must_use]
#[inline]
pub const fn new() -> Self {
Self(VecDeque::new())
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self(VecDeque::with_capacity(capacity))
}
#[must_use]
#[inline]
pub fn from_vec(vec: Vec<Value>) -> Self {
vec.into()
}
#[must_use]
#[inline]
pub fn into_vec(self) -> Vec<Value> {
self.into()
}
#[allow(unused)]
#[inline]
pub(crate) fn from_lua_iter<T: ToLua>(
l: &lua::State,
iter: impl IntoIterator<Item = T>,
) -> Self {
let iter = iter.into_iter();
let mut multi_value = Self::with_capacity(iter.size_hint().0);
for value in iter {
multi_value.push_back(value.to_value(l));
}
multi_value
}
}
impl From<Vec<Value>> for MultiValue {
#[inline]
fn from(value: Vec<Value>) -> Self {
Self(value.into())
}
}
impl From<MultiValue> for Vec<Value> {
#[inline]
fn from(value: MultiValue) -> Self {
value.0.into()
}
}
impl FromIterator<Value> for MultiValue {
#[inline]
fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
let mut multi_value = Self::new();
multi_value.extend(iter);
multi_value
}
}
impl IntoIterator for MultiValue {
type Item = Value;
type IntoIter = vec_deque::IntoIter<Value>;
#[inline]
fn into_iter(mut self) -> Self::IntoIter {
let deque = std::mem::take(&mut self.0);
std::mem::forget(self);
deque.into_iter()
}
}
impl ToLuaMulti for MultiValue {
fn push_to_stack_multi(self, l: &lua::State) {
for value in self {
value.push_to_stack(l);
}
}
fn push_to_stack_multi_count(self, l: &lua::State) -> i32 {
let count = self.0.len() as i32;
for value in self {
value.push_to_stack(l);
}
count
}
}
impl ToLuaMulti for &MultiValue {
fn push_to_stack_multi(self, l: &lua::State) {
for value in self.iter() {
value.push_to_stack(l);
}
}
fn push_to_stack_multi_count(self, l: &lua::State) -> i32 {
let count = self.0.len() as i32;
for value in self.iter() {
value.push_to_stack(l);
}
count
}
}
impl FromLuaMulti for MultiValue {
fn try_from_stack_multi(l: &lua::State, start_index: i32, count: i32) -> Result<(Self, i32)> {
let mut multi_value = Self::with_capacity(count as usize);
for i in 0..count {
multi_value.push_back(Value::from_stack(l, start_index + i));
}
Ok((multi_value, count))
}
}