1#![deny(missing_docs)]
30
31use crate::error::throw_type_error;
32use crate::jsapi::NewArrayObject1;
33use crate::jsapi::JS;
34use crate::jsapi::{Heap, JS_DefineElement};
35use crate::jsapi::{JSContext, JSObject, JSString};
36use crate::jsapi::{JS_DeprecatedStringHasLatin1Chars, JS_NewStringCopyUTF8N, JSPROP_ENUMERATE};
37use crate::jsval::{BooleanValue, DoubleValue, Int32Value, NullValue, UInt32Value, UndefinedValue};
38use crate::jsval::{JSVal, ObjectOrNullValue, ObjectValue, StringValue, SymbolValue};
39use crate::rooted;
40use crate::rust::for_of;
41use crate::rust::maybe_wrap_value;
42use crate::rust::wrappers2::{
43 AssertSameCompartment, JS_GetLatin1StringCharsAndLength, JS_GetTwoByteStringCharsAndLength,
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 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue);
138
139 fn safe_to_jsval(&self, cx: &mut crate::context::JSContext, rval: MutableHandleValue) {
141 unsafe { self.to_jsval(cx.raw_cx(), rval) }
142 }
143}
144
145#[derive(PartialEq, Eq, Clone, Debug)]
147pub enum ConversionResult<T> {
148 Success(T),
150 Failure(Cow<'static, CStr>),
152}
153
154impl<T> ConversionResult<T> {
155 pub fn get_success_value(&self) -> Option<&T> {
157 match *self {
158 ConversionResult::Success(ref v) => Some(v),
159 _ => None,
160 }
161 }
162}
163
164pub trait FromJSValConvertible: Sized {
166 type Config;
168
169 fn safe_from_jsval(
175 cx: &mut crate::context::JSContext,
176 val: HandleValue,
177 option: Self::Config,
178 ) -> Result<ConversionResult<Self>, ()>;
179}
180
181pub trait FromJSValConvertibleRc: Sized {
183 fn safe_from_jsval(
187 cx: &mut crate::context::JSContext,
188 val: HandleValue,
189 ) -> Result<ConversionResult<Rc<Self>>, ()>;
190}
191
192impl<T: FromJSValConvertibleRc> FromJSValConvertible for Rc<T> {
193 type Config = ();
194
195 fn safe_from_jsval(
196 cx: &mut crate::context::JSContext,
197 val: HandleValue,
198 _option: (),
199 ) -> Result<ConversionResult<Rc<T>>, ()> {
200 <T as FromJSValConvertibleRc>::safe_from_jsval(cx, val)
201 }
202}
203
204#[derive(PartialEq, Eq, Clone)]
206pub enum ConversionBehavior {
207 Default,
209 EnforceRange,
211 Clamp,
213}
214
215fn enforce_range<D>(cx: &mut crate::context::JSContext, d: f64) -> Result<ConversionResult<D>, ()>
219where
220 D: Number + As<f64>,
221 f64: As<D>,
222{
223 if d.is_infinite() {
224 unsafe {
225 throw_type_error(
226 cx.raw_cx(),
227 c"value out of range in an EnforceRange argument",
228 )
229 };
230 return Err(());
231 }
232
233 let rounded = d.signum() * d.abs().floor();
234 if D::MIN.cast() <= rounded && rounded <= D::MAX.cast() {
235 Ok(ConversionResult::Success(rounded.cast()))
236 } else {
237 unsafe {
238 throw_type_error(
239 cx.raw_cx(),
240 c"value out of range in an EnforceRange argument",
241 )
242 };
243 Err(())
244 }
245}
246
247fn clamp_to<D>(d: f64) -> D
257where
258 D: Number + PrimInt + As<f64>,
259 f64: As<D>,
260{
261 if d.is_nan() {
263 return D::ZERO;
264 }
265
266 if d >= D::MAX.cast() {
267 return D::MAX;
268 }
269 if d <= D::MIN.cast() {
270 return D::MIN;
271 }
272
273 debug_assert!(d.is_finite());
274
275 let to_truncate = if d < 0.0 { d - 0.5 } else { d + 0.5 };
281
282 let mut truncated: D = to_truncate.cast();
283
284 if truncated.cast() == to_truncate {
285 truncated = truncated & !D::one();
291 }
292
293 truncated
294}
295
296impl ToJSValConvertible for () {
298 #[inline]
299 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
300 rval.set(UndefinedValue());
301 }
302}
303
304impl FromJSValConvertible for JSVal {
305 type Config = ();
306
307 fn safe_from_jsval(
308 _cx: &mut crate::context::JSContext,
309 value: HandleValue,
310 _option: (),
311 ) -> Result<ConversionResult<JSVal>, ()> {
312 Ok(ConversionResult::Success(value.get()))
313 }
314}
315
316impl ToJSValConvertible for JSVal {
317 #[inline]
318 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
319 rval.set(*self);
320 maybe_wrap_value(cx, rval);
321 }
322}
323
324impl<'a> ToJSValConvertible for HandleValue<'a> {
325 #[inline]
326 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
327 rval.set(self.get());
328 maybe_wrap_value(cx, rval);
329 }
330}
331
332impl ToJSValConvertible for Heap<JSVal> {
333 #[inline]
334 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
335 rval.set(self.get());
336 maybe_wrap_value(cx, rval);
337 }
338}
339
340#[inline]
341fn convert_int_from_jsval<T, M>(
342 cx: &mut crate::context::JSContext,
343 value: HandleValue,
344 option: ConversionBehavior,
345 convert_fn: unsafe fn(*mut JSContext, HandleValue) -> Result<M, ()>,
346) -> Result<ConversionResult<T>, ()>
347where
348 T: Number + As<f64> + PrimInt,
349 M: Number + As<T>,
350 f64: As<T>,
351{
352 match option {
353 ConversionBehavior::Default => Ok(ConversionResult::Success(unsafe {
354 convert_fn(cx.raw_cx(), value)?.cast()
355 })),
356 ConversionBehavior::EnforceRange => {
357 let number = unsafe { ToNumber(cx.raw_cx(), value) }?;
358 enforce_range(cx, number)
359 }
360 ConversionBehavior::Clamp => Ok(ConversionResult::Success(clamp_to(unsafe {
361 ToNumber(cx.raw_cx(), value)
362 }?))),
363 }
364}
365
366impl ToJSValConvertible for bool {
368 #[inline]
369 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
370 rval.set(BooleanValue(*self));
371 }
372}
373
374impl FromJSValConvertible for bool {
376 type Config = ();
377
378 fn safe_from_jsval(
379 _cx: &mut crate::context::JSContext,
380 val: HandleValue,
381 _option: (),
382 ) -> Result<ConversionResult<bool>, ()> {
383 unsafe { Ok(ToBoolean(val)).map(ConversionResult::Success) }
384 }
385}
386
387impl ToJSValConvertible for i8 {
389 #[inline]
390 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
391 rval.set(Int32Value(*self as i32));
392 }
393}
394
395impl FromJSValConvertible for i8 {
397 type Config = ConversionBehavior;
398
399 fn safe_from_jsval(
400 cx: &mut crate::context::JSContext,
401 val: HandleValue,
402 option: ConversionBehavior,
403 ) -> Result<ConversionResult<i8>, ()> {
404 convert_int_from_jsval(cx, val, option, ToInt32)
405 }
406}
407
408impl ToJSValConvertible for u8 {
410 #[inline]
411 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
412 rval.set(Int32Value(*self as i32));
413 }
414}
415
416impl FromJSValConvertible for u8 {
418 type Config = ConversionBehavior;
419
420 fn safe_from_jsval(
421 cx: &mut crate::context::JSContext,
422 val: HandleValue,
423 option: ConversionBehavior,
424 ) -> Result<ConversionResult<u8>, ()> {
425 convert_int_from_jsval(cx, val, option, ToInt32)
426 }
427}
428
429impl ToJSValConvertible for i16 {
431 #[inline]
432 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
433 rval.set(Int32Value(*self as i32));
434 }
435}
436
437impl FromJSValConvertible for i16 {
439 type Config = ConversionBehavior;
440
441 fn safe_from_jsval(
442 cx: &mut crate::context::JSContext,
443 val: HandleValue,
444 option: ConversionBehavior,
445 ) -> Result<ConversionResult<i16>, ()> {
446 convert_int_from_jsval(cx, val, option, ToInt32)
447 }
448}
449
450impl ToJSValConvertible for u16 {
452 #[inline]
453 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
454 rval.set(Int32Value(*self as i32));
455 }
456}
457
458impl FromJSValConvertible for u16 {
460 type Config = ConversionBehavior;
461
462 fn safe_from_jsval(
463 cx: &mut crate::context::JSContext,
464 val: HandleValue,
465 option: ConversionBehavior,
466 ) -> Result<ConversionResult<u16>, ()> {
467 convert_int_from_jsval(cx, val, option, ToUint16)
468 }
469}
470
471impl ToJSValConvertible for i32 {
473 #[inline]
474 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
475 rval.set(Int32Value(*self));
476 }
477}
478
479impl FromJSValConvertible for i32 {
481 type Config = ConversionBehavior;
482
483 fn safe_from_jsval(
484 cx: &mut crate::context::JSContext,
485 val: HandleValue,
486 option: ConversionBehavior,
487 ) -> Result<ConversionResult<i32>, ()> {
488 convert_int_from_jsval(cx, val, option, ToInt32)
489 }
490}
491
492impl ToJSValConvertible for u32 {
494 #[inline]
495 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
496 rval.set(UInt32Value(*self));
497 }
498}
499
500impl FromJSValConvertible for u32 {
502 type Config = ConversionBehavior;
503
504 fn safe_from_jsval(
505 cx: &mut crate::context::JSContext,
506 val: HandleValue,
507 option: ConversionBehavior,
508 ) -> Result<ConversionResult<u32>, ()> {
509 convert_int_from_jsval(cx, val, option, ToUint32)
510 }
511}
512
513impl ToJSValConvertible for i64 {
515 #[inline]
516 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
517 rval.set(DoubleValue(*self as f64));
518 }
519}
520
521impl FromJSValConvertible for i64 {
523 type Config = ConversionBehavior;
524
525 fn safe_from_jsval(
526 cx: &mut crate::context::JSContext,
527 val: HandleValue,
528 option: ConversionBehavior,
529 ) -> Result<ConversionResult<i64>, ()> {
530 convert_int_from_jsval(cx, val, option, ToInt64)
531 }
532}
533
534impl ToJSValConvertible for u64 {
536 #[inline]
537 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
538 rval.set(DoubleValue(*self as f64));
539 }
540}
541
542impl FromJSValConvertible for u64 {
544 type Config = ConversionBehavior;
545
546 fn safe_from_jsval(
547 cx: &mut crate::context::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
567 fn safe_from_jsval(
568 cx: &mut crate::context::JSContext,
569 val: HandleValue,
570 _option: (),
571 ) -> Result<ConversionResult<f32>, ()> {
572 let result = unsafe { ToNumber(cx.raw_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
589 fn safe_from_jsval(
590 cx: &mut crate::context::JSContext,
591 val: HandleValue,
592 _option: (),
593 ) -> Result<ConversionResult<f64>, ()> {
594 unsafe { ToNumber(cx.raw_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
696 fn safe_from_jsval(
697 cx: &mut crate::context::JSContext,
698 value: HandleValue,
699 _config: Self::Config,
700 ) -> Result<ConversionResult<String>, ()> {
701 let jsstr = unsafe { ToString(cx, value) };
702 let Some(jsstr) = NonNull::new(jsstr) else {
703 debug!("ToString failed");
704 return Err(());
705 };
706 Ok(unsafe { jsstr_to_string(cx, jsstr) }).map(ConversionResult::Success)
707 }
708}
709
710impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> {
711 #[inline]
712 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
713 match self {
714 &Some(ref value) => value.to_jsval(cx, rval),
715 &None => rval.set(NullValue()),
716 }
717 }
718}
719
720impl<T: FromJSValConvertible> FromJSValConvertible for Option<T> {
721 type Config = T::Config;
722
723 fn safe_from_jsval(
724 cx: &mut crate::context::JSContext,
725 value: HandleValue,
726 option: T::Config,
727 ) -> Result<ConversionResult<Option<T>>, ()> {
728 if value.get().is_null_or_undefined() {
729 Ok(ConversionResult::Success(None))
730 } else {
731 Ok(
732 match FromJSValConvertible::safe_from_jsval(cx, value, option)? {
733 ConversionResult::Success(v) => ConversionResult::Success(Some(v)),
734 ConversionResult::Failure(v) => ConversionResult::Failure(v),
735 },
736 )
737 }
738 }
739}
740
741impl<T: ToJSValConvertible> ToJSValConvertible for &'_ T {
742 #[inline]
743 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
744 (**self).to_jsval(cx, rval)
745 }
746}
747
748impl<T: ToJSValConvertible> ToJSValConvertible for Box<T> {
749 #[inline]
750 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
751 (**self).to_jsval(cx, rval)
752 }
753}
754
755impl<T: ToJSValConvertible> ToJSValConvertible for Rc<T> {
756 #[inline]
757 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
758 (**self).to_jsval(cx, rval)
759 }
760}
761
762impl<T: ToJSValConvertible> ToJSValConvertible for [T] {
764 #[inline]
765 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
766 rooted!(in(cx) let js_array = NewArrayObject1(cx, self.len() as libc::size_t));
767 assert!(!js_array.handle().is_null());
768
769 rooted!(in(cx) let mut val = UndefinedValue());
770 for (index, obj) in self.iter().enumerate() {
771 obj.to_jsval(cx, val.handle_mut());
772
773 assert!(JS_DefineElement(
774 cx,
775 js_array.handle().into(),
776 index as u32,
777 val.handle().into(),
778 JSPROP_ENUMERATE as u32
779 ));
780 }
781
782 rval.set(ObjectValue(js_array.handle().get()));
783 }
784}
785
786impl<T: ToJSValConvertible> ToJSValConvertible for Vec<T> {
788 #[inline]
789 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
790 <[_]>::to_jsval(self, cx, rval)
791 }
792}
793
794impl<C: Clone, T: FromJSValConvertible<Config = C>> FromJSValConvertible for Vec<T> {
795 type Config = C;
796
797 fn safe_from_jsval(
798 cx: &mut crate::context::JSContext,
799 value: HandleValue,
800 option: C,
801 ) -> Result<ConversionResult<Vec<T>>, ()> {
802 if !value.is_object() {
803 return Ok(ConversionResult::Failure(c"Value is not an object".into()));
804 }
805
806 let mut return_value = vec![];
807 let result = for_of(unsafe { cx.raw_cx() }, value, |iterator_element| {
808 let conversion_result = T::safe_from_jsval(cx, iterator_element, option.clone())
809 .map_err(|_| ForOfIterationFailure::JSFailed)?;
810 return_value.push(match conversion_result {
811 ConversionResult::Success(value) => value,
812 ConversionResult::Failure(error) => {
813 return Err(ForOfIterationFailure::Other(error));
814 }
815 });
816
817 Ok(ControlFlow::Continue(()))
818 });
819
820 match result {
821 Ok(_) => Ok(ConversionResult::Success(return_value)),
822 Err(ForOfIterationFailure::ValueIsNotIterable) => {
823 Ok(ConversionResult::Failure(c"Value is not iterable".into()))
824 }
825 Err(ForOfIterationFailure::JSFailed) => Err(()),
826 Err(ForOfIterationFailure::Other(error)) => {
827 unsafe { throw_type_error(cx.raw_cx(), error.as_ref()) };
828 Err(())
829 }
830 }
831 }
832}
833
834impl ToJSValConvertible for *mut JSObject {
836 #[inline]
837 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
838 rval.set(ObjectOrNullValue(*self));
839 maybe_wrap_object_or_null_value(cx, rval);
840 }
841}
842
843impl ToJSValConvertible for ptr::NonNull<JSObject> {
845 #[inline]
846 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
847 rval.set(ObjectValue(self.as_ptr()));
848 maybe_wrap_object_value(cx, rval);
849 }
850}
851
852impl ToJSValConvertible for Heap<*mut JSObject> {
854 #[inline]
855 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
856 rval.set(ObjectOrNullValue(self.get()));
857 maybe_wrap_object_or_null_value(cx, rval);
858 }
859}
860
861impl FromJSValConvertible for *mut JSObject {
863 type Config = ();
864
865 #[inline]
866 fn safe_from_jsval(
867 cx: &mut crate::context::JSContext,
868 value: HandleValue,
869 _option: (),
870 ) -> Result<ConversionResult<*mut JSObject>, ()> {
871 if !value.is_object() {
872 unsafe {
873 throw_type_error(cx.raw_cx(), c"value is not an object");
874 }
875 return Err(());
876 }
877
878 unsafe { AssertSameCompartment(cx, value.to_object()) };
879
880 Ok(ConversionResult::Success(value.to_object()))
881 }
882}
883
884impl ToJSValConvertible for *mut JS::Symbol {
885 #[inline]
886 unsafe fn to_jsval(&self, _: *mut JSContext, mut rval: MutableHandleValue) {
887 rval.set(SymbolValue(&**self));
888 }
889}
890
891impl FromJSValConvertible for *mut JS::Symbol {
892 type Config = ();
893
894 #[inline]
895 fn safe_from_jsval(
896 cx: &mut crate::context::JSContext,
897 value: HandleValue,
898 _option: (),
899 ) -> Result<ConversionResult<*mut JS::Symbol>, ()> {
900 if !value.is_symbol() {
901 unsafe {
902 throw_type_error(cx.raw_cx(), c"value is not a symbol");
903 }
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}