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 let zero = mem::zeroed();
803 let mut iterator = ForOfIterator {
804 cx_: cx,
805 iterator: RootedObject::new_unrooted(ptr::null_mut()),
806 nextMethod: RootedValue::new_unrooted(JSVal { asBits_: 0 }),
807 index: ::std::u32::MAX, ..zero
809 };
810 let iterator = ForOfIteratorGuard::new(cx, &mut iterator);
811 let iterator: &mut ForOfIterator = &mut *iterator.root;
812
813 if !iterator.init(
814 value.into(),
815 ForOfIterator_NonIterableBehavior::AllowNonIterable,
816 ) {
817 return Err(());
818 }
819
820 if iterator.iterator.data.is_null() {
821 return Ok(ConversionResult::Failure(c"Value is not iterable".into()));
822 }
823
824 let mut ret = vec![];
825
826 loop {
827 let mut done = false;
828 rooted!(in(cx) let mut val = UndefinedValue());
829 if !iterator.next(val.handle_mut().into(), &mut done) {
830 return Err(());
831 }
832
833 if done {
834 break;
835 }
836
837 ret.push(match T::from_jsval(cx, val.handle(), option.clone())? {
838 ConversionResult::Success(v) => v,
839 ConversionResult::Failure(e) => {
840 throw_type_error(cx, e.as_ref());
841 return Err(());
842 }
843 });
844 }
845
846 Ok(ret).map(ConversionResult::Success)
847 }
848}
849
850impl ToJSValConvertible for *mut JSObject {
852 #[inline]
853 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
854 rval.set(ObjectOrNullValue(*self));
855 maybe_wrap_object_or_null_value(cx, rval);
856 }
857}
858
859impl ToJSValConvertible for ptr::NonNull<JSObject> {
861 #[inline]
862 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
863 rval.set(ObjectValue(self.as_ptr()));
864 maybe_wrap_object_value(cx, rval);
865 }
866}
867
868impl ToJSValConvertible for Heap<*mut JSObject> {
870 #[inline]
871 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
872 rval.set(ObjectOrNullValue(self.get()));
873 maybe_wrap_object_or_null_value(cx, rval);
874 }
875}
876
877impl FromJSValConvertible for *mut JSObject {
879 type Config = ();
880 #[inline]
881 unsafe fn from_jsval(
882 cx: *mut JSContext,
883 value: HandleValue,
884 _option: (),
885 ) -> Result<ConversionResult<*mut JSObject>, ()> {
886 if !value.is_object() {
887 throw_type_error(cx, c"value is not an object");
888 return Err(());
889 }
890
891 AssertSameCompartment(cx, value.to_object());
892
893 Ok(ConversionResult::Success(value.to_object()))
894 }
895}
896
897impl ToJSValConvertible for *mut JS::Symbol {
898 #[inline]
899 unsafe fn to_jsval(&self, _: *mut JSContext, mut rval: MutableHandleValue) {
900 rval.set(SymbolValue(&**self));
901 }
902}
903
904impl FromJSValConvertible for *mut JS::Symbol {
905 type Config = ();
906 #[inline]
907 unsafe fn from_jsval(
908 cx: *mut JSContext,
909 value: HandleValue,
910 _option: (),
911 ) -> Result<ConversionResult<*mut JS::Symbol>, ()> {
912 if !value.is_symbol() {
913 throw_type_error(cx, c"value is not a symbol");
914 return Err(());
915 }
916
917 Ok(ConversionResult::Success(value.to_symbol()))
918 }
919}
920
921pub struct Utf8Chars<'a> {
925 lt_marker: std::marker::PhantomData<&'a ()>,
926 inner: crate::jsapi::UTF8Chars,
927}
928
929impl<'a> std::ops::Deref for Utf8Chars<'a> {
930 type Target = crate::jsapi::UTF8Chars;
931
932 fn deref(&self) -> &Self::Target {
933 &self.inner
934 }
935}
936
937impl<'a> From<&'a str> for Utf8Chars<'a> {
938 #[allow(unsafe_code)]
939 fn from(value: &'a str) -> Self {
940 use std::marker::PhantomData;
941
942 use crate::jsapi::mozilla::{Range, RangedPtr};
943 use crate::jsapi::UTF8Chars;
944
945 let range = value.as_bytes().as_ptr_range();
946 let range_start = range.start as *mut _;
947 let range_end = range.end as *mut _;
948 let start = RangedPtr {
949 _phantom_0: PhantomData,
950 mPtr: range_start,
951 #[cfg(feature = "debugmozjs")]
952 mRangeStart: range_start,
953 #[cfg(feature = "debugmozjs")]
954 mRangeEnd: range_end,
955 };
956 let end = RangedPtr {
957 _phantom_0: PhantomData,
958 mPtr: range_end,
959 #[cfg(feature = "debugmozjs")]
960 mRangeStart: range_start,
961 #[cfg(feature = "debugmozjs")]
962 mRangeEnd: range_end,
963 };
964 let base = Range {
965 _phantom_0: PhantomData,
966 mStart: start,
967 mEnd: end,
968 };
969 let inner = UTF8Chars { _base: base };
970 Self {
971 lt_marker: PhantomData,
972 inner,
973 }
974 }
975}