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}