├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── examples ├── callback.rs ├── callback_closure.rs ├── hello.rs ├── properties.rs └── punjs │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── cli │ ├── Cargo.toml │ ├── cmd.rs │ ├── cmd │ │ └── run.rs │ └── main.rs │ └── testing │ └── hello.js ├── macros ├── .gitignore ├── Cargo.lock ├── Cargo.toml └── src │ └── lib.rs ├── src ├── closure.rs ├── internal.rs └── lib.rs └── sys ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "pkg-config" 7 | version = "0.3.26" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" 10 | 11 | [[package]] 12 | name = "proc-macro-error" 13 | version = "1.0.4" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 16 | dependencies = [ 17 | "proc-macro-error-attr", 18 | "proc-macro2", 19 | "quote", 20 | "syn", 21 | "version_check", 22 | ] 23 | 24 | [[package]] 25 | name = "proc-macro-error-attr" 26 | version = "1.0.4" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 29 | dependencies = [ 30 | "proc-macro2", 31 | "quote", 32 | "version_check", 33 | ] 34 | 35 | [[package]] 36 | name = "proc-macro2" 37 | version = "1.0.54" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" 40 | dependencies = [ 41 | "unicode-ident", 42 | ] 43 | 44 | [[package]] 45 | name = "quote" 46 | version = "1.0.26" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" 49 | dependencies = [ 50 | "proc-macro2", 51 | ] 52 | 53 | [[package]] 54 | name = "rusty_jsc" 55 | version = "0.1.0" 56 | dependencies = [ 57 | "rusty_jsc_macros", 58 | "rusty_jsc_sys", 59 | ] 60 | 61 | [[package]] 62 | name = "rusty_jsc_macros" 63 | version = "0.1.0" 64 | dependencies = [ 65 | "pkg-config", 66 | "proc-macro-error", 67 | "quote", 68 | "syn", 69 | ] 70 | 71 | [[package]] 72 | name = "rusty_jsc_sys" 73 | version = "0.1.0" 74 | dependencies = [ 75 | "pkg-config", 76 | ] 77 | 78 | [[package]] 79 | name = "syn" 80 | version = "1.0.109" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 83 | dependencies = [ 84 | "proc-macro2", 85 | "quote", 86 | "unicode-ident", 87 | ] 88 | 89 | [[package]] 90 | name = "unicode-ident" 91 | version = "1.0.8" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" 94 | 95 | [[package]] 96 | name = "version_check" 97 | version = "0.9.4" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 100 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rusty_jsc" 3 | version = "0.1.0" 4 | description = "Rust bindings for the JavaScriptCore engine" 5 | keywords = [ "javascriptcore", "javascript" ] 6 | authors = [ "Wasmer Engineering Team ", "Pekka Enberg", "Adrien Zinger" ] 7 | license = "MIT" 8 | repository = "https://github.com/wasmerio/rusty_jsc" 9 | edition = "2021" 10 | 11 | [lib] 12 | 13 | [dependencies] 14 | rusty_jsc_macros = { path = "./macros", version = "0.1.0" } 15 | rusty_jsc_sys = { path = "./sys", version = "0.1.0" } 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Pekka Enberg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaScriptCore API for Rust 2 | 3 | [![crates](https://img.shields.io/crates/v/rusty_jsc.svg)](https://crates.io/crates/rusty_jsc) 4 | [![docs](https://docs.rs/rusty_jsc/badge.svg)](https://docs.rs/rusty_jsc) 5 | 6 | This library provides a Rust API for the JavaScriptCore engine with the following goals: 7 | 8 | * High-level API like the JavaScriptCore API for Swift 9 | * Wrap the low-level C++ API instead of `jsc` to avoid the dependency to GTK. 10 | 11 | ## Getting Started 12 | 13 | ### Implementing a JavaScript runtime 14 | 15 | Please check out [PunJS](examples/punjs) for an example of how to implement a JavaScript runtime with `rusty_jsc`. 16 | 17 | ### Evaluating a JavaScript script 18 | ```rust 19 | use rusty_jsc::{JSContext}; 20 | 21 | fn main() { 22 | let mut context = JSContext::default(); 23 | match context.evaluate_script("'Hello World!'", 1) { 24 | Ok(value) => { 25 | println!("{}", value.to_string(&context).unwrap()); 26 | } 27 | Err(e) => { 28 | println!("Uncaught: {}", e.to_string(&context).unwrap()) 29 | } 30 | } 31 | } 32 | ``` 33 | 34 | ### Callbacks from JavaScript to Rust 35 | 36 | ```rust 37 | use rusty_jsc::{JSContext, JSValue}; 38 | use rusty_jsc_macros::callback; 39 | 40 | #[callback] 41 | fn greet( 42 | ctx: JSContext, 43 | function: JSObject, 44 | this: JSObject, 45 | args: &[JSValue], 46 | ) -> Result { 47 | Ok(JSValue::string(&ctx, format!("Hello, {}", args[0].to_string(&ctx).unwrap()))) 48 | } 49 | 50 | fn main() { 51 | let mut context = JSContext::default(); 52 | let callback = JSValue::callback(&context, Some(greet)); 53 | let global = context.get_global_object(); 54 | global.set_property(&context, "greet", callback).unwrap(); 55 | 56 | match context.evaluate_script("greet('Tom')", 1) { 57 | Ok(value) => { 58 | println!("{}", value.to_string(&context).unwrap()); 59 | } 60 | Err(e) => { 61 | println!("Uncaught: {}", e.to_string(&context).unwrap()) 62 | } 63 | } 64 | } 65 | ``` 66 | 67 | #### Passing functions to a callback 68 | 69 | ```rust 70 | use rusty_jsc::{JSContext, JSObject, JSValue, JSString}; 71 | use rusty_jsc_macros::callback; 72 | 73 | #[callback] 74 | fn greet( 75 | ctx: JSContext, 76 | function: JSObject, 77 | this: JSObject, 78 | args: &[JSValue], 79 | ) -> Result { 80 | // Parse the argument as a function and call it with an argument 81 | let callback_function = args[0].to_object(&ctx).unwrap().call(&ctx, None, &[JSValue::string(&ctx, "Tom")]).unwrap(); 82 | Ok(callback_function) 83 | } 84 | 85 | fn main() { 86 | let mut context = JSContext::default(); 87 | let callback = JSValue::callback(&context, Some(greet)); 88 | let global = context.get_global_object(); 89 | global.set_property(&context, "greet", callback).unwrap(); 90 | 91 | match context.evaluate_script("greet((name) => 'Hello, ' + name)", 1) { 92 | Ok(value) => { 93 | println!("{}", value.to_string(&context).unwrap()); 94 | } 95 | Err(e) => { 96 | println!("Uncaught: {}", e.to_string(&context).unwrap()) 97 | } 98 | } 99 | } 100 | ``` 101 | 102 | ## FAQ 103 | 104 | ### What about the other JavaScriptCore bindings for Rust? 105 | 106 | The wrappers in `rusty_jsc` are built against `` header rather than the `jsc` variant that requires GTK. 107 | 108 | ### Why JavaScriptCore when there's already `rusty_v8`? 109 | 110 | [Bun](https://bun.sh) has shown that JavaScriptCore is a worthy contender to V8 on the server-side, so let's bring it over to the Rust ecosystem as well. 111 | 112 | ### How were the C++ low-level bindings generated? 113 | 114 | I first used `bindgen` to do the rough conversion of `JavaScript/JavaScript.h` header and then cleaned it up by hand. 115 | The plan is to maintain the low-level bindings by hand. 116 | -------------------------------------------------------------------------------- /examples/callback.rs: -------------------------------------------------------------------------------- 1 | use rusty_jsc::{JSContext, JSObject, JSValue}; 2 | use rusty_jsc_macros::callback; 3 | 4 | #[callback] 5 | fn example( 6 | ctx: JSContext, 7 | _function: JSObject, 8 | _this: JSObject, 9 | args: &[JSValue], 10 | ) -> Result { 11 | println!( 12 | "hello from Rust land! len: {}, value[0]: {}", 13 | args.len(), 14 | args[0].to_js_string(&ctx).unwrap() 15 | ); 16 | Ok(JSValue::string(&ctx, "Returning a string to JS!")) 17 | } 18 | 19 | #[callback] 20 | #[allow(unused)] // Just for the example 21 | fn example2( 22 | ctx: JSContext, 23 | _function: JSObject, 24 | _this: JSObject, 25 | _args: &[JSValue], 26 | ) -> Result 27 | where 28 | T: Clone, 29 | { 30 | println!("hello from Rust land!"); 31 | Ok(JSValue::string(&ctx, "Hey")) 32 | } 33 | 34 | fn main() { 35 | let mut context = JSContext::default(); 36 | let callback = JSValue::callback(&context, Some(example)); 37 | 38 | let mut global = context.get_global_object(); 39 | global.set_property(&context, "example", callback).unwrap(); 40 | let example = global 41 | .get_property(&context, "example") 42 | .unwrap() 43 | .to_object(&context) 44 | .unwrap(); 45 | let result = example.call_as_function( 46 | &context, 47 | None, 48 | &[ 49 | JSValue::number(&context, 5f64), 50 | JSValue::number(&context, 6f64), 51 | ], 52 | ); 53 | println!( 54 | "direct call: {}", 55 | result.unwrap().to_js_string(&context).unwrap() 56 | ); 57 | match context.evaluate_script("example(1, 2, 3)", 1) { 58 | Ok(value) => { 59 | println!("{}", value.to_js_string(&context).unwrap()); 60 | } 61 | Err(e) => { 62 | println!("Uncaught: {}", e.to_js_string(&context).unwrap()) 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /examples/callback_closure.rs: -------------------------------------------------------------------------------- 1 | use rusty_jsc::{callback_closure, JSContext, JSValue}; 2 | 3 | fn main() { 4 | let context = JSContext::default(); 5 | 6 | let multiplier = 10f64; 7 | let callback = callback_closure!( 8 | &context, 9 | move |ctx: JSContext, _func: JSObject, _this: JSObject, args: &[JSValue]| { 10 | let num = args[0].to_number(&ctx).unwrap(); 11 | Ok(JSValue::number(&ctx, num * multiplier)) 12 | } 13 | ); 14 | 15 | let result = callback 16 | .call_as_function( 17 | &context, 18 | Some(&callback), 19 | &[JSValue::number(&context, 5f64)], 20 | ) 21 | .unwrap(); 22 | 23 | assert_eq!(result.to_number(&context).unwrap(), 50f64) 24 | } 25 | -------------------------------------------------------------------------------- /examples/hello.rs: -------------------------------------------------------------------------------- 1 | use rusty_jsc::JSContext; 2 | 3 | fn main() { 4 | let mut context = JSContext::default(); 5 | let value = context.evaluate_script("'hello, world'", 1); 6 | if let Ok(value) = value { 7 | println!("{}", value.to_js_string(&context).unwrap()); 8 | } else { 9 | let ex = value.unwrap_err().to_js_string(&context).unwrap(); 10 | println!("Uncaught: {}", ex); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/properties.rs: -------------------------------------------------------------------------------- 1 | use rusty_jsc::{JSContext, JSValue}; 2 | 3 | fn main() { 4 | let mut context = JSContext::default(); 5 | let mut global = context.get_global_object(); 6 | let hello = JSValue::string(&context, "hello, world!"); 7 | global.set_property(&context, "hello", hello).unwrap(); 8 | match context.evaluate_script("hello", 1) { 9 | Ok(value) => { 10 | println!("{}", value.to_js_string(&context).unwrap()); 11 | } 12 | Err(e) => { 13 | println!("Uncaught: {}", e.to_js_string(&context).unwrap()) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/punjs/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /examples/punjs/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.64" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "b9a8f622bcf6ff3df478e9deba3e03e4e04b300f8e6a139e192c05fa3490afc7" 10 | 11 | [[package]] 12 | name = "atty" 13 | version = "0.2.14" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 16 | dependencies = [ 17 | "hermit-abi", 18 | "libc", 19 | "winapi", 20 | ] 21 | 22 | [[package]] 23 | name = "autocfg" 24 | version = "1.1.0" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 27 | 28 | [[package]] 29 | name = "bitflags" 30 | version = "1.3.2" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 33 | 34 | [[package]] 35 | name = "clap" 36 | version = "3.2.22" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" 39 | dependencies = [ 40 | "atty", 41 | "bitflags", 42 | "clap_derive", 43 | "clap_lex", 44 | "indexmap", 45 | "once_cell", 46 | "strsim", 47 | "termcolor", 48 | "textwrap", 49 | ] 50 | 51 | [[package]] 52 | name = "clap_derive" 53 | version = "3.2.18" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" 56 | dependencies = [ 57 | "heck", 58 | "proc-macro-error", 59 | "proc-macro2", 60 | "quote", 61 | "syn", 62 | ] 63 | 64 | [[package]] 65 | name = "clap_lex" 66 | version = "0.2.4" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" 69 | dependencies = [ 70 | "os_str_bytes", 71 | ] 72 | 73 | [[package]] 74 | name = "hashbrown" 75 | version = "0.12.3" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 78 | 79 | [[package]] 80 | name = "heck" 81 | version = "0.4.0" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 84 | 85 | [[package]] 86 | name = "hermit-abi" 87 | version = "0.1.19" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 90 | dependencies = [ 91 | "libc", 92 | ] 93 | 94 | [[package]] 95 | name = "indexmap" 96 | version = "1.9.1" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" 99 | dependencies = [ 100 | "autocfg", 101 | "hashbrown", 102 | ] 103 | 104 | [[package]] 105 | name = "libc" 106 | version = "0.2.132" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" 109 | 110 | [[package]] 111 | name = "litejs" 112 | version = "0.0.0" 113 | dependencies = [ 114 | "anyhow", 115 | "clap", 116 | "rusty_jsc", 117 | "rusty_jsc_macros", 118 | "rusty_jsc_sys", 119 | ] 120 | 121 | [[package]] 122 | name = "once_cell" 123 | version = "1.14.0" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" 126 | 127 | [[package]] 128 | name = "os_str_bytes" 129 | version = "6.3.0" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" 132 | 133 | [[package]] 134 | name = "pkg-config" 135 | version = "0.3.25" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" 138 | 139 | [[package]] 140 | name = "proc-macro-error" 141 | version = "1.0.4" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 144 | dependencies = [ 145 | "proc-macro-error-attr", 146 | "proc-macro2", 147 | "quote", 148 | "syn", 149 | "version_check", 150 | ] 151 | 152 | [[package]] 153 | name = "proc-macro-error-attr" 154 | version = "1.0.4" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 157 | dependencies = [ 158 | "proc-macro2", 159 | "quote", 160 | "version_check", 161 | ] 162 | 163 | [[package]] 164 | name = "proc-macro2" 165 | version = "1.0.43" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" 168 | dependencies = [ 169 | "unicode-ident", 170 | ] 171 | 172 | [[package]] 173 | name = "quote" 174 | version = "1.0.21" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" 177 | dependencies = [ 178 | "proc-macro2", 179 | ] 180 | 181 | [[package]] 182 | name = "rusty_jsc" 183 | version = "0.0.2" 184 | dependencies = [ 185 | "anyhow", 186 | "rusty_jsc_macros", 187 | "rusty_jsc_sys", 188 | ] 189 | 190 | [[package]] 191 | name = "rusty_jsc_macros" 192 | version = "0.0.2" 193 | dependencies = [ 194 | "pkg-config", 195 | "quote", 196 | "syn", 197 | ] 198 | 199 | [[package]] 200 | name = "rusty_jsc_sys" 201 | version = "0.0.2" 202 | dependencies = [ 203 | "pkg-config", 204 | ] 205 | 206 | [[package]] 207 | name = "strsim" 208 | version = "0.10.0" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 211 | 212 | [[package]] 213 | name = "syn" 214 | version = "1.0.99" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" 217 | dependencies = [ 218 | "proc-macro2", 219 | "quote", 220 | "unicode-ident", 221 | ] 222 | 223 | [[package]] 224 | name = "termcolor" 225 | version = "1.1.3" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 228 | dependencies = [ 229 | "winapi-util", 230 | ] 231 | 232 | [[package]] 233 | name = "textwrap" 234 | version = "0.15.1" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" 237 | 238 | [[package]] 239 | name = "unicode-ident" 240 | version = "1.0.3" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" 243 | 244 | [[package]] 245 | name = "version_check" 246 | version = "0.9.4" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 249 | 250 | [[package]] 251 | name = "winapi" 252 | version = "0.3.9" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 255 | dependencies = [ 256 | "winapi-i686-pc-windows-gnu", 257 | "winapi-x86_64-pc-windows-gnu", 258 | ] 259 | 260 | [[package]] 261 | name = "winapi-i686-pc-windows-gnu" 262 | version = "0.4.0" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 265 | 266 | [[package]] 267 | name = "winapi-util" 268 | version = "0.1.5" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 271 | dependencies = [ 272 | "winapi", 273 | ] 274 | 275 | [[package]] 276 | name = "winapi-x86_64-pc-windows-gnu" 277 | version = "0.4.0" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 280 | -------------------------------------------------------------------------------- /examples/punjs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "cli" 5 | ] 6 | -------------------------------------------------------------------------------- /examples/punjs/README.md: -------------------------------------------------------------------------------- 1 | # Pun 2 | 3 | Pun is an example of how you would build a JavaScript core using `rusty_jsc`. 4 | -------------------------------------------------------------------------------- /examples/punjs/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "punjs" 3 | version = "0.0.0" 4 | authors = ["Pekka Enberg"] 5 | edition = "2021" 6 | default-run = "punjs" 7 | 8 | [[bin]] 9 | name = "punjs" 10 | path = "main.rs" 11 | 12 | [dependencies] 13 | anyhow = "1.0.62" 14 | clap = { version = "3.2.22", features = [ "derive" ] } 15 | rusty_jsc = { path = "../../../" } 16 | rusty_jsc_macros = { path = "../../../macros" } 17 | rusty_jsc_sys = { path = "../../../sys" } 18 | -------------------------------------------------------------------------------- /examples/punjs/cli/cmd.rs: -------------------------------------------------------------------------------- 1 | mod run; 2 | 3 | pub use run::run; 4 | -------------------------------------------------------------------------------- /examples/punjs/cli/cmd/run.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{Context, Result}; 2 | use rusty_jsc::{JSContext, JSValue}; 3 | use rusty_jsc_macros::callback; 4 | use std::fs; 5 | use std::path::PathBuf; 6 | 7 | pub fn run(input: PathBuf) -> Result<()> { 8 | let script = fs::read_to_string(&input) 9 | .with_context(|| format!("Failed to load module `{}`", input.display()))?; 10 | let mut context = JSContext::new(); 11 | setup_prelude(&context); 12 | let _ = context.evaluate_script(&script, 1); 13 | if let Some(ex) = context.get_exception() { 14 | anyhow::bail!("Uncaught {}", ex.to_string(&context)); 15 | } 16 | Ok(()) 17 | } 18 | 19 | fn setup_prelude(context: &JSContext) { 20 | let require_fn = JSValue::callback(&context, Some(require)); 21 | // require() 22 | let mut global = context.get_global_object(); 23 | global.set_property(&context, "require".to_string(), require_fn); 24 | // foo() 25 | let callback = JSValue::callback(&context, Some(foo)); 26 | global.set_property(&context, "foo".to_string(), callback); 27 | } 28 | 29 | #[callback] 30 | fn require(_context: JSContext) { 31 | println!("warning: `require` is not implemented.") 32 | } 33 | 34 | #[callback] 35 | fn foo(_context: JSContext) { 36 | println!("hello from Rust land!"); 37 | } 38 | -------------------------------------------------------------------------------- /examples/punjs/cli/main.rs: -------------------------------------------------------------------------------- 1 | mod cmd; 2 | 3 | use anyhow::Result; 4 | use clap::StructOpt; 5 | use std::path::PathBuf; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(about = "A light-weight runtime for TypeScript/JavaScript")] 9 | enum Command { 10 | /// Run a TypeScript/JavaScript program. 11 | Run { 12 | /// Input file 13 | #[structopt(parse(from_os_str))] 14 | input: PathBuf, 15 | }, 16 | } 17 | 18 | #[derive(StructOpt)] 19 | struct Opt { 20 | #[structopt(subcommand)] 21 | cmd: Command, 22 | } 23 | 24 | fn main() -> Result<()> { 25 | let opt = Opt::from_args(); 26 | match opt.cmd { 27 | Command::Run { input } => { 28 | cmd::run(input)?; 29 | } 30 | } 31 | Ok(()) 32 | } 33 | -------------------------------------------------------------------------------- /examples/punjs/testing/hello.js: -------------------------------------------------------------------------------- 1 | console.log("hello, world"); 2 | -------------------------------------------------------------------------------- /macros/.gitignore: -------------------------------------------------------------------------------- 1 | /target -------------------------------------------------------------------------------- /macros/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "pkg-config" 7 | version = "0.3.26" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" 10 | 11 | [[package]] 12 | name = "proc-macro-error" 13 | version = "1.0.4" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 16 | dependencies = [ 17 | "proc-macro-error-attr", 18 | "proc-macro2", 19 | "quote", 20 | "syn", 21 | "version_check", 22 | ] 23 | 24 | [[package]] 25 | name = "proc-macro-error-attr" 26 | version = "1.0.4" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 29 | dependencies = [ 30 | "proc-macro2", 31 | "quote", 32 | "version_check", 33 | ] 34 | 35 | [[package]] 36 | name = "proc-macro2" 37 | version = "1.0.54" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" 40 | dependencies = [ 41 | "unicode-ident", 42 | ] 43 | 44 | [[package]] 45 | name = "quote" 46 | version = "1.0.26" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" 49 | dependencies = [ 50 | "proc-macro2", 51 | ] 52 | 53 | [[package]] 54 | name = "rusty_jsc_macros" 55 | version = "0.1.0" 56 | dependencies = [ 57 | "pkg-config", 58 | "proc-macro-error", 59 | "quote", 60 | "syn", 61 | ] 62 | 63 | [[package]] 64 | name = "syn" 65 | version = "1.0.109" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 68 | dependencies = [ 69 | "proc-macro2", 70 | "quote", 71 | "unicode-ident", 72 | ] 73 | 74 | [[package]] 75 | name = "unicode-ident" 76 | version = "1.0.8" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" 79 | 80 | [[package]] 81 | name = "version_check" 82 | version = "0.9.4" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 85 | -------------------------------------------------------------------------------- /macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rusty_jsc_macros" 3 | version = "0.1.0" 4 | description = "Macros for rusty_jsc" 5 | authors = [ "Wasmer Engineering Team ", "Pekka Enberg", "Adrien Zinger" ] 6 | repository = "https://github.com/wasmerio/rusty_jsc" 7 | license = "MIT" 8 | edition = "2021" 9 | 10 | [lib] 11 | proc-macro = true 12 | 13 | [target.'cfg(target_os = "linux")'.build-dependencies] 14 | pkg-config = "0.3.9" 15 | 16 | [dependencies] 17 | quote = "1.0.21" 18 | syn = { version = "1", features = [ "full" ] } 19 | proc-macro-error = "1.0.4" 20 | -------------------------------------------------------------------------------- /macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::TokenStream; 2 | use proc_macro_error::{emit_error, proc_macro_error}; 3 | use quote::quote; 4 | 5 | use syn::{FnArg, Ident, Pat}; 6 | 7 | fn get_name(func_argument: &FnArg) -> Ident { 8 | match func_argument { 9 | FnArg::Typed(fn_type) => get_name_pat(&*fn_type.pat), 10 | _ => { 11 | panic!("Not supported function argument") 12 | } 13 | } 14 | } 15 | 16 | fn get_name_pat(func_argument: &Pat) -> Ident { 17 | match func_argument { 18 | Pat::Ident(ident) => ident.ident.clone(), 19 | Pat::Type(pat_type) => get_name_pat(&*pat_type.pat), 20 | _ => { 21 | panic!("Not supported function argument") 22 | } 23 | } 24 | } 25 | 26 | #[proc_macro_attribute] 27 | pub fn callback(_attr: TokenStream, item: TokenStream) -> TokenStream { 28 | let func = syn::parse::(item).expect("expected a function"); 29 | let name = &func.sig.ident; 30 | 31 | // Use macroized function as block. Its will be inlined and it doesn't 32 | // change the performance. The difference between that and just using the 33 | // block is the availabity to early return inside the function. It also 34 | // remove the confusion when we got an error about a wrong return type. 35 | let target_func_name = quote::format_ident!("{}_callback", name); 36 | let target_func = { 37 | let mut func = func.clone(); 38 | func.sig.ident = target_func_name.clone(); 39 | func 40 | }; 41 | let target_func_name = if !func.sig.generics.params.is_empty() { 42 | let params = func.sig.generics.params.clone(); 43 | quote! { #target_func_name::<#params> } 44 | } else { 45 | quote! { #target_func_name } 46 | }; 47 | 48 | let all_inputs = func.sig.inputs.iter().collect::>(); 49 | assert_eq!(all_inputs.len(), 4); 50 | let context_var_name = get_name(all_inputs.get(0).unwrap()); 51 | let function_var_name = get_name(all_inputs.get(1).unwrap()); 52 | let this_var_name = get_name(all_inputs.get(2).unwrap()); 53 | let args_var_name = get_name(all_inputs.get(3).unwrap()); 54 | 55 | let attrs = func.attrs; 56 | 57 | // Automatically return an undefined value if there is no output. 58 | let block_call = match func.sig.output { 59 | syn::ReturnType::Default => quote! { 60 | #target_func_name( 61 | #context_var_name, 62 | #function_var_name, 63 | #this_var_name, 64 | #args_var_name, 65 | ); 66 | rusty_jsc::private::JSValueMakeUndefined(__base_ctx) 67 | }, 68 | _ => quote! { 69 | //let res: Result = todo!(); 70 | let res: Result = #target_func_name( 71 | #context_var_name, 72 | #function_var_name, 73 | #this_var_name, 74 | #args_var_name, 75 | ); 76 | match res { 77 | Ok(res) => res.into(), 78 | Err(err) => { 79 | *__exception = err.into(); 80 | let ctx2 = rusty_jsc::JSContext::from(__base_ctx); 81 | rusty_jsc::private::JSValueMakeUndefined(__base_ctx) 82 | } 83 | } 84 | }, 85 | }; 86 | 87 | let result = quote! { 88 | unsafe extern "C" fn #name( 89 | __base_ctx: rusty_jsc::private::JSContextRef, 90 | __function: rusty_jsc::private::JSObjectRef, 91 | __this_object: rusty_jsc::private::JSObjectRef, 92 | __argument_count: rusty_jsc::private::size_t, 93 | __arguments: *const rusty_jsc::private::JSValueRef, 94 | mut __exception: *mut rusty_jsc::private::JSValueRef, 95 | ) -> rusty_jsc::private::JSValueRef { 96 | let #context_var_name = rusty_jsc::JSContext::from(__base_ctx); 97 | let #function_var_name: rusty_jsc::JSObject= __function.into(); 98 | let #this_var_name: rusty_jsc::JSObject = __this_object.into(); 99 | let #args_var_name = if __argument_count == 0 { 100 | vec![] 101 | } 102 | else { 103 | let __args_refs_slice = unsafe { std::slice::from_raw_parts(__arguments, __argument_count as _) }; 104 | __args_refs_slice.iter().map(|r| (*r).into()).collect::>() 105 | }; 106 | let #args_var_name: &[JSValue] = &#args_var_name; 107 | 108 | #block_call 109 | } 110 | }; 111 | let new_func = result.into(); 112 | // We do this so we make sure the function generics and other properties are preserved 113 | let mut new_func = syn::parse::(new_func).expect("expected a function"); 114 | new_func.attrs = attrs.clone(); 115 | new_func.vis = func.vis; 116 | new_func.sig.generics = func.sig.generics; 117 | new_func.sig.constness = func.sig.constness; 118 | new_func.sig.variadic = func.sig.variadic; 119 | new_func.sig.asyncness = func.sig.asyncness; 120 | 121 | quote! { 122 | #[inline] 123 | #target_func 124 | #new_func 125 | } 126 | .into() 127 | } 128 | 129 | #[proc_macro_error] 130 | #[proc_macro_attribute] 131 | pub fn constructor(_attr: TokenStream, item: TokenStream) -> TokenStream { 132 | let func = syn::parse::(item).expect("expected a function"); 133 | let name = &func.sig.ident; 134 | let target_func = { 135 | let mut func = func.clone(); 136 | func.sig.ident = quote::format_ident!("{}_call", name); 137 | func 138 | }; 139 | let target_name = &target_func.sig.ident; 140 | 141 | let mut inputs_adaptation = vec![]; 142 | let mut inputs_number = func.sig.inputs.len(); 143 | 144 | if inputs_number == 4 { 145 | emit_error! { func, "Fourth exception parameter is unimplemented" } 146 | inputs_number -= 1; 147 | } 148 | if inputs_number == 3 { 149 | inputs_adaptation.push(quote! { 150 | let arguments = (0.._argument_count as isize) 151 | .map(|arg_index| JSValue::from(_arguments.offset(arg_index).read())) 152 | .collect(); 153 | }); 154 | inputs_number -= 1; 155 | } 156 | if inputs_number == 2 { 157 | inputs_adaptation.push(quote! { 158 | let constructor = JSObject::from(_constructor); 159 | }); 160 | inputs_number -= 1; 161 | } 162 | if inputs_number == 1 { 163 | inputs_adaptation.push(quote! { 164 | let context = JSContext::from(_ctx); 165 | }); 166 | } 167 | 168 | let function_call = match func.sig.inputs.len() { 169 | 1 => quote! { #target_name(context) }, 170 | 2 => quote! { #target_name(context, constructor) }, 171 | 3 => quote! { #target_name(context, constructor, arguments) }, 172 | _ => quote! { #target_name() }, 173 | }; 174 | 175 | let result = quote! { 176 | use rusty_jsc_sys::*; 177 | 178 | #target_func 179 | 180 | unsafe extern "C" fn #name( 181 | _ctx: JSContextRef, 182 | _constructor: JSObjectRef, 183 | _argument_count: size_t, 184 | _arguments: *const JSValueRef, 185 | _exception: *mut JSValueRef, 186 | ) -> JSObjectRef { 187 | #(#inputs_adaptation)* 188 | #function_call; 189 | _constructor 190 | } 191 | }; 192 | result.into() 193 | } 194 | -------------------------------------------------------------------------------- /src/closure.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! callback_closure { 3 | ($ctx:expr, $closure:expr) => {{ 4 | use rusty_jsc::{callback, JSContext, JSObject, JSValue}; 5 | type CallbackType = 6 | dyn FnMut(JSContext, JSObject, JSObject, &[JSValue]) -> Result; 7 | 8 | let mut base_callback = $closure; 9 | 10 | // This leaks memory 11 | // TODO: fix 12 | let mut base_callback_trait_obj: &mut CallbackType = Box::leak(Box::new(base_callback)); 13 | let base_callback_trait_obj_ref = Box::leak(Box::new(base_callback_trait_obj)); 14 | 15 | let closure_pointer_pointer = 16 | base_callback_trait_obj_ref as *mut _ as *mut std::ffi::c_void; 17 | let lparam = closure_pointer_pointer as usize; 18 | 19 | #[callback] 20 | fn trampoline( 21 | ctx: JSContext, 22 | function: JSObject, 23 | this: JSObject, 24 | args: &[JSValue], 25 | ) -> Result { 26 | let lparam = args[0].to_number(&ctx).unwrap() as usize; 27 | let callback: &mut &mut CallbackType = unsafe { 28 | let closure_pointer_pointer = lparam as *mut std::ffi::c_void; 29 | &mut *(closure_pointer_pointer as *mut _) 30 | }; 31 | callback(ctx, function, this, &args[1..]) 32 | } 33 | 34 | let callback = JSValue::callback($ctx, Some(trampoline)) 35 | .to_object($ctx) 36 | .unwrap(); 37 | 38 | let bind = callback 39 | .get_property($ctx, "bind") 40 | .unwrap() 41 | .to_object($ctx) 42 | .unwrap(); 43 | let binded_callback = bind 44 | .call_as_function( 45 | $ctx, 46 | Some(&callback), 47 | &[ 48 | JSValue::undefined($ctx), 49 | JSValue::number($ctx, lparam as f64), 50 | ], 51 | ) 52 | .unwrap(); 53 | 54 | binded_callback.to_object($ctx).unwrap() 55 | }}; 56 | } 57 | -------------------------------------------------------------------------------- /src/internal.rs: -------------------------------------------------------------------------------- 1 | use rusty_jsc_sys::*; 2 | use std::{ 3 | ffi::{CString, NulError}, 4 | string::FromUtf8Error, 5 | }; 6 | 7 | /// A JavaScript string. 8 | pub struct JSString { 9 | pub inner: JSStringRef, 10 | } 11 | 12 | impl Drop for JSString { 13 | fn drop(&mut self) { 14 | unsafe { 15 | JSStringRelease(self.inner); 16 | } 17 | } 18 | } 19 | 20 | impl std::fmt::Display for JSString { 21 | fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { 22 | let res = self.to_string_utf8().unwrap(); // TODO: return format error 23 | write!(fmt, "{res}") 24 | } 25 | } 26 | 27 | impl JSString { 28 | pub fn from(inner: JSStringRef) -> Self { 29 | Self { inner } 30 | } 31 | 32 | pub fn into_string_utf8(self) -> Result { 33 | let len = unsafe { JSStringGetMaximumUTF8CStringSize(self.inner) }; 34 | let mut chars = vec![0u8; len as usize]; 35 | let len = unsafe { JSStringGetUTF8CString(self.inner, chars.as_mut_ptr() as _, len) }; 36 | String::from_utf8(chars[0..(len - 1) as usize].to_vec()) 37 | } 38 | 39 | /// Returns the `JSString` as a Rust `String` 40 | pub fn to_string_utf8(&self) -> Result { 41 | let len = unsafe { JSStringGetMaximumUTF8CStringSize(self.inner) }; 42 | let mut chars = vec![0u8; len as usize]; 43 | let len = unsafe { JSStringGetUTF8CString(self.inner, chars.as_mut_ptr() as _, len) }; 44 | String::from_utf8(chars[0..(len - 1) as usize].to_vec()) 45 | } 46 | 47 | /// Constructs a JSString from a Rust `String` 48 | pub fn from_utf8(value: String) -> Result { 49 | let value = CString::new(value.as_bytes())?; 50 | let inner = unsafe { JSStringCreateWithUTF8CString(value.as_ptr()) }; 51 | Ok(JSString { inner }) 52 | } 53 | } 54 | 55 | impl From for JSString { 56 | fn from(value: String) -> JSString { 57 | Self::from_utf8(value).unwrap() 58 | } 59 | } 60 | 61 | impl From<&str> for JSString { 62 | fn from(value: &str) -> JSString { 63 | Self::from_utf8(value.to_string()).unwrap() 64 | } 65 | } 66 | 67 | impl From for String { 68 | fn from(value: JSString) -> String { 69 | value.to_string() 70 | } 71 | } 72 | impl std::fmt::Debug for JSString { 73 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 74 | write!(f, "JSString({})", self) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This library provides a Rust API for the JavaScriptCore engine. 2 | //! 3 | //! # Example 4 | //! 5 | //! The JavaScriptCore engine lets you evaluate JavaScript scripts from your 6 | //! own application. You first need to create a `JSContext` object and then 7 | //! call its `evaluate_script` method. 8 | //! 9 | //! ```rust 10 | //! use rusty_jsc::JSContext; 11 | //! 12 | //! let mut context = JSContext::default(); 13 | //! match context.evaluate_script("'hello, world'", 1) { 14 | //! Ok(value) => { 15 | //! println!("{}", value.to_string(&context).unwrap()); 16 | //! } 17 | //! Err(e) => { 18 | //! println!( 19 | //! "Uncaught: {}", 20 | //! e.to_string(&context).unwrap() 21 | //! ) 22 | //! } 23 | //! } 24 | //! ``` 25 | 26 | mod internal; 27 | 28 | use std::panic; 29 | 30 | pub use crate::internal::JSString; 31 | // #[macro_export] 32 | mod closure; 33 | pub use rusty_jsc_macros::callback; 34 | pub use rusty_jsc_sys::JSObjectCallAsFunctionCallback; 35 | use rusty_jsc_sys::*; 36 | use std::fmt; 37 | pub mod private { 38 | pub use rusty_jsc_sys::*; 39 | } 40 | 41 | // pub use crate::closure::callback_closure; 42 | 43 | /// A JavaScript value. 44 | #[derive(Debug, Clone)] 45 | pub struct JSValue { 46 | inner: JSValueRef, 47 | } 48 | 49 | impl From> for JSValue { 50 | fn from(js_object: JSObject) -> Self { 51 | // The two objects are very simple and will not be differents in any 52 | // cases. 53 | 54 | // Note: this is also the case of a JSPromise since we don't need 55 | // to protect or retain anything. 56 | Self { 57 | inner: js_object.inner, 58 | } 59 | } 60 | } 61 | 62 | impl From> for JSValue { 63 | fn from(js_object: JSObject) -> Self { 64 | Self { 65 | inner: js_object.inner, 66 | } 67 | } 68 | } 69 | 70 | impl From> for JSValue { 71 | fn from(js_object: JSObject) -> Self { 72 | Self { 73 | inner: js_object.inner, 74 | } 75 | } 76 | } 77 | 78 | impl From for JSValue { 79 | /// Wraps a `JSValue` from a `JSValueRef`. 80 | fn from(inner: JSValueRef) -> Self { 81 | Self { inner } 82 | } 83 | } 84 | 85 | impl From<*mut OpaqueJSValue> for JSValue { 86 | /// Wraps a `JSValue` from a `JSValueRef`. 87 | fn from(inner: *mut OpaqueJSValue) -> Self { 88 | Self { inner } 89 | } 90 | } 91 | 92 | impl JSValue { 93 | pub fn get_ref(&self) -> JSValueRef { 94 | self.inner 95 | } 96 | 97 | /// Creates an `undefined` value. 98 | pub fn undefined(context: &JSContext) -> JSValue { 99 | JSValue::from(unsafe { JSValueMakeUndefined(context.inner) }) 100 | } 101 | 102 | /// Creates a `null` value. 103 | pub fn null(context: &JSContext) -> JSValue { 104 | JSValue::from(unsafe { JSValueMakeNull(context.inner) }) 105 | } 106 | 107 | /// Creates a `boolean` value. 108 | pub fn boolean(context: &JSContext, value: bool) -> JSValue { 109 | JSValue::from(unsafe { JSValueMakeBoolean(context.inner, value) }) 110 | } 111 | 112 | /// Creates a `number` value. 113 | pub fn number(context: &JSContext, value: f64) -> JSValue { 114 | JSValue::from(unsafe { JSValueMakeNumber(context.inner, value) }) 115 | } 116 | 117 | /// Creates a `string` value. 118 | pub fn string(context: &JSContext, value: impl Into) -> JSValue { 119 | let value: JSString = value.into(); 120 | JSValue::from(unsafe { JSValueMakeString(context.inner, value.inner) }) 121 | } 122 | 123 | /// Creates a function callback 124 | pub fn callback(context: &JSContext, callback: JSObjectCallAsFunctionCallback) -> JSValue { 125 | let name: JSString = "".into(); 126 | let func = unsafe { JSObjectMakeFunctionWithCallback(context.inner, name.inner, callback) }; 127 | JSValue::from(func) 128 | } 129 | 130 | /// Checks if this value is `undefined`. 131 | pub fn is_undefined(&self, context: &JSContext) -> bool { 132 | unsafe { JSValueIsUndefined(context.inner, self.inner) } 133 | } 134 | 135 | /// Checks if this value is `null`. 136 | pub fn is_null(&self, context: &JSContext) -> bool { 137 | unsafe { JSValueIsNull(context.inner, self.inner) } 138 | } 139 | 140 | /// Checks if this value is `boolean`. 141 | pub fn is_bool(&self, context: &JSContext) -> bool { 142 | unsafe { JSValueIsBoolean(context.inner, self.inner) } 143 | } 144 | 145 | /// Checks if this value is `Array`. 146 | pub fn is_array(&self, context: &JSContext) -> bool { 147 | unsafe { JSValueIsArray(context.inner, self.inner) } 148 | } 149 | 150 | /// Checks if this value is `number`. 151 | pub fn is_number(&self, context: &JSContext) -> bool { 152 | unsafe { JSValueIsNumber(context.inner, self.inner) } 153 | } 154 | 155 | /// Checks if this value is `string`. 156 | pub fn is_string(&self, context: &JSContext) -> bool { 157 | unsafe { JSValueIsString(context.inner, self.inner) } 158 | } 159 | 160 | /// Checks if this value is `date`. 161 | pub fn is_date(&self, context: &JSContext) -> bool { 162 | unsafe { JSValueIsDate(context.inner, self.inner) } 163 | } 164 | 165 | /// Checks if this value is `symbol`. 166 | pub fn is_symbol(&self, context: &JSContext) -> bool { 167 | unsafe { JSValueIsSymbol(context.inner, self.inner) } 168 | } 169 | 170 | /// Gets this value as a `bool`. 171 | pub fn to_bool(&self, context: &JSContext) -> bool { 172 | unsafe { JSValueToBoolean(context.inner, self.inner) } 173 | } 174 | 175 | /// Formats this value as a `JSString`. 176 | pub fn to_js_string(&self, context: &JSContext) -> Result { 177 | let mut exception: JSValueRef = std::ptr::null_mut(); 178 | let string = unsafe { JSValueToStringCopy(context.inner, self.inner, &mut exception) }; 179 | if !exception.is_null() { 180 | return Err(JSValue::from(exception)); 181 | } 182 | Ok(JSString::from(string)) 183 | } 184 | 185 | // Tries to convert the value to a number 186 | pub fn to_number(&self, context: &JSContext) -> Result { 187 | let mut exception: JSValueRef = std::ptr::null_mut(); 188 | let num = unsafe { JSValueToNumber(context.inner, self.inner, &mut exception) }; 189 | if !exception.is_null() { 190 | return Err(JSValue::from(exception)); 191 | } 192 | Ok(num) 193 | } 194 | 195 | // Tries to convert the value to an object 196 | pub fn to_object(&self, context: &JSContext) -> Result { 197 | let mut exception: JSValueRef = std::ptr::null_mut(); 198 | let object_ref = unsafe { JSValueToObject(context.inner, self.inner, &mut exception) }; 199 | if !exception.is_null() { 200 | return Err(JSValue::from(exception)); 201 | } 202 | let obj = JSObject::from(object_ref); 203 | Ok(obj) 204 | } 205 | 206 | /// Convert value into a protected object (protected from garbage collection) 207 | pub fn into_protected_object(self, context: &JSContext) -> JSObject { 208 | unsafe { 209 | JSValueProtect(context.inner, self.inner); 210 | JSObject:: { 211 | inner: self.inner as _, // TODO: should have been translated before 212 | data: Some(JSProtected { 213 | inner: self.inner, 214 | context: context.inner, 215 | }), 216 | } 217 | } 218 | } 219 | } 220 | 221 | #[derive(Clone)] 222 | pub struct JSObjectGeneric; 223 | 224 | /// A JavaScript object. 225 | #[derive(Debug, Clone)] 226 | pub struct JSObject { 227 | inner: JSObjectRef, 228 | /// The data is used to keep track if the JSObject is eventually constructed 229 | /// as a class or a protected value 230 | data: Option, 231 | } 232 | 233 | impl From for JSObject { 234 | /// Wraps a `JSObject` from a `JSObjectRef`. 235 | fn from(inner: JSObjectRef) -> Self { 236 | Self { inner, data: None } 237 | } 238 | } 239 | 240 | impl JSObject { 241 | /// Create a new generic object 242 | /// 243 | /// Note: you cannot set private datas inside this object because it doesn't 244 | /// derive from a class. If you would like to use private datas, create a 245 | /// class object with JSObject::class or JSClass::create().make_object() 246 | pub fn new(context: &JSContext) -> JSObject { 247 | unsafe { JSObjectMake(context.inner, std::ptr::null_mut(), std::ptr::null_mut()).into() } 248 | } 249 | 250 | /// Creates a new class. 251 | pub fn class( 252 | context: &mut JSContext, 253 | class_name: impl ToString, 254 | constructor: JSObjectCallAsConstructorCallback, 255 | ) -> JSObject { 256 | let class = JSClass::create_ref(class_name, constructor); 257 | unsafe { 258 | JSObject { 259 | inner: JSObjectMake(context.get_ref(), class, std::ptr::null_mut()), 260 | data: Some(class.into()), 261 | } 262 | } 263 | } 264 | 265 | /// Creates a new deffered promise. 266 | pub fn promise(context: &mut JSContext) -> JSObject { 267 | // TODO: not sure if I'm supposed to protect these function from garbage collecting 268 | // The article https://devsday.ru/blog/details/114430 could be interesting 269 | let mut resolve = JSObject::::new(context); 270 | let mut reject = JSObject::::new(context); 271 | let inner = unsafe { 272 | JSObjectMakeDeferredPromise( 273 | context.get_ref(), 274 | &mut resolve.inner, 275 | &mut reject.inner, 276 | std::ptr::null_mut(), 277 | ) 278 | }; 279 | JSObject:: { 280 | inner, 281 | data: Some(JSPromise { 282 | resolve, 283 | reject, 284 | context: context.get_ref(), 285 | }), 286 | } 287 | } 288 | 289 | /// Create a new Array Object with the given arguments 290 | pub fn new_array(context: &JSContext, args: &[JSValue]) -> Result { 291 | let args_refs = args.iter().map(|arg| arg.inner).collect::>(); 292 | let mut exception: JSValueRef = std::ptr::null_mut(); 293 | let o_ref = unsafe { 294 | JSObjectMakeArray( 295 | context.inner, 296 | args.len() as _, 297 | args_refs.as_slice().as_ptr(), 298 | &mut exception, 299 | ) 300 | }; 301 | if !exception.is_null() { 302 | return Err(JSValue::from(exception)); 303 | } 304 | Ok(Self::from(o_ref)) 305 | } 306 | 307 | pub fn new_function_with_callback( 308 | context: &JSContext, 309 | name: impl Into, 310 | callback: JSObjectCallAsFunctionCallback, 311 | ) -> Self { 312 | let name = name.into(); 313 | let o_ref = 314 | unsafe { JSObjectMakeFunctionWithCallback(context.inner, name.inner, callback) }; 315 | Self::from(o_ref) 316 | } 317 | 318 | /// Calls the object constructor 319 | pub fn construct(&self, context: &JSContext, args: &[JSValue]) -> Result { 320 | let args_refs = args.iter().map(|arg| arg.inner).collect::>(); 321 | let mut exception: JSValueRef = std::ptr::null_mut(); 322 | let result = unsafe { 323 | JSObjectCallAsConstructor( 324 | context.inner, 325 | self.inner, 326 | args.len() as _, 327 | args_refs.as_slice().as_ptr(), 328 | &mut exception, 329 | ) 330 | }; 331 | if !exception.is_null() { 332 | return Err(JSValue::from(exception)); 333 | } 334 | if result.is_null() { 335 | return Err(JSValue::string( 336 | context, 337 | format!( 338 | "Can't call constructor for {:?}: not a valid constructor", 339 | JSValue::from(self.inner).to_js_string(context) 340 | ), 341 | )); 342 | } 343 | Ok(Self::from(result)) 344 | } 345 | 346 | /// Call the object as if it a function 347 | pub fn call_as_function( 348 | &self, 349 | context: &JSContext, 350 | this: Option<&JSObject>, 351 | args: &[JSValue], 352 | ) -> Result { 353 | let args_refs = args.iter().map(|arg| arg.inner).collect::>(); 354 | let mut exception: JSValueRef = std::ptr::null_mut(); 355 | let result = unsafe { 356 | JSObjectCallAsFunction( 357 | context.inner, 358 | self.inner, 359 | this.map(|t| t.inner).unwrap_or_else(std::ptr::null_mut), 360 | args.len() as _, 361 | args_refs.as_slice().as_ptr(), 362 | &mut exception, 363 | ) 364 | }; 365 | if !exception.is_null() { 366 | return Err(JSValue::from(exception)); 367 | } 368 | if result.is_null() { 369 | return Err(JSValue::string( 370 | context, 371 | format!( 372 | "Can't call the object {:?}: not a valid function", 373 | JSValue::from(self.inner).to_js_string(context) 374 | ), 375 | )); 376 | } 377 | Ok(JSValue::from(result)) 378 | } 379 | 380 | pub fn create_typed_array_with_bytes( 381 | context: &JSContext, 382 | bytes: &mut [u8], 383 | ) -> Result { 384 | let deallocator_ctx = std::ptr::null_mut(); 385 | let mut exception: JSValueRef = std::ptr::null_mut(); 386 | let result = unsafe { 387 | JSObjectMakeTypedArrayWithBytesNoCopy( 388 | context.inner, 389 | JSTypedArrayType_kJSTypedArrayTypeUint8Array, 390 | bytes.as_ptr() as _, 391 | bytes.len() as _, 392 | None, 393 | deallocator_ctx, 394 | &mut exception, 395 | ) 396 | }; 397 | if !exception.is_null() { 398 | return Err(JSValue::from(exception)); 399 | } 400 | if result.is_null() { 401 | return Err(JSValue::string(context, "Can't create a type array")); 402 | } 403 | Ok(Self::from(result)) 404 | } 405 | 406 | pub fn create_typed_array_from_buffer( 407 | context: &JSContext, 408 | buffer: JSObject, 409 | ) -> Result { 410 | let mut exception: JSValueRef = std::ptr::null_mut(); 411 | let result = unsafe { 412 | JSObjectMakeTypedArrayWithArrayBuffer( 413 | context.inner, 414 | JSTypedArrayType_kJSTypedArrayTypeUint8Array, 415 | buffer.inner, 416 | &mut exception, 417 | ) 418 | }; 419 | if !exception.is_null() { 420 | return Err(JSValue::from(exception)); 421 | } 422 | if result.is_null() { 423 | return Err(JSValue::string( 424 | context, 425 | "Can't create a typed array from the provided buffer", 426 | )); 427 | } 428 | Ok(JSObject::from(result)) 429 | } 430 | 431 | /// Get a mutable typed array buffer from current object. 432 | /// 433 | /// # Safety 434 | /// 435 | /// Only use that buffer in a synchronous context. The pointer (of slice) 436 | /// returned by this function is temporary and is not guaranteed to remain 437 | /// valid across JavaScriptCore API calls. 438 | pub unsafe fn get_typed_array_buffer(&self, context: &JSContext) -> Result<&mut [u8], JSValue> { 439 | let mut exception: JSValueRef = std::ptr::null_mut(); 440 | let arr_ptr = JSObjectGetTypedArrayBytesPtr(context.inner, self.inner, &mut exception); 441 | if !exception.is_null() { 442 | return Err(JSValue::from(exception)); 443 | } 444 | let arr_len = JSObjectGetTypedArrayByteLength(context.inner, self.inner, &mut exception); 445 | if !exception.is_null() { 446 | return Err(JSValue::from(exception)); 447 | } 448 | let slice = std::slice::from_raw_parts_mut(arr_ptr as _, arr_len as usize); 449 | Ok(slice) 450 | } 451 | 452 | /// Gets the property of an object. 453 | pub fn get_property( 454 | &self, 455 | context: &JSContext, 456 | property_name: impl Into, 457 | ) -> Option { 458 | let property_name = property_name.into(); 459 | let mut exception: JSValueRef = std::ptr::null_mut(); 460 | let jsvalue_ref = unsafe { 461 | JSObjectGetProperty( 462 | context.inner, 463 | self.inner, 464 | property_name.inner, 465 | &mut exception, 466 | ) 467 | }; 468 | if unsafe { JSValueIsNull(context.inner, jsvalue_ref) } { 469 | None 470 | } else { 471 | Some(JSValue::from(jsvalue_ref)) 472 | } 473 | } 474 | 475 | /// Gets the property of an object at a given index 476 | pub fn get_property_at_index( 477 | &self, 478 | context: &JSContext, 479 | property_index: u32, 480 | ) -> Result { 481 | let mut exception: JSValueRef = std::ptr::null_mut(); 482 | let property = unsafe { 483 | JSObjectGetPropertyAtIndex(context.inner, self.inner, property_index, &mut exception) 484 | }; 485 | if !exception.is_null() { 486 | return Err(JSValue::from(exception)); 487 | } 488 | Ok(JSValue::from(property)) 489 | } 490 | 491 | pub fn get_property_names(&self, context: &JSContext) -> Vec { 492 | let property_name_array = unsafe { JSObjectCopyPropertyNames(context.inner, self.inner) }; 493 | let num_properties = unsafe { JSPropertyNameArrayGetCount(property_name_array) }; 494 | (0..num_properties) 495 | .map(|property_index| { 496 | JSString::from(unsafe { 497 | JSPropertyNameArrayGetNameAtIndex(property_name_array, property_index) 498 | }) 499 | .to_string() 500 | }) 501 | .collect::>() 502 | } 503 | 504 | // Get the object as an array buffer 505 | pub fn get_array_buffer(&self, context: &JSContext) -> Result<&mut [u8], JSValue> { 506 | let mut exception: JSValueRef = std::ptr::null_mut(); 507 | let arr_ptr = 508 | unsafe { JSObjectGetArrayBufferBytesPtr(context.inner, self.inner, &mut exception) }; 509 | if !exception.is_null() { 510 | return Err(JSValue::from(exception)); 511 | } 512 | let arr_len = 513 | unsafe { JSObjectGetArrayBufferByteLength(context.inner, self.inner, &mut exception) }; 514 | if !exception.is_null() { 515 | return Err(JSValue::from(exception)); 516 | } 517 | let slice = unsafe { std::slice::from_raw_parts_mut(arr_ptr as _, arr_len as usize) }; 518 | Ok(slice) 519 | } 520 | 521 | /// Sets the property of an object. 522 | pub fn set_property( 523 | &mut self, 524 | context: &JSContext, 525 | property_name: impl Into, 526 | value: JSValue, 527 | ) -> Result<(), JSValue> { 528 | let property_name = property_name.into(); 529 | let attributes = 0; // TODO 530 | let mut exception: JSValueRef = std::ptr::null_mut(); 531 | unsafe { 532 | JSObjectSetProperty( 533 | context.inner, 534 | self.inner, 535 | property_name.inner, 536 | value.inner, 537 | attributes, 538 | &mut exception, 539 | ) 540 | } 541 | if !exception.is_null() { 542 | return Err(JSValue::from(exception)); 543 | } 544 | Ok(()) 545 | } 546 | 547 | /// Sets the property of an object at a given index 548 | pub fn set_property_at_index( 549 | &mut self, 550 | context: &JSContext, 551 | index: u32, 552 | value: JSValue, 553 | ) -> Result<(), JSValue> { 554 | let mut exception: JSValueRef = std::ptr::null_mut(); 555 | unsafe { 556 | JSObjectSetPropertyAtIndex( 557 | context.inner, 558 | self.inner, 559 | index, 560 | value.inner, 561 | &mut exception, 562 | ) 563 | } 564 | if !exception.is_null() { 565 | return Err(JSValue::from(exception)); 566 | } 567 | Ok(()) 568 | } 569 | 570 | /// Deletes the property of an object. 571 | pub fn delete_property(&mut self, context: &JSContext, property_name: impl ToString) { 572 | let property_name = JSString::from_utf8(property_name.to_string()).unwrap(); 573 | let mut exception: JSValueRef = std::ptr::null_mut(); 574 | unsafe { 575 | JSObjectDeleteProperty( 576 | context.inner, 577 | self.inner, 578 | property_name.inner, 579 | &mut exception, 580 | ); 581 | } 582 | } 583 | } 584 | 585 | impl From for JSValueRef { 586 | fn from(val: JSValue) -> Self { 587 | val.inner 588 | } 589 | } 590 | 591 | impl From for JSObjectRef { 592 | fn from(val: JSObject) -> JSObjectRef { 593 | val.inner 594 | } 595 | } 596 | 597 | // Private data implementation. This is available only for JSObject and 598 | // JSObject. 599 | 600 | pub trait HasPrivateData {} 601 | impl HasPrivateData for JSObject {} 602 | impl HasPrivateData for JSObject {} 603 | 604 | impl JSObject 605 | where 606 | JSObject: HasPrivateData, 607 | { 608 | /// Set private data 609 | pub fn set_private_data(&mut self, data: N) -> Result<(), Box> { 610 | let boxed = Box::new(data); 611 | let data_ptr = Box::into_raw(boxed); 612 | if !unsafe { JSObjectSetPrivate(self.inner, data_ptr as _) } { 613 | return Err(unsafe { Box::from_raw(data_ptr) }); 614 | } 615 | Ok(()) 616 | } 617 | 618 | /// Get private data 619 | /// 620 | /// # Safety 621 | /// The pointer to the private data isn't guaranted to be type N if you put 622 | /// something else before. 623 | pub unsafe fn get_private_data(&mut self) -> Option<*mut N> { 624 | let data = JSObjectGetPrivate(self.inner); 625 | if data.is_null() { 626 | None 627 | } else { 628 | Some(data as _) 629 | } 630 | } 631 | } 632 | 633 | pub struct JSClass { 634 | inner: JSClassRef, 635 | } 636 | 637 | /// Specification of a `JSObject` as `JSObject` that is a 638 | /// variation of a `JSGenericObject` available to store private data. 639 | pub struct JSObjectGenericClass; 640 | 641 | impl JSClass { 642 | pub fn create(name: impl ToString, constructor: JSObjectCallAsConstructorCallback) -> JSClass { 643 | JSClass::create_ref(name, constructor).into() 644 | } 645 | 646 | fn create_ref( 647 | name: impl ToString, 648 | constructor: JSObjectCallAsConstructorCallback, 649 | ) -> JSClassRef { 650 | let mut class_definition = unsafe { kJSClassDefinitionEmpty }; 651 | class_definition.className = name.to_string().as_bytes().as_ptr() as _; 652 | class_definition.callAsConstructor = constructor; 653 | // TODO: we should manage the attributes and static parameters (even if it 654 | // looks broken for the version 4.0) 655 | // class_definition.attributes = kJSClassAttributeNoAutomaticPrototype; 656 | // class_definition.staticValues = values; 657 | // class_definition.staticFunctions = log; 658 | 659 | // TODO: manage private datas if any, we give std::ptr::null_mut() for the 660 | // moment. 661 | unsafe { 662 | let class = JSClassCreate([class_definition].as_ptr() as _); 663 | JSClassRetain(class); 664 | class 665 | } 666 | } 667 | 668 | /// Creates a generic object derived from this class. 669 | /// 670 | /// Note: if you drop this object that won't affect the class itself. 671 | pub fn make_object(&self, context: &JSContext) -> JSObject { 672 | unsafe { 673 | JSObject { 674 | inner: JSObjectMake(context.get_ref(), self.inner, std::ptr::null_mut()), 675 | data: None, 676 | } 677 | } 678 | } 679 | } 680 | 681 | impl Drop for JSClass { 682 | fn drop(&mut self) { 683 | // Here we want to drop and release the class. But we might have transfered the ownership 684 | // of the pointer to someone else. If any, we should have also swap the inner value with 685 | // a null pointer because we dont want to signal to JSC to release anything. 686 | if !self.inner.is_null() { 687 | unsafe { JSClassRelease(self.inner) } 688 | } 689 | } 690 | } 691 | 692 | impl From for JSClass { 693 | fn from(inner: JSClassRef) -> Self { 694 | Self { inner } 695 | } 696 | } 697 | 698 | impl From> for JSObject { 699 | fn from(gc: JSObject) -> Self { 700 | unsafe { std::mem::transmute(gc) } 701 | } 702 | } 703 | 704 | /// Deffered promise. 705 | #[derive(Clone)] 706 | pub struct JSPromise { 707 | resolve: JSObject, 708 | reject: JSObject, 709 | context: JSContextRef, 710 | // TODO: exception: Option 711 | // exception are almost never managed in this library and 712 | // it will be neat to do something about. 713 | } 714 | 715 | impl JSObject { 716 | /// Call `resolve` function and consume the deffered promise. 717 | /// 718 | /// Note: you can assume that the promise will be garbage collected after 719 | /// that call. 720 | pub fn resolve(self, arguments: &[JSValue]) { 721 | let data = self.data.unwrap(); 722 | unsafe { 723 | JSObjectCallAsFunction( 724 | data.context, 725 | data.resolve.inner, 726 | self.inner, // TODO: need some investigation of what is the this. 727 | arguments.len() as _, 728 | arguments 729 | .iter() 730 | .map(|s| s.inner) 731 | .collect::>() 732 | .as_ptr(), 733 | std::ptr::null_mut(), 734 | ) 735 | }; 736 | } 737 | 738 | /// Call `reject` function and consume the deffered promise. 739 | /// 740 | /// Note: you can assume that the promise will be garbage collected after 741 | /// that call. 742 | pub fn reject(self, arguments: &[JSValue]) { 743 | let data = self.data.unwrap(); 744 | unsafe { 745 | JSObjectCallAsFunction( 746 | data.context, 747 | data.reject.inner, 748 | self.inner, // TODO: need some investigation of what is the this. 749 | arguments.len() as _, 750 | arguments 751 | .iter() 752 | .map(|s| s.inner) 753 | .collect::>() 754 | .as_ptr(), 755 | std::ptr::null_mut(), 756 | ) 757 | }; 758 | } 759 | 760 | pub fn context(&self) -> JSContext { 761 | if let Some(data) = &self.data { 762 | data.context.into() 763 | } else { 764 | panic!("unexpected empty promise") 765 | } 766 | } 767 | } 768 | 769 | // It is usually forbidden to keep track of JSObject references and JSValues if 770 | // they are not retained before... Here we assume that JSC wont garbage collect 771 | // any function because there always is a reference to a resolve or a reject 772 | // function until one of these function has been called. 773 | unsafe impl Send for JSObject {} 774 | 775 | /// The JSProtected is used as a JSObject specification. You can create the 776 | /// JSObject from a JSValue and it will call `JSValueProtect`. 777 | /// 778 | /// Note: The context can be droped before the instance of JSProtected if we 779 | /// persist to store every object. We should say that any stored value has to be 780 | /// droped BEFORE stored contexts (or at least the linked context). But we have 781 | /// to put an effort on tracking the number of references for each linked 782 | /// contexts to avoid bugs. 783 | pub struct JSProtected { 784 | inner: JSValueRef, 785 | context: JSContextRef, 786 | } 787 | 788 | impl JSObject { 789 | pub fn context(&self) -> JSContext { 790 | // todo. 1 there is some duplicated code. 2. we should manage this 791 | // context through an ARC or something that prevent to release the 792 | // linked JSContext before the protected value. 793 | if let Some(data) = &self.data { 794 | data.context.into() 795 | } else { 796 | panic!("unexpected empty protected value") 797 | } 798 | } 799 | } 800 | 801 | impl Drop for JSProtected { 802 | fn drop(&mut self) { 803 | unsafe { JSValueUnprotect(self.context, self.inner) } 804 | } 805 | } 806 | 807 | /// The protection around the value reference allow us to store the object and 808 | /// send it between threads safely. (since the linked context is still 809 | /// retained... TODO: add a reference counter or a protection arround linked 810 | /// contexts) 811 | unsafe impl Send for JSObject {} 812 | 813 | /// A JavaScript virtual machine. 814 | #[derive(Clone)] 815 | pub struct JSVirtualMachine { 816 | context_group: JSContextGroupRef, 817 | global_context: JSGlobalContextRef, 818 | } 819 | 820 | impl JSVirtualMachine { 821 | /// Creates a new `JSVirtualMachine` object from a context. 822 | fn from(context: JSContextRef) -> Self { 823 | let global_context = unsafe { JSContextGetGlobalContext(context) }; 824 | unsafe { 825 | JSGlobalContextRetain(global_context); 826 | } 827 | let context_group = unsafe { JSContextGetGroup(global_context) }; 828 | unsafe { 829 | JSContextGroupRetain(context_group); 830 | } 831 | Self { 832 | context_group, 833 | global_context, 834 | } 835 | } 836 | 837 | /// Creates a new `JSVirtualMachine` object. 838 | fn new() -> Self { 839 | let context_group = unsafe { JSContextGroupCreate() }; 840 | let global_context = 841 | unsafe { JSGlobalContextCreateInGroup(context_group, std::ptr::null_mut()) }; 842 | Self { 843 | context_group, 844 | global_context, 845 | } 846 | } 847 | } 848 | 849 | impl Drop for JSVirtualMachine { 850 | fn drop(&mut self) { 851 | unsafe { 852 | JSGlobalContextRelease(self.global_context); 853 | JSContextGroupRelease(self.context_group); 854 | } 855 | } 856 | } 857 | 858 | /// A JavaScript execution context. 859 | pub struct JSContext { 860 | inner: JSContextRef, 861 | vm: JSVirtualMachine, 862 | } 863 | 864 | impl JSContext { 865 | /// Create a new context in the same virtual machine 866 | pub fn split(&self) -> Self { 867 | unsafe { 868 | let context = JSGlobalContextCreateInGroup(self.vm.context_group, std::ptr::null_mut()); 869 | JSContextGroupRetain(self.vm.context_group); 870 | JSGlobalContextRetain(context); 871 | let mut vm = self.vm.clone(); 872 | vm.global_context = context; 873 | Self { inner: context, vm } 874 | } 875 | } 876 | 877 | /// Get inner opaque object. 878 | pub fn get_ref(&self) -> JSContextRef { 879 | self.inner 880 | } 881 | 882 | /// Create a new `JSContext` object. 883 | /// 884 | /// Note that this associated function also creates a new `JSVirtualMachine`. 885 | /// If you want to create a `JSContext` object within an existing virtual 886 | /// machine, please use the `with_virtual_machine` associated function. 887 | pub fn new() -> Self { 888 | let vm = JSVirtualMachine::new(); 889 | Self { 890 | inner: vm.global_context, 891 | vm, 892 | } 893 | } 894 | 895 | /// Create a new `JSContext` object within the provided `JSVirtualMachine`. 896 | pub fn with_virtual_machine(vm: JSVirtualMachine) -> Self { 897 | Self { 898 | inner: vm.global_context, 899 | vm, 900 | } 901 | } 902 | 903 | /// Returns the context global object. 904 | pub fn get_global_object(&self) -> JSObject { 905 | unsafe { JSContextGetGlobalObject(self.inner) }.into() 906 | } 907 | 908 | /// Evaluate the script. 909 | /// 910 | /// Returns the value the script evaluates to. If the script throws an 911 | /// exception, this function returns `None`. You can query the thrown 912 | /// exception with the `get_exception` method. 913 | pub fn evaluate_script( 914 | &mut self, 915 | script: &str, 916 | starting_line_number: i32, 917 | ) -> Result { 918 | let script: JSString = script.into(); 919 | let this_object = std::ptr::null_mut(); 920 | let source_url = std::ptr::null_mut(); 921 | let mut exception: JSValueRef = std::ptr::null_mut(); 922 | let value = unsafe { 923 | JSEvaluateScript( 924 | self.vm.global_context, 925 | script.inner, 926 | this_object, 927 | source_url, 928 | starting_line_number, 929 | &mut exception, 930 | ) 931 | }; 932 | let value = JSValue::from(value); 933 | if value.is_null(self) { 934 | Err(JSValue::from(exception)) 935 | } else { 936 | Ok(value) 937 | } 938 | } 939 | } 940 | 941 | impl fmt::Debug for JSContext { 942 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 943 | f.debug_struct("JSContext").finish() 944 | } 945 | } 946 | 947 | impl Default for JSContext { 948 | fn default() -> Self { 949 | JSContext::new() 950 | } 951 | } 952 | 953 | impl From for JSContext { 954 | fn from(ctx: JSContextRef) -> Self { 955 | let vm = JSVirtualMachine::from(ctx); 956 | Self { inner: ctx, vm } 957 | } 958 | } 959 | -------------------------------------------------------------------------------- /sys/.gitignore: -------------------------------------------------------------------------------- 1 | /target -------------------------------------------------------------------------------- /sys/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "pkg-config" 7 | version = "0.3.25" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" 10 | 11 | [[package]] 12 | name = "rusty_jsc_sys" 13 | version = "0.1.0" 14 | dependencies = [ 15 | "pkg-config", 16 | ] 17 | -------------------------------------------------------------------------------- /sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rusty_jsc_sys" 3 | version = "0.1.0" 4 | description = "Raw bindings for the JavaScriptCore engine" 5 | authors = [ "Wasmer Engineering Team ", "Pekka Enberg", "Adrien Zinger" ] 6 | repository = "https://github.com/wasmerio/rusty_jsc" 7 | license = "MIT" 8 | edition = "2021" 9 | 10 | [lib] 11 | 12 | [target.'cfg(target_os = "linux")'.build-dependencies] 13 | pkg-config = "0.3.9" 14 | -------------------------------------------------------------------------------- /sys/build.rs: -------------------------------------------------------------------------------- 1 | #[cfg(target_os = "macos")] 2 | fn main() { 3 | println!("cargo:rustc-link-lib=framework=JavaScriptCore"); 4 | } 5 | 6 | #[cfg(target_os = "linux")] 7 | fn main() { 8 | pkg_config::probe_library("javascriptcoregtk-4.1").unwrap(); 9 | } 10 | -------------------------------------------------------------------------------- /sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | #![allow(non_snake_case)] 3 | #![allow(non_upper_case_globals)] 4 | 5 | #[repr(C)] 6 | pub struct OpaqueJSContextGroup { 7 | _unused: [u8; 0], 8 | } 9 | 10 | pub type JSContextGroupRef = *const OpaqueJSContextGroup; 11 | 12 | #[repr(C)] 13 | pub struct OpaqueJSContext { 14 | _unused: [u8; 0], 15 | } 16 | 17 | pub type JSContextRef = *const OpaqueJSContext; 18 | 19 | pub type JSGlobalContextRef = *mut OpaqueJSContext; 20 | 21 | #[repr(C)] 22 | pub struct OpaqueJSString { 23 | _unused: [u8; 0], 24 | } 25 | 26 | pub type JSStringRef = *mut OpaqueJSString; 27 | 28 | #[repr(C)] 29 | pub struct OpaqueJSClass { 30 | _unused: [u8; 0], 31 | } 32 | 33 | pub type JSClassRef = *mut OpaqueJSClass; 34 | 35 | #[repr(C)] 36 | pub struct OpaqueJSPropertyNameArray { 37 | _unused: [u8; 0], 38 | } 39 | 40 | pub type JSPropertyNameArrayRef = *mut OpaqueJSPropertyNameArray; 41 | 42 | #[repr(C)] 43 | pub struct OpaqueJSPropertyNameAccumulator { 44 | _unused: [u8; 0], 45 | } 46 | 47 | pub type JSPropertyNameAccumulatorRef = *mut OpaqueJSPropertyNameAccumulator; 48 | 49 | pub type JSTypedArrayBytesDeallocator = ::std::option::Option< 50 | unsafe extern "C" fn( 51 | bytes: *mut ::std::os::raw::c_void, 52 | deallocatorContext: *mut ::std::os::raw::c_void, 53 | ), 54 | >; 55 | 56 | #[repr(C)] 57 | pub struct OpaqueJSValue { 58 | _unused: [u8; 0], 59 | } 60 | 61 | pub type JSValueRef = *const OpaqueJSValue; 62 | 63 | pub type JSObjectRef = *mut OpaqueJSValue; 64 | 65 | extern "C" { 66 | 67 | pub fn JSEvaluateScript( 68 | ctx: JSContextRef, 69 | script: JSStringRef, 70 | thisObject: JSObjectRef, 71 | sourceURL: JSStringRef, 72 | startingLineNumber: ::std::os::raw::c_int, 73 | exception: *mut JSValueRef, 74 | ) -> JSValueRef; 75 | } 76 | extern "C" { 77 | 78 | pub fn JSCheckScriptSyntax( 79 | ctx: JSContextRef, 80 | script: JSStringRef, 81 | sourceURL: JSStringRef, 82 | startingLineNumber: ::std::os::raw::c_int, 83 | exception: *mut JSValueRef, 84 | ) -> bool; 85 | 86 | pub fn JSGarbageCollect(ctx: JSContextRef); 87 | } 88 | pub const JSType_kJSTypeUndefined: JSType = 0; 89 | pub const JSType_kJSTypeNull: JSType = 1; 90 | pub const JSType_kJSTypeBoolean: JSType = 2; 91 | pub const JSType_kJSTypeNumber: JSType = 3; 92 | pub const JSType_kJSTypeString: JSType = 4; 93 | pub const JSType_kJSTypeObject: JSType = 5; 94 | pub const JSType_kJSTypeSymbol: JSType = 6; 95 | 96 | pub type JSType = ::std::os::raw::c_uint; 97 | pub const JSTypedArrayType_kJSTypedArrayTypeInt8Array: JSTypedArrayType = 0; 98 | pub const JSTypedArrayType_kJSTypedArrayTypeInt16Array: JSTypedArrayType = 1; 99 | pub const JSTypedArrayType_kJSTypedArrayTypeInt32Array: JSTypedArrayType = 2; 100 | pub const JSTypedArrayType_kJSTypedArrayTypeUint8Array: JSTypedArrayType = 3; 101 | pub const JSTypedArrayType_kJSTypedArrayTypeUint8ClampedArray: JSTypedArrayType = 4; 102 | pub const JSTypedArrayType_kJSTypedArrayTypeUint16Array: JSTypedArrayType = 5; 103 | pub const JSTypedArrayType_kJSTypedArrayTypeUint32Array: JSTypedArrayType = 6; 104 | pub const JSTypedArrayType_kJSTypedArrayTypeFloat32Array: JSTypedArrayType = 7; 105 | pub const JSTypedArrayType_kJSTypedArrayTypeFloat64Array: JSTypedArrayType = 8; 106 | pub const JSTypedArrayType_kJSTypedArrayTypeArrayBuffer: JSTypedArrayType = 9; 107 | pub const JSTypedArrayType_kJSTypedArrayTypeNone: JSTypedArrayType = 10; 108 | pub const JSTypedArrayType_kJSTypedArrayTypeBigInt64Array: JSTypedArrayType = 11; 109 | pub const JSTypedArrayType_kJSTypedArrayTypeBigUint64Array: JSTypedArrayType = 12; 110 | 111 | pub type JSTypedArrayType = ::std::os::raw::c_uint; 112 | extern "C" { 113 | pub fn JSValueGetType(ctx: JSContextRef, value: JSValueRef) -> JSType; 114 | pub fn JSValueIsUndefined(ctx: JSContextRef, value: JSValueRef) -> bool; 115 | pub fn JSValueIsNull(ctx: JSContextRef, value: JSValueRef) -> bool; 116 | pub fn JSValueIsBoolean(ctx: JSContextRef, value: JSValueRef) -> bool; 117 | pub fn JSValueIsNumber(ctx: JSContextRef, value: JSValueRef) -> bool; 118 | pub fn JSValueIsString(ctx: JSContextRef, value: JSValueRef) -> bool; 119 | pub fn JSValueIsSymbol(ctx: JSContextRef, value: JSValueRef) -> bool; 120 | pub fn JSValueIsObject(ctx: JSContextRef, value: JSValueRef) -> bool; 121 | pub fn JSValueIsObjectOfClass( 122 | ctx: JSContextRef, 123 | value: JSValueRef, 124 | jsClass: JSClassRef, 125 | ) -> bool; 126 | pub fn JSValueIsArray(ctx: JSContextRef, value: JSValueRef) -> bool; 127 | pub fn JSValueIsDate(ctx: JSContextRef, value: JSValueRef) -> bool; 128 | pub fn JSValueGetTypedArrayType( 129 | ctx: JSContextRef, 130 | value: JSValueRef, 131 | exception: *mut JSValueRef, 132 | ) -> JSTypedArrayType; 133 | pub fn JSValueIsEqual( 134 | ctx: JSContextRef, 135 | a: JSValueRef, 136 | b: JSValueRef, 137 | exception: *mut JSValueRef, 138 | ) -> bool; 139 | pub fn JSValueIsStrictEqual(ctx: JSContextRef, a: JSValueRef, b: JSValueRef) -> bool; 140 | pub fn JSValueIsInstanceOfConstructor( 141 | ctx: JSContextRef, 142 | value: JSValueRef, 143 | constructor: JSObjectRef, 144 | exception: *mut JSValueRef, 145 | ) -> bool; 146 | pub fn JSValueMakeUndefined(ctx: JSContextRef) -> JSValueRef; 147 | pub fn JSValueMakeNull(ctx: JSContextRef) -> JSValueRef; 148 | pub fn JSValueMakeBoolean(ctx: JSContextRef, boolean: bool) -> JSValueRef; 149 | pub fn JSValueMakeNumber(ctx: JSContextRef, number: f64) -> JSValueRef; 150 | pub fn JSValueMakeString(ctx: JSContextRef, string: JSStringRef) -> JSValueRef; 151 | pub fn JSValueMakeSymbol(ctx: JSContextRef, description: JSStringRef) -> JSValueRef; 152 | pub fn JSValueMakeFromJSONString(ctx: JSContextRef, string: JSStringRef) -> JSValueRef; 153 | pub fn JSValueCreateJSONString( 154 | ctx: JSContextRef, 155 | value: JSValueRef, 156 | indent: ::std::os::raw::c_uint, 157 | exception: *mut JSValueRef, 158 | ) -> JSStringRef; 159 | pub fn JSValueToBoolean(ctx: JSContextRef, value: JSValueRef) -> bool; 160 | pub fn JSValueToNumber(ctx: JSContextRef, value: JSValueRef, exception: *mut JSValueRef) 161 | -> f64; 162 | pub fn JSValueToStringCopy( 163 | ctx: JSContextRef, 164 | value: JSValueRef, 165 | exception: *mut JSValueRef, 166 | ) -> JSStringRef; 167 | pub fn JSValueToObject( 168 | ctx: JSContextRef, 169 | value: JSValueRef, 170 | exception: *mut JSValueRef, 171 | ) -> JSObjectRef; 172 | pub fn JSValueProtect(ctx: JSContextRef, value: JSValueRef); 173 | pub fn JSValueUnprotect(ctx: JSContextRef, value: JSValueRef); 174 | } 175 | pub type size_t = ::std::os::raw::c_ulong; 176 | pub type wchar_t = ::std::os::raw::c_int; 177 | 178 | pub const kJSPropertyAttributeNone: _bindgen_ty_1 = 0; 179 | pub const kJSPropertyAttributeReadOnly: _bindgen_ty_1 = 2; 180 | pub const kJSPropertyAttributeDontEnum: _bindgen_ty_1 = 4; 181 | pub const kJSPropertyAttributeDontDelete: _bindgen_ty_1 = 8; 182 | 183 | pub type _bindgen_ty_1 = ::std::os::raw::c_uint; 184 | 185 | pub type JSPropertyAttributes = ::std::os::raw::c_uint; 186 | pub const kJSClassAttributeNone: _bindgen_ty_2 = 0; 187 | pub const kJSClassAttributeNoAutomaticPrototype: _bindgen_ty_2 = 2; 188 | 189 | pub type _bindgen_ty_2 = ::std::os::raw::c_uint; 190 | 191 | pub type JSClassAttributes = ::std::os::raw::c_uint; 192 | 193 | pub type JSObjectInitializeCallback = 194 | ::std::option::Option; 195 | 196 | pub type JSObjectFinalizeCallback = 197 | ::std::option::Option; 198 | 199 | pub type JSObjectHasPropertyCallback = ::std::option::Option< 200 | unsafe extern "C" fn(ctx: JSContextRef, object: JSObjectRef, propertyName: JSStringRef) -> bool, 201 | >; 202 | 203 | pub type JSObjectGetPropertyCallback = ::std::option::Option< 204 | unsafe extern "C" fn( 205 | ctx: JSContextRef, 206 | object: JSObjectRef, 207 | propertyName: JSStringRef, 208 | exception: *mut JSValueRef, 209 | ) -> JSValueRef, 210 | >; 211 | 212 | pub type JSObjectSetPropertyCallback = ::std::option::Option< 213 | unsafe extern "C" fn( 214 | ctx: JSContextRef, 215 | object: JSObjectRef, 216 | propertyName: JSStringRef, 217 | value: JSValueRef, 218 | exception: *mut JSValueRef, 219 | ) -> bool, 220 | >; 221 | 222 | pub type JSObjectDeletePropertyCallback = ::std::option::Option< 223 | unsafe extern "C" fn( 224 | ctx: JSContextRef, 225 | object: JSObjectRef, 226 | propertyName: JSStringRef, 227 | exception: *mut JSValueRef, 228 | ) -> bool, 229 | >; 230 | 231 | pub type JSObjectGetPropertyNamesCallback = ::std::option::Option< 232 | unsafe extern "C" fn( 233 | ctx: JSContextRef, 234 | object: JSObjectRef, 235 | propertyNames: JSPropertyNameAccumulatorRef, 236 | ), 237 | >; 238 | 239 | pub type JSObjectCallAsFunctionCallback = ::std::option::Option< 240 | unsafe extern "C" fn( 241 | ctx: JSContextRef, 242 | function: JSObjectRef, 243 | thisObject: JSObjectRef, 244 | argumentCount: size_t, 245 | arguments: *const JSValueRef, 246 | exception: *mut JSValueRef, 247 | ) -> JSValueRef, 248 | >; 249 | 250 | pub type JSObjectCallAsConstructorCallback = ::std::option::Option< 251 | unsafe extern "C" fn( 252 | ctx: JSContextRef, 253 | constructor: JSObjectRef, 254 | argumentCount: size_t, 255 | arguments: *const JSValueRef, 256 | exception: *mut JSValueRef, 257 | ) -> JSObjectRef, 258 | >; 259 | 260 | pub type JSObjectHasInstanceCallback = ::std::option::Option< 261 | unsafe extern "C" fn( 262 | ctx: JSContextRef, 263 | constructor: JSObjectRef, 264 | possibleInstance: JSValueRef, 265 | exception: *mut JSValueRef, 266 | ) -> bool, 267 | >; 268 | 269 | pub type JSObjectConvertToTypeCallback = ::std::option::Option< 270 | unsafe extern "C" fn( 271 | ctx: JSContextRef, 272 | object: JSObjectRef, 273 | type_: JSType, 274 | exception: *mut JSValueRef, 275 | ) -> JSValueRef, 276 | >; 277 | 278 | #[repr(C)] 279 | pub struct JSStaticValue { 280 | pub name: *const ::std::os::raw::c_char, 281 | pub getProperty: JSObjectGetPropertyCallback, 282 | pub setProperty: JSObjectSetPropertyCallback, 283 | pub attributes: JSPropertyAttributes, 284 | } 285 | 286 | impl Default for JSStaticValue { 287 | fn default() -> Self { 288 | Self { 289 | name: std::ptr::null(), 290 | getProperty: None, 291 | setProperty: None, 292 | attributes: 0, 293 | } 294 | } 295 | } 296 | 297 | #[test] 298 | fn bindgen_test_layout_JSStaticValue() { 299 | assert_eq!( 300 | ::std::mem::size_of::(), 301 | 32usize, 302 | concat!("Size of: ", stringify!(JSStaticValue)) 303 | ); 304 | assert_eq!( 305 | ::std::mem::align_of::(), 306 | 8usize, 307 | concat!("Alignment of ", stringify!(JSStaticValue)) 308 | ); 309 | fn test_field_name() { 310 | assert_eq!( 311 | unsafe { 312 | let uninit = ::std::mem::MaybeUninit::::uninit(); 313 | let ptr = uninit.as_ptr(); 314 | ::std::ptr::addr_of!((*ptr).name) as usize - ptr as usize 315 | }, 316 | 0usize, 317 | concat!( 318 | "Offset of field: ", 319 | stringify!(JSStaticValue), 320 | "::", 321 | stringify!(name) 322 | ) 323 | ); 324 | } 325 | test_field_name(); 326 | fn test_field_getProperty() { 327 | assert_eq!( 328 | unsafe { 329 | let uninit = ::std::mem::MaybeUninit::::uninit(); 330 | let ptr = uninit.as_ptr(); 331 | ::std::ptr::addr_of!((*ptr).getProperty) as usize - ptr as usize 332 | }, 333 | 8usize, 334 | concat!( 335 | "Offset of field: ", 336 | stringify!(JSStaticValue), 337 | "::", 338 | stringify!(getProperty) 339 | ) 340 | ); 341 | } 342 | test_field_getProperty(); 343 | fn test_field_setProperty() { 344 | assert_eq!( 345 | unsafe { 346 | let uninit = ::std::mem::MaybeUninit::::uninit(); 347 | let ptr = uninit.as_ptr(); 348 | ::std::ptr::addr_of!((*ptr).setProperty) as usize - ptr as usize 349 | }, 350 | 16usize, 351 | concat!( 352 | "Offset of field: ", 353 | stringify!(JSStaticValue), 354 | "::", 355 | stringify!(setProperty) 356 | ) 357 | ); 358 | } 359 | test_field_setProperty(); 360 | fn test_field_attributes() { 361 | assert_eq!( 362 | unsafe { 363 | let uninit = ::std::mem::MaybeUninit::::uninit(); 364 | let ptr = uninit.as_ptr(); 365 | ::std::ptr::addr_of!((*ptr).attributes) as usize - ptr as usize 366 | }, 367 | 24usize, 368 | concat!( 369 | "Offset of field: ", 370 | stringify!(JSStaticValue), 371 | "::", 372 | stringify!(attributes) 373 | ) 374 | ); 375 | } 376 | test_field_attributes(); 377 | } 378 | 379 | #[repr(C)] 380 | pub struct JSStaticFunction { 381 | pub name: *const ::std::os::raw::c_char, 382 | pub callAsFunction: JSObjectCallAsFunctionCallback, 383 | pub attributes: JSPropertyAttributes, 384 | } 385 | 386 | impl Default for JSStaticFunction { 387 | fn default() -> Self { 388 | Self { 389 | name: std::ptr::null(), 390 | callAsFunction: None, 391 | attributes: 0, 392 | } 393 | } 394 | } 395 | 396 | #[test] 397 | fn bindgen_test_layout_JSStaticFunction() { 398 | assert_eq!( 399 | ::std::mem::size_of::(), 400 | 24usize, 401 | concat!("Size of: ", stringify!(JSStaticFunction)) 402 | ); 403 | assert_eq!( 404 | ::std::mem::align_of::(), 405 | 8usize, 406 | concat!("Alignment of ", stringify!(JSStaticFunction)) 407 | ); 408 | fn test_field_name() { 409 | assert_eq!( 410 | unsafe { 411 | let uninit = ::std::mem::MaybeUninit::::uninit(); 412 | let ptr = uninit.as_ptr(); 413 | ::std::ptr::addr_of!((*ptr).name) as usize - ptr as usize 414 | }, 415 | 0usize, 416 | concat!( 417 | "Offset of field: ", 418 | stringify!(JSStaticFunction), 419 | "::", 420 | stringify!(name) 421 | ) 422 | ); 423 | } 424 | test_field_name(); 425 | fn test_field_callAsFunction() { 426 | assert_eq!( 427 | unsafe { 428 | let uninit = ::std::mem::MaybeUninit::::uninit(); 429 | let ptr = uninit.as_ptr(); 430 | ::std::ptr::addr_of!((*ptr).callAsFunction) as usize - ptr as usize 431 | }, 432 | 8usize, 433 | concat!( 434 | "Offset of field: ", 435 | stringify!(JSStaticFunction), 436 | "::", 437 | stringify!(callAsFunction) 438 | ) 439 | ); 440 | } 441 | test_field_callAsFunction(); 442 | fn test_field_attributes() { 443 | assert_eq!( 444 | unsafe { 445 | let uninit = ::std::mem::MaybeUninit::::uninit(); 446 | let ptr = uninit.as_ptr(); 447 | ::std::ptr::addr_of!((*ptr).attributes) as usize - ptr as usize 448 | }, 449 | 16usize, 450 | concat!( 451 | "Offset of field: ", 452 | stringify!(JSStaticFunction), 453 | "::", 454 | stringify!(attributes) 455 | ) 456 | ); 457 | } 458 | test_field_attributes(); 459 | } 460 | 461 | #[repr(C)] 462 | #[derive(Clone, Copy)] 463 | pub struct JSClassDefinition { 464 | pub version: ::std::os::raw::c_int, 465 | pub attributes: JSClassAttributes, 466 | pub className: *const ::std::os::raw::c_char, 467 | pub parentClass: JSClassRef, 468 | pub staticValues: *const JSStaticValue, 469 | pub staticFunctions: *const JSStaticFunction, 470 | pub initialize: JSObjectInitializeCallback, 471 | pub finalize: JSObjectFinalizeCallback, 472 | pub hasProperty: JSObjectHasPropertyCallback, 473 | pub getProperty: JSObjectGetPropertyCallback, 474 | pub setProperty: JSObjectSetPropertyCallback, 475 | pub deleteProperty: JSObjectDeletePropertyCallback, 476 | pub getPropertyNames: JSObjectGetPropertyNamesCallback, 477 | pub callAsFunction: JSObjectCallAsFunctionCallback, 478 | pub callAsConstructor: JSObjectCallAsConstructorCallback, 479 | pub hasInstance: JSObjectHasInstanceCallback, 480 | pub convertToType: JSObjectConvertToTypeCallback, 481 | } 482 | 483 | #[test] 484 | fn bindgen_test_layout_JSClassDefinition() { 485 | assert_eq!( 486 | ::std::mem::size_of::(), 487 | 128usize, 488 | concat!("Size of: ", stringify!(JSClassDefinition)) 489 | ); 490 | assert_eq!( 491 | ::std::mem::align_of::(), 492 | 8usize, 493 | concat!("Alignment of ", stringify!(JSClassDefinition)) 494 | ); 495 | fn test_field_version() { 496 | assert_eq!( 497 | unsafe { 498 | let uninit = ::std::mem::MaybeUninit::::uninit(); 499 | let ptr = uninit.as_ptr(); 500 | ::std::ptr::addr_of!((*ptr).version) as usize - ptr as usize 501 | }, 502 | 0usize, 503 | concat!( 504 | "Offset of field: ", 505 | stringify!(JSClassDefinition), 506 | "::", 507 | stringify!(version) 508 | ) 509 | ); 510 | } 511 | test_field_version(); 512 | fn test_field_attributes() { 513 | assert_eq!( 514 | unsafe { 515 | let uninit = ::std::mem::MaybeUninit::::uninit(); 516 | let ptr = uninit.as_ptr(); 517 | ::std::ptr::addr_of!((*ptr).attributes) as usize - ptr as usize 518 | }, 519 | 4usize, 520 | concat!( 521 | "Offset of field: ", 522 | stringify!(JSClassDefinition), 523 | "::", 524 | stringify!(attributes) 525 | ) 526 | ); 527 | } 528 | test_field_attributes(); 529 | fn test_field_className() { 530 | assert_eq!( 531 | unsafe { 532 | let uninit = ::std::mem::MaybeUninit::::uninit(); 533 | let ptr = uninit.as_ptr(); 534 | ::std::ptr::addr_of!((*ptr).className) as usize - ptr as usize 535 | }, 536 | 8usize, 537 | concat!( 538 | "Offset of field: ", 539 | stringify!(JSClassDefinition), 540 | "::", 541 | stringify!(className) 542 | ) 543 | ); 544 | } 545 | test_field_className(); 546 | fn test_field_parentClass() { 547 | assert_eq!( 548 | unsafe { 549 | let uninit = ::std::mem::MaybeUninit::::uninit(); 550 | let ptr = uninit.as_ptr(); 551 | ::std::ptr::addr_of!((*ptr).parentClass) as usize - ptr as usize 552 | }, 553 | 16usize, 554 | concat!( 555 | "Offset of field: ", 556 | stringify!(JSClassDefinition), 557 | "::", 558 | stringify!(parentClass) 559 | ) 560 | ); 561 | } 562 | test_field_parentClass(); 563 | fn test_field_staticValues() { 564 | assert_eq!( 565 | unsafe { 566 | let uninit = ::std::mem::MaybeUninit::::uninit(); 567 | let ptr = uninit.as_ptr(); 568 | ::std::ptr::addr_of!((*ptr).staticValues) as usize - ptr as usize 569 | }, 570 | 24usize, 571 | concat!( 572 | "Offset of field: ", 573 | stringify!(JSClassDefinition), 574 | "::", 575 | stringify!(staticValues) 576 | ) 577 | ); 578 | } 579 | test_field_staticValues(); 580 | fn test_field_staticFunctions() { 581 | assert_eq!( 582 | unsafe { 583 | let uninit = ::std::mem::MaybeUninit::::uninit(); 584 | let ptr = uninit.as_ptr(); 585 | ::std::ptr::addr_of!((*ptr).staticFunctions) as usize - ptr as usize 586 | }, 587 | 32usize, 588 | concat!( 589 | "Offset of field: ", 590 | stringify!(JSClassDefinition), 591 | "::", 592 | stringify!(staticFunctions) 593 | ) 594 | ); 595 | } 596 | test_field_staticFunctions(); 597 | fn test_field_initialize() { 598 | assert_eq!( 599 | unsafe { 600 | let uninit = ::std::mem::MaybeUninit::::uninit(); 601 | let ptr = uninit.as_ptr(); 602 | ::std::ptr::addr_of!((*ptr).initialize) as usize - ptr as usize 603 | }, 604 | 40usize, 605 | concat!( 606 | "Offset of field: ", 607 | stringify!(JSClassDefinition), 608 | "::", 609 | stringify!(initialize) 610 | ) 611 | ); 612 | } 613 | test_field_initialize(); 614 | fn test_field_finalize() { 615 | assert_eq!( 616 | unsafe { 617 | let uninit = ::std::mem::MaybeUninit::::uninit(); 618 | let ptr = uninit.as_ptr(); 619 | ::std::ptr::addr_of!((*ptr).finalize) as usize - ptr as usize 620 | }, 621 | 48usize, 622 | concat!( 623 | "Offset of field: ", 624 | stringify!(JSClassDefinition), 625 | "::", 626 | stringify!(finalize) 627 | ) 628 | ); 629 | } 630 | test_field_finalize(); 631 | fn test_field_hasProperty() { 632 | assert_eq!( 633 | unsafe { 634 | let uninit = ::std::mem::MaybeUninit::::uninit(); 635 | let ptr = uninit.as_ptr(); 636 | ::std::ptr::addr_of!((*ptr).hasProperty) as usize - ptr as usize 637 | }, 638 | 56usize, 639 | concat!( 640 | "Offset of field: ", 641 | stringify!(JSClassDefinition), 642 | "::", 643 | stringify!(hasProperty) 644 | ) 645 | ); 646 | } 647 | test_field_hasProperty(); 648 | fn test_field_getProperty() { 649 | assert_eq!( 650 | unsafe { 651 | let uninit = ::std::mem::MaybeUninit::::uninit(); 652 | let ptr = uninit.as_ptr(); 653 | ::std::ptr::addr_of!((*ptr).getProperty) as usize - ptr as usize 654 | }, 655 | 64usize, 656 | concat!( 657 | "Offset of field: ", 658 | stringify!(JSClassDefinition), 659 | "::", 660 | stringify!(getProperty) 661 | ) 662 | ); 663 | } 664 | test_field_getProperty(); 665 | fn test_field_setProperty() { 666 | assert_eq!( 667 | unsafe { 668 | let uninit = ::std::mem::MaybeUninit::::uninit(); 669 | let ptr = uninit.as_ptr(); 670 | ::std::ptr::addr_of!((*ptr).setProperty) as usize - ptr as usize 671 | }, 672 | 72usize, 673 | concat!( 674 | "Offset of field: ", 675 | stringify!(JSClassDefinition), 676 | "::", 677 | stringify!(setProperty) 678 | ) 679 | ); 680 | } 681 | test_field_setProperty(); 682 | fn test_field_deleteProperty() { 683 | assert_eq!( 684 | unsafe { 685 | let uninit = ::std::mem::MaybeUninit::::uninit(); 686 | let ptr = uninit.as_ptr(); 687 | ::std::ptr::addr_of!((*ptr).deleteProperty) as usize - ptr as usize 688 | }, 689 | 80usize, 690 | concat!( 691 | "Offset of field: ", 692 | stringify!(JSClassDefinition), 693 | "::", 694 | stringify!(deleteProperty) 695 | ) 696 | ); 697 | } 698 | test_field_deleteProperty(); 699 | fn test_field_getPropertyNames() { 700 | assert_eq!( 701 | unsafe { 702 | let uninit = ::std::mem::MaybeUninit::::uninit(); 703 | let ptr = uninit.as_ptr(); 704 | ::std::ptr::addr_of!((*ptr).getPropertyNames) as usize - ptr as usize 705 | }, 706 | 88usize, 707 | concat!( 708 | "Offset of field: ", 709 | stringify!(JSClassDefinition), 710 | "::", 711 | stringify!(getPropertyNames) 712 | ) 713 | ); 714 | } 715 | test_field_getPropertyNames(); 716 | fn test_field_callAsFunction() { 717 | assert_eq!( 718 | unsafe { 719 | let uninit = ::std::mem::MaybeUninit::::uninit(); 720 | let ptr = uninit.as_ptr(); 721 | ::std::ptr::addr_of!((*ptr).callAsFunction) as usize - ptr as usize 722 | }, 723 | 96usize, 724 | concat!( 725 | "Offset of field: ", 726 | stringify!(JSClassDefinition), 727 | "::", 728 | stringify!(callAsFunction) 729 | ) 730 | ); 731 | } 732 | test_field_callAsFunction(); 733 | fn test_field_callAsConstructor() { 734 | assert_eq!( 735 | unsafe { 736 | let uninit = ::std::mem::MaybeUninit::::uninit(); 737 | let ptr = uninit.as_ptr(); 738 | ::std::ptr::addr_of!((*ptr).callAsConstructor) as usize - ptr as usize 739 | }, 740 | 104usize, 741 | concat!( 742 | "Offset of field: ", 743 | stringify!(JSClassDefinition), 744 | "::", 745 | stringify!(callAsConstructor) 746 | ) 747 | ); 748 | } 749 | test_field_callAsConstructor(); 750 | fn test_field_hasInstance() { 751 | assert_eq!( 752 | unsafe { 753 | let uninit = ::std::mem::MaybeUninit::::uninit(); 754 | let ptr = uninit.as_ptr(); 755 | ::std::ptr::addr_of!((*ptr).hasInstance) as usize - ptr as usize 756 | }, 757 | 112usize, 758 | concat!( 759 | "Offset of field: ", 760 | stringify!(JSClassDefinition), 761 | "::", 762 | stringify!(hasInstance) 763 | ) 764 | ); 765 | } 766 | test_field_hasInstance(); 767 | fn test_field_convertToType() { 768 | assert_eq!( 769 | unsafe { 770 | let uninit = ::std::mem::MaybeUninit::::uninit(); 771 | let ptr = uninit.as_ptr(); 772 | ::std::ptr::addr_of!((*ptr).convertToType) as usize - ptr as usize 773 | }, 774 | 120usize, 775 | concat!( 776 | "Offset of field: ", 777 | stringify!(JSClassDefinition), 778 | "::", 779 | stringify!(convertToType) 780 | ) 781 | ); 782 | } 783 | test_field_convertToType(); 784 | } 785 | 786 | extern "C" { 787 | pub static kJSClassDefinitionEmpty: JSClassDefinition; 788 | pub fn JSClassCreate(definition: *const JSClassDefinition) -> JSClassRef; 789 | pub fn JSClassRetain(jsClass: JSClassRef) -> JSClassRef; 790 | pub fn JSClassRelease(jsClass: JSClassRef); 791 | 792 | /// Creates a JavaScript object. 793 | /// 794 | /// # Parameters 795 | /// * ctx The execution context to use. 796 | /// * jsClass The JSClass to assign to the object. Pass NULL to use the 797 | /// default object class. 798 | /// * data A void* to set as the object's private data. Pass NULL to 799 | /// specify no private data. 800 | /// 801 | /// # Result 802 | /// A JSObject with the given class and private data. 803 | /// 804 | /// # Notes 805 | /// The default object class does not allocate storage for private data, so 806 | /// you must provide a non-NULL jsClass to JSObjectMake if you want your 807 | /// object to be able to store private data. 808 | /// 809 | /// Data is set on the created object before the intialize methods in its 810 | /// class chain are called. This enables the initialize methods to retrieve 811 | /// and manipulate data through JSObjectGetPrivate. 812 | pub fn JSObjectMake( 813 | ctx: JSContextRef, 814 | jsClass: JSClassRef, 815 | data: *mut ::std::os::raw::c_void, 816 | ) -> JSObjectRef; 817 | pub fn JSObjectMakeFunctionWithCallback( 818 | ctx: JSContextRef, 819 | name: JSStringRef, 820 | callAsFunction: JSObjectCallAsFunctionCallback, 821 | ) -> JSObjectRef; 822 | pub fn JSObjectMakeConstructor( 823 | ctx: JSContextRef, 824 | jsClass: JSClassRef, 825 | callAsConstructor: JSObjectCallAsConstructorCallback, 826 | ) -> JSObjectRef; 827 | pub fn JSObjectMakeArray( 828 | ctx: JSContextRef, 829 | argumentCount: size_t, 830 | arguments: *const JSValueRef, 831 | exception: *mut JSValueRef, 832 | ) -> JSObjectRef; 833 | pub fn JSObjectMakeDate( 834 | ctx: JSContextRef, 835 | argumentCount: size_t, 836 | arguments: *const JSValueRef, 837 | exception: *mut JSValueRef, 838 | ) -> JSObjectRef; 839 | pub fn JSObjectMakeError( 840 | ctx: JSContextRef, 841 | argumentCount: size_t, 842 | arguments: *const JSValueRef, 843 | exception: *mut JSValueRef, 844 | ) -> JSObjectRef; 845 | pub fn JSObjectMakeRegExp( 846 | ctx: JSContextRef, 847 | argumentCount: size_t, 848 | arguments: *const JSValueRef, 849 | exception: *mut JSValueRef, 850 | ) -> JSObjectRef; 851 | /// Creates a JavaScript promise object by invoking the provided executor. 852 | /// 853 | /// # Parameters 854 | /// * ctx The execution context to use. 855 | /// * resolve A pointer to a JSObjectRef in which to store the resolve 856 | /// function for the new promise. Pass NULL if you do not care to store 857 | /// the resolve callback. 858 | /// * reject A pointer to a JSObjectRef in which to store the reject 859 | /// function for the new promise. Pass NULL if you do not care to store 860 | /// the reject callback. 861 | /// * exception A pointer to a JSValueRef in which to store an exception, if 862 | /// any. Pass NULL if you do not care to store an exception. 863 | /// 864 | /// # Return 865 | /// A JSObject that is a promise or NULL if an exception occurred. 866 | pub fn JSObjectMakeDeferredPromise( 867 | ctx: JSContextRef, 868 | resolve: *mut JSObjectRef, 869 | reject: *mut JSObjectRef, 870 | exception: *mut JSValueRef, 871 | ) -> JSObjectRef; 872 | pub fn JSObjectMakeFunction( 873 | ctx: JSContextRef, 874 | name: JSStringRef, 875 | parameterCount: ::std::os::raw::c_uint, 876 | parameterNames: *const JSStringRef, 877 | body: JSStringRef, 878 | sourceURL: JSStringRef, 879 | startingLineNumber: ::std::os::raw::c_int, 880 | exception: *mut JSValueRef, 881 | ) -> JSObjectRef; 882 | pub fn JSObjectGetPrototype(ctx: JSContextRef, object: JSObjectRef) -> JSValueRef; 883 | pub fn JSObjectSetPrototype(ctx: JSContextRef, object: JSObjectRef, value: JSValueRef); 884 | pub fn JSObjectHasProperty( 885 | ctx: JSContextRef, 886 | object: JSObjectRef, 887 | propertyName: JSStringRef, 888 | ) -> bool; 889 | pub fn JSObjectGetProperty( 890 | ctx: JSContextRef, 891 | object: JSObjectRef, 892 | propertyName: JSStringRef, 893 | exception: *mut JSValueRef, 894 | ) -> JSValueRef; 895 | pub fn JSObjectSetProperty( 896 | ctx: JSContextRef, 897 | object: JSObjectRef, 898 | propertyName: JSStringRef, 899 | value: JSValueRef, 900 | attributes: JSPropertyAttributes, 901 | exception: *mut JSValueRef, 902 | ); 903 | pub fn JSObjectDeleteProperty( 904 | ctx: JSContextRef, 905 | object: JSObjectRef, 906 | propertyName: JSStringRef, 907 | exception: *mut JSValueRef, 908 | ) -> bool; 909 | pub fn JSObjectHasPropertyForKey( 910 | ctx: JSContextRef, 911 | object: JSObjectRef, 912 | propertyKey: JSValueRef, 913 | exception: *mut JSValueRef, 914 | ) -> bool; 915 | pub fn JSObjectGetPropertyForKey( 916 | ctx: JSContextRef, 917 | object: JSObjectRef, 918 | propertyKey: JSValueRef, 919 | exception: *mut JSValueRef, 920 | ) -> JSValueRef; 921 | pub fn JSObjectSetPropertyForKey( 922 | ctx: JSContextRef, 923 | object: JSObjectRef, 924 | propertyKey: JSValueRef, 925 | value: JSValueRef, 926 | attributes: JSPropertyAttributes, 927 | exception: *mut JSValueRef, 928 | ); 929 | pub fn JSObjectDeletePropertyForKey( 930 | ctx: JSContextRef, 931 | object: JSObjectRef, 932 | propertyKey: JSValueRef, 933 | exception: *mut JSValueRef, 934 | ) -> bool; 935 | pub fn JSObjectGetPropertyAtIndex( 936 | ctx: JSContextRef, 937 | object: JSObjectRef, 938 | propertyIndex: ::std::os::raw::c_uint, 939 | exception: *mut JSValueRef, 940 | ) -> JSValueRef; 941 | pub fn JSObjectSetPropertyAtIndex( 942 | ctx: JSContextRef, 943 | object: JSObjectRef, 944 | propertyIndex: ::std::os::raw::c_uint, 945 | value: JSValueRef, 946 | exception: *mut JSValueRef, 947 | ); 948 | pub fn JSObjectGetPrivate(object: JSObjectRef) -> *mut ::std::os::raw::c_void; 949 | pub fn JSObjectSetPrivate(object: JSObjectRef, data: *mut ::std::os::raw::c_void) -> bool; 950 | pub fn JSObjectIsFunction(ctx: JSContextRef, object: JSObjectRef) -> bool; 951 | /// Calls an object as a function. 952 | /// 953 | /// # Parameters 954 | /// * ctx The execution context to use. 955 | /// * object The JSObject to call as a function. 956 | /// * thisObject The object to use as "this," or NULL to use the global 957 | /// object as "this." 958 | /// * argumentCount An integer count of the number of arguments in 959 | /// arguments. 960 | /// * arguments A JSValue array of arguments to pass to the function. Pass 961 | /// NULL if argumentCount is 0. 962 | /// * exception A pointer to a JSValueRef in which to store an exception, if 963 | /// any. Pass NULL if you do not care to store an exception. 964 | /// 965 | /// # Result 966 | /// The JSValue that results from calling object as a function, or NULL if 967 | /// an exception is thrown or object is not a function. 968 | pub fn JSObjectCallAsFunction( 969 | ctx: JSContextRef, 970 | object: JSObjectRef, 971 | thisObject: JSObjectRef, 972 | argumentCount: size_t, 973 | arguments: *const JSValueRef, 974 | exception: *mut JSValueRef, 975 | ) -> JSValueRef; 976 | pub fn JSObjectIsConstructor(ctx: JSContextRef, object: JSObjectRef) -> bool; 977 | pub fn JSObjectCallAsConstructor( 978 | ctx: JSContextRef, 979 | object: JSObjectRef, 980 | argumentCount: size_t, 981 | arguments: *const JSValueRef, 982 | exception: *mut JSValueRef, 983 | ) -> JSObjectRef; 984 | pub fn JSObjectCopyPropertyNames( 985 | ctx: JSContextRef, 986 | object: JSObjectRef, 987 | ) -> JSPropertyNameArrayRef; 988 | pub fn JSPropertyNameArrayRetain(array: JSPropertyNameArrayRef) -> JSPropertyNameArrayRef; 989 | pub fn JSPropertyNameArrayRelease(array: JSPropertyNameArrayRef); 990 | pub fn JSPropertyNameArrayGetCount(array: JSPropertyNameArrayRef) -> size_t; 991 | pub fn JSPropertyNameArrayGetNameAtIndex( 992 | array: JSPropertyNameArrayRef, 993 | index: size_t, 994 | ) -> JSStringRef; 995 | pub fn JSPropertyNameAccumulatorAddName( 996 | accumulator: JSPropertyNameAccumulatorRef, 997 | propertyName: JSStringRef, 998 | ); 999 | pub fn JSContextGroupCreate() -> JSContextGroupRef; 1000 | pub fn JSContextGroupRetain(group: JSContextGroupRef) -> JSContextGroupRef; 1001 | pub fn JSContextGroupRelease(group: JSContextGroupRef); 1002 | pub fn JSGlobalContextCreate(globalObjectClass: JSClassRef) -> JSGlobalContextRef; 1003 | pub fn JSGlobalContextCreateInGroup( 1004 | group: JSContextGroupRef, 1005 | globalObjectClass: JSClassRef, 1006 | ) -> JSGlobalContextRef; 1007 | pub fn JSGlobalContextRetain(ctx: JSGlobalContextRef) -> JSGlobalContextRef; 1008 | pub fn JSGlobalContextRelease(ctx: JSGlobalContextRef); 1009 | pub fn JSContextGetGlobalObject(ctx: JSContextRef) -> JSObjectRef; 1010 | pub fn JSContextGetGroup(ctx: JSContextRef) -> JSContextGroupRef; 1011 | pub fn JSContextGetGlobalContext(ctx: JSContextRef) -> JSGlobalContextRef; 1012 | pub fn JSGlobalContextCopyName(ctx: JSGlobalContextRef) -> JSStringRef; 1013 | pub fn JSGlobalContextSetName(ctx: JSGlobalContextRef, name: JSStringRef); 1014 | } 1015 | 1016 | pub type JSChar = ::std::os::raw::c_ushort; 1017 | 1018 | extern "C" { 1019 | pub fn JSStringCreateWithCharacters(chars: *const JSChar, numChars: size_t) -> JSStringRef; 1020 | pub fn JSStringCreateWithUTF8CString(string: *const ::std::os::raw::c_char) -> JSStringRef; 1021 | pub fn JSStringRetain(string: JSStringRef) -> JSStringRef; 1022 | pub fn JSStringRelease(string: JSStringRef); 1023 | pub fn JSStringGetLength(string: JSStringRef) -> size_t; 1024 | pub fn JSStringGetCharactersPtr(string: JSStringRef) -> *const JSChar; 1025 | pub fn JSStringGetMaximumUTF8CStringSize(string: JSStringRef) -> size_t; 1026 | pub fn JSStringGetUTF8CString( 1027 | string: JSStringRef, 1028 | buffer: *mut ::std::os::raw::c_char, 1029 | bufferSize: size_t, 1030 | ) -> size_t; 1031 | pub fn JSStringIsEqual(a: JSStringRef, b: JSStringRef) -> bool; 1032 | pub fn JSStringIsEqualToUTF8CString(a: JSStringRef, b: *const ::std::os::raw::c_char) -> bool; 1033 | pub fn JSObjectMakeTypedArray( 1034 | ctx: JSContextRef, 1035 | arrayType: JSTypedArrayType, 1036 | length: size_t, 1037 | exception: *mut JSValueRef, 1038 | ) -> JSObjectRef; 1039 | pub fn JSObjectMakeTypedArrayWithBytesNoCopy( 1040 | ctx: JSContextRef, 1041 | arrayType: JSTypedArrayType, 1042 | bytes: *mut ::std::os::raw::c_void, 1043 | byteLength: size_t, 1044 | bytesDeallocator: JSTypedArrayBytesDeallocator, 1045 | deallocatorContext: *mut ::std::os::raw::c_void, 1046 | exception: *mut JSValueRef, 1047 | ) -> JSObjectRef; 1048 | pub fn JSObjectMakeTypedArrayWithArrayBuffer( 1049 | ctx: JSContextRef, 1050 | arrayType: JSTypedArrayType, 1051 | buffer: JSObjectRef, 1052 | exception: *mut JSValueRef, 1053 | ) -> JSObjectRef; 1054 | pub fn JSObjectMakeTypedArrayWithArrayBufferAndOffset( 1055 | ctx: JSContextRef, 1056 | arrayType: JSTypedArrayType, 1057 | buffer: JSObjectRef, 1058 | byteOffset: size_t, 1059 | length: size_t, 1060 | exception: *mut JSValueRef, 1061 | ) -> JSObjectRef; 1062 | /// Returns a pointer to the raw data buffer that serves as object's backing 1063 | /// store or NULL if object is not a Typed Array object. 1064 | /// 1065 | /// Note: The pointer returned by this function is temporary and is not 1066 | /// guaranteed to remain valid across JavaScriptCore API calls. 1067 | /// 1068 | /// # Parameters 1069 | /// * ctx The execution context to use. 1070 | /// * object The Typed Array object whose backing store pointer to 1071 | /// return. 1072 | /// * exception A pointer to a JSValueRef in which to store an exception, 1073 | /// if any. Pass NULL if you do not care to store an 1074 | /// exception. 1075 | pub fn JSObjectGetTypedArrayBytesPtr( 1076 | ctx: JSContextRef, 1077 | object: JSObjectRef, 1078 | exception: *mut JSValueRef, 1079 | ) -> *mut ::std::os::raw::c_void; 1080 | 1081 | /// Returns the length of the Typed Array object or 0 if the object is not a 1082 | /// Typed Array object. 1083 | /// 1084 | /// # Parameters 1085 | /// * ctx The execution context to use. 1086 | /// * object The Typed Array object whose length to return. 1087 | /// * exception A pointer to a JSValueRef in which to store an exception, 1088 | /// if any. Pass NULL if you do not care to store an 1089 | /// exception. 1090 | pub fn JSObjectGetTypedArrayLength( 1091 | ctx: JSContextRef, 1092 | object: JSObjectRef, 1093 | exception: *mut JSValueRef, 1094 | ) -> size_t; 1095 | /// Return the byte length of the Typed Array object or 0 if the object is 1096 | /// not a Typed Array object. 1097 | /// 1098 | /// # Parameters 1099 | /// 1100 | /// * ctx The execution context to use. 1101 | /// * object The Typed Array object whose byte length to return. 1102 | /// * exception A pointer to a JSValueRef in which to store an exception, 1103 | /// if any. Pass NULL if you do not care to store an 1104 | /// exception. 1105 | pub fn JSObjectGetTypedArrayByteLength( 1106 | ctx: JSContextRef, 1107 | object: JSObjectRef, 1108 | exception: *mut JSValueRef, 1109 | ) -> size_t; 1110 | pub fn JSObjectGetTypedArrayByteOffset( 1111 | ctx: JSContextRef, 1112 | object: JSObjectRef, 1113 | exception: *mut JSValueRef, 1114 | ) -> size_t; 1115 | pub fn JSObjectGetTypedArrayBuffer( 1116 | ctx: JSContextRef, 1117 | object: JSObjectRef, 1118 | exception: *mut JSValueRef, 1119 | ) -> JSObjectRef; 1120 | pub fn JSObjectMakeArrayBufferWithBytesNoCopy( 1121 | ctx: JSContextRef, 1122 | bytes: *mut ::std::os::raw::c_void, 1123 | byteLength: size_t, 1124 | bytesDeallocator: JSTypedArrayBytesDeallocator, 1125 | deallocatorContext: *mut ::std::os::raw::c_void, 1126 | exception: *mut JSValueRef, 1127 | ) -> JSObjectRef; 1128 | pub fn JSObjectGetArrayBufferBytesPtr( 1129 | ctx: JSContextRef, 1130 | object: JSObjectRef, 1131 | exception: *mut JSValueRef, 1132 | ) -> *mut ::std::os::raw::c_void; 1133 | pub fn JSObjectGetArrayBufferByteLength( 1134 | ctx: JSContextRef, 1135 | object: JSObjectRef, 1136 | exception: *mut JSValueRef, 1137 | ) -> size_t; 1138 | } 1139 | --------------------------------------------------------------------------------