Attribute Macro rquickjs::bind [−][src]
#[bind]
An attribute to generate bindings easy
This macro allows register Rust constants, functions, data types and modules to use it from JavaScript.
NOTE: To export any nested items it should be public.
Supported attributes
Any attributes which is enclosed by a #[quickjs(...)]
will be interpreted by this macro to control bindings.
Macro attributes
Attribute | Description |
---|---|
ident = "MyModule" | The name of target unit struct to export |
public , public = "self/super/crate" | Makes the target unit struct visible |
module | Adds the ModuleDef impl to use bindings as ES6 module |
object | Adds the ObjectDef impl for attaching bindings to an object |
init , init = "js_module_init" | Adds the js_module_init function (in particular for creating dynamically loadable modules or static libraries to use from C ) |
crate = "rquickjs" | Allows rename rquickjs crate |
Module attributes
Attribute | Description |
---|---|
rename = "new_name" | Renames module to export |
bare | Exports contents of the module to the parent module instead of creating submodule (this is off by default) |
skip | Skips exporting this module |
hide | Do not output this module (bindings only) |
Constant attributes
Attribute | Description |
---|---|
rename = "new_name" | Renames constant to export |
value | Defines a property |
writable | Makes property to be writable |
configurable | Makes property to be configurable |
enumerable | Makes property to be enumerable |
proto | Sets constant or property to prototype |
skip | Skips exporting this contant |
hide | Do not output this constant (bindings only) |
Function attributes
Attribute | Description |
---|---|
rename = "new_name" | Renames function to export |
get | Uses function as a getter for a property |
set | Uses function as a setter for a property |
configurable | Makes property to be configurable |
enumerable | Makes property to be enumerable |
constructor , constructor = true | Forces creating contructor |
constructor = false | Disables creating contructor |
skip | Skips exporting this function |
hide | Do not output this function (bindings only) |
When multiple functions is declared with same name (i.e. same rename
attribute value) it will be overloaded. The overloading rules is dead simple, so currently you should be care to get it works.
Overloading is not supported for property getters/setters.
Data type attributes
This attributes applies to structs and enums to use it as ES6 classes.
Attribute | Description |
---|---|
rename = "new_name" | Renames data type to export |
has_refs | Marks data which has internal refs to other JS values (requires HasRefs to be implemented) |
cloneable | Marks data type which implements Clone trait |
skip | Skips exporting this data type |
hide | Do not output this data type (bindings only) |
The following traits will be implemented for data type:
The following traits will be implemented for references to data type:
Data field attributes
This attributes applies to data fields to use it as a properties.
Attribute | Description |
---|---|
rename = "new_name" | Renames field to export |
readonly | Makes this field to be readonly |
skip | Skips exporting this field |
impl
block attributes
This attributes applies to impl
blocks to bind class methods and properties and also adding static constants and functions.
Attribute | Description |
---|---|
rename = "new_name" | Renames data type to export |
has_refs | Marks data which has internal refs to other JS values (requires HasRefs to be implemented) |
skip | Skips exporting this impl block |
hide | Do not output this impl block (bindings only) |
Examples
Single function binding
use rquickjs::{Runtime, Context, bind}; #[bind(object)] pub fn add2(a: f32, b: f32) -> f32 { a + b } let rt = Runtime::new().unwrap(); let ctx = Context::full(&rt).unwrap(); ctx.with(|ctx| { let glob = ctx.globals(); glob.init_def::<Add2>().unwrap(); let res: f32 = ctx.eval(r#"add2(1, 2)"#).unwrap(); assert_eq!(res, 3.0); });
Module with two functions
use rquickjs::{Runtime, Context, Object, bind}; #[bind(object)] pub mod math { pub const PI: f32 = core::f32::consts::PI; pub fn add2(a: f32, b: f32) -> f32 { a + b } pub fn mul2(a: f32, b: f32) -> f32 { a * b } } let rt = Runtime::new().unwrap(); let ctx = Context::full(&rt).unwrap(); ctx.with(|ctx| { let glob = ctx.globals(); glob.init_def::<Math>().unwrap(); let res: f32 = ctx.eval(r#"math.mul2(3, math.add2(1, 2))"#).unwrap(); assert_eq!(res, 9.0); });
Module with two functions which reused from another module
use rquickjs::{Runtime, Context, Object, bind}; mod my_math { pub const PI: f32 = core::f32::consts::PI; pub fn add2(a: f32, b: f32) -> f32 { a + b } pub fn mul2(a: f32, b: f32) -> f32 { a * b } } #[bind(object)] mod math { pub use super::my_math::*; #[quickjs(hide)] pub const PI: f32 = (); #[quickjs(hide)] pub fn add2(a: f32, b: f32) -> f32 {} #[quickjs(hide)] pub fn mul2(a: f32, b: f32) -> f32 {} } let rt = Runtime::new().unwrap(); let ctx = Context::full(&rt).unwrap(); ctx.with(|ctx| { let glob = ctx.globals(); glob.init_def::<Math>().unwrap(); let res: f32 = ctx.eval(r#"math.mul2(3, math.add2(1, 2))"#).unwrap(); assert_eq!(res, 9.0); });
Bare module definition
use rquickjs::{Runtime, Context, Object, bind}; #[bind(object)] #[quickjs(bare)] pub mod math { #[quickjs(name = "pi")] pub const PI: f32 = core::f32::consts::PI; pub fn add2(a: f32, b: f32) -> f32 { a + b } pub fn mul2(a: f32, b: f32) -> f32 { a * b } } let rt = Runtime::new().unwrap(); let ctx = Context::full(&rt).unwrap(); ctx.with(|ctx| { let glob = ctx.globals(); glob.init_def::<Math>().unwrap(); let res: f32 = ctx.eval(r#"mul2(3, add2(1, 2))"#).unwrap(); assert_eq!(res, 9.0); });
Async function binding
use rquickjs::{Runtime, Context, Promise, bind, AsyncStd}; #[bind(object)] pub async fn sleep(msecs: u64) { async_std::task::sleep( std::time::Duration::from_millis(msecs) ).await; } let rt = Runtime::new().unwrap(); let ctx = Context::full(&rt).unwrap(); rt.spawn_executor(AsyncStd); ctx.with(|ctx| { ctx.globals().init_def::<Sleep>().unwrap(); }); let promise: Promise<String> = ctx.with(|ctx| { ctx.eval(r#" async function mysleep() { await sleep(50); return "ok"; } mysleep() "#).unwrap() }); let res = promise.await.unwrap(); assert_eq!(res, "ok"); rt.idle().await;
Class binding
use rquickjs::{bind, Runtime, Context, Error}; #[bind(object)] #[quickjs(bare)] mod geom { pub struct Point { // field properties pub x: f64, pub y: f64, } impl Point { // constructor pub fn new(x: f64, y: f64) -> Self { Self { x, y } } // instance method pub fn norm(&self) -> f64 { Self::dot(self, self).sqrt() } // instance property getter #[quickjs(get, enumerable)] pub fn xy(&self) -> (f64, f64) { (self.x, self.y) } // instance property setter #[quickjs(rename = "xy", set)] pub fn set_xy(&mut self, xy: (f64, f64)) { self.x = xy.0; self.y = xy.1; } // static method pub fn dot(a: &Point, b: &Point) -> f64 { a.x * b.x + a.y * b.y } // static property with getter #[quickjs(get)] pub fn zero() -> Self { Point { x: 0.0, y: 0.0 } } } } let rt = Runtime::new().unwrap(); let ctx = Context::full(&rt).unwrap(); ctx.with(|ctx| { ctx.globals().init_def::<Geom>().unwrap(); }); ctx.with(|ctx| { ctx.eval::<(), _>(r#" function assert(res) { if (!res) throw new Error("Assertion failed"); } class ColorPoint extends Point { constructor(x, y, color) { super(x, y); this.color = color; } get_color() { return this.color; } } let pt = new Point(2, 3); assert(pt.x === 2); assert(pt.y === 3); pt.x = 4; assert(pt.x === 4); assert(pt.norm() == 5); let xy = pt.xy; assert(xy.length === 2); assert(xy[0] === 4); assert(xy[1] === 3); pt.xy = [3, 4]; assert(pt.x === 3); assert(pt.y === 4); assert(Point.dot(pt, Point(2, 1)) == 10); let ptz = Point.zero; assert(ptz.x === 0); assert(ptz.y === 0); let ptc = new ColorPoint(2, 3, 0xffffff); assert(ptc.x === 2); assert(ptc.color === 0xffffff); assert(ptc.get_color() === 0xffffff); "#).unwrap(); });