1use std::ptr;
8
9pub use mozjs::conversions::ConversionBehavior;
10use mozjs::conversions::{ConversionResult, FromJSValConvertible as _};
11use mozjs::jsapi::{
12 AssertSameCompartment, AssertSameCompartment1, ForOfIterator, ForOfIterator_NonIterableBehavior, JSFunction,
13 JSObject, JSString, RootedObject, RootedValue, Symbol as JSSymbol,
14};
15use mozjs::jsval::{JSVal, UndefinedValue};
16use mozjs::rust::{ToBoolean, ToNumber, ToString};
17use mozjs::typedarray as jsta;
18use mozjs::typedarray::JSObjectStorage;
19
20use crate::object::RegExp;
21use crate::string::byte::{BytePredicate, ByteString};
22use crate::typedarray::{ArrayBuffer, TypedArray, TypedArrayElement};
23use crate::{
24 Array, Context, Date, Error, ErrorKind, Exception, Function, Object, Promise, Result, StringRef, Symbol, Value,
25};
26
27pub trait FromValue<'cx>: Sized {
29 type Config;
30
31 fn from_value(cx: &'cx Context, value: &Value, strict: bool, config: Self::Config) -> Result<Self>;
35}
36
37impl<'cx> FromValue<'cx> for bool {
38 type Config = ();
39
40 fn from_value(_: &'cx Context, value: &Value, strict: bool, _: ()) -> Result<bool> {
41 let value = value.handle();
42 if value.is_boolean() {
43 return Ok(value.to_boolean());
44 }
45
46 if strict {
47 Err(Error::new("Expected Boolean in Strict Conversion", ErrorKind::Type))
48 } else {
49 Ok(unsafe { ToBoolean(value) })
50 }
51 }
52}
53
54macro_rules! impl_from_value_for_integer {
55 ($ty:ty) => {
56 impl<'cx> FromValue<'cx> for $ty {
57 type Config = ConversionBehavior;
58
59 fn from_value(cx: &'cx Context, value: &Value, strict: bool, config: ConversionBehavior) -> Result<$ty> {
60 let value = value.handle();
61 if strict && !value.is_number() {
62 return Err(Error::new(
63 "Expected Number in Strict Conversion",
64 ErrorKind::Type,
65 ));
66 }
67
68 match unsafe { <$ty>::from_jsval(cx.as_ptr(), value, config) } {
69 Ok(ConversionResult::Success(number)) => Ok(number),
70 Err(_) => Err(Exception::new(cx)?.unwrap().to_error()),
71 _ => unreachable!(),
72 }
73 }
74 }
75 };
76}
77
78impl_from_value_for_integer!(u8);
79impl_from_value_for_integer!(u16);
80impl_from_value_for_integer!(u32);
81impl_from_value_for_integer!(u64);
82
83impl_from_value_for_integer!(i8);
84impl_from_value_for_integer!(i16);
85impl_from_value_for_integer!(i32);
86impl_from_value_for_integer!(i64);
87
88impl<'cx> FromValue<'cx> for f32 {
89 type Config = ();
90
91 fn from_value(cx: &'cx Context, value: &Value, strict: bool, _: ()) -> Result<f32> {
92 f64::from_value(cx, value, strict, ()).map(|float| float as f32)
93 }
94}
95
96impl<'cx> FromValue<'cx> for f64 {
97 type Config = ();
98
99 fn from_value(cx: &'cx Context, value: &Value, strict: bool, _: ()) -> Result<f64> {
100 let value = value.handle();
101 if strict && !value.is_number() {
102 return Err(Error::new("Expected Number in Strict Conversion", ErrorKind::Type));
103 }
104
105 let number = unsafe { ToNumber(cx.as_ptr(), value) };
106 number.map_err(|_| Error::new("Unable to Convert Value to Number", ErrorKind::Type))
107 }
108}
109
110impl<'cx> FromValue<'cx> for *mut JSString {
111 type Config = ();
112
113 fn from_value(cx: &'cx Context, value: &Value, strict: bool, _: ()) -> Result<*mut JSString> {
114 let value = value.handle();
115 if strict && !value.is_string() {
116 return Err(Error::new("Expected String in Strict Conversion", ErrorKind::Type));
117 }
118
119 let str = unsafe { ToString(cx.as_ptr(), value) };
120 if str.is_null() {
121 Err(Error::new("Failed to convert value to String", ErrorKind::Type))
122 } else {
123 Ok(str)
124 }
125 }
126}
127
128impl<'cx> FromValue<'cx> for crate::String<'cx> {
129 type Config = ();
130
131 fn from_value(cx: &'cx Context, value: &Value, strict: bool, config: ()) -> Result<crate::String<'cx>> {
132 <*mut JSString>::from_value(cx, value, strict, config).map(|str| crate::String::from(cx.root(str)))
133 }
134}
135
136impl<'cx> FromValue<'cx> for StringRef<'cx> {
137 type Config = ();
138
139 fn from_value(cx: &'cx Context, value: &Value, strict: bool, config: ()) -> Result<StringRef<'cx>> {
140 crate::String::from_value(cx, value, strict, config).map(|str| str.as_ref(cx))
141 }
142}
143
144impl<'cx, T: BytePredicate> FromValue<'cx> for ByteString<T> {
145 type Config = ();
146
147 fn from_value(cx: &'cx Context, value: &Value, strict: bool, config: ()) -> Result<ByteString<T>> {
148 const INVALID_CHARACTERS: &str = "ByteString contains invalid characters";
149 let string = StringRef::from_value(cx, value, strict, config)?;
150 match string {
151 StringRef::Latin1(bstr) => {
152 ByteString::from(bstr.to_vec()).ok_or_else(|| Error::new(INVALID_CHARACTERS, ErrorKind::Type))
153 }
154 StringRef::Utf16(wstr) => {
155 let bytes = wstr
156 .as_bytes()
157 .chunks_exact(2)
158 .map(|chunk| {
159 let codepoint = u16::from_ne_bytes([chunk[0], chunk[1]]);
160 u8::try_from(codepoint).map_err(|_| Error::new(INVALID_CHARACTERS, ErrorKind::Type))
161 })
162 .collect::<Result<Vec<_>>>()?;
163 ByteString::from(bytes).ok_or_else(|| Error::new(INVALID_CHARACTERS, ErrorKind::Type))
164 }
165 }
166 }
167}
168
169impl<'cx> FromValue<'cx> for String {
170 type Config = ();
171
172 fn from_value(cx: &'cx Context, value: &Value, strict: bool, config: ()) -> Result<String> {
173 let str = crate::String::from_value(cx, value, strict, config)?;
174 str.to_owned(cx)
175 }
176}
177
178impl<'cx> FromValue<'cx> for *mut JSObject {
179 type Config = ();
180
181 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<*mut JSObject> {
182 let value = value.handle();
183 if !value.is_object() {
184 return Err(Error::new("Expected Object", ErrorKind::Type));
185 }
186 let object = value.to_object();
187 unsafe {
188 AssertSameCompartment(cx.as_ptr(), object);
189 }
190
191 Ok(object)
192 }
193}
194
195impl<'cx> FromValue<'cx> for Object<'cx> {
196 type Config = ();
197
198 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<Object<'cx>> {
199 if !value.handle().is_object() {
200 return Err(Error::new("Expected Object", ErrorKind::Type));
201 }
202 let object = value.to_object(cx);
203 unsafe {
204 AssertSameCompartment(cx.as_ptr(), object.handle().get());
205 }
206
207 Ok(object)
208 }
209}
210
211impl<'cx> FromValue<'cx> for Array<'cx> {
212 type Config = ();
213
214 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<Array<'cx>> {
215 if !value.handle().is_object() {
216 return Err(Error::new("Expected Array", ErrorKind::Type));
217 }
218
219 let object = value.to_object(cx).into_local();
220 if let Some(array) = Array::from(cx, object) {
221 unsafe {
222 AssertSameCompartment(cx.as_ptr(), array.handle().get());
223 }
224 Ok(array)
225 } else {
226 Err(Error::new("Expected Array", ErrorKind::Type))
227 }
228 }
229}
230
231impl<'cx> FromValue<'cx> for Date<'cx> {
232 type Config = ();
233
234 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<Date<'cx>> {
235 if !value.handle().is_object() {
236 return Err(Error::new("Expected Date", ErrorKind::Type));
237 }
238
239 let object = value.to_object(cx).into_local();
240 if let Some(date) = Date::from(cx, object) {
241 unsafe {
242 AssertSameCompartment(cx.as_ptr(), date.get());
243 }
244 Ok(date)
245 } else {
246 Err(Error::new("Expected Date", ErrorKind::Type))
247 }
248 }
249}
250
251impl<'cx> FromValue<'cx> for Promise<'cx> {
252 type Config = ();
253
254 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<Promise<'cx>> {
255 if !value.handle().is_object() {
256 return Err(Error::new("Expected Promise", ErrorKind::Type));
257 }
258
259 let object = value.to_object(cx).into_local();
260 if let Some(promise) = Promise::from(object) {
261 unsafe {
262 AssertSameCompartment(cx.as_ptr(), promise.get());
263 }
264 Ok(promise)
265 } else {
266 Err(Error::new("Expected Promise", ErrorKind::Type))
267 }
268 }
269}
270
271impl<'cx> FromValue<'cx> for RegExp<'cx> {
272 type Config = ();
273
274 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<RegExp<'cx>> {
275 if !value.handle().is_object() {
276 return Err(Error::new("Expected RegExp", ErrorKind::Type));
277 }
278
279 let object = value.to_object(cx).into_local();
280 if let Some(regexp) = RegExp::from(cx, object) {
281 unsafe {
282 AssertSameCompartment(cx.as_ptr(), regexp.get());
283 }
284 Ok(regexp)
285 } else {
286 Err(Error::new("Expected RegExp", ErrorKind::Type))
287 }
288 }
289}
290
291impl<'cx, T: jsta::TypedArrayElement, S: JSObjectStorage> FromValue<'cx> for jsta::TypedArray<T, S> {
292 type Config = ();
293
294 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<jsta::TypedArray<T, S>> {
295 let value = value.handle();
296 if value.is_object() {
297 let object = value.to_object();
298 cx.root(object);
299 jsta::TypedArray::from(object).map_err(|_| Error::new("Expected Typed Array", ErrorKind::Type))
300 } else {
301 Err(Error::new("Expected Object", ErrorKind::Type))
302 }
303 }
304}
305
306impl<'cx> FromValue<'cx> for ArrayBuffer<'cx> {
307 type Config = ();
308
309 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<ArrayBuffer<'cx>> {
310 if !value.handle().is_object() {
311 return Err(Error::new("Expected ArrayBuffer", ErrorKind::Type));
312 }
313
314 let object = value.to_object(cx).into_local();
315 if let Some(buffer) = ArrayBuffer::from(object) {
316 unsafe {
317 AssertSameCompartment(cx.as_ptr(), buffer.get());
318 }
319 Ok(buffer)
320 } else {
321 Err(Error::new("Expected ArrayBuffer", ErrorKind::Type))
322 }
323 }
324}
325
326impl<'cx, T: TypedArrayElement> FromValue<'cx> for TypedArray<'cx, T> {
327 type Config = ();
328
329 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<TypedArray<'cx, T>> {
330 if !value.handle().is_object() {
331 return Err(Error::new("Expected ArrayBuffer", ErrorKind::Type));
332 }
333
334 let object = value.to_object(cx).into_local();
335 if let Some(array) = TypedArray::from(object) {
336 unsafe {
337 AssertSameCompartment(cx.as_ptr(), array.get());
338 }
339 Ok(array)
340 } else {
341 Err(Error::new("Expected ArrayBuffer", ErrorKind::Type))
342 }
343 }
344}
345
346impl<'cx> FromValue<'cx> for *mut JSFunction {
347 type Config = ();
348
349 fn from_value(cx: &'cx Context, value: &Value, strict: bool, config: ()) -> Result<*mut JSFunction> {
350 Function::from_value(cx, value, strict, config).map(|f| f.get())
351 }
352}
353
354impl<'cx> FromValue<'cx> for Function<'cx> {
355 type Config = ();
356
357 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<Function<'cx>> {
358 if !value.handle().is_object() {
359 return Err(Error::new("Expected Function", ErrorKind::Type));
360 }
361
362 let function_obj = value.to_object(cx);
363 if let Some(function) = Function::from_object(cx, &function_obj) {
364 unsafe {
365 AssertSameCompartment(cx.as_ptr(), function_obj.handle().get());
366 }
367 Ok(function)
368 } else {
369 Err(Error::new("Expected Function", ErrorKind::Type))
370 }
371 }
372}
373
374impl<'cx> FromValue<'cx> for *mut JSSymbol {
375 type Config = ();
376
377 fn from_value(_: &'cx Context, value: &Value, _: bool, _: ()) -> Result<*mut JSSymbol> {
378 let value = value.handle();
379 if value.is_symbol() {
380 Ok(value.to_symbol())
381 } else {
382 Err(Error::new("Expected Symbol", ErrorKind::Type))
383 }
384 }
385}
386
387impl<'cx> FromValue<'cx> for Symbol<'cx> {
388 type Config = ();
389
390 fn from_value(cx: &'cx Context, value: &Value, strict: bool, config: Self::Config) -> Result<Symbol<'cx>> {
391 <*mut JSSymbol>::from_value(cx, value, strict, config).map(|s| cx.root(s).into())
392 }
393}
394
395impl<'cx> FromValue<'cx> for JSVal {
396 type Config = ();
397
398 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<JSVal> {
399 let value = value.handle();
400 unsafe {
401 AssertSameCompartment1(cx.as_ptr(), value.into());
402 }
403 Ok(value.get())
404 }
405}
406
407impl<'cx> FromValue<'cx> for Value<'cx> {
408 type Config = ();
409
410 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<Value<'cx>> {
411 let value = value.handle();
412 unsafe {
413 AssertSameCompartment1(cx.as_ptr(), value.into());
414 }
415 Ok(cx.root(value.get()).into())
416 }
417}
418
419impl<'cx, T: FromValue<'cx>> FromValue<'cx> for Option<T> {
420 type Config = T::Config;
421
422 fn from_value(cx: &'cx Context, value: &Value, strict: bool, config: T::Config) -> Result<Option<T>> {
423 if value.handle().is_null_or_undefined() {
424 Ok(None)
425 } else {
426 Ok(Some(T::from_value(cx, value, strict, config)?))
427 }
428 }
429}
430
431struct ForOfIteratorGuard<'a> {
433 root: &'a mut ForOfIterator,
434}
435
436impl<'a> ForOfIteratorGuard<'a> {
437 fn new(cx: &Context, root: &'a mut ForOfIterator) -> Self {
438 cx.root(root.iterator.data);
439 ForOfIteratorGuard { root }
440 }
441}
442
443impl<'cx, T: FromValue<'cx>> FromValue<'cx> for Vec<T>
444where
445 T::Config: Clone,
446{
447 type Config = T::Config;
448
449 fn from_value(cx: &'cx Context, value: &Value, strict: bool, config: T::Config) -> Result<Vec<T>> {
451 if !value.handle().is_object() {
452 return Err(Error::new("Expected Object", ErrorKind::Type));
453 }
454 let object = value.to_object(cx);
455 if strict && !Array::is_array(cx, &object) {
456 return Err(Error::new("Expected Array", ErrorKind::Type));
457 }
458
459 let mut iterator = ForOfIterator {
460 cx_: cx.as_ptr(),
461 iterator: RootedObject::new_unrooted(ptr::null_mut()),
462 nextMethod: RootedValue::new_unrooted(UndefinedValue()),
463 index: u32::MAX, };
465 let iterator = ForOfIteratorGuard::new(cx, &mut iterator);
466 let iterator = &mut *iterator.root;
467
468 let init = unsafe {
469 iterator.init(
470 value.handle().into(),
471 ForOfIterator_NonIterableBehavior::AllowNonIterable,
472 )
473 };
474 if !init {
475 return Err(Error::new("Failed to Initialise Iterator", ErrorKind::Type));
476 }
477
478 if iterator.iterator.data.is_null() {
479 return Err(Error::new("Expected Iterable", ErrorKind::Type));
480 }
481
482 let mut ret = vec![];
483
484 let mut value = Value::undefined(cx);
485 loop {
486 let mut done = false;
487 if unsafe { !iterator.next(value.handle_mut().into(), &raw mut done) } {
488 return Err(Error::new("Failed to Execute Next on Iterator", ErrorKind::Type));
489 }
490
491 if done {
492 break;
493 }
494 ret.push(T::from_value(cx, &value, strict, config.clone())?);
495 }
496 Ok(ret)
497 }
498}
499
500#[cfg(test)]
501mod tests {
502 use std::f64::consts::PI;
503
504 use chrono::{TimeZone as _, Utc};
505 use mozjs::conversions::ConversionBehavior;
506 use mozjs::gc::{RootableVec, RootedVec};
507 use mozjs::jsval::Int32Value;
508
509 use crate::conversions::{FromValue as _, ToValue as _};
510 use crate::utils::test::TestRuntime;
511 use crate::{Array, Date, Object, Promise, Value};
512
513 #[test]
514 fn boolean() {
515 let rt = TestRuntime::new();
516 let cx = &rt.cx;
517
518 let value = Value::bool(cx, false);
519 let result = bool::from_value(cx, &value, true, ());
520 assert!(!result.unwrap());
521
522 let value = Value::i32(cx, 0);
523 let result = bool::from_value(cx, &value, true, ());
524 result.unwrap_err();
525 let result = bool::from_value(cx, &value, false, ());
526 assert!(!result.unwrap());
527
528 let value = Value::f64(cx, PI);
529 let result = bool::from_value(cx, &value, true, ());
530 result.unwrap_err();
531 let result = bool::from_value(cx, &value, false, ());
532 assert!(result.unwrap());
533
534 let value = Value::string(cx, "");
535 let result = bool::from_value(cx, &value, true, ());
536 result.unwrap_err();
537 let result = bool::from_value(cx, &value, false, ());
538 assert!(!result.unwrap());
539
540 let value = Value::string(cx, "spider");
541 let result = bool::from_value(cx, &value, true, ());
542 result.unwrap_err();
543 let result = bool::from_value(cx, &value, false, ());
544 assert!(result.unwrap());
545
546 let value = Value::undefined(cx);
547 let result = bool::from_value(cx, &value, true, ());
548 result.unwrap_err();
549 let result = bool::from_value(cx, &value, false, ());
550 assert!(!result.unwrap());
551
552 let value = Value::null(cx);
553 let result = bool::from_value(cx, &value, true, ());
554 result.unwrap_err();
555 let result = bool::from_value(cx, &value, false, ());
556 assert!(!result.unwrap());
557
558 let object = Object::new(cx);
559 let value = object.as_value(cx);
560 let result = bool::from_value(cx, &value, true, ());
561 result.unwrap_err();
562 let result = bool::from_value(cx, &value, false, ());
563 assert!(result.unwrap());
564
565 let array = Array::new(cx);
566 let value = array.as_value(cx);
567 let result = bool::from_value(cx, &value, true, ());
568 result.unwrap_err();
569 let result = bool::from_value(cx, &value, false, ());
570 assert!(result.unwrap());
571 }
572
573 #[test]
574 fn integer() {
575 let rt = TestRuntime::new();
576 let cx = &rt.cx;
577
578 let value = Value::bool(cx, true);
579 let result = i32::from_value(cx, &value, true, ConversionBehavior::EnforceRange);
580 result.unwrap_err();
581 let result = i32::from_value(cx, &value, false, ConversionBehavior::EnforceRange);
582 assert_eq!(result.unwrap(), 1);
583
584 let value = Value::i32(cx, 255);
585 let result = u8::from_value(cx, &value, true, ConversionBehavior::EnforceRange);
586 assert_eq!(result.unwrap(), 255);
587
588 let value = Value::string(cx, "spider");
589 let result = u16::from_value(cx, &value, true, ConversionBehavior::EnforceRange);
590 result.unwrap_err();
591 let result = u16::from_value(cx, &value, false, ConversionBehavior::EnforceRange);
592 result.unwrap_err();
593
594 let value = Value::string(cx, "-64");
595 let result = i64::from_value(cx, &value, true, ConversionBehavior::EnforceRange);
596 result.unwrap_err();
597 let result = i64::from_value(cx, &value, false, ConversionBehavior::EnforceRange);
598 assert_eq!(result.unwrap(), -64);
599
600 let value = Value::undefined(cx);
601 let result = i64::from_value(cx, &value, true, ConversionBehavior::EnforceRange);
602 result.unwrap_err();
603 let result = i64::from_value(cx, &value, false, ConversionBehavior::EnforceRange);
604 result.unwrap_err();
605
606 let value = Value::null(cx);
607 let result = i64::from_value(cx, &value, true, ConversionBehavior::EnforceRange);
608 result.unwrap_err();
609 let result = i64::from_value(cx, &value, false, ConversionBehavior::EnforceRange);
610 assert_eq!(result.unwrap(), 0);
611
612 let object = Object::new(cx);
613 let value = object.as_value(cx);
614 let result = u32::from_value(cx, &value, true, ConversionBehavior::EnforceRange);
615 result.unwrap_err();
616 let result = u32::from_value(cx, &value, false, ConversionBehavior::EnforceRange);
617 result.unwrap_err();
618 }
619
620 #[test]
621 fn string() {
622 let rt = TestRuntime::new();
623 let cx = &rt.cx;
624
625 let value = Value::bool(cx, false);
626 let result = String::from_value(cx, &value, true, ());
627 result.unwrap_err();
628 let result = String::from_value(cx, &value, false, ());
629 assert_eq!(&result.unwrap(), "false");
630
631 let value = Value::f64(cx, 1.5);
632 let result = String::from_value(cx, &value, true, ());
633 result.unwrap_err();
634 let result = String::from_value(cx, &value, false, ());
635 assert_eq!(&result.unwrap(), "1.5");
636
637 let value = Value::string(cx, "spider");
638 let result = String::from_value(cx, &value, true, ());
639 assert_eq!(&result.unwrap(), "spider");
640
641 let value = Value::undefined(cx);
642 let result = String::from_value(cx, &value, true, ());
643 result.unwrap_err();
644 let result = String::from_value(cx, &value, false, ());
645 assert_eq!(&result.unwrap(), "undefined");
646
647 let value = Value::null(cx);
648 let result = String::from_value(cx, &value, true, ());
649 result.unwrap_err();
650 let result = String::from_value(cx, &value, false, ());
651 assert_eq!(&result.unwrap(), "null");
652
653 let object = Object::new(cx);
654 let value = object.as_value(cx);
655 let result = String::from_value(cx, &value, true, ());
656 result.unwrap_err();
657 let result = String::from_value(cx, &value, false, ());
658 assert_eq!(&result.unwrap(), "[object Object]");
659 }
660
661 #[test]
662 fn object() {
663 let rt = TestRuntime::new();
664 let cx = &rt.cx;
665
666 let value = Value::bool(cx, false);
667 let result = Object::from_value(cx, &value, true, ());
668 result.unwrap_err();
669 let result = Object::from_value(cx, &value, false, ());
670 result.unwrap_err();
671
672 let value = Value::f64(cx, 144.0);
673 let result = Object::from_value(cx, &value, true, ());
674 result.unwrap_err();
675 let result = Object::from_value(cx, &value, false, ());
676 result.unwrap_err();
677
678 let value = Value::string(cx, "spider");
679 let result = Object::from_value(cx, &value, true, ());
680 result.unwrap_err();
681 let result = Object::from_value(cx, &value, false, ());
682 result.unwrap_err();
683
684 let value = Value::undefined(cx);
685 let result = Object::from_value(cx, &value, true, ());
686 result.unwrap_err();
687 let result = Object::from_value(cx, &value, false, ());
688 result.unwrap_err();
689
690 let value = Value::null(cx);
691 let result = Object::from_value(cx, &value, true, ());
692 result.unwrap_err();
693 let result = Object::from_value(cx, &value, false, ());
694 result.unwrap_err();
695
696 let object = Object::new(cx);
697 let value = object.as_value(cx);
698 let result = Object::from_value(cx, &value, true, ());
699 result.unwrap();
700
701 let array = Array::new(cx);
702 let value = array.as_value(cx);
703 let result = Array::from_value(cx, &value, true, ());
704 result.unwrap();
705
706 let timestamp = Utc.timestamp_millis_opt(Utc::now().timestamp_millis()).unwrap();
707 let date = Date::from_date(cx, timestamp);
708 let value = date.as_value(cx);
709 let result = Date::from_value(cx, &value, true, ());
710 assert_eq!(result.unwrap().to_date(cx).unwrap(), timestamp);
711
712 let promise = Promise::new(cx);
713 let value = promise.as_value(cx);
714 let result = Promise::from_value(cx, &value, true, ());
715 result.unwrap();
716 }
717
718 #[test]
719 fn option() {
720 type Opt = Option<bool>;
721
722 let rt = TestRuntime::new();
723 let cx = &rt.cx;
724
725 let value = Value::bool(cx, true);
726 let result = Opt::from_value(cx, &value, true, ());
727 assert_eq!(result.unwrap(), Some(true));
728
729 let value = Value::undefined(cx);
730 let result = Opt::from_value(cx, &value, true, ());
731 assert_eq!(result.unwrap(), None);
732
733 let value = Value::null(cx);
734 let result = Opt::from_value(cx, &value, true, ());
735 assert_eq!(result.unwrap(), None);
736 }
737
738 #[test]
739 fn vec() {
740 let rt = TestRuntime::new();
741 let cx = &rt.cx;
742
743 let int_vec = vec![1, 256, -0x10000, 0x7FFF_FFFF];
744 let mut root = RootableVec::new_unrooted();
745 let vec = RootedVec::from_iter(&mut root, int_vec.iter().map(|i| Int32Value(*i)));
746 let array = Array::from_rooted_vec(cx, &vec);
747 let value = array.as_value(cx);
748
749 let result = <Vec<i32>>::from_value(cx, &value, true, ConversionBehavior::EnforceRange);
750 assert_eq!(result.unwrap(), int_vec);
751 }
752}