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