|
4 | 4 | // option. This file may not be copied, modified, or distributed
|
5 | 5 | // except according to those terms.
|
6 | 6 |
|
7 |
| -use super::{JSObject, JSString, JSValue}; |
8 |
| -use crate::sys; |
| 7 | +use super::{JSObject, JSString}; |
| 8 | +use crate::{sys, JSContext, JSException, JSValue}; |
9 | 9 | use std::ops::Deref;
|
10 | 10 | use std::ptr;
|
11 | 11 |
|
@@ -133,6 +133,70 @@ impl JSObject {
|
133 | 133 | ctx: self.value.ctx,
|
134 | 134 | }
|
135 | 135 | }
|
| 136 | + |
| 137 | + /// Call this object considering it is a valid function. |
| 138 | + /// |
| 139 | + /// ```rust |
| 140 | + /// # use javascriptcore::{JSContext, JSValue}; |
| 141 | + /// let ctx = JSContext::default(); |
| 142 | + /// let global = ctx.global_object().unwrap(); |
| 143 | + /// let math = global.get_property("Math").as_object().unwrap(); |
| 144 | + /// let pow = math.get_property("pow").as_object().unwrap(); |
| 145 | + /// |
| 146 | + /// let result = pow.call_as_function( |
| 147 | + /// &ctx, |
| 148 | + /// None, |
| 149 | + /// &[JSValue::new_number(&ctx, 2.), JSValue::new_number(&ctx, 3.)], |
| 150 | + /// ).unwrap(); |
| 151 | + /// |
| 152 | + /// assert_eq!(result.as_number().unwrap(), 8.); |
| 153 | + /// ``` |
| 154 | + pub fn call_as_function( |
| 155 | + &self, |
| 156 | + context: &JSContext, |
| 157 | + this: Option<&JSObject>, |
| 158 | + arguments: &[JSValue], |
| 159 | + ) -> Result<JSValue, JSException> { |
| 160 | + let arguments = arguments |
| 161 | + .iter() |
| 162 | + .map(|argument| argument.raw) |
| 163 | + .collect::<Vec<_>>(); |
| 164 | + let mut exception: sys::JSValueRef = ptr::null_mut(); |
| 165 | + |
| 166 | + let result = unsafe { |
| 167 | + sys::JSObjectCallAsFunction( |
| 168 | + context.raw, |
| 169 | + self.raw, |
| 170 | + this.map(|this| this.raw).unwrap_or_else(ptr::null_mut), |
| 171 | + arguments.len(), |
| 172 | + arguments.as_slice().as_ptr(), |
| 173 | + &mut exception, |
| 174 | + ) |
| 175 | + }; |
| 176 | + |
| 177 | + if !exception.is_null() { |
| 178 | + return Err(JSException { |
| 179 | + value: JSValue { |
| 180 | + raw: exception, |
| 181 | + ctx: context.raw, |
| 182 | + }, |
| 183 | + }); |
| 184 | + } |
| 185 | + |
| 186 | + if result.is_null() { |
| 187 | + return Err(JSException { |
| 188 | + value: JSValue::new_string( |
| 189 | + context, |
| 190 | + "Cannot call this object as a function: it is not a valid function", |
| 191 | + ), |
| 192 | + }); |
| 193 | + } |
| 194 | + |
| 195 | + Ok(JSValue { |
| 196 | + raw: result, |
| 197 | + ctx: context.raw, |
| 198 | + }) |
| 199 | + } |
136 | 200 | }
|
137 | 201 |
|
138 | 202 | /// A `JSObject` can be dereferenced to return the underlying `JSValue`.
|
@@ -173,6 +237,8 @@ impl Iterator for JSObjectPropertyNameIter {
|
173 | 237 |
|
174 | 238 | #[cfg(test)]
|
175 | 239 | mod tests {
|
| 240 | + use crate::JSException; |
| 241 | + |
176 | 242 | use super::super::{JSContext, JSValue};
|
177 | 243 |
|
178 | 244 | #[test]
|
@@ -222,4 +288,27 @@ mod tests {
|
222 | 288 | assert!(v.is_object());
|
223 | 289 | assert!(o.is_object());
|
224 | 290 | }
|
| 291 | + |
| 292 | + #[test] |
| 293 | + fn call_as_function() -> Result<(), JSException> { |
| 294 | + let ctx = JSContext::default(); |
| 295 | + let global = ctx.global_object()?; |
| 296 | + let math = global.get_property("Math").as_object()?; |
| 297 | + let pow = math.get_property("pow").as_object()?; |
| 298 | + |
| 299 | + let result = pow.call_as_function( |
| 300 | + &ctx, |
| 301 | + None, |
| 302 | + &[JSValue::new_number(&ctx, 2.), JSValue::new_number(&ctx, 3.)], |
| 303 | + )?; |
| 304 | + |
| 305 | + assert_eq!(result.as_number()?, 8.); |
| 306 | + |
| 307 | + // Not a function, it's a constant. |
| 308 | + let e = math.get_property("E").as_object()?; |
| 309 | + |
| 310 | + assert!(e.call_as_function(&ctx, None, &[]).is_err()); |
| 311 | + |
| 312 | + Ok(()) |
| 313 | + } |
225 | 314 | }
|
0 commit comments