1#![deny(missing_docs)]
30
31use crate::error::throw_type_error;
32use crate::jsapi::AssertSameCompartment;
33use crate::jsapi::JS;
34use crate::jsapi::{ForOfIterator, ForOfIterator_NonIterableBehavior};
35use crate::jsapi::{Heap, JS_DefineElement, JS_GetLatin1StringCharsAndLength};
36use crate::jsapi::{JSContext, JSObject, JSString, RootedObject, RootedValue};
37use crate::jsapi::{JS_DeprecatedStringHasLatin1Chars, JS_NewUCStringCopyN, JSPROP_ENUMERATE};
38use crate::jsapi::{JS_GetTwoByteStringCharsAndLength, NewArrayObject1};
39use crate::jsval::{BooleanValue, DoubleValue, Int32Value, NullValue, UInt32Value, UndefinedValue};
40use crate::jsval::{JSVal, ObjectOrNullValue, ObjectValue, StringValue, SymbolValue};
41use crate::rooted;
42use crate::rust::maybe_wrap_value;
43use crate::rust::{maybe_wrap_object_or_null_value, maybe_wrap_object_value, ToString};
44use crate::rust::{HandleValue, MutableHandleValue};
45use crate::rust::{ToBoolean, ToInt32, ToInt64, ToNumber, ToUint16, ToUint32, ToUint64};
46use libc;
47use log::debug;
48use mozjs_sys::jsgc::Rooted;
49use std::borrow::Cow;
50use std::mem;
51use std::ptr::NonNull;
52use std::rc::Rc;
53use std::{ptr, slice};
54
55trait As<O>: Copy {
56 fn cast(self) -> O;
57}
58
59macro_rules! impl_as {
60 ($I:ty, $O:ty) => {
61 impl As<$O> for $I {
62 fn cast(self) -> $O {
63 self as $O
64 }
65 }
66 };
67}
68
69impl_as!(f64, u8);
70impl_as!(f64, u16);
71impl_as!(f64, u32);
72impl_as!(f64, u64);
73impl_as!(f64, i8);
74impl_as!(f64, i16);
75impl_as!(f64, i32);
76impl_as!(f64, i64);
77
78impl_as!(u8, f64);
79impl_as!(u16, f64);
80impl_as!(u32, f64);
81impl_as!(u64, f64);
82impl_as!(i8, f64);
83impl_as!(i16, f64);
84impl_as!(i32, f64);
85impl_as!(i64, f64);
86
87impl_as!(i32, i8);
88impl_as!(i32, u8);
89impl_as!(i32, i16);
90impl_as!(u16, u16);
91impl_as!(i32, i32);
92impl_as!(u32, u32);
93impl_as!(i64, i64);
94impl_as!(u64, u64);
95
96pub trait Number {
98 const ZERO: Self;
100 const MIN: Self;
102 const MAX: Self;
104}
105
106macro_rules! impl_num {
107 ($N:ty, $zero:expr, $min:expr, $max:expr) => {
108 impl Number for $N {
109 const ZERO: $N = $zero;
110 const MIN: $N = $min;
111 const MAX: $N = $max;
112 }
113 };
114}
115
116impl_num!(u8, 0, u8::MIN, u8::MAX);
118impl_num!(u16, 0, u16::MIN, u16::MAX);
119impl_num!(u32, 0, u32::MIN, u32::MAX);
120impl_num!(u64, 0, 0, (1 << 53) - 1);
121
122impl_num!(i8, 0, i8::MIN, i8::MAX);
123impl_num!(i16, 0, i16::MIN, i16::MAX);
124impl_num!(i32, 0, i32::MIN, i32::MAX);
125impl_num!(i64, 0, -(1 << 53) + 1, (1 << 53) - 1);
126
127impl_num!(f32, 0.0, f32::MIN, f32::MAX);
128impl_num!(f64, 0.0, f64::MIN, f64::MAX);
129
130pub trait ToJSValConvertible {
132 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue);
134}
135
136#[derive(PartialEq, Eq, Clone, Debug)]
138pub enum ConversionResult<T> {
139 Success(T),
141 Failure(Cow<'static, str>),
143}
144
145impl<T> ConversionResult<T> {
146 pub fn get_success_value(&self) -> Option<&T> {
148 match *self {
149 ConversionResult::Success(ref v) => Some(v),
150 _ => None,
151 }
152 }
153}
154
155pub trait FromJSValConvertible: Sized {
157 type Config;
159 unsafe fn from_jsval(
165 cx: *mut JSContext,
166 val: HandleValue,
167 option: Self::Config,
168 ) -> Result<ConversionResult<Self>, ()>;
169}
170
171pub trait FromJSValConvertibleRc: Sized {
173 unsafe fn from_jsval(
177 cx: *mut JSContext,
178 val: HandleValue,
179 ) -> Result<ConversionResult<Rc<Self>>, ()>;
180}
181
182impl<T: FromJSValConvertibleRc> FromJSValConvertible for Rc<T> {
183 type Config = ();
184
185 unsafe fn from_jsval(
186 cx: *mut JSContext,
187 val: HandleValue,
188 _option: (),
189 ) -> Result<ConversionResult<Rc<T>>, ()> {
190 <T as FromJSValConvertibleRc>::from_jsval(cx, val)
191 }
192}
193
194#[derive(PartialEq, Eq, Clone)]
196pub enum ConversionBehavior {
197 Default,
199 EnforceRange,
201 Clamp,
203}
204
205unsafe fn enforce_range<D>(cx: *mut JSContext, d: f64) -> Result<ConversionResult<D>, ()>
209where
210 D: Number + As<f64>,
211 f64: As<D>,
212{
213 if d.is_infinite() {
214 throw_type_error(cx, "value out of range in an EnforceRange argument");
215 return Err(());
216 }
217
218 let rounded = d.signum() * d.abs().floor();
219 if D::MIN.cast() <= rounded && rounded <= D::MAX.cast() {
220 Ok(ConversionResult::Success(rounded.cast()))
221 } else {
222 throw_type_error(cx, "value out of range in an EnforceRange argument");
223 Err(())
224 }
225}
226
227fn clamp_to<D>(d: f64) -> D
231where
232 D: Number + As<f64>,
233 f64: As<D>,
234{
235 if d.is_nan() {
236 D::ZERO
237 } else if d > D::MAX.cast() {
238 D::MAX
239 } else if d < D::MIN.cast() {
240 D::MIN
241 } else {
242 d.cast()
243 }
244}
245
246impl ToJSValConvertible for () {
248 #[inline]
249 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
250 rval.set(UndefinedValue());
251 }
252}
253
254impl FromJSValConvertible for JSVal {
255 type Config = ();
256 unsafe fn from_jsval(
257 _cx: *mut JSContext,
258 value: HandleValue,
259 _option: (),
260 ) -> Result<ConversionResult<JSVal>, ()> {
261 Ok(ConversionResult::Success(value.get()))
262 }
263}
264
265impl ToJSValConvertible for JSVal {
266 #[inline]
267 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
268 rval.set(*self);
269 maybe_wrap_value(cx, rval);
270 }
271}
272
273impl<'a> ToJSValConvertible for HandleValue<'a> {
274 #[inline]
275 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
276 rval.set(self.get());
277 maybe_wrap_value(cx, rval);
278 }
279}
280
281impl ToJSValConvertible for Heap<JSVal> {
282 #[inline]
283 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
284 rval.set(self.get());
285 maybe_wrap_value(cx, rval);
286 }
287}
288
289#[inline]
290unsafe fn convert_int_from_jsval<T, M>(
291 cx: *mut JSContext,
292 value: HandleValue,
293 option: ConversionBehavior,
294 convert_fn: unsafe fn(*mut JSContext, HandleValue) -> Result<M, ()>,
295) -> Result<ConversionResult<T>, ()>
296where
297 T: Number + As<f64>,
298 M: Number + As<T>,
299 f64: As<T>,
300{
301 match option {
302 ConversionBehavior::Default => Ok(ConversionResult::Success(convert_fn(cx, value)?.cast())),
303 ConversionBehavior::EnforceRange => enforce_range(cx, ToNumber(cx, value)?),
304 ConversionBehavior::Clamp => Ok(ConversionResult::Success(clamp_to(ToNumber(cx, value)?))),
305 }
306}
307
308impl ToJSValConvertible for bool {
310 #[inline]
311 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
312 rval.set(BooleanValue(*self));
313 }
314}
315
316impl FromJSValConvertible for bool {
318 type Config = ();
319 unsafe fn from_jsval(
320 _cx: *mut JSContext,
321 val: HandleValue,
322 _option: (),
323 ) -> Result<ConversionResult<bool>, ()> {
324 Ok(ToBoolean(val)).map(ConversionResult::Success)
325 }
326}
327
328impl ToJSValConvertible for i8 {
330 #[inline]
331 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
332 rval.set(Int32Value(*self as i32));
333 }
334}
335
336impl FromJSValConvertible for i8 {
338 type Config = ConversionBehavior;
339 unsafe fn from_jsval(
340 cx: *mut JSContext,
341 val: HandleValue,
342 option: ConversionBehavior,
343 ) -> Result<ConversionResult<i8>, ()> {
344 convert_int_from_jsval(cx, val, option, ToInt32)
345 }
346}
347
348impl ToJSValConvertible for u8 {
350 #[inline]
351 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
352 rval.set(Int32Value(*self as i32));
353 }
354}
355
356impl FromJSValConvertible for u8 {
358 type Config = ConversionBehavior;
359 unsafe fn from_jsval(
360 cx: *mut JSContext,
361 val: HandleValue,
362 option: ConversionBehavior,
363 ) -> Result<ConversionResult<u8>, ()> {
364 convert_int_from_jsval(cx, val, option, ToInt32)
365 }
366}
367
368impl ToJSValConvertible for i16 {
370 #[inline]
371 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
372 rval.set(Int32Value(*self as i32));
373 }
374}
375
376impl FromJSValConvertible for i16 {
378 type Config = ConversionBehavior;
379 unsafe fn from_jsval(
380 cx: *mut JSContext,
381 val: HandleValue,
382 option: ConversionBehavior,
383 ) -> Result<ConversionResult<i16>, ()> {
384 convert_int_from_jsval(cx, val, option, ToInt32)
385 }
386}
387
388impl ToJSValConvertible for u16 {
390 #[inline]
391 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
392 rval.set(Int32Value(*self as i32));
393 }
394}
395
396impl FromJSValConvertible for u16 {
398 type Config = ConversionBehavior;
399 unsafe fn from_jsval(
400 cx: *mut JSContext,
401 val: HandleValue,
402 option: ConversionBehavior,
403 ) -> Result<ConversionResult<u16>, ()> {
404 convert_int_from_jsval(cx, val, option, ToUint16)
405 }
406}
407
408impl ToJSValConvertible for i32 {
410 #[inline]
411 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
412 rval.set(Int32Value(*self));
413 }
414}
415
416impl FromJSValConvertible for i32 {
418 type Config = ConversionBehavior;
419 unsafe fn from_jsval(
420 cx: *mut JSContext,
421 val: HandleValue,
422 option: ConversionBehavior,
423 ) -> Result<ConversionResult<i32>, ()> {
424 convert_int_from_jsval(cx, val, option, ToInt32)
425 }
426}
427
428impl ToJSValConvertible for u32 {
430 #[inline]
431 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
432 rval.set(UInt32Value(*self));
433 }
434}
435
436impl FromJSValConvertible for u32 {
438 type Config = ConversionBehavior;
439 unsafe fn from_jsval(
440 cx: *mut JSContext,
441 val: HandleValue,
442 option: ConversionBehavior,
443 ) -> Result<ConversionResult<u32>, ()> {
444 convert_int_from_jsval(cx, val, option, ToUint32)
445 }
446}
447
448impl ToJSValConvertible for i64 {
450 #[inline]
451 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
452 rval.set(DoubleValue(*self as f64));
453 }
454}
455
456impl FromJSValConvertible for i64 {
458 type Config = ConversionBehavior;
459 unsafe fn from_jsval(
460 cx: *mut JSContext,
461 val: HandleValue,
462 option: ConversionBehavior,
463 ) -> Result<ConversionResult<i64>, ()> {
464 convert_int_from_jsval(cx, val, option, ToInt64)
465 }
466}
467
468impl ToJSValConvertible for u64 {
470 #[inline]
471 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
472 rval.set(DoubleValue(*self as f64));
473 }
474}
475
476impl FromJSValConvertible for u64 {
478 type Config = ConversionBehavior;
479 unsafe fn from_jsval(
480 cx: *mut JSContext,
481 val: HandleValue,
482 option: ConversionBehavior,
483 ) -> Result<ConversionResult<u64>, ()> {
484 convert_int_from_jsval(cx, val, option, ToUint64)
485 }
486}
487
488impl ToJSValConvertible for f32 {
490 #[inline]
491 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
492 rval.set(DoubleValue(*self as f64));
493 }
494}
495
496impl FromJSValConvertible for f32 {
498 type Config = ();
499 unsafe fn from_jsval(
500 cx: *mut JSContext,
501 val: HandleValue,
502 _option: (),
503 ) -> Result<ConversionResult<f32>, ()> {
504 let result = ToNumber(cx, val);
505 result.map(|f| f as f32).map(ConversionResult::Success)
506 }
507}
508
509impl ToJSValConvertible for f64 {
511 #[inline]
512 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
513 rval.set(DoubleValue(*self))
514 }
515}
516
517impl FromJSValConvertible for f64 {
519 type Config = ();
520 unsafe fn from_jsval(
521 cx: *mut JSContext,
522 val: HandleValue,
523 _option: (),
524 ) -> Result<ConversionResult<f64>, ()> {
525 ToNumber(cx, val).map(ConversionResult::Success)
526 }
527}
528
529pub unsafe fn latin1_to_string(cx: *mut JSContext, s: NonNull<JSString>) -> String {
532 assert!(JS_DeprecatedStringHasLatin1Chars(s.as_ptr()));
533
534 let mut length = 0;
535 let chars = unsafe {
536 let chars = JS_GetLatin1StringCharsAndLength(cx, ptr::null(), s.as_ptr(), &mut length);
537 assert!(!chars.is_null());
538
539 slice::from_raw_parts(chars, length as usize)
540 };
541 let mut v = vec![0; chars.len() * 2];
545 let real_size = encoding_rs::mem::convert_latin1_to_utf8(chars, v.as_mut_slice());
546
547 v.truncate(real_size);
548
549 unsafe { String::from_utf8_unchecked(v) }
552}
553
554pub unsafe fn jsstr_to_string(cx: *mut JSContext, jsstr: NonNull<JSString>) -> String {
556 if JS_DeprecatedStringHasLatin1Chars(jsstr.as_ptr()) {
557 return latin1_to_string(cx, jsstr);
558 }
559
560 let mut length = 0;
561 let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), jsstr.as_ptr(), &mut length);
562 assert!(!chars.is_null());
563 let char_vec = slice::from_raw_parts(chars, length as usize);
564 String::from_utf16_lossy(char_vec)
565}
566
567impl ToJSValConvertible for str {
569 #[inline]
570 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
571 let mut string_utf16: Vec<u16> = Vec::with_capacity(self.len());
572 string_utf16.extend(self.encode_utf16());
573 let jsstr = JS_NewUCStringCopyN(
574 cx,
575 string_utf16.as_ptr(),
576 string_utf16.len() as libc::size_t,
577 );
578 if jsstr.is_null() {
579 panic!("JS_NewUCStringCopyN failed");
580 }
581 rval.set(StringValue(&*jsstr));
582 }
583}
584
585impl ToJSValConvertible for String {
587 #[inline]
588 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
589 (**self).to_jsval(cx, rval);
590 }
591}
592
593impl FromJSValConvertible for String {
595 type Config = ();
596 unsafe fn from_jsval(
597 cx: *mut JSContext,
598 value: HandleValue,
599 _: (),
600 ) -> Result<ConversionResult<String>, ()> {
601 let jsstr = ToString(cx, value);
602 let Some(jsstr) = NonNull::new(jsstr) else {
603 debug!("ToString failed");
604 return Err(());
605 };
606 Ok(jsstr_to_string(cx, jsstr)).map(ConversionResult::Success)
607 }
608}
609
610impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> {
611 #[inline]
612 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
613 match self {
614 &Some(ref value) => value.to_jsval(cx, rval),
615 &None => rval.set(NullValue()),
616 }
617 }
618}
619
620impl<T: FromJSValConvertible> FromJSValConvertible for Option<T> {
621 type Config = T::Config;
622 unsafe fn from_jsval(
623 cx: *mut JSContext,
624 value: HandleValue,
625 option: T::Config,
626 ) -> Result<ConversionResult<Option<T>>, ()> {
627 if value.get().is_null_or_undefined() {
628 Ok(ConversionResult::Success(None))
629 } else {
630 Ok(match FromJSValConvertible::from_jsval(cx, value, option)? {
631 ConversionResult::Success(v) => ConversionResult::Success(Some(v)),
632 ConversionResult::Failure(v) => ConversionResult::Failure(v),
633 })
634 }
635 }
636}
637
638impl<T: ToJSValConvertible> ToJSValConvertible for &'_ T {
639 #[inline]
640 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
641 (**self).to_jsval(cx, rval)
642 }
643}
644
645impl<T: ToJSValConvertible> ToJSValConvertible for Box<T> {
646 #[inline]
647 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
648 (**self).to_jsval(cx, rval)
649 }
650}
651
652impl<T: ToJSValConvertible> ToJSValConvertible for Rc<T> {
653 #[inline]
654 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
655 (**self).to_jsval(cx, rval)
656 }
657}
658
659impl<T: ToJSValConvertible> ToJSValConvertible for [T] {
661 #[inline]
662 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
663 rooted!(in(cx) let js_array = NewArrayObject1(cx, self.len() as libc::size_t));
664 assert!(!js_array.handle().is_null());
665
666 rooted!(in(cx) let mut val = UndefinedValue());
667 for (index, obj) in self.iter().enumerate() {
668 obj.to_jsval(cx, val.handle_mut());
669
670 assert!(JS_DefineElement(
671 cx,
672 js_array.handle().into(),
673 index as u32,
674 val.handle().into(),
675 JSPROP_ENUMERATE as u32
676 ));
677 }
678
679 rval.set(ObjectValue(js_array.handle().get()));
680 }
681}
682
683impl<T: ToJSValConvertible> ToJSValConvertible for Vec<T> {
685 #[inline]
686 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
687 <[_]>::to_jsval(self, cx, rval)
688 }
689}
690
691struct ForOfIteratorGuard<'a> {
696 root: &'a mut ForOfIterator,
697}
698
699impl<'a> ForOfIteratorGuard<'a> {
700 fn new(cx: *mut JSContext, root: &'a mut ForOfIterator) -> Self {
701 unsafe {
702 Rooted::add_to_root_stack(&raw mut root.iterator, cx);
703 }
704 ForOfIteratorGuard { root }
705 }
706}
707
708impl<'a> Drop for ForOfIteratorGuard<'a> {
709 fn drop(&mut self) {
710 unsafe {
711 self.root.iterator.remove_from_root_stack();
712 }
713 }
714}
715
716impl<C: Clone, T: FromJSValConvertible<Config = C>> FromJSValConvertible for Vec<T> {
717 type Config = C;
718
719 unsafe fn from_jsval(
720 cx: *mut JSContext,
721 value: HandleValue,
722 option: C,
723 ) -> Result<ConversionResult<Vec<T>>, ()> {
724 if !value.is_object() {
725 return Ok(ConversionResult::Failure("Value is not an object".into()));
726 }
727
728 let zero = mem::zeroed();
734 let mut iterator = ForOfIterator {
735 cx_: cx,
736 iterator: RootedObject::new_unrooted(ptr::null_mut()),
737 nextMethod: RootedValue::new_unrooted(JSVal { asBits_: 0 }),
738 index: ::std::u32::MAX, ..zero
740 };
741 let iterator = ForOfIteratorGuard::new(cx, &mut iterator);
742 let iterator: &mut ForOfIterator = &mut *iterator.root;
743
744 if !iterator.init(
745 value.into(),
746 ForOfIterator_NonIterableBehavior::AllowNonIterable,
747 ) {
748 return Err(());
749 }
750
751 if iterator.iterator.data.is_null() {
752 return Ok(ConversionResult::Failure("Value is not iterable".into()));
753 }
754
755 let mut ret = vec![];
756
757 loop {
758 let mut done = false;
759 rooted!(in(cx) let mut val = UndefinedValue());
760 if !iterator.next(val.handle_mut().into(), &mut done) {
761 return Err(());
762 }
763
764 if done {
765 break;
766 }
767
768 ret.push(match T::from_jsval(cx, val.handle(), option.clone())? {
769 ConversionResult::Success(v) => v,
770 ConversionResult::Failure(e) => {
771 throw_type_error(cx, &e);
772 return Err(());
773 }
774 });
775 }
776
777 Ok(ret).map(ConversionResult::Success)
778 }
779}
780
781impl ToJSValConvertible for *mut JSObject {
783 #[inline]
784 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
785 rval.set(ObjectOrNullValue(*self));
786 maybe_wrap_object_or_null_value(cx, rval);
787 }
788}
789
790impl ToJSValConvertible for ptr::NonNull<JSObject> {
792 #[inline]
793 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
794 rval.set(ObjectValue(self.as_ptr()));
795 maybe_wrap_object_value(cx, rval);
796 }
797}
798
799impl ToJSValConvertible for Heap<*mut JSObject> {
801 #[inline]
802 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
803 rval.set(ObjectOrNullValue(self.get()));
804 maybe_wrap_object_or_null_value(cx, rval);
805 }
806}
807
808impl FromJSValConvertible for *mut JSObject {
810 type Config = ();
811 #[inline]
812 unsafe fn from_jsval(
813 cx: *mut JSContext,
814 value: HandleValue,
815 _option: (),
816 ) -> Result<ConversionResult<*mut JSObject>, ()> {
817 if !value.is_object() {
818 throw_type_error(cx, "value is not an object");
819 return Err(());
820 }
821
822 AssertSameCompartment(cx, value.to_object());
823
824 Ok(ConversionResult::Success(value.to_object()))
825 }
826}
827
828impl ToJSValConvertible for *mut JS::Symbol {
829 #[inline]
830 unsafe fn to_jsval(&self, _: *mut JSContext, mut rval: MutableHandleValue) {
831 rval.set(SymbolValue(&**self));
832 }
833}
834
835impl FromJSValConvertible for *mut JS::Symbol {
836 type Config = ();
837 #[inline]
838 unsafe fn from_jsval(
839 cx: *mut JSContext,
840 value: HandleValue,
841 _option: (),
842 ) -> Result<ConversionResult<*mut JS::Symbol>, ()> {
843 if !value.is_symbol() {
844 throw_type_error(cx, "value is not a symbol");
845 return Err(());
846 }
847
848 Ok(ConversionResult::Success(value.to_symbol()))
849 }
850}