rquickjs_core/value/
atom.rs1use crate::{qjs, Ctx, Error, Result, String, Value};
4use alloc::string::{String as StdString, ToString as _};
5use core::{ffi::CStr, hash::Hash, ptr::null_mut};
6
7mod predefined;
8pub use predefined::PredefinedAtom;
9
10#[derive(Debug)]
23pub struct Atom<'js> {
24 pub(crate) atom: qjs::JSAtom,
25 pub(crate) ctx: Ctx<'js>,
26}
27
28impl<'js> PartialEq for Atom<'js> {
29 fn eq(&self, other: &Self) -> bool {
30 self.atom == other.atom
31 }
32}
33impl<'js> Eq for Atom<'js> {}
34
35impl<'js> Hash for Atom<'js> {
36 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
37 state.write_u32(self.atom)
38 }
39}
40
41impl<'js> Atom<'js> {
42 pub fn from_value(ctx: Ctx<'js>, val: &Value<'js>) -> Result<Atom<'js>> {
44 let atom = unsafe { qjs::JS_ValueToAtom(ctx.as_ptr(), val.as_js_value()) };
45 if atom == qjs::JS_ATOM_NULL {
46 return Err(ctx.raise_exception());
49 }
50 Ok(Atom { atom, ctx })
51 }
52
53 pub fn from_u32(ctx: Ctx<'js>, val: u32) -> Result<Atom<'js>> {
55 let atom = unsafe { qjs::JS_NewAtomUInt32(ctx.as_ptr(), val) };
56 if atom == qjs::JS_ATOM_NULL {
57 return Err(Error::Exception);
59 }
60 Ok(Atom { atom, ctx })
61 }
62
63 pub fn from_i32(ctx: Ctx<'js>, val: i32) -> Result<Atom<'js>> {
65 let atom =
66 unsafe { qjs::JS_ValueToAtom(ctx.as_ptr(), qjs::JS_MKVAL(qjs::JS_TAG_INT, val)) };
67 if atom == qjs::JS_ATOM_NULL {
68 return Err(Error::Exception);
70 }
71 Ok(Atom { atom, ctx })
72 }
73
74 pub fn from_bool(ctx: Ctx<'js>, val: bool) -> Result<Atom<'js>> {
76 let val = if val { qjs::JS_TRUE } else { qjs::JS_FALSE };
77 let atom = unsafe { qjs::JS_ValueToAtom(ctx.as_ptr(), val) };
78 if atom == qjs::JS_ATOM_NULL {
79 return Err(Error::Exception);
81 }
82 Ok(Atom { atom, ctx })
83 }
84
85 pub fn from_f64(ctx: Ctx<'js>, val: f64) -> Result<Atom<'js>> {
87 let atom = unsafe { qjs::JS_ValueToAtom(ctx.as_ptr(), qjs::JS_NewFloat64(val)) };
88 if atom == qjs::JS_ATOM_NULL {
89 return Err(Error::Exception);
91 }
92 Ok(Atom { atom, ctx })
93 }
94
95 pub fn from_str(ctx: Ctx<'js>, name: &str) -> Result<Atom<'js>> {
97 unsafe {
98 let ptr = name.as_ptr() as *const core::ffi::c_char;
99 let atom = qjs::JS_NewAtomLen(ctx.as_ptr(), ptr, name.len() as _);
100 if atom == qjs::JS_ATOM_NULL {
101 return Err(Error::Exception);
103 }
104 Ok(Atom { atom, ctx })
105 }
106 }
107
108 pub fn from_predefined(ctx: Ctx<'js>, predefined: PredefinedAtom) -> Atom<'js> {
110 unsafe { Atom::from_atom_val(ctx, predefined as qjs::JSAtom) }
111 }
112
113 pub fn to_string(&self) -> Result<StdString> {
115 unsafe {
116 let c_str = qjs::JS_AtomToCStringLen(self.ctx.as_ptr(), null_mut(), self.atom);
117 if c_str.is_null() {
118 qjs::JS_FreeCString(self.ctx.as_ptr(), c_str);
121 return Err(Error::Unknown);
122 }
123 let bytes = CStr::from_ptr(c_str).to_bytes();
124 let res = core::str::from_utf8_unchecked(bytes).to_string();
126 qjs::JS_FreeCString(self.ctx.as_ptr(), c_str);
127 Ok(res)
128 }
129 }
130
131 pub fn to_js_string(&self) -> Result<String<'js>> {
133 unsafe {
134 let val = qjs::JS_AtomToString(self.ctx.as_ptr(), self.atom);
135 let val = self.ctx.handle_exception(val)?;
136 Ok(String::from_js_value(self.ctx.clone(), val))
137 }
138 }
139
140 pub fn to_value(&self) -> Result<Value<'js>> {
142 self.to_js_string().map(|String(value)| value)
143 }
144
145 pub(crate) unsafe fn from_atom_val(ctx: Ctx<'js>, val: qjs::JSAtom) -> Self {
146 Atom { atom: val, ctx }
147 }
148
149 pub(crate) unsafe fn from_atom_val_dup(ctx: Ctx<'js>, val: qjs::JSAtom) -> Self {
150 qjs::JS_DupAtom(ctx.as_ptr(), val);
151 Atom { atom: val, ctx }
152 }
153}
154
155impl<'js> Clone for Atom<'js> {
156 fn clone(&self) -> Atom<'js> {
157 let atom = unsafe { qjs::JS_DupAtom(self.ctx.as_ptr(), self.atom) };
158 Atom {
159 atom,
160 ctx: self.ctx.clone(),
161 }
162 }
163}
164
165impl<'js> Drop for Atom<'js> {
166 fn drop(&mut self) {
167 unsafe {
168 qjs::JS_FreeAtom(self.ctx.as_ptr(), self.atom);
169 }
170 }
171}