rquickjs_core/value/
symbol.rs

1use crate::{qjs, Atom, Ctx, Result, Value};
2
3/// Rust representation of a JavaScript symbol.
4#[derive(Debug, Clone, PartialEq, Hash)]
5#[repr(transparent)]
6pub struct Symbol<'js>(pub(crate) Value<'js>);
7
8impl<'js> Symbol<'js> {
9    /// Get the symbol description
10    pub fn description(&self) -> Result<Value<'js>> {
11        let atom = Atom::from_str(self.0.ctx.clone(), "description")?;
12        unsafe {
13            let val = qjs::JS_GetProperty(self.0.ctx.as_ptr(), self.0.as_js_value(), atom.atom);
14            let val = self.0.ctx.handle_exception(val)?;
15            Ok(Value::from_js_value(self.0.ctx.clone(), val))
16        }
17    }
18
19    /// Convert a symbol into a atom.
20    pub fn as_atom(&self) -> Atom<'js> {
21        Atom::from_value(self.0.ctx().clone(), &self.0)
22            .expect("symbols should always convert to atoms")
23    }
24}
25
26macro_rules! impl_symbols {
27    ($($(#[$m:meta])? $fn_name:ident => $const_name:ident)*) => {
28        impl<'js> Symbol<'js> {
29            $(
30            $(#[$m])*
31            pub fn $fn_name(ctx: Ctx<'js>) -> Self {
32                // No-op in most cases but with certain dump flags static symbols maintain a ref count.
33                let v = unsafe {
34                    let v = qjs::JS_AtomToValue(ctx.as_ptr(),qjs::$const_name as qjs::JSAtom);
35                    Value::from_js_value(ctx, v)
36                };
37
38                v.into_symbol().unwrap()
39            }
40            )*
41        }
42    };
43}
44
45impl_symbols! {
46    /// returns the symbol for `toPrimitive`
47    to_primitive => JS_ATOM_Symbol_toPrimitive
48    /// returns the symbol for `iterator`
49    iterator => JS_ATOM_Symbol_iterator
50    /// returns the symbol for `match`
51    r#match => JS_ATOM_Symbol_match
52    /// returns the symbol for `matchAll`
53    match_all => JS_ATOM_Symbol_matchAll
54    /// returns the symbol for `replace`
55    replace => JS_ATOM_Symbol_replace
56    /// returns the symbol for `search`
57    search => JS_ATOM_Symbol_search
58    /// returns the symbol for `split`
59    split => JS_ATOM_Symbol_split
60    /// returns the symbol for `hasInstance`
61    has_instance => JS_ATOM_Symbol_hasInstance
62    /// returns the symbol for `species`
63    species => JS_ATOM_Symbol_species
64    /// returns the symbol for `unscopables`
65    unscopables => JS_ATOM_Symbol_unscopables
66    /// returns the symbol for `asyncIterator`
67    async_iterator => JS_ATOM_Symbol_asyncIterator
68}
69
70#[cfg(test)]
71mod test {
72    use crate::*;
73
74    #[test]
75    fn description() {
76        test_with(|ctx| {
77            let s: Symbol<'_> = ctx.eval("Symbol('foo bar baz')").unwrap();
78            assert_eq!(
79                s.description()
80                    .unwrap()
81                    .into_string()
82                    .unwrap()
83                    .to_string()
84                    .unwrap(),
85                "foo bar baz"
86            );
87
88            let s: Symbol<'_> = ctx.eval("Symbol()").unwrap();
89            assert!(s.description().unwrap().is_undefined());
90        });
91    }
92}