lucia_lang/objects/
conversion.rs

1use crate::{
2    errors::{Error, ErrorKind},
3    objects::{
4        AnyCallback, Closure, Function, GcError, Str, Table, TableEntries, TableState, Value,
5        ValueType,
6    },
7    Context,
8};
9
10impl<'gc> From<bool> for Value<'gc> {
11    fn from(v: bool) -> Value<'gc> {
12        Value::Bool(v)
13    }
14}
15
16impl<'gc> From<i64> for Value<'gc> {
17    fn from(v: i64) -> Value<'gc> {
18        Value::Int(v)
19    }
20}
21
22impl<'gc> From<f64> for Value<'gc> {
23    fn from(v: f64) -> Value<'gc> {
24        Value::Float(v)
25    }
26}
27
28impl<'gc> From<Str<'gc>> for Value<'gc> {
29    fn from(v: Str<'gc>) -> Value<'gc> {
30        Value::Str(v)
31    }
32}
33
34impl<'gc> From<Table<'gc>> for Value<'gc> {
35    fn from(v: Table<'gc>) -> Value<'gc> {
36        Value::Table(v)
37    }
38}
39
40impl<'gc> From<Function<'gc>> for Value<'gc> {
41    fn from(v: Function<'gc>) -> Value<'gc> {
42        Value::Function(v)
43    }
44}
45
46impl<'gc> From<Closure<'gc>> for Value<'gc> {
47    fn from(v: Closure<'gc>) -> Value<'gc> {
48        Value::Function(Function::Closure(v))
49    }
50}
51
52impl<'gc> From<AnyCallback<'gc>> for Value<'gc> {
53    fn from(v: AnyCallback<'gc>) -> Value<'gc> {
54        Value::Function(Function::Callback(v))
55    }
56}
57
58pub trait IntoValue<'gc> {
59    fn into_value(self, ctx: Context<'gc>) -> Value<'gc>;
60}
61
62impl<'gc, T: Into<Value<'gc>>> IntoValue<'gc> for T {
63    fn into_value(self, _ctx: Context<'gc>) -> Value<'gc> {
64        self.into()
65    }
66}
67
68impl<'gc> IntoValue<'gc> for &'static str {
69    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
70        Value::Str(Str::new(&ctx, self.to_string()))
71    }
72}
73
74impl<'gc> IntoValue<'gc> for String {
75    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
76        Value::Str(Str::new(&ctx, self))
77    }
78}
79
80impl<'gc, T: IntoValue<'gc>> IntoValue<'gc> for Option<T> {
81    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
82        match self {
83            Some(t) => t.into_value(ctx),
84            None => Value::Null,
85        }
86    }
87}
88
89impl<'gc> IntoValue<'gc> for TableEntries<'gc> {
90    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
91        Value::Table(Table::from(
92            &ctx,
93            TableState {
94                entries: self,
95                metatable: None,
96            },
97        ))
98    }
99}
100
101impl<'gc> IntoValue<'gc> for Error<'gc> {
102    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
103        Value::Error(GcError::new(&ctx, self))
104    }
105}
106
107impl<'gc, T: IntoValue<'gc>> IntoValue<'gc> for Vec<T> {
108    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
109        TableEntries::from_iter(self.into_iter().map(|x| x.into_value(ctx))).into_value(ctx)
110    }
111}
112
113impl<'gc, K: IntoValue<'gc>, V: IntoValue<'gc>> IntoValue<'gc> for Vec<(K, V)> {
114    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
115        TableEntries::from_iter(
116            self.into_iter()
117                .map(|(k, v)| (k.into_value(ctx), v.into_value(ctx))),
118        )
119        .into_value(ctx)
120    }
121}
122
123impl<'gc, const N: usize, T: IntoValue<'gc>> IntoValue<'gc> for [T; N] {
124    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
125        Value::Table(Table::from(
126            &ctx,
127            TableState {
128                entries: TableEntries::from_iter(self.into_iter().map(|x| x.into_value(ctx))),
129                metatable: None,
130            },
131        ))
132    }
133}
134
135impl<'gc, const N: usize, K: IntoValue<'gc>, V: IntoValue<'gc>> IntoValue<'gc> for [(K, V); N] {
136    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
137        TableEntries::from_iter(
138            self.into_iter()
139                .map(|(k, v)| (k.into_value(ctx), v.into_value(ctx))),
140        )
141        .into_value(ctx)
142    }
143}
144
145macro_rules! unexpected_type_error {
146    ($expected:expr, $found:expr) => {
147        Error::new(ErrorKind::UnexpectedType {
148            expected: $expected,
149            found: $found.value_type(),
150        })
151    };
152}
153
154pub trait FromValue<'gc>: Sized {
155    fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>>;
156}
157
158impl<'gc> FromValue<'gc> for Value<'gc> {
159    fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>> {
160        Ok(value)
161    }
162}
163
164impl<'gc, T: FromValue<'gc>> FromValue<'gc> for Option<T> {
165    fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>> {
166        Ok(if value.is_null() {
167            None
168        } else {
169            Some(T::from_value(value)?)
170        })
171    }
172}
173
174impl<'gc, T: FromValue<'gc>> FromValue<'gc> for Vec<T> {
175    fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>> {
176        if let Value::Table(table) = value {
177            (1..=table.len())
178                .map(|i| T::from_value(table.get_index(i).map_or(Value::Null, |x| x.1)))
179                .collect()
180        } else {
181            Err(unexpected_type_error!(ValueType::Table, value))
182        }
183    }
184}
185
186macro_rules! impl_int_from {
187    ($($i:ty),* $(,)?) => {
188        $(
189            impl<'gc> FromValue<'gc> for $i {
190                fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>> {
191                    if let Value::Int(i) = value {
192                        if let Ok(i) = <$i>::try_from(i) {
193                            Ok(i)
194                        } else {
195                            Err(unexpected_type_error!( ValueType::Int, value))
196                        }
197                    } else {
198                        Err(unexpected_type_error!( ValueType::Int, value))
199                    }
200                }
201            }
202        )*
203    };
204}
205impl_int_from!(i64, u64, i32, u32, i16, u16, i8, u8, isize, usize);
206
207macro_rules! impl_float_from {
208    ($($f:ty),* $(,)?) => {
209        $(
210            impl<'gc> FromValue<'gc> for $f {
211                fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>> {
212                    if let Value::Float(v) = value {
213                        Ok(v as $f)
214                    } else {
215                        Err(unexpected_type_error!(ValueType::Float, value))
216                    }
217                }
218            }
219        )*
220    };
221}
222impl_float_from!(f32, f64);
223
224macro_rules! impl_from {
225    ($([$e:ident $t:ty]),* $(,)?) => {
226        $(
227            impl<'gc> FromValue<'gc> for $t {
228                fn from_value( value: Value<'gc>) -> Result<Self, Error<'gc>> {
229                    if let Value::$e(v) = value {
230                        Ok(v)
231                    } else {
232                        Err(unexpected_type_error!(ValueType::$e, value))
233                    }
234                }
235            }
236        )*
237    };
238}
239impl_from! {
240    [Bool bool],
241    [Str Str<'gc>],
242    [Table Table<'gc>],
243    [Function Function<'gc>],
244}
245
246impl<'gc> FromValue<'gc> for Closure<'gc> {
247    fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>> {
248        match value {
249            Value::Function(Function::Closure(c)) => Ok(c),
250            _ => Err(unexpected_type_error!(ValueType::Function, value)),
251        }
252    }
253}
254
255impl<'gc> FromValue<'gc> for AnyCallback<'gc> {
256    fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>> {
257        match value {
258            Value::Function(Function::Callback(c)) => Ok(c),
259            _ => Err(unexpected_type_error!(ValueType::Function, value)),
260        }
261    }
262}
263
264impl<'gc> From<Value<'gc>> for bool {
265    fn from(value: Value) -> Self {
266        match value {
267            Value::Null => false,
268            Value::Bool(v) => v,
269            Value::Int(v) => v != 0,
270            Value::Float(v) => v != 0.0,
271            _ => true,
272        }
273    }
274}