1use crate::prelude::CaoLangTable;
2use crate::vm::runtime::cao_lang_object::{CaoLangObject, CaoLangObjectBody};
3use std::convert::{From, TryFrom};
4use std::ops::{Add, Div, Mul, Sub};
5use std::ptr::NonNull;
6
7#[derive(Default, Clone, Copy)]
8pub enum Value {
9 #[default]
10 Nil,
11 Object(NonNull<CaoLangObject>),
12 Integer(i64),
13 Real(f64),
14}
15
16impl std::fmt::Debug for Value {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 match self {
19 Self::Nil => write!(f, "Nil"),
20 Self::Object(arg0) => f
21 .debug_tuple("Object")
22 .field(&arg0)
23 .field(unsafe { arg0.as_ref() })
24 .finish(),
25 Self::Integer(arg0) => f.debug_tuple("Integer").field(arg0).finish(),
26 Self::Real(arg0) => f.debug_tuple("Real").field(arg0).finish(),
27 }
28 }
29}
30
31impl PartialOrd for Value {
32 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
33 let (this, other) = self.try_cast_match(*other);
34 match (this, other) {
35 (Value::Object(a), Value::Object(b)) => unsafe { a.as_ref().partial_cmp(b.as_ref()) },
36 (Value::Integer(a), Value::Integer(b)) => a.partial_cmp(&b),
37 (Value::Real(a), Value::Real(b)) => a.partial_cmp(&b),
38 _ => None,
39 }
40 }
41}
42
43impl std::hash::Hash for Value {
44 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
45 match self {
46 Value::Nil => 0u8.hash(state),
47 Value::Integer(i) => {
48 i.hash(state);
49 }
50 Value::Real(f) => {
51 f.to_bits().hash(state);
52 }
53 Value::Object(o) => unsafe {
54 o.as_ref().hash(state);
55 },
56 }
57 }
58}
59
60impl PartialEq for Value {
61 fn eq(&self, other: &Self) -> bool {
62 match (*self, *other) {
63 (Value::Nil, Value::Nil) => true,
64 (Value::Object(lhs), Value::Object(rhs)) => unsafe { lhs.as_ref().eq(rhs.as_ref()) },
65 (Value::Integer(lhs), Value::Integer(rhs)) => lhs == rhs,
66 (Value::Real(lhs), Value::Real(rhs)) => lhs == rhs,
67 _ => false,
68 }
69 }
70}
71
72impl Eq for Value {}
73
74#[derive(Default, Debug, Clone)]
109#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
110pub enum OwnedValue {
111 #[default]
112 Nil,
113 String(String),
114 Table(Vec<OwnedEntry>),
115 Integer(i64),
116 Real(f64),
117}
118
119#[derive(Debug, Clone)]
120#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
121pub struct OwnedEntry {
122 pub key: OwnedValue,
123 pub value: OwnedValue,
124}
125
126impl TryFrom<Value> for OwnedValue {
127 type Error = Value;
128
129 fn try_from(v: Value) -> Result<Self, Self::Error> {
130 let res = match v {
131 Value::Nil => Self::Nil,
132 Value::Object(ptr) => unsafe {
133 match &ptr.as_ref().body {
134 CaoLangObjectBody::Table(t) => {
135 let mut entries = Vec::with_capacity(t.len());
136 for (k, v) in t.iter() {
137 entries.push(OwnedEntry {
138 key: (*k).try_into()?,
139 value: (*v).try_into()?,
140 });
141 }
142 Self::Table(entries)
143 }
144 CaoLangObjectBody::String(s) => Self::String(s.as_str().to_owned()),
145 CaoLangObjectBody::Function(_)
146 | CaoLangObjectBody::Closure(_)
147 | CaoLangObjectBody::NativeFunction(_)
148 | CaoLangObjectBody::Upvalue(_) => {
149 return Err(v);
150 }
151 }
152 },
153 Value::Integer(x) => Self::Integer(x),
154 Value::Real(x) => Self::Real(x),
155 };
156 Ok(res)
157 }
158}
159
160impl Value {
161 #[inline]
162 pub fn as_bool(self) -> bool {
163 match self {
164 Value::Object(i) => unsafe { !i.as_ref().is_empty() },
165 Value::Integer(i) => i != 0,
166 Value::Real(i) => i != 0.0,
167 Value::Nil => false,
168 }
169 }
170
171 pub fn type_name(self) -> &'static str {
173 match self {
174 Value::Nil => "Nil",
175 Value::Object(o) => unsafe { o.as_ref().type_name() },
176 Value::Integer(_) => "Integer",
177 Value::Real(_) => "Real",
178 }
179 }
180
181 #[inline]
182 pub fn is_float(self) -> bool {
183 matches!(self, Value::Real(_))
184 }
185
186 pub unsafe fn as_str<'a>(self) -> Option<&'a str> {
196 match self {
197 Value::Object(o) => unsafe { o.as_ref().as_str() },
198 _ => None,
199 }
200 }
201
202 pub unsafe fn as_table<'a>(self) -> Option<&'a CaoLangTable> {
212 match self {
213 Value::Object(table) => table.as_ref().as_table(),
214 _ => None,
215 }
216 }
217
218 pub fn as_int(self) -> Option<i64> {
219 match self {
220 Value::Integer(x) => Some(x),
221 _ => None,
222 }
223 }
224
225 pub fn as_real(self) -> Option<f64> {
226 match self {
227 Value::Real(x) => Some(x),
228 _ => None,
229 }
230 }
231
232 #[inline]
233 pub fn is_obj(self) -> bool {
234 matches!(self, Value::Object(_))
235 }
236
237 #[inline]
238 pub fn is_integer(self) -> bool {
239 matches!(self, Value::Integer(_))
240 }
241
242 #[inline]
243 pub fn is_null(self) -> bool {
244 matches!(self, Value::Nil)
245 }
246
247 fn try_cast_match(self, other: Self) -> (Self, Self) {
249 if self.is_float() || other.is_float() {
250 if let Ok(a) = f64::try_from(self) {
251 if let Ok(b) = f64::try_from(other) {
252 return (Value::Real(a), Value::Real(b));
253 }
254 }
255 }
256 if self.is_integer() || other.is_integer() {
257 if let Ok(a) = i64::try_from(self) {
258 if let Ok(b) = i64::try_from(other) {
259 return (Value::Integer(a), Value::Integer(b));
260 }
261 }
262 }
263 (self, other)
264 }
265}
266
267impl TryFrom<Value> for &str {
268 type Error = Value;
269
270 fn try_from(value: Value) -> Result<Self, Self::Error> {
271 match value {
272 Value::Object(o) => unsafe { o.as_ref().as_str().ok_or(value) },
273 _ => Err(value),
274 }
275 }
276}
277
278impl From<Value> for bool {
279 fn from(s: Value) -> Self {
280 s.as_bool()
281 }
282}
283
284impl TryFrom<Value> for *mut CaoLangTable {
285 type Error = Value;
286
287 fn try_from(v: Value) -> Result<Self, Value> {
288 match v {
289 Value::Object(mut p) => unsafe {
290 match p.as_mut().as_table_mut() {
291 Some(t) => Ok(t as *mut _),
292 _ => Err(v),
293 }
294 },
295 _ => Err(v),
296 }
297 }
298}
299
300impl TryFrom<Value> for &CaoLangTable {
301 type Error = Value;
302
303 fn try_from(v: Value) -> Result<Self, Value> {
304 match v {
305 Value::Object(p) => unsafe { p.as_ref().as_table().ok_or(v) },
306 _ => Err(v),
307 }
308 }
309}
310
311impl TryFrom<Value> for &mut CaoLangTable {
312 type Error = Value;
313
314 fn try_from(v: Value) -> Result<Self, Value> {
315 match v {
316 Value::Object(mut p) => unsafe { p.as_mut().as_table_mut().ok_or(v) },
317 _ => Err(v),
318 }
319 }
320}
321
322impl TryFrom<Value> for i64 {
323 type Error = Value;
324
325 fn try_from(v: Value) -> Result<Self, Value> {
326 match v {
327 Value::Integer(i) => Ok(i),
328 Value::Real(r) => Ok(r as i64),
329 Value::Object(o) => Ok(unsafe { o.as_ref().len() as i64 }),
330 Value::Nil => Ok(0),
331 }
332 }
333}
334
335impl TryFrom<Value> for f64 {
336 type Error = Value;
337
338 fn try_from(v: Value) -> Result<Self, Value> {
339 match v {
340 Value::Real(i) => Ok(i),
341 Value::Integer(i) => Ok(i as f64),
342 Value::Object(o) => Ok(unsafe { o.as_ref().len() as f64 }),
343 Value::Nil => Ok(0.0),
344 }
345 }
346}
347
348impl From<i64> for Value {
349 fn from(i: i64) -> Self {
350 Value::Integer(i)
351 }
352}
353
354impl From<bool> for Value {
355 fn from(i: bool) -> Self {
356 Value::Integer(i as i64)
357 }
358}
359
360macro_rules! binary_op {
361 ($a: expr, $b: expr, $op: tt) => {
362 {
363 let (a, b) = $a.try_cast_match($b);
364 match (a, b) {
365 (Value::Integer(a), Value::Integer(b)) => {
366 Value::Integer(a $op b)
367 }
368 (Value::Real(a), Value::Real(b)) => Value::Real(a $op b),
369 _ => Value::Nil
370 }
371 }
372 }
373}
374
375impl Add for Value {
376 type Output = Self;
377
378 fn add(self, other: Self) -> Self {
379 binary_op!(self, other, +)
380 }
381}
382
383impl Sub for Value {
384 type Output = Self;
385
386 fn sub(self, other: Self) -> Self {
387 binary_op!(self, other, -)
388 }
389}
390
391impl Mul for Value {
392 type Output = Self;
393
394 fn mul(self, other: Self) -> Self {
395 binary_op!(self, other, *)
396 }
397}
398
399impl Div for Value {
400 type Output = Self;
401
402 fn div(self, other: Self) -> Self {
403 let (a, b) = self.try_cast_match(other);
404 match (a, b) {
405 (Value::Integer(a), Value::Integer(b)) => Value::Real(a as f64 / b as f64),
406 (Value::Real(a), Value::Real(b)) => Value::Real(a / b),
407 _ => Value::Nil,
408 }
409 }
410}
411
412impl std::borrow::Borrow<str> for Value {
413 fn borrow(&self) -> &str {
414 match self {
415 Value::Object(s) => unsafe { s.as_ref().as_str().unwrap_or("") },
416 _ => "",
417 }
418 }
419}
420
421impl std::borrow::Borrow<i64> for Value {
422 fn borrow(&self) -> &i64 {
423 match self {
424 Value::Integer(i) => i,
425 _ => &(!0),
426 }
427 }
428}
429
430pub struct Nilable<T>(pub Option<T>);
433
434impl<T> TryFrom<Value> for Nilable<T>
435where
436 T: TryFrom<Value>,
437{
438 type Error = Value;
439
440 fn try_from(value: Value) -> Result<Self, Self::Error> {
441 match value {
442 Value::Nil => Ok(Nilable(None)),
443 _ => {
444 let res = value.try_into().map_err(|_| value)?;
445 Ok(Nilable(Some(res)))
446 }
447 }
448 }
449}