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