quickjs_runtime/quickjs_utils/
primitives.rs1use crate::jsutils::JsError;
2use crate::quickjsrealmadapter::QuickJsRealmAdapter;
3use crate::quickjsvalueadapter::QuickJsValueAdapter;
4use core::ptr;
5use libquickjs_sys as q;
6use std::os::raw::c_char;
7
8pub fn to_bool(value_ref: &QuickJsValueAdapter) -> Result<bool, JsError> {
9 if value_ref.is_bool() {
10 let r = value_ref.borrow_value();
11 let raw = unsafe { r.u.int32 };
12 let val: bool = raw > 0;
13 Ok(val)
14 } else {
15 Err(JsError::new_str("value is not a boolean"))
16 }
17}
18
19pub fn from_bool(b: bool) -> QuickJsValueAdapter {
20 let raw = unsafe { q::JS_NewBool(ptr::null_mut(), b) };
21 QuickJsValueAdapter::new_no_context(raw, "primitives::from_bool")
22}
23
24pub fn to_f64(value_ref: &QuickJsValueAdapter) -> Result<f64, JsError> {
25 if value_ref.is_f64() {
26 let r = value_ref.borrow_value();
27 let val = unsafe { r.u.float64 };
28 Ok(val)
29 } else {
30 Err(JsError::new_str("value was not a float64"))
31 }
32}
33
34pub fn from_f64(f: f64) -> QuickJsValueAdapter {
35 #[cfg(feature = "bellard")]
36 let raw = unsafe { q::JS_NewFloat64(ptr::null_mut(), f) };
37
38 #[cfg(feature = "quickjs-ng")]
39 let raw = unsafe { q::JS_NewNumber(ptr::null_mut(), f) };
40
41 QuickJsValueAdapter::new_no_context(raw, "primitives::from_f64")
42}
43
44pub fn to_i32(value_ref: &QuickJsValueAdapter) -> Result<i32, JsError> {
45 if value_ref.is_i32() {
46 let r = value_ref.borrow_value();
47 let val: i32 = unsafe { r.u.int32 };
48 Ok(val)
49 } else {
50 Err(JsError::new_str("val is not an int"))
51 }
52}
53
54pub fn from_i32(i: i32) -> QuickJsValueAdapter {
55 let raw = unsafe { q::JS_NewInt32(ptr::null_mut(), i) };
56 QuickJsValueAdapter::new_no_context(raw, "primitives::from_i32")
57}
58
59pub fn to_string_q(
60 q_ctx: &QuickJsRealmAdapter,
61 value_ref: &QuickJsValueAdapter,
62) -> Result<String, JsError> {
63 unsafe { to_string(q_ctx.context, value_ref) }
64}
65pub unsafe fn to_string(
68 context: *mut q::JSContext,
69 value_ref: &QuickJsValueAdapter,
70) -> Result<String, JsError> {
71 assert!(value_ref.is_string());
74
75 let mut len = 0;
76
77 #[cfg(feature = "bellard")]
78 let ptr: *const c_char = q::JS_ToCStringLen2(context, &mut len, *value_ref.borrow_value(), 0);
79 #[cfg(feature = "quickjs-ng")]
80 let ptr: *const c_char =
81 q::JS_ToCStringLen2(context, &mut len, *value_ref.borrow_value(), false);
82
83 if len == 0 {
84 return Ok("".to_string());
85 }
86
87 if ptr.is_null() {
88 return Err(JsError::new_str(
89 "Could not convert string: got a null pointer",
90 ));
91 }
92
93 let cstr = std::ffi::CStr::from_ptr(ptr);
94
95 let s = cstr.to_string_lossy().into_owned();
96
97 q::JS_FreeCString(context, ptr);
99
100 Ok(s)
101}
102
103pub unsafe fn to_str(
106 context: *mut q::JSContext,
107 value_ref: &QuickJsValueAdapter,
108) -> Result<&str, JsError> {
109 assert!(value_ref.is_string());
112
113 let mut len = 0;
114
115 #[cfg(feature = "bellard")]
116 let ptr: *const c_char = q::JS_ToCStringLen2(context, &mut len, *value_ref.borrow_value(), 0);
117 #[cfg(feature = "quickjs-ng")]
118 let ptr: *const c_char =
119 q::JS_ToCStringLen2(context, &mut len, *value_ref.borrow_value(), false);
120 q::JS_FreeCString(context, ptr);
122 if len == 0 {
125 return Ok("");
126 }
127
128 if ptr.is_null() {
129 return Err(JsError::new_str(
130 "Could not convert string: got a null pointer",
131 ));
132 }
133
134 let cstr = std::ffi::CStr::from_ptr(ptr);
135 cstr.to_str()
136 .map_err(|e| JsError::new_string(format!("utf8 error: {e}")))
137
138 }
142
143pub fn from_string_q(q_ctx: &QuickJsRealmAdapter, s: &str) -> Result<QuickJsValueAdapter, JsError> {
144 unsafe { from_string(q_ctx.context, s) }
145}
146pub unsafe fn from_string(
149 context: *mut q::JSContext,
150 s: &str,
151) -> Result<QuickJsValueAdapter, JsError> {
152 let qval = q::JS_NewStringLen(context, s.as_ptr() as *const c_char, s.len() as _);
153 let ret = QuickJsValueAdapter::new(context, qval, false, true, "primitives::from_string qval");
154 if ret.is_exception() {
155 return Err(JsError::new_str("Could not create string in runtime"));
156 }
157
158 Ok(ret)
159}
160
161#[cfg(test)]
162pub mod tests {
163
164 use crate::facades::tests::init_test_rt;
165 use crate::jsutils::Script;
166
167 #[tokio::test]
168 async fn test_emoji() {
169 let rt = init_test_rt();
170
171 let res = rt.eval(None, Script::new("testEmoji.js", "'hi'")).await;
172
173 match res {
174 Ok(fac) => {
175 assert_eq!(fac.get_str(), "hi");
176 }
177 Err(e) => {
178 panic!("script failed: {}", e);
179 }
180 }
181
182 let res = rt.eval(None, Script::new("testEmoji.js", "'๐'")).await;
183
184 match res {
185 Ok(fac) => {
186 assert_eq!(fac.get_str(), "๐");
187 }
188 Err(e) => {
189 panic!("script failed: {}", e);
190 }
191 }
192
193 let res = rt.eval(None, Script::new("testEmoji.js", "'pre๐'")).await;
194
195 match res {
196 Ok(fac) => {
197 assert_eq!(fac.get_str(), "pre๐");
198 }
199 Err(e) => {
200 panic!("script failed: {}", e);
201 }
202 }
203
204 let res = rt.eval(None, Script::new("testEmoji.js", "'๐post'")).await;
205
206 match res {
207 Ok(fac) => {
208 assert_eq!(fac.get_str(), "๐post");
209 }
210 Err(e) => {
211 panic!("script failed: {}", e);
212 }
213 }
214
215 let res = rt
216 .eval(None, Script::new("testEmoji.js", "'pre๐post'"))
217 .await;
218
219 match res {
220 Ok(fac) => {
221 assert_eq!(fac.get_str(), "pre๐post");
222 }
223 Err(e) => {
224 panic!("script failed: {}", e);
225 }
226 }
227
228 let res = rt
229 .eval(
230 None,
231 Script::new("testEmoji.js", "JSON.stringify({c: '๐'})"),
232 )
233 .await;
234
235 match res {
236 Ok(fac) => {
237 assert_eq!(fac.get_str(), "{\"c\":\"๐\"}");
238 }
239 Err(e) => {
240 panic!("script failed: {}", e);
241 }
242 }
243 }
244}