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_NewStringCopyUTF8N, 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 num_traits::PrimInt;
50use std::borrow::Cow;
51use std::ffi::CStr;
52use std::mem;
53use std::ptr::NonNull;
54use std::rc::Rc;
55use std::{ptr, slice};
56
57trait As<O>: Copy {
58 fn cast(self) -> O;
59}
60
61macro_rules! impl_as {
62 ($I:ty, $O:ty) => {
63 impl As<$O> for $I {
64 fn cast(self) -> $O {
65 self as $O
66 }
67 }
68 };
69}
70
71impl_as!(f64, u8);
72impl_as!(f64, u16);
73impl_as!(f64, u32);
74impl_as!(f64, u64);
75impl_as!(f64, i8);
76impl_as!(f64, i16);
77impl_as!(f64, i32);
78impl_as!(f64, i64);
79
80impl_as!(u8, f64);
81impl_as!(u16, f64);
82impl_as!(u32, f64);
83impl_as!(u64, f64);
84impl_as!(i8, f64);
85impl_as!(i16, f64);
86impl_as!(i32, f64);
87impl_as!(i64, f64);
88
89impl_as!(i32, i8);
90impl_as!(i32, u8);
91impl_as!(i32, i16);
92impl_as!(u16, u16);
93impl_as!(i32, i32);
94impl_as!(u32, u32);
95impl_as!(i64, i64);
96impl_as!(u64, u64);
97
98pub trait Number {
100 const ZERO: Self;
102 const MIN: Self;
104 const MAX: Self;
106}
107
108macro_rules! impl_num {
109 ($N:ty, $zero:expr, $min:expr, $max:expr) => {
110 impl Number for $N {
111 const ZERO: $N = $zero;
112 const MIN: $N = $min;
113 const MAX: $N = $max;
114 }
115 };
116}
117
118impl_num!(u8, 0, u8::MIN, u8::MAX);
120impl_num!(u16, 0, u16::MIN, u16::MAX);
121impl_num!(u32, 0, u32::MIN, u32::MAX);
122impl_num!(u64, 0, 0, (1 << 53) - 1);
123
124impl_num!(i8, 0, i8::MIN, i8::MAX);
125impl_num!(i16, 0, i16::MIN, i16::MAX);
126impl_num!(i32, 0, i32::MIN, i32::MAX);
127impl_num!(i64, 0, -(1 << 53) + 1, (1 << 53) - 1);
128
129impl_num!(f32, 0.0, f32::MIN, f32::MAX);
130impl_num!(f64, 0.0, f64::MIN, f64::MAX);
131
132pub trait ToJSValConvertible {
134 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue);
136
137 fn safe_to_jsval(&self, cx: &mut crate::context::JSContext, rval: MutableHandleValue) {
139 unsafe { self.to_jsval(cx.raw_cx(), rval) }
140 }
141}
142
143#[derive(PartialEq, Eq, Clone, Debug)]
145pub enum ConversionResult<T> {
146 Success(T),
148 Failure(Cow<'static, CStr>),
150}
151
152impl<T> ConversionResult<T> {
153 pub fn get_success_value(&self) -> Option<&T> {
155 match *self {
156 ConversionResult::Success(ref v) => Some(v),
157 _ => None,
158 }
159 }
160}
161
162pub trait FromJSValConvertible: Sized {
164 type Config;
166 unsafe fn from_jsval(
172 cx: *mut JSContext,
173 val: HandleValue,
174 option: Self::Config,
175 ) -> Result<ConversionResult<Self>, ()>;
176
177 fn safe_from_jsval(
183 cx: &mut crate::context::JSContext,
184 val: HandleValue,
185 option: Self::Config,
186 ) -> Result<ConversionResult<Self>, ()> {
187 unsafe { Self::from_jsval(cx.raw_cx(), val, option) }
188 }
189}
190
191pub trait FromJSValConvertibleRc: Sized {
193 unsafe fn from_jsval(
197 cx: *mut JSContext,
198 val: HandleValue,
199 ) -> Result<ConversionResult<Rc<Self>>, ()>;
200
201 fn safe_from_jsval(
205 cx: &mut crate::context::JSContext,
206 val: HandleValue,
207 ) -> Result<ConversionResult<Rc<Self>>, ()> {
208 unsafe { Self::from_jsval(cx.raw_cx(), val) }
209 }
210}
211
212impl<T: FromJSValConvertibleRc> FromJSValConvertible for Rc<T> {
213 type Config = ();
214
215 unsafe fn from_jsval(
216 cx: *mut JSContext,
217 val: HandleValue,
218 _option: (),
219 ) -> Result<ConversionResult<Rc<T>>, ()> {
220 <T as FromJSValConvertibleRc>::from_jsval(cx, val)
221 }
222
223 fn safe_from_jsval(
224 cx: &mut crate::context::JSContext,
225 val: HandleValue,
226 _option: (),
227 ) -> Result<ConversionResult<Rc<T>>, ()> {
228 <T as FromJSValConvertibleRc>::safe_from_jsval(cx, val)
229 }
230}
231
232#[derive(PartialEq, Eq, Clone)]
234pub enum ConversionBehavior {
235 Default,
237 EnforceRange,
239 Clamp,
241}
242
243unsafe fn enforce_range<D>(cx: *mut JSContext, d: f64) -> Result<ConversionResult<D>, ()>
247where
248 D: Number + As<f64>,
249 f64: As<D>,
250{
251 if d.is_infinite() {
252 throw_type_error(cx, c"value out of range in an EnforceRange argument");
253 return Err(());
254 }
255
256 let rounded = d.signum() * d.abs().floor();
257 if D::MIN.cast() <= rounded && rounded <= D::MAX.cast() {
258 Ok(ConversionResult::Success(rounded.cast()))
259 } else {
260 throw_type_error(cx, c"value out of range in an EnforceRange argument");
261 Err(())
262 }
263}
264
265fn clamp_to<D>(d: f64) -> D
275where
276 D: Number + PrimInt + As<f64>,
277 f64: As<D>,
278{
279 if d.is_nan() {
281 return D::ZERO;
282 }
283
284 if d >= D::MAX.cast() {
285 return D::MAX;
286 }
287 if d <= D::MIN.cast() {
288 return D::MIN;
289 }
290
291 debug_assert!(d.is_finite());
292
293 let to_truncate = if d < 0.0 { d - 0.5 } else { d + 0.5 };
299
300 let mut truncated: D = to_truncate.cast();
301
302 if truncated.cast() == to_truncate {
303 truncated = truncated & !D::one();
309 }
310
311 truncated
312}
313
314impl ToJSValConvertible for () {
316 #[inline]
317 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
318 rval.set(UndefinedValue());
319 }
320}
321
322impl FromJSValConvertible for JSVal {
323 type Config = ();
324 unsafe fn from_jsval(
325 _cx: *mut JSContext,
326 value: HandleValue,
327 _option: (),
328 ) -> Result<ConversionResult<JSVal>, ()> {
329 Ok(ConversionResult::Success(value.get()))
330 }
331}
332
333impl ToJSValConvertible for JSVal {
334 #[inline]
335 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
336 rval.set(*self);
337 maybe_wrap_value(cx, rval);
338 }
339}
340
341impl<'a> ToJSValConvertible for HandleValue<'a> {
342 #[inline]
343 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
344 rval.set(self.get());
345 maybe_wrap_value(cx, rval);
346 }
347}
348
349impl ToJSValConvertible for Heap<JSVal> {
350 #[inline]
351 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
352 rval.set(self.get());
353 maybe_wrap_value(cx, rval);
354 }
355}
356
357#[inline]
358unsafe fn convert_int_from_jsval<T, M>(
359 cx: *mut JSContext,
360 value: HandleValue,
361 option: ConversionBehavior,
362 convert_fn: unsafe fn(*mut JSContext, HandleValue) -> Result<M, ()>,
363) -> Result<ConversionResult<T>, ()>
364where
365 T: Number + As<f64> + PrimInt,
366 M: Number + As<T>,
367 f64: As<T>,
368{
369 match option {
370 ConversionBehavior::Default => Ok(ConversionResult::Success(convert_fn(cx, value)?.cast())),
371 ConversionBehavior::EnforceRange => enforce_range(cx, ToNumber(cx, value)?),
372 ConversionBehavior::Clamp => Ok(ConversionResult::Success(clamp_to(ToNumber(cx, value)?))),
373 }
374}
375
376impl ToJSValConvertible for bool {
378 #[inline]
379 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
380 rval.set(BooleanValue(*self));
381 }
382}
383
384impl FromJSValConvertible for bool {
386 type Config = ();
387 unsafe fn from_jsval(
388 _cx: *mut JSContext,
389 val: HandleValue,
390 _option: (),
391 ) -> Result<ConversionResult<bool>, ()> {
392 Ok(ToBoolean(val)).map(ConversionResult::Success)
393 }
394}
395
396impl ToJSValConvertible for i8 {
398 #[inline]
399 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
400 rval.set(Int32Value(*self as i32));
401 }
402}
403
404impl FromJSValConvertible for i8 {
406 type Config = ConversionBehavior;
407 unsafe fn from_jsval(
408 cx: *mut JSContext,
409 val: HandleValue,
410 option: ConversionBehavior,
411 ) -> Result<ConversionResult<i8>, ()> {
412 convert_int_from_jsval(cx, val, option, ToInt32)
413 }
414}
415
416impl ToJSValConvertible for u8 {
418 #[inline]
419 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
420 rval.set(Int32Value(*self as i32));
421 }
422}
423
424impl FromJSValConvertible for u8 {
426 type Config = ConversionBehavior;
427 unsafe fn from_jsval(
428 cx: *mut JSContext,
429 val: HandleValue,
430 option: ConversionBehavior,
431 ) -> Result<ConversionResult<u8>, ()> {
432 convert_int_from_jsval(cx, val, option, ToInt32)
433 }
434}
435
436impl ToJSValConvertible for i16 {
438 #[inline]
439 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
440 rval.set(Int32Value(*self as i32));
441 }
442}
443
444impl FromJSValConvertible for i16 {
446 type Config = ConversionBehavior;
447 unsafe fn from_jsval(
448 cx: *mut JSContext,
449 val: HandleValue,
450 option: ConversionBehavior,
451 ) -> Result<ConversionResult<i16>, ()> {
452 convert_int_from_jsval(cx, val, option, ToInt32)
453 }
454}
455
456impl ToJSValConvertible for u16 {
458 #[inline]
459 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
460 rval.set(Int32Value(*self as i32));
461 }
462}
463
464impl FromJSValConvertible for u16 {
466 type Config = ConversionBehavior;
467 unsafe fn from_jsval(
468 cx: *mut JSContext,
469 val: HandleValue,
470 option: ConversionBehavior,
471 ) -> Result<ConversionResult<u16>, ()> {
472 convert_int_from_jsval(cx, val, option, ToUint16)
473 }
474}
475
476impl ToJSValConvertible for i32 {
478 #[inline]
479 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
480 rval.set(Int32Value(*self));
481 }
482}
483
484impl FromJSValConvertible for i32 {
486 type Config = ConversionBehavior;
487 unsafe fn from_jsval(
488 cx: *mut JSContext,
489 val: HandleValue,
490 option: ConversionBehavior,
491 ) -> Result<ConversionResult<i32>, ()> {
492 convert_int_from_jsval(cx, val, option, ToInt32)
493 }
494}
495
496impl ToJSValConvertible for u32 {
498 #[inline]
499 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
500 rval.set(UInt32Value(*self));
501 }
502}
503
504impl FromJSValConvertible for u32 {
506 type Config = ConversionBehavior;
507 unsafe fn from_jsval(
508 cx: *mut JSContext,
509 val: HandleValue,
510 option: ConversionBehavior,
511 ) -> Result<ConversionResult<u32>, ()> {
512 convert_int_from_jsval(cx, val, option, ToUint32)
513 }
514}
515
516impl ToJSValConvertible for i64 {
518 #[inline]
519 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
520 rval.set(DoubleValue(*self as f64));
521 }
522}
523
524impl FromJSValConvertible for i64 {
526 type Config = ConversionBehavior;
527 unsafe fn from_jsval(
528 cx: *mut JSContext,
529 val: HandleValue,
530 option: ConversionBehavior,
531 ) -> Result<ConversionResult<i64>, ()> {
532 convert_int_from_jsval(cx, val, option, ToInt64)
533 }
534}
535
536impl ToJSValConvertible for u64 {
538 #[inline]
539 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
540 rval.set(DoubleValue(*self as f64));
541 }
542}
543
544impl FromJSValConvertible for u64 {
546 type Config = ConversionBehavior;
547 unsafe fn from_jsval(
548 cx: *mut JSContext,
549 val: HandleValue,
550 option: ConversionBehavior,
551 ) -> Result<ConversionResult<u64>, ()> {
552 convert_int_from_jsval(cx, val, option, ToUint64)
553 }
554}
555
556impl ToJSValConvertible for f32 {
558 #[inline]
559 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
560 rval.set(DoubleValue(*self as f64));
561 }
562}
563
564impl FromJSValConvertible for f32 {
566 type Config = ();
567 unsafe fn from_jsval(
568 cx: *mut JSContext,
569 val: HandleValue,
570 _option: (),
571 ) -> Result<ConversionResult<f32>, ()> {
572 let result = ToNumber(cx, val);
573 result.map(|f| f as f32).map(ConversionResult::Success)
574 }
575}
576
577impl ToJSValConvertible for f64 {
579 #[inline]
580 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
581 rval.set(DoubleValue(*self))
582 }
583}
584
585impl FromJSValConvertible for f64 {
587 type Config = ();
588 unsafe fn from_jsval(
589 cx: *mut JSContext,
590 val: HandleValue,
591 _option: (),
592 ) -> Result<ConversionResult<f64>, ()> {
593 ToNumber(cx, val).map(ConversionResult::Success)
594 }
595}
596
597pub unsafe fn latin1_to_string(cx: *mut JSContext, s: NonNull<JSString>) -> String {
600 assert!(JS_DeprecatedStringHasLatin1Chars(s.as_ptr()));
601
602 let mut length = 0;
603 let chars = unsafe {
604 let chars = JS_GetLatin1StringCharsAndLength(cx, ptr::null(), s.as_ptr(), &mut length);
605 assert!(!chars.is_null());
606
607 slice::from_raw_parts(chars, length as usize)
608 };
609 let mut v = vec![0; chars.len() * 2];
613 let real_size = encoding_rs::mem::convert_latin1_to_utf8(chars, v.as_mut_slice());
614
615 v.truncate(real_size);
616
617 unsafe { String::from_utf8_unchecked(v) }
620}
621
622pub unsafe fn jsstr_to_string(cx: *mut JSContext, jsstr: NonNull<JSString>) -> String {
624 if JS_DeprecatedStringHasLatin1Chars(jsstr.as_ptr()) {
625 return latin1_to_string(cx, jsstr);
626 }
627
628 let mut length = 0;
629 let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), jsstr.as_ptr(), &mut length);
630 assert!(!chars.is_null());
631 let char_vec = slice::from_raw_parts(chars, length as usize);
632 String::from_utf16_lossy(char_vec)
633}
634
635impl ToJSValConvertible for str {
637 #[inline]
638 #[deny(unsafe_op_in_unsafe_fn)]
639 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
640 let s = Utf8Chars::from(self);
644 let jsstr = unsafe { JS_NewStringCopyUTF8N(cx, &*s as *const _) };
645 if jsstr.is_null() {
646 panic!("JS String copy routine failed");
647 }
648 unsafe {
649 rval.set(StringValue(&*jsstr));
650 }
651 }
652}
653
654impl ToJSValConvertible for String {
656 #[inline]
657 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
658 (**self).to_jsval(cx, rval);
659 }
660}
661
662impl FromJSValConvertible for String {
664 type Config = ();
665 unsafe fn from_jsval(
666 cx: *mut JSContext,
667 value: HandleValue,
668 _: (),
669 ) -> Result<ConversionResult<String>, ()> {
670 let jsstr = ToString(cx, value);
671 let Some(jsstr) = NonNull::new(jsstr) else {
672 debug!("ToString failed");
673 return Err(());
674 };
675 Ok(jsstr_to_string(cx, jsstr)).map(ConversionResult::Success)
676 }
677}
678
679impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> {
680 #[inline]
681 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
682 match self {
683 &Some(ref value) => value.to_jsval(cx, rval),
684 &None => rval.set(NullValue()),
685 }
686 }
687}
688
689impl<T: FromJSValConvertible> FromJSValConvertible for Option<T> {
690 type Config = T::Config;
691 unsafe fn from_jsval(
692 cx: *mut JSContext,
693 value: HandleValue,
694 option: T::Config,
695 ) -> Result<ConversionResult<Option<T>>, ()> {
696 if value.get().is_null_or_undefined() {
697 Ok(ConversionResult::Success(None))
698 } else {
699 Ok(match FromJSValConvertible::from_jsval(cx, value, option)? {
700 ConversionResult::Success(v) => ConversionResult::Success(Some(v)),
701 ConversionResult::Failure(v) => ConversionResult::Failure(v),
702 })
703 }
704 }
705}
706
707impl<T: ToJSValConvertible> ToJSValConvertible for &'_ T {
708 #[inline]
709 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
710 (**self).to_jsval(cx, rval)
711 }
712}
713
714impl<T: ToJSValConvertible> ToJSValConvertible for Box<T> {
715 #[inline]
716 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
717 (**self).to_jsval(cx, rval)
718 }
719}
720
721impl<T: ToJSValConvertible> ToJSValConvertible for Rc<T> {
722 #[inline]
723 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
724 (**self).to_jsval(cx, rval)
725 }
726}
727
728impl<T: ToJSValConvertible> ToJSValConvertible for [T] {
730 #[inline]
731 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
732 rooted!(in(cx) let js_array = NewArrayObject1(cx, self.len() as libc::size_t));
733 assert!(!js_array.handle().is_null());
734
735 rooted!(in(cx) let mut val = UndefinedValue());
736 for (index, obj) in self.iter().enumerate() {
737 obj.to_jsval(cx, val.handle_mut());
738
739 assert!(JS_DefineElement(
740 cx,
741 js_array.handle().into(),
742 index as u32,
743 val.handle().into(),
744 JSPROP_ENUMERATE as u32
745 ));
746 }
747
748 rval.set(ObjectValue(js_array.handle().get()));
749 }
750}
751
752impl<T: ToJSValConvertible> ToJSValConvertible for Vec<T> {
754 #[inline]
755 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
756 <[_]>::to_jsval(self, cx, rval)
757 }
758}
759
760struct ForOfIteratorGuard<'a> {
765 root: &'a mut ForOfIterator,
766}
767
768impl<'a> ForOfIteratorGuard<'a> {
769 fn new(cx: *mut JSContext, root: &'a mut ForOfIterator) -> Self {
770 unsafe {
771 Rooted::add_to_root_stack(&raw mut root.iterator, cx);
772 }
773 ForOfIteratorGuard { root }
774 }
775}
776
777impl<'a> Drop for ForOfIteratorGuard<'a> {
778 fn drop(&mut self) {
779 unsafe {
780 self.root.iterator.remove_from_root_stack();
781 }
782 }
783}
784
785impl<C: Clone, T: FromJSValConvertible<Config = C>> FromJSValConvertible for Vec<T> {
786 type Config = C;
787
788 unsafe fn from_jsval(
789 cx: *mut JSContext,
790 value: HandleValue,
791 option: C,
792 ) -> Result<ConversionResult<Vec<T>>, ()> {
793 if !value.is_object() {
794 return Ok(ConversionResult::Failure(c"Value is not an object".into()));
795 }
796
797 #[allow(unused_variables)]
803 let zero = mem::zeroed();
804 let mut iterator = ForOfIterator {
805 cx_: cx,
806 iterator: RootedObject::new_unrooted(ptr::null_mut()),
807 nextMethod: RootedValue::new_unrooted(JSVal { asBits_: 0 }),
808 index: ::std::u32::MAX, ..zero
810 };
811 let iterator = ForOfIteratorGuard::new(cx, &mut iterator);
812 let iterator: &mut ForOfIterator = &mut *iterator.root;
813
814 if !iterator.init(
815 value.into(),
816 ForOfIterator_NonIterableBehavior::AllowNonIterable,
817 ) {
818 return Err(());
819 }
820
821 if iterator.iterator.data.is_null() {
822 return Ok(ConversionResult::Failure(c"Value is not iterable".into()));
823 }
824
825 let mut ret = vec![];
826
827 loop {
828 let mut done = false;
829 rooted!(in(cx) let mut val = UndefinedValue());
830 if !iterator.next(val.handle_mut().into(), &mut done) {
831 return Err(());
832 }
833
834 if done {
835 break;
836 }
837
838 ret.push(match T::from_jsval(cx, val.handle(), option.clone())? {
839 ConversionResult::Success(v) => v,
840 ConversionResult::Failure(e) => {
841 throw_type_error(cx, e.as_ref());
842 return Err(());
843 }
844 });
845 }
846
847 Ok(ret).map(ConversionResult::Success)
848 }
849}
850
851impl ToJSValConvertible for *mut JSObject {
853 #[inline]
854 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
855 rval.set(ObjectOrNullValue(*self));
856 maybe_wrap_object_or_null_value(cx, rval);
857 }
858}
859
860impl ToJSValConvertible for ptr::NonNull<JSObject> {
862 #[inline]
863 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
864 rval.set(ObjectValue(self.as_ptr()));
865 maybe_wrap_object_value(cx, rval);
866 }
867}
868
869impl ToJSValConvertible for Heap<*mut JSObject> {
871 #[inline]
872 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
873 rval.set(ObjectOrNullValue(self.get()));
874 maybe_wrap_object_or_null_value(cx, rval);
875 }
876}
877
878impl FromJSValConvertible for *mut JSObject {
880 type Config = ();
881 #[inline]
882 unsafe fn from_jsval(
883 cx: *mut JSContext,
884 value: HandleValue,
885 _option: (),
886 ) -> Result<ConversionResult<*mut JSObject>, ()> {
887 if !value.is_object() {
888 throw_type_error(cx, c"value is not an object");
889 return Err(());
890 }
891
892 AssertSameCompartment(cx, value.to_object());
893
894 Ok(ConversionResult::Success(value.to_object()))
895 }
896}
897
898impl ToJSValConvertible for *mut JS::Symbol {
899 #[inline]
900 unsafe fn to_jsval(&self, _: *mut JSContext, mut rval: MutableHandleValue) {
901 rval.set(SymbolValue(&**self));
902 }
903}
904
905impl FromJSValConvertible for *mut JS::Symbol {
906 type Config = ();
907 #[inline]
908 unsafe fn from_jsval(
909 cx: *mut JSContext,
910 value: HandleValue,
911 _option: (),
912 ) -> Result<ConversionResult<*mut JS::Symbol>, ()> {
913 if !value.is_symbol() {
914 throw_type_error(cx, c"value is not a symbol");
915 return Err(());
916 }
917
918 Ok(ConversionResult::Success(value.to_symbol()))
919 }
920}
921
922pub struct Utf8Chars<'a> {
926 lt_marker: std::marker::PhantomData<&'a ()>,
927 inner: crate::jsapi::UTF8Chars,
928}
929
930impl<'a> std::ops::Deref for Utf8Chars<'a> {
931 type Target = crate::jsapi::UTF8Chars;
932
933 fn deref(&self) -> &Self::Target {
934 &self.inner
935 }
936}
937
938impl<'a> From<&'a str> for Utf8Chars<'a> {
939 #[allow(unsafe_code)]
940 fn from(value: &'a str) -> Self {
941 use std::marker::PhantomData;
942
943 use crate::jsapi::mozilla::{Range, RangedPtr};
944 use crate::jsapi::UTF8Chars;
945
946 let range = value.as_bytes().as_ptr_range();
947 let range_start = range.start as *mut _;
948 let range_end = range.end as *mut _;
949 let start = RangedPtr {
950 _phantom_0: PhantomData,
951 mPtr: range_start,
952 #[cfg(feature = "debugmozjs")]
953 mRangeStart: range_start,
954 #[cfg(feature = "debugmozjs")]
955 mRangeEnd: range_end,
956 };
957 let end = RangedPtr {
958 _phantom_0: PhantomData,
959 mPtr: range_end,
960 #[cfg(feature = "debugmozjs")]
961 mRangeStart: range_start,
962 #[cfg(feature = "debugmozjs")]
963 mRangeEnd: range_end,
964 };
965 let base = Range {
966 _phantom_0: PhantomData,
967 mStart: start,
968 mEnd: end,
969 };
970 let inner = UTF8Chars { _base: base };
971 Self {
972 lt_marker: PhantomData,
973 inner,
974 }
975 }
976}