neige_lua/value/
value.rs

1use std::{fmt::Debug, hash::Hash, rc::Rc};
2
3use neige_infra::{math::float_to_integer, Constant, LuaType, Prototype};
4use serde::{ser::SerializeMap, Serialize};
5
6use super::{
7    closure::{Closure, RustFn},
8    table::LuaTable,
9};
10
11#[derive(Clone)]
12pub enum LuaValue {
13    Nil,
14    Boolean(bool),
15    Integer(i64),
16    Number(f64),
17    Str(String),
18    Table(Rc<LuaTable>),
19    Function(Rc<Closure>),
20}
21
22impl LuaValue {
23    pub fn is_nil(&self) -> bool {
24        match self {
25            Self::Nil => true,
26            _ => false,
27        }
28    }
29
30    pub fn new_table(n_arr: usize, n_rec: usize) -> LuaValue {
31        LuaValue::Table(Rc::new(LuaTable::new(n_arr, n_rec)))
32    }
33
34    pub fn new_lua_closure(proto: Rc<Prototype>) -> LuaValue {
35        LuaValue::Function(Rc::new(Closure::new_lua_closure(proto)))
36    }
37
38    pub fn new_rust_closure(f: RustFn, n_upvals: usize) -> LuaValue {
39        LuaValue::Function(Rc::new(Closure::new_rust_closure(f, n_upvals)))
40    }
41
42    pub fn type_of(&self) -> LuaType {
43        match self {
44            LuaValue::Nil => LuaType::Nil,
45            LuaValue::Boolean(_) => LuaType::Boolean,
46            LuaValue::Integer(_) => LuaType::Number,
47            LuaValue::Number(_) => LuaType::Number,
48            LuaValue::Str(_) => LuaType::String,
49            LuaValue::Table(_) => LuaType::Table,
50            LuaValue::Function(_) => LuaType::Function,
51        }
52    }
53}
54
55impl LuaValue {
56    pub fn from_const(val: &Constant) -> Self {
57        match val {
58            Constant::Nil => LuaValue::Nil,
59            Constant::Boolean(b) => LuaValue::Boolean(*b),
60            Constant::Number(n) => LuaValue::Number(*n),
61            Constant::Integer(i) => LuaValue::Integer(*i),
62            Constant::Str(s) => LuaValue::Str(s.clone()),
63        }
64    }
65
66    pub fn convert_to_boolean(&self) -> bool {
67        match self {
68            LuaValue::Nil => false,
69            LuaValue::Boolean(b) => *b,
70            _ => true,
71        }
72    }
73
74    pub fn convert_to_integer(&self) -> Option<i64> {
75        match self {
76            LuaValue::Integer(i) => Some(*i),
77            LuaValue::Number(n) => float_to_integer(*n),
78            LuaValue::Str(s) => {
79                if let Ok(i) = s.parse() {
80                    Some(i)
81                } else {
82                    None
83                }
84            }
85            _ => None,
86        }
87    }
88
89    pub fn convert_to_float(&self) -> Option<f64> {
90        match self {
91            LuaValue::Integer(i) => Some(*i as f64),
92            LuaValue::Number(f) => Some(*f),
93            LuaValue::Str(s) => {
94                if let Ok(f) = s.parse() {
95                    Some(f)
96                } else {
97                    None
98                }
99            }
100            _ => None,
101        }
102    }
103}
104
105impl Debug for LuaValue {
106    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107        match self {
108            Self::Nil => write!(f, "(nil)"),
109            Self::Boolean(b) => write!(f, "({})", b),
110            Self::Integer(i) => write!(f, "({})", i),
111            Self::Number(n) => write!(f, "({})", n),
112            Self::Str(s) => write!(f, "({})", s),
113            Self::Table(_) => write!(f, "(table)"),
114            Self::Function(_) => write!(f, "(function)"),
115        }
116    }
117}
118
119impl PartialEq for LuaValue {
120    fn eq(&self, other: &Self) -> bool {
121        match (self, other) {
122            (Self::Nil, Self::Nil) => true,
123            (&Self::Boolean(x), &Self::Boolean(y)) => x == y,
124            (&Self::Integer(x), &Self::Integer(y)) => x == y,
125            (&Self::Integer(i), &Self::Number(f)) | (&Self::Number(f), &Self::Integer(i)) => {
126                i as f64 == f && f as i64 == i
127            }
128            (&Self::Number(x), &Self::Number(y)) => x == y,
129            (Self::Str(x), Self::Str(y)) => x == y,
130            (Self::Table(x), Self::Table(y)) => Rc::ptr_eq(x, y),
131            (Self::Function(x), Self::Function(y)) => Rc::ptr_eq(x, y),
132            _ => false,
133        }
134    }
135}
136impl Eq for LuaValue {}
137
138impl Hash for LuaValue {
139    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
140        match self {
141            LuaValue::Nil => (),
142            LuaValue::Boolean(b) => b.hash(state),
143            LuaValue::Integer(i) => i.hash(state),
144            &LuaValue::Number(f) => {
145                if let Some(i) = float_to_integer(f) {
146                    i.hash(state)
147                } else {
148                    (f.to_bits() as i64).hash(state)
149                }
150            }
151            LuaValue::Str(s) => s.hash(state),
152            LuaValue::Table(t) => t.as_ref().hash(state),
153            LuaValue::Function(f) => f.as_ref().hash(state),
154        }
155    }
156}
157
158impl Serialize for LuaValue {
159    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
160    where
161        S: serde::Serializer,
162    {
163        match self {
164            LuaValue::Nil => serializer.serialize_none(),
165            LuaValue::Boolean(b) => serializer.serialize_bool(*b),
166            LuaValue::Integer(i) => serializer.serialize_i64(*i),
167            LuaValue::Number(f) => serializer.serialize_f64(*f),
168            LuaValue::Str(s) => serializer.serialize_str(s),
169            LuaValue::Function(_) => panic!("function can not serialize"),
170            LuaValue::Table(table) => {
171                let map = table.map.borrow();
172                if map.len() == 0 {
173                    table.arr.borrow().serialize(serializer)
174                } else {
175                    let arr = table.arr.borrow();
176                    let mut obj = serializer.serialize_map(Some(map.len() + arr.len()))?;
177                    for (i, val) in arr.iter().enumerate() {
178                        obj.serialize_entry(&(i + 1).to_string(), val)?;
179                    }
180                    for (k, val) in map.iter() {
181                        obj.serialize_entry(k, val)?;
182                    }
183                    obj.end()
184                }
185            }
186        }
187    }
188}