1#![deny(missing_docs)]
30
31use crate::error::throw_type_error;
32use crate::jsapi::AssertSameCompartment;
33use crate::jsapi::NewArrayObject1;
34use crate::jsapi::JS;
35use crate::jsapi::{Heap, JS_DefineElement};
36use crate::jsapi::{JSContext, JSObject, JSString};
37use crate::jsapi::{JS_DeprecatedStringHasLatin1Chars, JS_NewStringCopyUTF8N, JSPROP_ENUMERATE};
38use crate::jsval::{BooleanValue, DoubleValue, Int32Value, NullValue, UInt32Value, UndefinedValue};
39use crate::jsval::{JSVal, ObjectOrNullValue, ObjectValue, StringValue, SymbolValue};
40use crate::rooted;
41use crate::rust::for_of;
42use crate::rust::maybe_wrap_value;
43use crate::rust::wrappers2::{JS_GetLatin1StringCharsAndLength, JS_GetTwoByteStringCharsAndLength};
44use crate::rust::ForOfIterationFailure;
45use crate::rust::{maybe_wrap_object_or_null_value, maybe_wrap_object_value, ToString};
46use crate::rust::{HandleValue, MutableHandleValue};
47use crate::rust::{ToBoolean, ToInt32, ToInt64, ToNumber, ToUint16, ToUint32, ToUint64};
48use libc;
49use log::debug;
50use num_traits::PrimInt;
51use std::borrow::Cow;
52use std::ffi::CStr;
53use std::ops::ControlFlow;
54use std::ptr::NonNull;
55use std::rc::Rc;
56use std::{ptr, slice};
57
58trait As<O>: Copy {
59 fn cast(self) -> O;
60}
61
62macro_rules! impl_as {
63 ($I:ty, $O:ty) => {
64 impl As<$O> for $I {
65 fn cast(self) -> $O {
66 self as $O
67 }
68 }
69 };
70}
71
72impl_as!(f64, u8);
73impl_as!(f64, u16);
74impl_as!(f64, u32);
75impl_as!(f64, u64);
76impl_as!(f64, i8);
77impl_as!(f64, i16);
78impl_as!(f64, i32);
79impl_as!(f64, i64);
80
81impl_as!(u8, f64);
82impl_as!(u16, f64);
83impl_as!(u32, f64);
84impl_as!(u64, f64);
85impl_as!(i8, f64);
86impl_as!(i16, f64);
87impl_as!(i32, f64);
88impl_as!(i64, f64);
89
90impl_as!(i32, i8);
91impl_as!(i32, u8);
92impl_as!(i32, i16);
93impl_as!(u16, u16);
94impl_as!(i32, i32);
95impl_as!(u32, u32);
96impl_as!(i64, i64);
97impl_as!(u64, u64);
98
99pub trait Number {
101 const ZERO: Self;
103 const MIN: Self;
105 const MAX: Self;
107}
108
109macro_rules! impl_num {
110 ($N:ty, $zero:expr, $min:expr, $max:expr) => {
111 impl Number for $N {
112 const ZERO: $N = $zero;
113 const MIN: $N = $min;
114 const MAX: $N = $max;
115 }
116 };
117}
118
119impl_num!(u8, 0, u8::MIN, u8::MAX);
121impl_num!(u16, 0, u16::MIN, u16::MAX);
122impl_num!(u32, 0, u32::MIN, u32::MAX);
123impl_num!(u64, 0, 0, (1 << 53) - 1);
124
125impl_num!(i8, 0, i8::MIN, i8::MAX);
126impl_num!(i16, 0, i16::MIN, i16::MAX);
127impl_num!(i32, 0, i32::MIN, i32::MAX);
128impl_num!(i64, 0, -(1 << 53) + 1, (1 << 53) - 1);
129
130impl_num!(f32, 0.0, f32::MIN, f32::MAX);
131impl_num!(f64, 0.0, f64::MIN, f64::MAX);
132
133pub trait ToJSValConvertible {
135 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue);
137
138 fn safe_to_jsval(&self, cx: &mut crate::context::JSContext, rval: MutableHandleValue) {
140 unsafe { self.to_jsval(cx.raw_cx(), rval) }
141 }
142}
143
144#[derive(PartialEq, Eq, Clone, Debug)]
146pub enum ConversionResult<T> {
147 Success(T),
149 Failure(Cow<'static, CStr>),
151}
152
153impl<T> ConversionResult<T> {
154 pub fn get_success_value(&self) -> Option<&T> {
156 match *self {
157 ConversionResult::Success(ref v) => Some(v),
158 _ => None,
159 }
160 }
161}
162
163pub trait FromJSValConvertible: Sized {
165 type Config;
167 unsafe fn from_jsval(
173 cx: *mut JSContext,
174 val: HandleValue,
175 option: Self::Config,
176 ) -> Result<ConversionResult<Self>, ()>;
177
178 fn safe_from_jsval(
184 cx: &mut crate::context::JSContext,
185 val: HandleValue,
186 option: Self::Config,
187 ) -> Result<ConversionResult<Self>, ()> {
188 unsafe { Self::from_jsval(cx.raw_cx(), val, option) }
189 }
190}
191
192pub trait FromJSValConvertibleRc: Sized {
194 unsafe fn from_jsval(
198 cx: *mut JSContext,
199 val: HandleValue,
200 ) -> Result<ConversionResult<Rc<Self>>, ()>;
201
202 fn safe_from_jsval(
206 cx: &mut crate::context::JSContext,
207 val: HandleValue,
208 ) -> Result<ConversionResult<Rc<Self>>, ()> {
209 unsafe { Self::from_jsval(cx.raw_cx(), val) }
210 }
211}
212
213impl<T: FromJSValConvertibleRc> FromJSValConvertible for Rc<T> {
214 type Config = ();
215
216 unsafe fn from_jsval(
217 cx: *mut JSContext,
218 val: HandleValue,
219 _option: (),
220 ) -> Result<ConversionResult<Rc<T>>, ()> {
221 <T as FromJSValConvertibleRc>::from_jsval(cx, val)
222 }
223
224 fn safe_from_jsval(
225 cx: &mut crate::context::JSContext,
226 val: HandleValue,
227 _option: (),
228 ) -> Result<ConversionResult<Rc<T>>, ()> {
229 <T as FromJSValConvertibleRc>::safe_from_jsval(cx, val)
230 }
231}
232
233#[derive(PartialEq, Eq, Clone)]
235pub enum ConversionBehavior {
236 Default,
238 EnforceRange,
240 Clamp,
242}
243
244unsafe fn enforce_range<D>(cx: *mut JSContext, d: f64) -> Result<ConversionResult<D>, ()>
248where
249 D: Number + As<f64>,
250 f64: As<D>,
251{
252 if d.is_infinite() {
253 throw_type_error(cx, c"value out of range in an EnforceRange argument");
254 return Err(());
255 }
256
257 let rounded = d.signum() * d.abs().floor();
258 if D::MIN.cast() <= rounded && rounded <= D::MAX.cast() {
259 Ok(ConversionResult::Success(rounded.cast()))
260 } else {
261 throw_type_error(cx, c"value out of range in an EnforceRange argument");
262 Err(())
263 }
264}
265
266fn clamp_to<D>(d: f64) -> D
276where
277 D: Number + PrimInt + As<f64>,
278 f64: As<D>,
279{
280 if d.is_nan() {
282 return D::ZERO;
283 }
284
285 if d >= D::MAX.cast() {
286 return D::MAX;
287 }
288 if d <= D::MIN.cast() {
289 return D::MIN;
290 }
291
292 debug_assert!(d.is_finite());
293
294 let to_truncate = if d < 0.0 { d - 0.5 } else { d + 0.5 };
300
301 let mut truncated: D = to_truncate.cast();
302
303 if truncated.cast() == to_truncate {
304 truncated = truncated & !D::one();
310 }
311
312 truncated
313}
314
315impl ToJSValConvertible for () {
317 #[inline]
318 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
319 rval.set(UndefinedValue());
320 }
321}
322
323impl FromJSValConvertible for JSVal {
324 type Config = ();
325 unsafe fn from_jsval(
326 _cx: *mut JSContext,
327 value: HandleValue,
328 _option: (),
329 ) -> Result<ConversionResult<JSVal>, ()> {
330 Ok(ConversionResult::Success(value.get()))
331 }
332}
333
334impl ToJSValConvertible for JSVal {
335 #[inline]
336 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
337 rval.set(*self);
338 maybe_wrap_value(cx, rval);
339 }
340}
341
342impl<'a> ToJSValConvertible for HandleValue<'a> {
343 #[inline]
344 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
345 rval.set(self.get());
346 maybe_wrap_value(cx, rval);
347 }
348}
349
350impl ToJSValConvertible for Heap<JSVal> {
351 #[inline]
352 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
353 rval.set(self.get());
354 maybe_wrap_value(cx, rval);
355 }
356}
357
358#[inline]
359unsafe fn convert_int_from_jsval<T, M>(
360 cx: *mut JSContext,
361 value: HandleValue,
362 option: ConversionBehavior,
363 convert_fn: unsafe fn(*mut JSContext, HandleValue) -> Result<M, ()>,
364) -> Result<ConversionResult<T>, ()>
365where
366 T: Number + As<f64> + PrimInt,
367 M: Number + As<T>,
368 f64: As<T>,
369{
370 match option {
371 ConversionBehavior::Default => Ok(ConversionResult::Success(convert_fn(cx, value)?.cast())),
372 ConversionBehavior::EnforceRange => enforce_range(cx, ToNumber(cx, value)?),
373 ConversionBehavior::Clamp => Ok(ConversionResult::Success(clamp_to(ToNumber(cx, value)?))),
374 }
375}
376
377impl ToJSValConvertible for bool {
379 #[inline]
380 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
381 rval.set(BooleanValue(*self));
382 }
383}
384
385impl FromJSValConvertible for bool {
387 type Config = ();
388 unsafe fn from_jsval(
389 _cx: *mut JSContext,
390 val: HandleValue,
391 _option: (),
392 ) -> Result<ConversionResult<bool>, ()> {
393 Ok(ToBoolean(val)).map(ConversionResult::Success)
394 }
395}
396
397impl ToJSValConvertible for i8 {
399 #[inline]
400 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
401 rval.set(Int32Value(*self as i32));
402 }
403}
404
405impl FromJSValConvertible for i8 {
407 type Config = ConversionBehavior;
408 unsafe fn from_jsval(
409 cx: *mut JSContext,
410 val: HandleValue,
411 option: ConversionBehavior,
412 ) -> Result<ConversionResult<i8>, ()> {
413 convert_int_from_jsval(cx, val, option, ToInt32)
414 }
415}
416
417impl ToJSValConvertible for u8 {
419 #[inline]
420 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
421 rval.set(Int32Value(*self as i32));
422 }
423}
424
425impl FromJSValConvertible for u8 {
427 type Config = ConversionBehavior;
428 unsafe fn from_jsval(
429 cx: *mut JSContext,
430 val: HandleValue,
431 option: ConversionBehavior,
432 ) -> Result<ConversionResult<u8>, ()> {
433 convert_int_from_jsval(cx, val, option, ToInt32)
434 }
435}
436
437impl ToJSValConvertible for i16 {
439 #[inline]
440 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
441 rval.set(Int32Value(*self as i32));
442 }
443}
444
445impl FromJSValConvertible for i16 {
447 type Config = ConversionBehavior;
448 unsafe fn from_jsval(
449 cx: *mut JSContext,
450 val: HandleValue,
451 option: ConversionBehavior,
452 ) -> Result<ConversionResult<i16>, ()> {
453 convert_int_from_jsval(cx, val, option, ToInt32)
454 }
455}
456
457impl ToJSValConvertible for u16 {
459 #[inline]
460 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
461 rval.set(Int32Value(*self as i32));
462 }
463}
464
465impl FromJSValConvertible for u16 {
467 type Config = ConversionBehavior;
468 unsafe fn from_jsval(
469 cx: *mut JSContext,
470 val: HandleValue,
471 option: ConversionBehavior,
472 ) -> Result<ConversionResult<u16>, ()> {
473 convert_int_from_jsval(cx, val, option, ToUint16)
474 }
475}
476
477impl ToJSValConvertible for i32 {
479 #[inline]
480 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
481 rval.set(Int32Value(*self));
482 }
483}
484
485impl FromJSValConvertible for i32 {
487 type Config = ConversionBehavior;
488 unsafe fn from_jsval(
489 cx: *mut JSContext,
490 val: HandleValue,
491 option: ConversionBehavior,
492 ) -> Result<ConversionResult<i32>, ()> {
493 convert_int_from_jsval(cx, val, option, ToInt32)
494 }
495}
496
497impl ToJSValConvertible for u32 {
499 #[inline]
500 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
501 rval.set(UInt32Value(*self));
502 }
503}
504
505impl FromJSValConvertible for u32 {
507 type Config = ConversionBehavior;
508 unsafe fn from_jsval(
509 cx: *mut JSContext,
510 val: HandleValue,
511 option: ConversionBehavior,
512 ) -> Result<ConversionResult<u32>, ()> {
513 convert_int_from_jsval(cx, val, option, ToUint32)
514 }
515}
516
517impl ToJSValConvertible for i64 {
519 #[inline]
520 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
521 rval.set(DoubleValue(*self as f64));
522 }
523}
524
525impl FromJSValConvertible for i64 {
527 type Config = ConversionBehavior;
528 unsafe fn from_jsval(
529 cx: *mut JSContext,
530 val: HandleValue,
531 option: ConversionBehavior,
532 ) -> Result<ConversionResult<i64>, ()> {
533 convert_int_from_jsval(cx, val, option, ToInt64)
534 }
535}
536
537impl ToJSValConvertible for u64 {
539 #[inline]
540 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
541 rval.set(DoubleValue(*self as f64));
542 }
543}
544
545impl FromJSValConvertible for u64 {
547 type Config = ConversionBehavior;
548 unsafe fn from_jsval(
549 cx: *mut JSContext,
550 val: HandleValue,
551 option: ConversionBehavior,
552 ) -> Result<ConversionResult<u64>, ()> {
553 convert_int_from_jsval(cx, val, option, ToUint64)
554 }
555}
556
557impl ToJSValConvertible for f32 {
559 #[inline]
560 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
561 rval.set(DoubleValue(*self as f64));
562 }
563}
564
565impl FromJSValConvertible for f32 {
567 type Config = ();
568 unsafe fn from_jsval(
569 cx: *mut JSContext,
570 val: HandleValue,
571 _option: (),
572 ) -> Result<ConversionResult<f32>, ()> {
573 let result = ToNumber(cx, val);
574 result.map(|f| f as f32).map(ConversionResult::Success)
575 }
576}
577
578impl ToJSValConvertible for f64 {
580 #[inline]
581 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
582 rval.set(DoubleValue(*self))
583 }
584}
585
586impl FromJSValConvertible for f64 {
588 type Config = ();
589 unsafe fn from_jsval(
590 cx: *mut JSContext,
591 val: HandleValue,
592 _option: (),
593 ) -> Result<ConversionResult<f64>, ()> {
594 ToNumber(cx, val).map(ConversionResult::Success)
595 }
596}
597
598pub unsafe fn latin1_to_string(cx: &crate::context::JSContext, s: NonNull<JSString>) -> String {
604 assert!(unsafe { JS_DeprecatedStringHasLatin1Chars(s.as_ptr()) });
605
606 let mut length = 0;
607 let chars = unsafe {
608 let chars = JS_GetLatin1StringCharsAndLength(cx, s.as_ptr(), &mut length);
609 assert!(!chars.is_null());
610
611 slice::from_raw_parts(chars, length as usize)
612 };
613 let mut v = vec![0; chars.len() * 2];
617 let real_size = encoding_rs::mem::convert_latin1_to_utf8(chars, v.as_mut_slice());
618
619 v.truncate(real_size);
620
621 unsafe { String::from_utf8_unchecked(v) }
624}
625
626pub unsafe fn jsstr_to_string(cx: &crate::context::JSContext, jsstr: NonNull<JSString>) -> String {
631 if unsafe { JS_DeprecatedStringHasLatin1Chars(jsstr.as_ptr()) } {
632 return latin1_to_string(cx, jsstr);
633 }
634
635 let mut length = 0;
636 let chars = unsafe { JS_GetTwoByteStringCharsAndLength(cx, jsstr.as_ptr(), &mut length) };
637 assert!(!chars.is_null());
638 let char_vec = unsafe { slice::from_raw_parts(chars, length as usize) };
639 String::from_utf16_lossy(char_vec)
640}
641
642#[deprecated(note = "Use latin1_to_string instead")]
647pub unsafe fn unsafe_latin1_to_string(cx: *mut JSContext, s: NonNull<JSString>) -> String {
648 let cx = crate::context::JSContext::from_ptr(NonNull::new(cx).unwrap());
651 latin1_to_string(&cx, s)
652}
653
654#[deprecated(note = "Use jsstr_to_string instead")]
658pub unsafe fn unsafe_jsstr_to_string(cx: *mut JSContext, jsstr: NonNull<JSString>) -> String {
659 let cx = crate::context::JSContext::from_ptr(NonNull::new(cx).unwrap());
662 jsstr_to_string(&cx, jsstr)
663}
664
665impl ToJSValConvertible for str {
667 #[inline]
668 #[deny(unsafe_op_in_unsafe_fn)]
669 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
670 let s = Utf8Chars::from(self);
674 let jsstr = unsafe { JS_NewStringCopyUTF8N(cx, &*s as *const _) };
675 if jsstr.is_null() {
676 panic!("JS String copy routine failed");
677 }
678 unsafe {
679 rval.set(StringValue(&*jsstr));
680 }
681 }
682}
683
684impl ToJSValConvertible for String {
686 #[inline]
687 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
688 (**self).to_jsval(cx, rval);
689 }
690}
691
692impl FromJSValConvertible for String {
694 type Config = ();
695 unsafe fn from_jsval(
696 cx: *mut JSContext,
697 value: HandleValue,
698 _: (),
699 ) -> Result<ConversionResult<String>, ()> {
700 let mut cx = crate::context::JSContext::from_ptr(NonNull::new(cx).unwrap());
702 FromJSValConvertible::safe_from_jsval(&mut cx, value, ())
703 }
704
705 fn safe_from_jsval(
706 cx: &mut crate::context::JSContext,
707 value: HandleValue,
708 _config: Self::Config,
709 ) -> Result<ConversionResult<String>, ()> {
710 let jsstr = unsafe { ToString(cx, value) };
711 let Some(jsstr) = NonNull::new(jsstr) else {
712 debug!("ToString failed");
713 return Err(());
714 };
715 Ok(unsafe { jsstr_to_string(cx, jsstr) }).map(ConversionResult::Success)
716 }
717}
718
719impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> {
720 #[inline]
721 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
722 match self {
723 &Some(ref value) => value.to_jsval(cx, rval),
724 &None => rval.set(NullValue()),
725 }
726 }
727}
728
729impl<T: FromJSValConvertible> FromJSValConvertible for Option<T> {
730 type Config = T::Config;
731 unsafe fn from_jsval(
732 cx: *mut JSContext,
733 value: HandleValue,
734 option: T::Config,
735 ) -> Result<ConversionResult<Option<T>>, ()> {
736 if value.get().is_null_or_undefined() {
737 Ok(ConversionResult::Success(None))
738 } else {
739 Ok(match FromJSValConvertible::from_jsval(cx, value, option)? {
740 ConversionResult::Success(v) => ConversionResult::Success(Some(v)),
741 ConversionResult::Failure(v) => ConversionResult::Failure(v),
742 })
743 }
744 }
745}
746
747impl<T: ToJSValConvertible> ToJSValConvertible for &'_ T {
748 #[inline]
749 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
750 (**self).to_jsval(cx, rval)
751 }
752}
753
754impl<T: ToJSValConvertible> ToJSValConvertible for Box<T> {
755 #[inline]
756 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
757 (**self).to_jsval(cx, rval)
758 }
759}
760
761impl<T: ToJSValConvertible> ToJSValConvertible for Rc<T> {
762 #[inline]
763 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
764 (**self).to_jsval(cx, rval)
765 }
766}
767
768impl<T: ToJSValConvertible> ToJSValConvertible for [T] {
770 #[inline]
771 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
772 rooted!(in(cx) let js_array = NewArrayObject1(cx, self.len() as libc::size_t));
773 assert!(!js_array.handle().is_null());
774
775 rooted!(in(cx) let mut val = UndefinedValue());
776 for (index, obj) in self.iter().enumerate() {
777 obj.to_jsval(cx, val.handle_mut());
778
779 assert!(JS_DefineElement(
780 cx,
781 js_array.handle().into(),
782 index as u32,
783 val.handle().into(),
784 JSPROP_ENUMERATE as u32
785 ));
786 }
787
788 rval.set(ObjectValue(js_array.handle().get()));
789 }
790}
791
792impl<T: ToJSValConvertible> ToJSValConvertible for Vec<T> {
794 #[inline]
795 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
796 <[_]>::to_jsval(self, cx, rval)
797 }
798}
799
800impl<C: Clone, T: FromJSValConvertible<Config = C>> FromJSValConvertible for Vec<T> {
801 type Config = C;
802
803 unsafe fn from_jsval(
804 cx: *mut JSContext,
805 value: HandleValue,
806 option: C,
807 ) -> Result<ConversionResult<Vec<T>>, ()> {
808 if !value.is_object() {
809 return Ok(ConversionResult::Failure(c"Value is not an object".into()));
810 }
811
812 let mut return_value = vec![];
813 let result = for_of(cx, value, |iterator_element| {
814 let conversion_result = T::from_jsval(cx, iterator_element, option.clone())
815 .map_err(|_| ForOfIterationFailure::JSFailed)?;
816 return_value.push(match conversion_result {
817 ConversionResult::Success(value) => value,
818 ConversionResult::Failure(error) => {
819 return Err(ForOfIterationFailure::Other(error));
820 }
821 });
822
823 Ok(ControlFlow::Continue(()))
824 });
825
826 match result {
827 Ok(_) => Ok(ConversionResult::Success(return_value)),
828 Err(ForOfIterationFailure::ValueIsNotIterable) => {
829 Ok(ConversionResult::Failure(c"Value is not iterable".into()))
830 }
831 Err(ForOfIterationFailure::JSFailed) => Err(()),
832 Err(ForOfIterationFailure::Other(error)) => {
833 throw_type_error(cx, error.as_ref());
834 Err(())
835 }
836 }
837 }
838}
839
840impl ToJSValConvertible for *mut JSObject {
842 #[inline]
843 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
844 rval.set(ObjectOrNullValue(*self));
845 maybe_wrap_object_or_null_value(cx, rval);
846 }
847}
848
849impl ToJSValConvertible for ptr::NonNull<JSObject> {
851 #[inline]
852 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
853 rval.set(ObjectValue(self.as_ptr()));
854 maybe_wrap_object_value(cx, rval);
855 }
856}
857
858impl ToJSValConvertible for Heap<*mut JSObject> {
860 #[inline]
861 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
862 rval.set(ObjectOrNullValue(self.get()));
863 maybe_wrap_object_or_null_value(cx, rval);
864 }
865}
866
867impl FromJSValConvertible for *mut JSObject {
869 type Config = ();
870 #[inline]
871 unsafe fn from_jsval(
872 cx: *mut JSContext,
873 value: HandleValue,
874 _option: (),
875 ) -> Result<ConversionResult<*mut JSObject>, ()> {
876 if !value.is_object() {
877 throw_type_error(cx, c"value is not an object");
878 return Err(());
879 }
880
881 AssertSameCompartment(cx, value.to_object());
882
883 Ok(ConversionResult::Success(value.to_object()))
884 }
885}
886
887impl ToJSValConvertible for *mut JS::Symbol {
888 #[inline]
889 unsafe fn to_jsval(&self, _: *mut JSContext, mut rval: MutableHandleValue) {
890 rval.set(SymbolValue(&**self));
891 }
892}
893
894impl FromJSValConvertible for *mut JS::Symbol {
895 type Config = ();
896 #[inline]
897 unsafe fn from_jsval(
898 cx: *mut JSContext,
899 value: HandleValue,
900 _option: (),
901 ) -> Result<ConversionResult<*mut JS::Symbol>, ()> {
902 if !value.is_symbol() {
903 throw_type_error(cx, c"value is not a symbol");
904 return Err(());
905 }
906
907 Ok(ConversionResult::Success(value.to_symbol()))
908 }
909}
910
911pub struct Utf8Chars<'a> {
915 lt_marker: std::marker::PhantomData<&'a ()>,
916 inner: crate::jsapi::UTF8Chars,
917}
918
919impl<'a> std::ops::Deref for Utf8Chars<'a> {
920 type Target = crate::jsapi::UTF8Chars;
921
922 fn deref(&self) -> &Self::Target {
923 &self.inner
924 }
925}
926
927impl<'a> From<&'a str> for Utf8Chars<'a> {
928 #[allow(unsafe_code)]
929 fn from(value: &'a str) -> Self {
930 use std::marker::PhantomData;
931
932 use crate::jsapi::mozilla::{Range, RangedPtr};
933 use crate::jsapi::UTF8Chars;
934
935 let range = value.as_bytes().as_ptr_range();
936 let range_start = range.start as *mut _;
937 let range_end = range.end as *mut _;
938 let start = RangedPtr {
939 _phantom_0: PhantomData,
940 mPtr: range_start,
941 #[cfg(feature = "debugmozjs")]
942 mRangeStart: range_start,
943 #[cfg(feature = "debugmozjs")]
944 mRangeEnd: range_end,
945 };
946 let end = RangedPtr {
947 _phantom_0: PhantomData,
948 mPtr: range_end,
949 #[cfg(feature = "debugmozjs")]
950 mRangeStart: range_start,
951 #[cfg(feature = "debugmozjs")]
952 mRangeEnd: range_end,
953 };
954 let base = Range {
955 _phantom_0: PhantomData,
956 mStart: start,
957 mEnd: end,
958 };
959 let inner = UTF8Chars { _base: base };
960 Self {
961 lt_marker: PhantomData,
962 inner,
963 }
964 }
965}