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 std::borrow::Cow;
50use std::mem;
51use std::ptr::NonNull;
52use std::rc::Rc;
53use std::{ptr, slice};
54
55trait As<O>: Copy {
56 fn cast(self) -> O;
57}
58
59macro_rules! impl_as {
60 ($I:ty, $O:ty) => {
61 impl As<$O> for $I {
62 fn cast(self) -> $O {
63 self as $O
64 }
65 }
66 };
67}
68
69impl_as!(f64, u8);
70impl_as!(f64, u16);
71impl_as!(f64, u32);
72impl_as!(f64, u64);
73impl_as!(f64, i8);
74impl_as!(f64, i16);
75impl_as!(f64, i32);
76impl_as!(f64, i64);
77
78impl_as!(u8, f64);
79impl_as!(u16, f64);
80impl_as!(u32, f64);
81impl_as!(u64, f64);
82impl_as!(i8, f64);
83impl_as!(i16, f64);
84impl_as!(i32, f64);
85impl_as!(i64, f64);
86
87impl_as!(i32, i8);
88impl_as!(i32, u8);
89impl_as!(i32, i16);
90impl_as!(u16, u16);
91impl_as!(i32, i32);
92impl_as!(u32, u32);
93impl_as!(i64, i64);
94impl_as!(u64, u64);
95
96pub trait Number {
98 const ZERO: Self;
100 const MIN: Self;
102 const MAX: Self;
104}
105
106macro_rules! impl_num {
107 ($N:ty, $zero:expr, $min:expr, $max:expr) => {
108 impl Number for $N {
109 const ZERO: $N = $zero;
110 const MIN: $N = $min;
111 const MAX: $N = $max;
112 }
113 };
114}
115
116impl_num!(u8, 0, u8::MIN, u8::MAX);
118impl_num!(u16, 0, u16::MIN, u16::MAX);
119impl_num!(u32, 0, u32::MIN, u32::MAX);
120impl_num!(u64, 0, 0, (1 << 53) - 1);
121
122impl_num!(i8, 0, i8::MIN, i8::MAX);
123impl_num!(i16, 0, i16::MIN, i16::MAX);
124impl_num!(i32, 0, i32::MIN, i32::MAX);
125impl_num!(i64, 0, -(1 << 53) + 1, (1 << 53) - 1);
126
127impl_num!(f32, 0.0, f32::MIN, f32::MAX);
128impl_num!(f64, 0.0, f64::MIN, f64::MAX);
129
130pub trait ToJSValConvertible {
132 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue);
134}
135
136#[derive(PartialEq, Eq, Clone, Debug)]
138pub enum ConversionResult<T> {
139 Success(T),
141 Failure(Cow<'static, str>),
143}
144
145impl<T> ConversionResult<T> {
146 pub fn get_success_value(&self) -> Option<&T> {
148 match *self {
149 ConversionResult::Success(ref v) => Some(v),
150 _ => None,
151 }
152 }
153}
154
155pub trait FromJSValConvertible: Sized {
157 type Config;
159 unsafe fn from_jsval(
165 cx: *mut JSContext,
166 val: HandleValue,
167 option: Self::Config,
168 ) -> Result<ConversionResult<Self>, ()>;
169}
170
171pub trait FromJSValConvertibleRc: Sized {
173 unsafe fn from_jsval(
177 cx: *mut JSContext,
178 val: HandleValue,
179 ) -> Result<ConversionResult<Rc<Self>>, ()>;
180}
181
182impl<T: FromJSValConvertibleRc> FromJSValConvertible for Rc<T> {
183 type Config = ();
184
185 unsafe fn from_jsval(
186 cx: *mut JSContext,
187 val: HandleValue,
188 _option: (),
189 ) -> Result<ConversionResult<Rc<T>>, ()> {
190 <T as FromJSValConvertibleRc>::from_jsval(cx, val)
191 }
192}
193
194#[derive(PartialEq, Eq, Clone)]
196pub enum ConversionBehavior {
197 Default,
199 EnforceRange,
201 Clamp,
203}
204
205unsafe fn enforce_range<D>(cx: *mut JSContext, d: f64) -> Result<ConversionResult<D>, ()>
209where
210 D: Number + As<f64>,
211 f64: As<D>,
212{
213 if d.is_infinite() {
214 throw_type_error(cx, "value out of range in an EnforceRange argument");
215 return Err(());
216 }
217
218 let rounded = d.signum() * d.abs().floor();
219 if D::MIN.cast() <= rounded && rounded <= D::MAX.cast() {
220 Ok(ConversionResult::Success(rounded.cast()))
221 } else {
222 throw_type_error(cx, "value out of range in an EnforceRange argument");
223 Err(())
224 }
225}
226
227fn clamp_to<D>(d: f64) -> D
231where
232 D: Number + As<f64>,
233 f64: As<D>,
234{
235 if d.is_nan() {
236 D::ZERO
237 } else if d > D::MAX.cast() {
238 D::MAX
239 } else if d < D::MIN.cast() {
240 D::MIN
241 } else {
242 d.cast()
243 }
244}
245
246impl ToJSValConvertible for () {
248 #[inline]
249 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
250 rval.set(UndefinedValue());
251 }
252}
253
254impl FromJSValConvertible for JSVal {
255 type Config = ();
256 unsafe fn from_jsval(
257 _cx: *mut JSContext,
258 value: HandleValue,
259 _option: (),
260 ) -> Result<ConversionResult<JSVal>, ()> {
261 Ok(ConversionResult::Success(value.get()))
262 }
263}
264
265impl ToJSValConvertible for JSVal {
266 #[inline]
267 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
268 rval.set(*self);
269 maybe_wrap_value(cx, rval);
270 }
271}
272
273impl<'a> ToJSValConvertible for HandleValue<'a> {
274 #[inline]
275 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
276 rval.set(self.get());
277 maybe_wrap_value(cx, rval);
278 }
279}
280
281impl ToJSValConvertible for Heap<JSVal> {
282 #[inline]
283 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
284 rval.set(self.get());
285 maybe_wrap_value(cx, rval);
286 }
287}
288
289#[inline]
290unsafe fn convert_int_from_jsval<T, M>(
291 cx: *mut JSContext,
292 value: HandleValue,
293 option: ConversionBehavior,
294 convert_fn: unsafe fn(*mut JSContext, HandleValue) -> Result<M, ()>,
295) -> Result<ConversionResult<T>, ()>
296where
297 T: Number + As<f64>,
298 M: Number + As<T>,
299 f64: As<T>,
300{
301 match option {
302 ConversionBehavior::Default => Ok(ConversionResult::Success(convert_fn(cx, value)?.cast())),
303 ConversionBehavior::EnforceRange => enforce_range(cx, ToNumber(cx, value)?),
304 ConversionBehavior::Clamp => Ok(ConversionResult::Success(clamp_to(ToNumber(cx, value)?))),
305 }
306}
307
308impl ToJSValConvertible for bool {
310 #[inline]
311 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
312 rval.set(BooleanValue(*self));
313 }
314}
315
316impl FromJSValConvertible for bool {
318 type Config = ();
319 unsafe fn from_jsval(
320 _cx: *mut JSContext,
321 val: HandleValue,
322 _option: (),
323 ) -> Result<ConversionResult<bool>, ()> {
324 Ok(ToBoolean(val)).map(ConversionResult::Success)
325 }
326}
327
328impl ToJSValConvertible for i8 {
330 #[inline]
331 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
332 rval.set(Int32Value(*self as i32));
333 }
334}
335
336impl FromJSValConvertible for i8 {
338 type Config = ConversionBehavior;
339 unsafe fn from_jsval(
340 cx: *mut JSContext,
341 val: HandleValue,
342 option: ConversionBehavior,
343 ) -> Result<ConversionResult<i8>, ()> {
344 convert_int_from_jsval(cx, val, option, ToInt32)
345 }
346}
347
348impl ToJSValConvertible for u8 {
350 #[inline]
351 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
352 rval.set(Int32Value(*self as i32));
353 }
354}
355
356impl FromJSValConvertible for u8 {
358 type Config = ConversionBehavior;
359 unsafe fn from_jsval(
360 cx: *mut JSContext,
361 val: HandleValue,
362 option: ConversionBehavior,
363 ) -> Result<ConversionResult<u8>, ()> {
364 convert_int_from_jsval(cx, val, option, ToInt32)
365 }
366}
367
368impl ToJSValConvertible for i16 {
370 #[inline]
371 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
372 rval.set(Int32Value(*self as i32));
373 }
374}
375
376impl FromJSValConvertible for i16 {
378 type Config = ConversionBehavior;
379 unsafe fn from_jsval(
380 cx: *mut JSContext,
381 val: HandleValue,
382 option: ConversionBehavior,
383 ) -> Result<ConversionResult<i16>, ()> {
384 convert_int_from_jsval(cx, val, option, ToInt32)
385 }
386}
387
388impl ToJSValConvertible for u16 {
390 #[inline]
391 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
392 rval.set(Int32Value(*self as i32));
393 }
394}
395
396impl FromJSValConvertible for u16 {
398 type Config = ConversionBehavior;
399 unsafe fn from_jsval(
400 cx: *mut JSContext,
401 val: HandleValue,
402 option: ConversionBehavior,
403 ) -> Result<ConversionResult<u16>, ()> {
404 convert_int_from_jsval(cx, val, option, ToUint16)
405 }
406}
407
408impl ToJSValConvertible for i32 {
410 #[inline]
411 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
412 rval.set(Int32Value(*self));
413 }
414}
415
416impl FromJSValConvertible for i32 {
418 type Config = ConversionBehavior;
419 unsafe fn from_jsval(
420 cx: *mut JSContext,
421 val: HandleValue,
422 option: ConversionBehavior,
423 ) -> Result<ConversionResult<i32>, ()> {
424 convert_int_from_jsval(cx, val, option, ToInt32)
425 }
426}
427
428impl ToJSValConvertible for u32 {
430 #[inline]
431 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
432 rval.set(UInt32Value(*self));
433 }
434}
435
436impl FromJSValConvertible for u32 {
438 type Config = ConversionBehavior;
439 unsafe fn from_jsval(
440 cx: *mut JSContext,
441 val: HandleValue,
442 option: ConversionBehavior,
443 ) -> Result<ConversionResult<u32>, ()> {
444 convert_int_from_jsval(cx, val, option, ToUint32)
445 }
446}
447
448impl ToJSValConvertible for i64 {
450 #[inline]
451 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
452 rval.set(DoubleValue(*self as f64));
453 }
454}
455
456impl FromJSValConvertible for i64 {
458 type Config = ConversionBehavior;
459 unsafe fn from_jsval(
460 cx: *mut JSContext,
461 val: HandleValue,
462 option: ConversionBehavior,
463 ) -> Result<ConversionResult<i64>, ()> {
464 convert_int_from_jsval(cx, val, option, ToInt64)
465 }
466}
467
468impl ToJSValConvertible for u64 {
470 #[inline]
471 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
472 rval.set(DoubleValue(*self as f64));
473 }
474}
475
476impl FromJSValConvertible for u64 {
478 type Config = ConversionBehavior;
479 unsafe fn from_jsval(
480 cx: *mut JSContext,
481 val: HandleValue,
482 option: ConversionBehavior,
483 ) -> Result<ConversionResult<u64>, ()> {
484 convert_int_from_jsval(cx, val, option, ToUint64)
485 }
486}
487
488impl ToJSValConvertible for f32 {
490 #[inline]
491 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
492 rval.set(DoubleValue(*self as f64));
493 }
494}
495
496impl FromJSValConvertible for f32 {
498 type Config = ();
499 unsafe fn from_jsval(
500 cx: *mut JSContext,
501 val: HandleValue,
502 _option: (),
503 ) -> Result<ConversionResult<f32>, ()> {
504 let result = ToNumber(cx, val);
505 result.map(|f| f as f32).map(ConversionResult::Success)
506 }
507}
508
509impl ToJSValConvertible for f64 {
511 #[inline]
512 unsafe fn to_jsval(&self, _cx: *mut JSContext, mut rval: MutableHandleValue) {
513 rval.set(DoubleValue(*self))
514 }
515}
516
517impl FromJSValConvertible for f64 {
519 type Config = ();
520 unsafe fn from_jsval(
521 cx: *mut JSContext,
522 val: HandleValue,
523 _option: (),
524 ) -> Result<ConversionResult<f64>, ()> {
525 ToNumber(cx, val).map(ConversionResult::Success)
526 }
527}
528
529pub unsafe fn latin1_to_string(cx: *mut JSContext, s: NonNull<JSString>) -> String {
532 assert!(JS_DeprecatedStringHasLatin1Chars(s.as_ptr()));
533
534 let mut length = 0;
535 let chars = unsafe {
536 let chars = JS_GetLatin1StringCharsAndLength(cx, ptr::null(), s.as_ptr(), &mut length);
537 assert!(!chars.is_null());
538
539 slice::from_raw_parts(chars, length as usize)
540 };
541 let mut v = vec![0; chars.len() * 2];
545 let real_size = encoding_rs::mem::convert_latin1_to_utf8(chars, v.as_mut_slice());
546
547 v.truncate(real_size);
548
549 unsafe { String::from_utf8_unchecked(v) }
552}
553
554pub unsafe fn jsstr_to_string(cx: *mut JSContext, jsstr: NonNull<JSString>) -> String {
556 if JS_DeprecatedStringHasLatin1Chars(jsstr.as_ptr()) {
557 return latin1_to_string(cx, jsstr);
558 }
559
560 let mut length = 0;
561 let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), jsstr.as_ptr(), &mut length);
562 assert!(!chars.is_null());
563 let char_vec = slice::from_raw_parts(chars, length as usize);
564 String::from_utf16_lossy(char_vec)
565}
566
567impl ToJSValConvertible for str {
569 #[inline]
570 #[deny(unsafe_op_in_unsafe_fn)]
571 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
572 let s = Utf8Chars::from(self);
576 let jsstr = unsafe { JS_NewStringCopyUTF8N(cx, &*s as *const _) };
577 if jsstr.is_null() {
578 panic!("JS String copy routine failed");
579 }
580 unsafe {
581 rval.set(StringValue(&*jsstr));
582 }
583 }
584}
585
586impl ToJSValConvertible for String {
588 #[inline]
589 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
590 (**self).to_jsval(cx, rval);
591 }
592}
593
594impl FromJSValConvertible for String {
596 type Config = ();
597 unsafe fn from_jsval(
598 cx: *mut JSContext,
599 value: HandleValue,
600 _: (),
601 ) -> Result<ConversionResult<String>, ()> {
602 let jsstr = ToString(cx, value);
603 let Some(jsstr) = NonNull::new(jsstr) else {
604 debug!("ToString failed");
605 return Err(());
606 };
607 Ok(jsstr_to_string(cx, jsstr)).map(ConversionResult::Success)
608 }
609}
610
611impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> {
612 #[inline]
613 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
614 match self {
615 &Some(ref value) => value.to_jsval(cx, rval),
616 &None => rval.set(NullValue()),
617 }
618 }
619}
620
621impl<T: FromJSValConvertible> FromJSValConvertible for Option<T> {
622 type Config = T::Config;
623 unsafe fn from_jsval(
624 cx: *mut JSContext,
625 value: HandleValue,
626 option: T::Config,
627 ) -> Result<ConversionResult<Option<T>>, ()> {
628 if value.get().is_null_or_undefined() {
629 Ok(ConversionResult::Success(None))
630 } else {
631 Ok(match FromJSValConvertible::from_jsval(cx, value, option)? {
632 ConversionResult::Success(v) => ConversionResult::Success(Some(v)),
633 ConversionResult::Failure(v) => ConversionResult::Failure(v),
634 })
635 }
636 }
637}
638
639impl<T: ToJSValConvertible> ToJSValConvertible for &'_ T {
640 #[inline]
641 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
642 (**self).to_jsval(cx, rval)
643 }
644}
645
646impl<T: ToJSValConvertible> ToJSValConvertible for Box<T> {
647 #[inline]
648 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
649 (**self).to_jsval(cx, rval)
650 }
651}
652
653impl<T: ToJSValConvertible> ToJSValConvertible for Rc<T> {
654 #[inline]
655 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
656 (**self).to_jsval(cx, rval)
657 }
658}
659
660impl<T: ToJSValConvertible> ToJSValConvertible for [T] {
662 #[inline]
663 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
664 rooted!(in(cx) let js_array = NewArrayObject1(cx, self.len() as libc::size_t));
665 assert!(!js_array.handle().is_null());
666
667 rooted!(in(cx) let mut val = UndefinedValue());
668 for (index, obj) in self.iter().enumerate() {
669 obj.to_jsval(cx, val.handle_mut());
670
671 assert!(JS_DefineElement(
672 cx,
673 js_array.handle().into(),
674 index as u32,
675 val.handle().into(),
676 JSPROP_ENUMERATE as u32
677 ));
678 }
679
680 rval.set(ObjectValue(js_array.handle().get()));
681 }
682}
683
684impl<T: ToJSValConvertible> ToJSValConvertible for Vec<T> {
686 #[inline]
687 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
688 <[_]>::to_jsval(self, cx, rval)
689 }
690}
691
692struct ForOfIteratorGuard<'a> {
697 root: &'a mut ForOfIterator,
698}
699
700impl<'a> ForOfIteratorGuard<'a> {
701 fn new(cx: *mut JSContext, root: &'a mut ForOfIterator) -> Self {
702 unsafe {
703 Rooted::add_to_root_stack(&raw mut root.iterator, cx);
704 }
705 ForOfIteratorGuard { root }
706 }
707}
708
709impl<'a> Drop for ForOfIteratorGuard<'a> {
710 fn drop(&mut self) {
711 unsafe {
712 self.root.iterator.remove_from_root_stack();
713 }
714 }
715}
716
717impl<C: Clone, T: FromJSValConvertible<Config = C>> FromJSValConvertible for Vec<T> {
718 type Config = C;
719
720 unsafe fn from_jsval(
721 cx: *mut JSContext,
722 value: HandleValue,
723 option: C,
724 ) -> Result<ConversionResult<Vec<T>>, ()> {
725 if !value.is_object() {
726 return Ok(ConversionResult::Failure("Value is not an object".into()));
727 }
728
729 let zero = mem::zeroed();
735 let mut iterator = ForOfIterator {
736 cx_: cx,
737 iterator: RootedObject::new_unrooted(ptr::null_mut()),
738 nextMethod: RootedValue::new_unrooted(JSVal { asBits_: 0 }),
739 index: ::std::u32::MAX, ..zero
741 };
742 let iterator = ForOfIteratorGuard::new(cx, &mut iterator);
743 let iterator: &mut ForOfIterator = &mut *iterator.root;
744
745 if !iterator.init(
746 value.into(),
747 ForOfIterator_NonIterableBehavior::AllowNonIterable,
748 ) {
749 return Err(());
750 }
751
752 if iterator.iterator.data.is_null() {
753 return Ok(ConversionResult::Failure("Value is not iterable".into()));
754 }
755
756 let mut ret = vec![];
757
758 loop {
759 let mut done = false;
760 rooted!(in(cx) let mut val = UndefinedValue());
761 if !iterator.next(val.handle_mut().into(), &mut done) {
762 return Err(());
763 }
764
765 if done {
766 break;
767 }
768
769 ret.push(match T::from_jsval(cx, val.handle(), option.clone())? {
770 ConversionResult::Success(v) => v,
771 ConversionResult::Failure(e) => {
772 throw_type_error(cx, &e);
773 return Err(());
774 }
775 });
776 }
777
778 Ok(ret).map(ConversionResult::Success)
779 }
780}
781
782impl ToJSValConvertible for *mut JSObject {
784 #[inline]
785 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
786 rval.set(ObjectOrNullValue(*self));
787 maybe_wrap_object_or_null_value(cx, rval);
788 }
789}
790
791impl ToJSValConvertible for ptr::NonNull<JSObject> {
793 #[inline]
794 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
795 rval.set(ObjectValue(self.as_ptr()));
796 maybe_wrap_object_value(cx, rval);
797 }
798}
799
800impl ToJSValConvertible for Heap<*mut JSObject> {
802 #[inline]
803 unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
804 rval.set(ObjectOrNullValue(self.get()));
805 maybe_wrap_object_or_null_value(cx, rval);
806 }
807}
808
809impl FromJSValConvertible for *mut JSObject {
811 type Config = ();
812 #[inline]
813 unsafe fn from_jsval(
814 cx: *mut JSContext,
815 value: HandleValue,
816 _option: (),
817 ) -> Result<ConversionResult<*mut JSObject>, ()> {
818 if !value.is_object() {
819 throw_type_error(cx, "value is not an object");
820 return Err(());
821 }
822
823 AssertSameCompartment(cx, value.to_object());
824
825 Ok(ConversionResult::Success(value.to_object()))
826 }
827}
828
829impl ToJSValConvertible for *mut JS::Symbol {
830 #[inline]
831 unsafe fn to_jsval(&self, _: *mut JSContext, mut rval: MutableHandleValue) {
832 rval.set(SymbolValue(&**self));
833 }
834}
835
836impl FromJSValConvertible for *mut JS::Symbol {
837 type Config = ();
838 #[inline]
839 unsafe fn from_jsval(
840 cx: *mut JSContext,
841 value: HandleValue,
842 _option: (),
843 ) -> Result<ConversionResult<*mut JS::Symbol>, ()> {
844 if !value.is_symbol() {
845 throw_type_error(cx, "value is not a symbol");
846 return Err(());
847 }
848
849 Ok(ConversionResult::Success(value.to_symbol()))
850 }
851}
852
853pub struct Utf8Chars<'a> {
857 lt_marker: std::marker::PhantomData<&'a ()>,
858 inner: crate::jsapi::UTF8Chars,
859}
860
861impl<'a> std::ops::Deref for Utf8Chars<'a> {
862 type Target = crate::jsapi::UTF8Chars;
863
864 fn deref(&self) -> &Self::Target {
865 &self.inner
866 }
867}
868
869impl<'a> From<&'a str> for Utf8Chars<'a> {
870 #[allow(unsafe_code)]
871 fn from(value: &'a str) -> Self {
872 use std::marker::PhantomData;
873
874 use crate::jsapi::mozilla::{Range, RangedPtr};
875 use crate::jsapi::UTF8Chars;
876
877 let range = value.as_bytes().as_ptr_range();
878 let range_start = range.start as *mut _;
879 let range_end = range.end as *mut _;
880 let start = RangedPtr {
881 _phantom_0: PhantomData,
882 mPtr: range_start,
883 #[cfg(feature = "debugmozjs")]
884 mRangeStart: range_start,
885 #[cfg(feature = "debugmozjs")]
886 mRangeEnd: range_end,
887 };
888 let end = RangedPtr {
889 _phantom_0: PhantomData,
890 mPtr: range_end,
891 #[cfg(feature = "debugmozjs")]
892 mRangeStart: range_start,
893 #[cfg(feature = "debugmozjs")]
894 mRangeEnd: range_end,
895 };
896 let base = Range {
897 _phantom_0: PhantomData,
898 mStart: start,
899 mEnd: end,
900 };
901 let inner = UTF8Chars { _base: base };
902 Self {
903 lt_marker: PhantomData,
904 inner,
905 }
906 }
907}