Skip to main content

luna_core/vm/
into_value.rs

1//! `IntoValue` trait (B4, Phase 2 P2-B) — convert Rust primitive
2//! types into Lua `Value`s through a `&mut Vm` (so string-shaped
3//! conversions can intern through the heap).
4//!
5//! ```
6//! use luna_core::vm::Vm;
7//! use luna_core::version::LuaVersion;
8//! use luna_core::runtime::Value;
9//!
10//! let mut vm = Vm::sandbox(LuaVersion::Lua55).open_base().build();
11//! vm.set_global("answer", 42).unwrap();
12//! vm.set_global("name", "luna").unwrap();
13//! let r = vm.eval("return answer, name").unwrap();
14//! assert_eq!(r.len(), 2);
15//! ```
16//!
17//! Built-in implementations cover the common cases:
18//! `Value` (identity), `()` (Nil), `bool`, `i64` / `i32` / `i16` /
19//! `i8` / `u32` / `u16` / `u8`, `f64` / `f32`, `&str` / `String`,
20//! `&[u8]` / `Vec<u8>`, `Gc<Table>`, `Gc<LuaClosure>`,
21//! `Gc<NativeClosure>`, and `Option<T> where T: IntoValue`.
22//!
23//! Embedders who want their own host types to flow into `Value`
24//! either implement `IntoValue` directly (when they own the type)
25//! or write a `From<MyType> for Value` impl and use it explicitly
26//! at call sites.
27
28use crate::runtime::heap::Gc;
29use crate::runtime::value::Value;
30use crate::runtime::{LuaClosure, NativeClosure, Table};
31use crate::vm::exec::Vm;
32
33/// Convert `self` into a Lua `Value`, possibly interning through
34/// the `Vm`'s heap (for string-shaped types).
35pub trait IntoValue {
36    /// Convert `self` to a Lua [`Value`], interning strings or allocating
37    /// other GC-managed types via `vm.heap` as needed.
38    fn into_value(self, vm: &mut Vm) -> Value;
39}
40
41// Identity + nil
42impl IntoValue for Value {
43    #[inline]
44    fn into_value(self, _vm: &mut Vm) -> Value {
45        self
46    }
47}
48
49impl IntoValue for () {
50    #[inline]
51    fn into_value(self, _vm: &mut Vm) -> Value {
52        Value::Nil
53    }
54}
55
56// Integers
57impl IntoValue for i64 {
58    #[inline]
59    fn into_value(self, _vm: &mut Vm) -> Value {
60        Value::Int(self)
61    }
62}
63
64macro_rules! impl_into_value_int {
65    ($($t:ty),+ $(,)?) => {
66        $(
67            impl IntoValue for $t {
68                #[inline]
69                fn into_value(self, _vm: &mut Vm) -> Value {
70                    Value::Int(self as i64)
71                }
72            }
73        )+
74    };
75}
76impl_into_value_int!(i32, i16, i8, u32, u16, u8);
77
78// Floats
79impl IntoValue for f64 {
80    #[inline]
81    fn into_value(self, _vm: &mut Vm) -> Value {
82        Value::Float(self)
83    }
84}
85impl IntoValue for f32 {
86    #[inline]
87    fn into_value(self, _vm: &mut Vm) -> Value {
88        Value::Float(self as f64)
89    }
90}
91
92// Bool
93impl IntoValue for bool {
94    #[inline]
95    fn into_value(self, _vm: &mut Vm) -> Value {
96        Value::Bool(self)
97    }
98}
99
100// Strings — intern through the heap
101impl IntoValue for &str {
102    #[inline]
103    fn into_value(self, vm: &mut Vm) -> Value {
104        Value::Str(vm.heap.intern(self.as_bytes()))
105    }
106}
107impl IntoValue for String {
108    #[inline]
109    fn into_value(self, vm: &mut Vm) -> Value {
110        Value::Str(vm.heap.intern(self.as_bytes()))
111    }
112}
113impl IntoValue for &[u8] {
114    #[inline]
115    fn into_value(self, vm: &mut Vm) -> Value {
116        Value::Str(vm.heap.intern(self))
117    }
118}
119impl IntoValue for Vec<u8> {
120    #[inline]
121    fn into_value(self, vm: &mut Vm) -> Value {
122        Value::Str(vm.heap.intern(&self))
123    }
124}
125
126// Gc handles — already a Value variant directly
127impl IntoValue for Gc<Table> {
128    #[inline]
129    fn into_value(self, _vm: &mut Vm) -> Value {
130        Value::Table(self)
131    }
132}
133impl IntoValue for Gc<LuaClosure> {
134    #[inline]
135    fn into_value(self, _vm: &mut Vm) -> Value {
136        Value::Closure(self)
137    }
138}
139impl IntoValue for Gc<NativeClosure> {
140    #[inline]
141    fn into_value(self, _vm: &mut Vm) -> Value {
142        Value::Native(self)
143    }
144}
145
146// Option<T> — None -> Nil, Some -> inner
147impl<T: IntoValue> IntoValue for Option<T> {
148    #[inline]
149    fn into_value(self, vm: &mut Vm) -> Value {
150        match self {
151            Some(v) => v.into_value(vm),
152            None => Value::Nil,
153        }
154    }
155}