1use std::rc::Rc;
8use std::string::String as RustString;
9
10use mozjs::jsapi::{JS_StringToId, JS_ValueToId, JSString, PropertyKey as JSPropertyKey, Symbol as JSSymbol};
11use mozjs::jsid::{SymbolId, VoidId};
12use mozjs::jsval::JSVal;
13
14use crate::symbol::WellKnownSymbolCode;
15use crate::{Context, OwnedKey, PropertyKey, String, Symbol, Value};
16
17pub trait ToPropertyKey<'cx> {
19 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>>;
22}
23
24macro_rules! impl_to_key_for_integer {
25 ($ty:ty) => {
26 impl<'cx> ToPropertyKey<'cx> for $ty {
27 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
28 Some(PropertyKey::with_int(cx, i32::from(*self)))
29 }
30 }
31 };
32}
33
34impl_to_key_for_integer!(i8);
35impl_to_key_for_integer!(i16);
36impl_to_key_for_integer!(i32);
37
38impl_to_key_for_integer!(u8);
39impl_to_key_for_integer!(u16);
40
41impl<'cx> ToPropertyKey<'cx> for u32 {
42 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
43 Some(PropertyKey::with_int(cx, *self as i32))
44 }
45}
46
47impl<'cx> ToPropertyKey<'cx> for *mut JSString {
48 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
49 String::from(cx.root(*self)).to_key(cx)
50 }
51}
52
53impl<'cx> ToPropertyKey<'cx> for String<'cx> {
54 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
55 let mut key = PropertyKey::from(cx.root(VoidId()));
56 (unsafe { JS_StringToId(cx.as_ptr(), self.handle().into(), key.handle_mut().into()) }).then_some(key)
57 }
58}
59
60impl<'cx> ToPropertyKey<'cx> for RustString {
61 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
62 String::copy_from_str(cx, self)?.to_key(cx)
63 }
64}
65
66impl<'cx> ToPropertyKey<'cx> for &str {
67 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
68 String::copy_from_str(cx, self)?.to_key(cx)
69 }
70}
71
72impl<'cx> ToPropertyKey<'cx> for *mut JSSymbol {
73 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
74 Some(cx.root(SymbolId(*self)).into())
75 }
76}
77
78impl<'cx> ToPropertyKey<'cx> for Symbol<'_> {
79 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
80 self.handle().to_key(cx)
81 }
82}
83
84impl<'cx> ToPropertyKey<'cx> for WellKnownSymbolCode {
85 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
86 Symbol::well_known(cx, *self).to_key(cx)
87 }
88}
89
90impl<'cx> ToPropertyKey<'cx> for JSVal {
91 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
92 Value::from(cx.root(*self)).to_key(cx)
93 }
94}
95
96impl<'cx> ToPropertyKey<'cx> for Value<'cx> {
97 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
98 let mut key = PropertyKey::from(cx.root(VoidId()));
99 (unsafe { JS_ValueToId(cx.as_ptr(), self.handle().into(), key.handle_mut().into()) }).then_some(key)
100 }
101}
102
103impl<'cx> ToPropertyKey<'cx> for JSPropertyKey {
104 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
105 Some(cx.root(*self).into())
106 }
107}
108
109impl<'cx> ToPropertyKey<'cx> for PropertyKey<'cx> {
110 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
111 self.handle().to_key(cx)
112 }
113}
114
115impl<'cx> ToPropertyKey<'cx> for OwnedKey<'cx> {
116 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
117 match self {
118 OwnedKey::Int(i) => i.to_key(cx),
119 OwnedKey::String(str) => str.to_key(cx),
120 OwnedKey::Symbol(symbol) => symbol.to_key(cx),
121 OwnedKey::Void => Some(cx.root(VoidId()).into()),
122 }
123 }
124}
125
126impl<'cx, K: ToPropertyKey<'cx>> ToPropertyKey<'cx> for &K {
127 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
128 (**self).to_key(cx)
129 }
130}
131
132impl<'cx, K: ToPropertyKey<'cx>> ToPropertyKey<'cx> for Box<K> {
133 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
134 (**self).to_key(cx)
135 }
136}
137
138impl<'cx, K: ToPropertyKey<'cx>> ToPropertyKey<'cx> for Rc<K> {
139 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
140 (**self).to_key(cx)
141 }
142}
143
144impl<'cx, K: ToPropertyKey<'cx>> ToPropertyKey<'cx> for Option<K> {
145 fn to_key(&self, cx: &'cx Context) -> Option<PropertyKey<'cx>> {
146 let key = self.as_ref()?;
147 key.to_key(cx)
148 }
149}