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}