use crate::{handle_exception, qjs, Ctx, Error, Result, String, Value};
use std::{ffi::CStr, mem, string::String as StdString};
pub struct Atom<'js> {
pub(crate) atom: qjs::JSAtom,
ctx: Ctx<'js>,
}
impl<'js> Atom<'js> {
pub fn from_value(ctx: Ctx<'js>, val: &Value<'js>) -> Atom<'js> {
let atom = unsafe { qjs::JS_ValueToAtom(ctx.ctx, val.as_js_value()) };
Atom { atom, ctx }
}
pub fn from_u32(ctx: Ctx<'js>, val: u32) -> Atom<'js> {
let atom = unsafe { qjs::JS_NewAtomUInt32(ctx.ctx, val) };
Atom { atom, ctx }
}
pub fn from_i32(ctx: Ctx<'js>, val: i32) -> Atom<'js> {
let atom = unsafe { qjs::JS_ValueToAtom(ctx.ctx, qjs::JS_MKVAL(qjs::JS_TAG_INT, val)) };
Atom { atom, ctx }
}
pub fn from_bool(ctx: Ctx<'js>, val: bool) -> Atom<'js> {
let val = if val { qjs::JS_TRUE } else { qjs::JS_FALSE };
let atom = unsafe { qjs::JS_ValueToAtom(ctx.ctx, val) };
Atom { atom, ctx }
}
pub fn from_f64(ctx: Ctx<'js>, val: f64) -> Atom<'js> {
let atom = unsafe { qjs::JS_ValueToAtom(ctx.ctx, qjs::JS_NewFloat64(val)) };
Atom { atom, ctx }
}
pub fn from_str(ctx: Ctx<'js>, name: &str) -> Atom<'js> {
unsafe {
let ptr = name.as_ptr() as *const std::os::raw::c_char;
let atom = qjs::JS_NewAtomLen(ctx.ctx, ptr, name.len() as _);
Atom { atom, ctx }
}
}
pub fn to_string(&self) -> Result<StdString> {
pub struct DropStr<'js>(Ctx<'js>, *const std::os::raw::c_char);
impl<'js> Drop for DropStr<'js> {
fn drop(&mut self) {
unsafe {
qjs::JS_FreeCString(self.0.ctx, self.1);
}
}
}
unsafe {
let c_str = qjs::JS_AtomToCString(self.ctx.ctx, self.atom);
let drop = DropStr(self.ctx, c_str);
if c_str.is_null() {
return Err(Error::Unknown);
}
let res = CStr::from_ptr(c_str).to_str()?.to_string();
mem::drop(drop);
Ok(res)
}
}
pub fn to_js_string(&self) -> Result<String<'js>> {
unsafe {
let val = qjs::JS_AtomToString(self.ctx.ctx, self.atom);
let val = handle_exception(self.ctx, val)?;
Ok(String::from_js_value(self.ctx, val))
}
}
pub fn to_value(&self) -> Result<Value<'js>> {
self.to_js_string().map(|String(value)| value)
}
pub(crate) unsafe fn from_atom_val(ctx: Ctx<'js>, val: qjs::JSAtom) -> Self {
Atom { atom: val, ctx }
}
}
impl<'js> Clone for Atom<'js> {
fn clone(&self) -> Atom<'js> {
let atom = unsafe { qjs::JS_DupAtom(self.ctx.ctx, self.atom) };
Atom {
atom,
ctx: self.ctx,
}
}
}
impl<'js> Drop for Atom<'js> {
fn drop(&mut self) {
unsafe {
qjs::JS_FreeAtom(self.ctx.ctx, self.atom);
}
}
}