#[cfg(test)]
mod tests;
use super::function::{make_builtin_fn, make_constructor_fn};
use crate::{
builtins::value::{RcString, RcSymbol, ResultValue, Value},
exec::Interpreter,
BoaProfiler,
};
use gc::{Finalize, Trace};
#[derive(Debug, Finalize, Trace, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Symbol(Option<RcString>, u32);
impl Symbol {
pub(crate) const NAME: &'static str = "Symbol";
pub(crate) const LENGTH: usize = 0;
pub fn description(&self) -> Option<&str> {
self.0.as_deref()
}
pub fn hash(&self) -> u32 {
self.1
}
fn this_symbol_value(value: &Value, ctx: &mut Interpreter) -> Result<RcSymbol, Value> {
match value {
Value::Symbol(ref symbol) => return Ok(symbol.clone()),
Value::Object(ref object) => {
let object = object.borrow();
if let Some(symbol) = object.as_symbol() {
return Ok(symbol);
}
}
_ => {}
}
Err(ctx.construct_type_error("'this' is not a Symbol"))
}
pub(crate) fn call(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
let description = match args.get(0) {
Some(ref value) if !value.is_undefined() => Some(ctx.to_string(value)?),
_ => None,
};
Ok(Value::symbol(Symbol(description, ctx.generate_hash())))
}
#[allow(clippy::wrong_self_convention)]
pub(crate) fn to_string(this: &Value, _: &[Value], ctx: &mut Interpreter) -> ResultValue {
let symbol = Self::this_symbol_value(this, ctx)?;
let description = symbol.description().unwrap_or("");
Ok(Value::from(format!("Symbol({})", description)))
}
pub(crate) fn create(global: &Value) -> Value {
let prototype = Value::new_object(Some(global));
make_builtin_fn(Self::to_string, "toString", &prototype, 0);
make_constructor_fn(
Self::NAME,
Self::LENGTH,
Self::call,
global,
prototype,
false,
)
}
#[inline]
pub fn init(global: &Value) -> (&str, Value) {
let _timer = BoaProfiler::global().start_event(Self::NAME, "init");
(Self::NAME, Self::create(global))
}
}