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