use crate::{qjs, Atom, Ctx, Result, Value};
#[derive(Debug, Clone, PartialEq, Hash)]
#[repr(transparent)]
pub struct Symbol<'js>(pub(crate) Value<'js>);
impl<'js> Symbol<'js> {
pub fn description(&self) -> Result<Value<'js>> {
let atom = Atom::from_str(self.0.ctx.clone(), "description")?;
unsafe {
let val = qjs::JS_GetProperty(self.0.ctx.as_ptr(), self.0.as_js_value(), atom.atom);
let val = self.0.ctx.handle_exception(val)?;
Ok(Value::from_js_value(self.0.ctx.clone(), val))
}
}
pub fn as_atom(&self) -> Atom<'js> {
Atom::from_value(self.0.ctx().clone(), &self.0)
.expect("symbols should always convert to atoms")
}
}
macro_rules! impl_symbols {
($($(#[$m:meta])? $fn_name:ident => $const_name:ident)*) => {
impl<'js> Symbol<'js> {
$(
$(#[$m])*
pub fn $fn_name(ctx: Ctx<'js>) -> Self {
let v = unsafe {
let v = qjs::JS_AtomToValue(ctx.as_ptr(),qjs::$const_name as qjs::JSAtom);
Value::from_js_value(ctx, v)
};
v.into_symbol().unwrap()
}
)*
}
};
}
impl_symbols! {
to_primitive => JS_ATOM_Symbol_toPrimitive
iterator => JS_ATOM_Symbol_iterator
r#match => JS_ATOM_Symbol_match
match_all => JS_ATOM_Symbol_matchAll
replace => JS_ATOM_Symbol_replace
search => JS_ATOM_Symbol_search
split => JS_ATOM_Symbol_split
has_instance => JS_ATOM_Symbol_hasInstance
species => JS_ATOM_Symbol_species
unscopables => JS_ATOM_Symbol_unscopables
async_iterator => JS_ATOM_Symbol_asyncIterator
operator_set => JS_ATOM_Symbol_operatorSet
}
#[cfg(test)]
mod test {
use crate::*;
#[test]
fn description() {
test_with(|ctx| {
let s: Symbol<'_> = ctx.eval("Symbol('foo bar baz')").unwrap();
assert_eq!(
s.description()
.unwrap()
.into_string()
.unwrap()
.to_string()
.unwrap(),
"foo bar baz"
);
let s: Symbol<'_> = ctx.eval("Symbol()").unwrap();
assert!(s.description().unwrap().is_undefined());
});
}
}