Module boa_engine::class

source ·
Expand description

Traits and structs for implementing native classes.

Native classes are implemented through the Class trait.

§Examples

// Can also be a struct containing `Trace` types.
#[derive(Debug, Trace, Finalize, JsData)]
enum Animal {
    Cat,
    Dog,
    Other,
}

impl Class for Animal {
    // we set the binging name of this function to be `"Animal"`.
    const NAME: &'static str = "Animal";

    // We set the length to `2` since we accept 2 arguments in the constructor.
    const LENGTH: usize = 2;

    // This is what is called when we do `new Animal()` to construct the inner data of the class.
    // `_new_target` is the target of the `new` invocation, in this case the `Animal` constructor
    // object.
    fn data_constructor(_new_target: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<Self> {
        // This is equivalent to `String(arg)`.
        let kind = args.get_or_undefined(0).to_string(context)?;

        let animal = match kind.to_std_string_escaped().as_str() {
            "cat" => Self::Cat,
            "dog" => Self::Dog,
            _ => Self::Other,
        };

        Ok(animal)
    }

    // This is also called on instance construction, but it receives the object wrapping the
    // native data as its `instance` argument.
    fn object_constructor(
        instance: &JsObject,
        args: &[JsValue],
        context: &mut Context,
    ) -> JsResult<()> {
        let age = args.get_or_undefined(1).to_number(context)?;

        // Roughly equivalent to `this.age = Number(age)`.
        instance.set(js_string!("age"), age, true, context)?;

        Ok(())
    }

    /// This is where the class object is initialized.
    fn init(class: &mut ClassBuilder) -> JsResult<()> {
        class.method(
            js_string!("speak"),
            0,
            NativeFunction::from_fn_ptr(|this, _args, _ctx| {
                if let Some(object) = this.as_object() {
                    if let Some(animal) = object.downcast_ref::<Animal>() {
                        return Ok(match &*animal {
                            Self::Cat => js_string!("meow"),
                            Self::Dog => js_string!("woof"),
                            Self::Other => js_string!(r"¯\_(ツ)_/¯"),
                        }.into());
                    }
                }
                Err(JsNativeError::typ().with_message("invalid this for class method").into())
            }),
        );
        Ok(())
    }
}

fn main() {
    let mut context = Context::default();

    context.register_global_class::<Animal>().unwrap();

    let result = context.eval(Source::from_bytes(r#"
        let pet = new Animal("dog", 3);

        `My pet is ${pet.age} years old. Right, buddy? - ${pet.speak()}!`
    "#)).unwrap();

    assert_eq!(
        result.as_string().unwrap(),
        &js_string!("My pet is 3 years old. Right, buddy? - woof!")
    );
}

Structs§

  • Class builder which allows adding methods and static methods to the class.

Traits§