Skip to main content

boa_engine/object/builtins/
jsgeneratorfunction.rs

1//! A Rust API wrapper for Boa's `GeneratorFunction` Builtin ECMAScript Object
2use crate::{
3    Context, JsNativeError, JsResult, JsValue,
4    builtins::function::OrdinaryFunction,
5    object::{JsObject, builtins::JsGenerator},
6    value::TryFromJs,
7};
8use boa_gc::{Finalize, Trace};
9use std::ops::Deref;
10
11/// `JsGeneratorFunction` provides a wrapper for Boa's implementation of the ECMAScript `GeneratorFunction` builtin object.
12#[derive(Debug, Clone, Trace, Finalize)]
13pub struct JsGeneratorFunction {
14    inner: JsObject,
15}
16
17impl JsGeneratorFunction {
18    /// Creates a `JsGeneratorFunction` from a generator function `JsObject`.
19    ///
20    /// More information:
21    ///  - [MDN documentation][mdn]
22    ///
23    /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/GeneratorFunction
24    #[inline]
25    pub fn from_object(object: JsObject) -> JsResult<Self> {
26        if object
27            .downcast_ref::<OrdinaryFunction>()
28            .is_some_and(|f| f.code.is_generator() && !f.code.is_async())
29        {
30            Ok(Self { inner: object })
31        } else {
32            Err(JsNativeError::typ()
33                .with_message("object is not a GeneratorFunction")
34                .into())
35        }
36    }
37
38    /// Calls the generator function and returns a new `JsGenerator` object.
39    ///
40    /// More information:
41    ///  - [MDN documentation][mdn]
42    ///
43    /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/GeneratorFunction
44    pub fn call(
45        &self,
46        this: &JsValue,
47        args: &[JsValue],
48        context: &mut Context,
49    ) -> JsResult<JsGenerator> {
50        let value = self.inner.call(this, args, context)?;
51        let obj = value
52            .as_object()
53            .ok_or_else(|| {
54                JsNativeError::typ().with_message("generator function did not return an object")
55            })?
56            .clone();
57        JsGenerator::from_object(obj)
58    }
59}
60
61impl From<JsGeneratorFunction> for JsObject {
62    #[inline]
63    fn from(o: JsGeneratorFunction) -> Self {
64        o.inner.clone()
65    }
66}
67
68impl From<JsGeneratorFunction> for JsValue {
69    #[inline]
70    fn from(o: JsGeneratorFunction) -> Self {
71        o.inner.clone().into()
72    }
73}
74
75impl Deref for JsGeneratorFunction {
76    type Target = JsObject;
77    #[inline]
78    fn deref(&self) -> &Self::Target {
79        &self.inner
80    }
81}
82
83impl TryFromJs for JsGeneratorFunction {
84    fn try_from_js(value: &JsValue, _context: &mut Context) -> JsResult<Self> {
85        if let Some(o) = value.as_object() {
86            Self::from_object(o.clone())
87        } else {
88            Err(JsNativeError::typ()
89                .with_message("value is not a GeneratorFunction object")
90                .into())
91        }
92    }
93}