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