ion/conversions/value/
to.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6
7use std::borrow::Cow;
8use std::ptr::NonNull;
9use std::rc::Rc;
10use std::time::SystemTime;
11
12use chrono::DateTime;
13use mozjs::jsapi::{
14	JS_GetFunctionObject, JS_IdToValue, JS_NewStringCopyN, JS_WrapValue, JSFunction, JSObject, JSString,
15	PropertyKey as JSPropertyKey, Symbol as JSSymbol,
16};
17use mozjs::jsval::{
18	BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, ObjectOrNullValue, ObjectValue, StringValue, SymbolValue,
19	UInt32Value, UndefinedValue,
20};
21use mozjs::rust::{maybe_wrap_object_or_null_value, maybe_wrap_object_value, maybe_wrap_value};
22use mozjs::typedarray as jsta;
23
24use crate::object::RegExp;
25use crate::string::byte::{BytePredicate, ByteStr, ByteString};
26use crate::typedarray::{ArrayBuffer, TypedArray, TypedArrayElement};
27use crate::{Array, Context, Date, Function, Object, Promise, PropertyKey, Symbol, Value};
28
29/// Represents types that can be converted to JavaScript [Values](Value).
30pub trait ToValue<'cx> {
31	/// Converts `self` to a [`Value`] and stores it in `value`.
32	fn to_value(&self, cx: &'cx Context, value: &mut Value);
33
34	/// Converts `self` to a new [`Value`].
35	fn as_value(&self, cx: &'cx Context) -> Value<'cx> {
36		let mut value = Value::undefined(cx);
37		self.to_value(cx, &mut value);
38		value
39	}
40}
41
42impl ToValue<'_> for () {
43	fn to_value(&self, _: &Context, value: &mut Value) {
44		value.handle_mut().set(UndefinedValue());
45	}
46}
47
48impl ToValue<'_> for bool {
49	fn to_value(&self, _: &Context, value: &mut Value) {
50		value.handle_mut().set(BooleanValue(*self));
51	}
52}
53
54macro_rules! impl_to_value_for_integer {
55	($ty:ty, signed) => {
56		impl ToValue<'_> for $ty {
57			fn to_value(&self, _: &Context, value: &mut Value) {
58				value.handle_mut().set(Int32Value(i32::from(*self)));
59			}
60		}
61	};
62	($ty:ty, unsigned) => {
63		impl ToValue<'_> for $ty {
64			fn to_value(&self, _: &Context, value: &mut Value) {
65				value.handle_mut().set(UInt32Value(u32::from(*self)));
66			}
67		}
68	};
69}
70
71impl_to_value_for_integer!(i8, signed);
72impl_to_value_for_integer!(i16, signed);
73impl_to_value_for_integer!(i32, signed);
74
75impl_to_value_for_integer!(u8, unsigned);
76impl_to_value_for_integer!(u16, unsigned);
77impl_to_value_for_integer!(u32, unsigned);
78
79macro_rules! impl_to_value_as_double {
80	($ty:ty, int) => {
81		impl ToValue<'_> for $ty {
82			fn to_value(&self, _: &Context, value: &mut Value) {
83				value.handle_mut().set(DoubleValue(*self as f64));
84			}
85		}
86	};
87	($ty:ty, float) => {
88		impl ToValue<'_> for $ty {
89			fn to_value(&self, _: &Context, value: &mut Value) {
90				value.handle_mut().set(DoubleValue(f64::from(*self)));
91			}
92		}
93	};
94}
95
96impl_to_value_as_double!(i64, int);
97impl_to_value_as_double!(u64, int);
98impl_to_value_as_double!(f32, float);
99impl_to_value_as_double!(f64, float);
100
101impl ToValue<'_> for *mut JSString {
102	fn to_value(&self, cx: &Context, value: &mut Value) {
103		value.handle_mut().set(StringValue(unsafe { &**self }));
104		unsafe {
105			JS_WrapValue(cx.as_ptr(), value.handle_mut().into());
106		}
107	}
108}
109
110impl<'cx> ToValue<'cx> for crate::String<'cx> {
111	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
112		self.handle().to_value(cx, value);
113	}
114}
115
116impl ToValue<'_> for str {
117	fn to_value(&self, cx: &Context, value: &mut Value) {
118		let string = crate::String::copy_from_str(cx, self);
119		if let Some(string) = string {
120			string.to_value(cx, value);
121		} else {
122			panic!("Failed to Instantiate String");
123		}
124	}
125}
126
127impl<'cx> ToValue<'cx> for String {
128	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
129		(**self).to_value(cx, value);
130	}
131}
132
133impl<'cx, T: ToOwned + ToValue<'cx>> ToValue<'cx> for Cow<'_, T> {
134	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
135		self.as_ref().to_value(cx, value);
136	}
137}
138
139impl<'cx, T: BytePredicate> ToValue<'cx> for ByteStr<T> {
140	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
141		unsafe { JS_NewStringCopyN(cx.as_ptr(), self.as_ptr().cast(), self.len()).to_value(cx, value) };
142	}
143}
144
145impl<'cx, T: BytePredicate> ToValue<'cx> for ByteString<T> {
146	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
147		(**self).to_value(cx, value);
148	}
149}
150
151impl ToValue<'_> for *mut JSObject {
152	fn to_value(&self, cx: &Context, value: &mut Value) {
153		value.handle_mut().set(ObjectOrNullValue(*self));
154		unsafe {
155			maybe_wrap_object_or_null_value(cx.as_ptr(), value.handle_mut());
156		}
157	}
158}
159
160impl ToValue<'_> for NonNull<JSObject> {
161	fn to_value(&self, cx: &Context, value: &mut Value) {
162		value.handle_mut().set(ObjectValue(self.as_ptr()));
163		unsafe {
164			maybe_wrap_object_value(cx.as_ptr(), value.handle_mut());
165		}
166	}
167}
168
169impl<'cx> ToValue<'cx> for Object<'cx> {
170	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
171		self.handle().to_value(cx, value);
172	}
173}
174
175impl<'cx> ToValue<'cx> for Array<'cx> {
176	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
177		self.handle().to_value(cx, value);
178	}
179}
180
181impl<'cx> ToValue<'cx> for Date<'cx> {
182	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
183		self.handle().to_value(cx, value);
184	}
185}
186
187impl ToValue<'_> for SystemTime {
188	fn to_value(&self, cx: &Context, value: &mut Value) {
189		Date::from_date(cx, DateTime::from(*self)).to_value(cx, value);
190	}
191}
192
193impl<'cx> ToValue<'cx> for Promise<'cx> {
194	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
195		self.handle().to_value(cx, value);
196	}
197}
198
199impl<'cx> ToValue<'cx> for RegExp<'cx> {
200	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
201		self.handle().to_value(cx, value);
202	}
203}
204
205impl<T: jsta::TypedArrayElement, S: jsta::JSObjectStorage> ToValue<'_> for jsta::TypedArray<T, S> {
206	fn to_value(&self, cx: &Context, value: &mut Value) {
207		unsafe { self.underlying_object().as_raw().to_value(cx, value) }
208	}
209}
210
211impl<'cx> ToValue<'cx> for ArrayBuffer<'cx> {
212	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
213		self.handle().to_value(cx, value);
214	}
215}
216
217impl<'cx, T: TypedArrayElement> ToValue<'cx> for TypedArray<'cx, T> {
218	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
219		self.handle().to_value(cx, value);
220	}
221}
222
223impl<'cx> ToValue<'cx> for *mut JSFunction {
224	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
225		unsafe { JS_GetFunctionObject(*self) }.to_value(cx, value);
226	}
227}
228
229impl<'cx> ToValue<'cx> for Function<'cx> {
230	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
231		self.handle().to_value(cx, value);
232	}
233}
234
235impl ToValue<'_> for *mut JSSymbol {
236	fn to_value(&self, _: &Context, value: &mut Value) {
237		value.handle_mut().set(SymbolValue(unsafe { &**self }));
238	}
239}
240
241impl<'cx> ToValue<'cx> for Symbol<'cx> {
242	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
243		self.handle().to_value(cx, value);
244	}
245}
246
247impl ToValue<'_> for JSVal {
248	fn to_value(&self, cx: &Context, value: &mut Value) {
249		value.handle_mut().set(*self);
250		unsafe {
251			maybe_wrap_value(cx.as_ptr(), value.handle_mut());
252		}
253	}
254}
255
256impl<'cx> ToValue<'cx> for Value<'cx> {
257	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
258		self.handle().to_value(cx, value);
259	}
260}
261
262impl<'cx> ToValue<'cx> for JSPropertyKey {
263	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
264		unsafe {
265			JS_IdToValue(cx.as_ptr(), *self, value.handle_mut().into());
266		}
267	}
268}
269
270impl<'cx> ToValue<'cx> for PropertyKey<'cx> {
271	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
272		self.handle().to_value(cx, value);
273	}
274}
275
276impl<'cx, T: ToValue<'cx> + ?Sized> ToValue<'cx> for &'_ T {
277	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
278		(*self).to_value(cx, value);
279	}
280}
281
282impl<'cx, T: ToValue<'cx> + ?Sized> ToValue<'cx> for Box<T> {
283	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
284		(**self).to_value(cx, value);
285	}
286}
287
288impl<'cx, T: ToValue<'cx> + ?Sized> ToValue<'cx> for Rc<T> {
289	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
290		(**self).to_value(cx, value);
291	}
292}
293
294impl<'cx, T: ToValue<'cx>> ToValue<'cx> for Option<T> {
295	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
296		match self {
297			Some(t) => t.to_value(cx, value),
298			None => value.handle_mut().set(NullValue()),
299		}
300	}
301}
302
303impl<'cx, T: ToValue<'cx>> ToValue<'cx> for [T] {
304	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
305		let array = Array::new_with_length(cx, self.len());
306
307		for (i, t) in self.iter().enumerate() {
308			assert!(array.set_as(cx, i as u32, t));
309		}
310
311		array.to_value(cx, value);
312	}
313}
314
315impl<'cx, const N: usize, T: ToValue<'cx>> ToValue<'cx> for [T; N] {
316	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
317		<[T]>::to_value(self, cx, value);
318	}
319}
320
321impl<'cx, T: ToValue<'cx>> ToValue<'cx> for Vec<T> {
322	fn to_value(&self, cx: &'cx Context, value: &mut Value) {
323		(**self).to_value(cx, value);
324	}
325}