ion/conversions/
key.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6
7use 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
17/// Represents types that can be converted to [property keys](PropertyKey).
18pub trait ToPropertyKey<'cx> {
19	/// Converts `self` to a new [`PropertyKey`].
20	/// Returns `None` when conversion fails.
21	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}