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 #[cfg(feature = "bellard")]
12 let raw = unsafe { r.u.uint64 };
13 #[cfg(feature = "quickjs-ng")]
14 let raw = unsafe { r.u.int32 };
15 let val: bool = raw > 0;
16 Ok(val)
17 } else {
18 Err(JsError::new_str("value is not a boolean"))
19 }
20}
21
22pub fn from_bool(b: bool) -> QuickJsValueAdapter {
23 let raw = unsafe { q::JS_NewBool(ptr::null_mut(), b) };
24 QuickJsValueAdapter::new_no_context(raw, "primitives::from_bool")
25}
26
27pub fn to_f64(value_ref: &QuickJsValueAdapter) -> Result<f64, JsError> {
28 if value_ref.is_f64() {
29 let r = value_ref.borrow_value();
30 let val = unsafe { r.u.float64 };
31 Ok(val)
32 } else {
33 Err(JsError::new_str("value was not a float64"))
34 }
35}
36
37pub fn from_f64(f: f64) -> QuickJsValueAdapter {
38 #[cfg(feature = "bellard")]
39 let raw = unsafe { q::JS_NewFloat64(ptr::null_mut(), f) };
40
41 #[cfg(feature = "quickjs-ng")]
42 let raw = unsafe { q::JS_NewNumber(ptr::null_mut(), f) };
43
44 QuickJsValueAdapter::new_no_context(raw, "primitives::from_f64")
45}
46
47pub fn to_i32(value_ref: &QuickJsValueAdapter) -> Result<i32, JsError> {
48 if value_ref.is_i32() {
49 let r = value_ref.borrow_value();
50
51 #[cfg(feature = "bellard")]
52 let val: i32 = unsafe { q::JS_ValueGetInt(*r) };
53
54 #[cfg(feature = "quickjs-ng")]
55 let val: i32 = unsafe { r.u.int32 };
56
57 Ok(val)
58 } else {
59 Err(JsError::new_str("val is not an int"))
60 }
61}
62
63pub fn from_i32(i: i32) -> QuickJsValueAdapter {
64 let raw = unsafe { q::JS_NewInt32(ptr::null_mut(), i) };
65 QuickJsValueAdapter::new_no_context(raw, "primitives::from_i32")
66}
67
68pub fn to_string_q(
69 q_ctx: &QuickJsRealmAdapter,
70 value_ref: &QuickJsValueAdapter,
71) -> Result<String, JsError> {
72 unsafe { to_string(q_ctx.context, value_ref) }
73}
74pub unsafe fn to_string(
77 context: *mut q::JSContext,
78 value_ref: &QuickJsValueAdapter,
79) -> Result<String, JsError> {
80 assert!(value_ref.is_string());
83
84 let mut len = 0;
85
86 #[cfg(feature = "bellard")]
87 let ptr: *const c_char = q::JS_ToCStringLen2(context, &mut len, *value_ref.borrow_value(), 0);
88 #[cfg(feature = "quickjs-ng")]
89 let ptr: *const c_char =
90 q::JS_ToCStringLen2(context, &mut len, *value_ref.borrow_value(), false);
91
92 if len == 0 {
93 return Ok("".to_string());
94 }
95
96 if ptr.is_null() {
97 return Err(JsError::new_str(
98 "Could not convert string: got a null pointer",
99 ));
100 }
101
102 let bytes = std::slice::from_raw_parts(ptr as *const u8, len);
103
104 let s = String::from_utf8_lossy(bytes).into_owned();
106
107 q::JS_FreeCString(context, ptr);
109
110 Ok(s)
111}
112
113pub fn from_string_q(q_ctx: &QuickJsRealmAdapter, s: &str) -> Result<QuickJsValueAdapter, JsError> {
114 unsafe { from_string(q_ctx.context, s) }
115}
116pub unsafe fn from_string(
119 context: *mut q::JSContext,
120 s: &str,
121) -> Result<QuickJsValueAdapter, JsError> {
122 let qval = q::JS_NewStringLen(context, s.as_ptr() as *const c_char, s.len() as _);
123 let ret = QuickJsValueAdapter::new(context, qval, false, true, "primitives::from_string qval");
124 if ret.is_exception() {
125 return Err(JsError::new_str("Could not create string in runtime"));
126 }
127
128 Ok(ret)
129}
130
131#[cfg(test)]
132pub mod tests {
133 use crate::facades::tests::init_test_rt;
134 use crate::jsutils::Script;
135
136 #[tokio::test]
137 async fn test_emoji() {
138 let rt = init_test_rt();
139
140 let res = rt.eval(None, Script::new("testEmoji.js", "'hi'")).await;
141
142 match res {
143 Ok(fac) => {
144 assert_eq!(fac.get_str(), "hi");
145 }
146 Err(e) => {
147 panic!("script failed: {}", e);
148 }
149 }
150
151 let res = rt.eval(None, Script::new("testEmoji.js", "'๐'")).await;
152
153 match res {
154 Ok(fac) => {
155 assert_eq!(fac.get_str(), "๐");
156 }
157 Err(e) => {
158 panic!("script failed: {}", e);
159 }
160 }
161
162 let res = rt.eval(None, Script::new("testEmoji.js", "'pre๐'")).await;
163
164 match res {
165 Ok(fac) => {
166 assert_eq!(fac.get_str(), "pre๐");
167 }
168 Err(e) => {
169 panic!("script failed: {}", e);
170 }
171 }
172
173 let res = rt.eval(None, Script::new("testEmoji.js", "'๐post'")).await;
174
175 match res {
176 Ok(fac) => {
177 assert_eq!(fac.get_str(), "๐post");
178 }
179 Err(e) => {
180 panic!("script failed: {}", e);
181 }
182 }
183
184 let res = rt
185 .eval(None, Script::new("testEmoji.js", "'pre๐post'"))
186 .await;
187
188 match res {
189 Ok(fac) => {
190 assert_eq!(fac.get_str(), "pre๐post");
191 }
192 Err(e) => {
193 panic!("script failed: {}", e);
194 }
195 }
196
197 let res = rt
198 .eval(
199 None,
200 Script::new("testEmoji.js", "JSON.stringify({c: '๐'})"),
201 )
202 .await;
203
204 match res {
205 Ok(fac) => {
206 assert_eq!(fac.get_str(), "{\"c\":\"๐\"}");
207 }
208 Err(e) => {
209 panic!("script failed: {}", e);
210 }
211 }
212 }
213}