Attribute Macro rquickjs::methods

source ·
#[methods]
Available on crate feature macro only.
Expand description

A attribute for implementing methods for a class.

This attribute can be added to a impl block which implements methods for a type which uses the class attribute to derive JsClass.

§Limitations

Due to limitations in the Rust type system this attribute can be used on only one impl block per type.

§Attribute options

The attribute has a number of options for configuring the generated trait implementation. These attributes can be passed to the methods attribute as an argument: #[methods(rename = "AnotherName")] or with a separate qjs attribute on the impl item: #[qjs(rename = "AnotherName")]. A option which is a Flag can be set just by adding the attribute: #[qjs(flag)] or by setting it to specific boolean value: #[qjs(flag = true)].

OptionValueDescription
crateStringChanges the name from which the attribute tries to use rquickjs types. Use when the name behind which the rquickjs crate is declared is not properly resolved by the macro.
renameStringChanges the name of the implemented class on the JavaScript side.
rename_allCasingConverts the case of all the fields of this struct which have implement accessors. Can be one of lowercase, UPPERCASE, camelCase, PascalCase,snake_case, or SCREAMING_SNAKE

§Item options

Each item of the impl block can also tagged with an attribute to change the resulting derived method definition. These attributes are all in the form of #[qjs(option = value)].

OptionValueDescription
getFlagMakes this method a getter for a field of the same name.
setFlagMakes this method a setter for a field of the same name.
enumerableFlagMakes the method, if it is a getter or setter, enumerable in JavaScript.
configurableFlagMakes the method, if it is a getter or setter, configurable in JavaScript.
renameString or PredefinedAtomChanges the name of the field getter and/or setter to the specified name in JavaScript.
staticFlagMakes the method a static method i.e. defined on the type constructor instead of the prototype.
constructorFlagMarks this method a the constructor for this type.
skipFlagSkips defining this method on the JavaScript class.

§Example

use rquickjs::{
    atom::PredefinedAtom, class::Trace, prelude::Func, CatchResultExt, Class, Context, Ctx,
    Object, Result, Runtime,
};

#[derive(Trace)]
#[rquickjs::class]
pub struct TestClass {
    value: u32,
    another_value: u32,
}

#[rquickjs::methods]
impl TestClass {
    /// Marks a method as a constructor.
    /// This method will be used when a new TestClass object is created from JavaScript.
    #[qjs(constructor)]
    pub fn new(value: u32) -> Self {
        TestClass {
            value,
            another_value: value,
        }
    }

    /// Mark a function as a getter.
    /// The value of this function can be accessed as a field.
    /// This function is also renamed to value
    #[qjs(get, rename = "value")]
    pub fn get_value(&self) -> u32 {
        self.value
    }

    /// Mark a function as a setter.
    /// The value of this function can be set as a field.
    /// This function is also renamed to value
    #[qjs(set, rename = "value")]
    pub fn set_value(&mut self, v: u32) {
        self.value = v
    }

    /// Mark a function as a enumerable gettter.
    #[qjs(get, rename = "anotherValue", enumerable)]
    pub fn get_another_value(&self) -> u32 {
        self.another_value
    }

    #[qjs(set, rename = "anotherValue", enumerable)]
    pub fn set_another_value(&mut self, v: u32) {
        self.another_value = v
    }

    /// Marks a function as static. It will be defined on the constructor object instead of the
    /// Class prototype.
    #[qjs(static)]
    pub fn compare(a: &Self, b: &Self) -> bool {
        a.value == b.value && a.another_value == b.another_value
    }

    /// All functions declared in this impl block will be defined on the prototype of the
    /// class. This attributes allows you to skip certain functions.
    #[qjs(skip)]
    pub fn inner_function(&self) {}

    /// Functions can also be renamed to specific symbols. This allows you to make an Rust type
    /// act like an iteratable value for example.
    #[qjs(rename = PredefinedAtom::SymbolIterator)]
    pub fn iterate<'js>(&self, ctx: Ctx<'js>) -> Result<Object<'js>> {
        let res = Object::new(ctx)?;

        res.set(
            PredefinedAtom::Next,
            Func::from(|ctx: Ctx<'js>| -> Result<Object<'js>> {
                let res = Object::new(ctx)?;
                res.set(PredefinedAtom::Done, true)?;
                Ok(res)
            }),
        )?;
        Ok(res)
    }
}

pub fn main() {
    let rt = Runtime::new().unwrap();
    let ctx = Context::full(&rt).unwrap();

    ctx.with(|ctx| {
        /// Define the class constructor on the globals object.
        Class::<TestClass>::define(&ctx.globals()).unwrap();
        ctx.eval::<(), _>(
            r#"
            let nv = new TestClass(5);
            if(nv.value !== 5){
                throw new Error('invalid value')
            }
        "#,
        ).catch(&ctx).unwrap();
    });
}