├── .gitignore ├── .gitmodules ├── .travis.yml ├── Cargo.toml ├── README.md ├── duktape_sys ├── .gitignore ├── Cargo.toml ├── build.rs └── src │ ├── bindings.h │ ├── bindings.rs │ ├── generate.c │ ├── generated.rs │ ├── glue.c │ ├── glue.rs │ └── lib.rs └── src ├── context.rs ├── decoder.rs ├── encoder.rs ├── errors.rs ├── lib.rs └── types.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | /duktape_sys/src/generate 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "duktape-releases"] 2 | path = duktape_sys/duktape 3 | url = https://github.com/svaarala/duktape-releases 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | env: 3 | global: 4 | - secure: t96QPmFsQzXtmWkNR0uvPXXvb9zS/gzXILaH3whnA1wx1R81d/2x4spmYe0joZ2RU0BzIkZTsrs0cxu0aVaA3huDal78HdCmj6SpJT3ajuCFXdcDsnSWEh3mrURPfBCc32Nr6FovNi1YLJd8T5rfksH/5VSAU1GFqVjitQx+wqw= 5 | after_script: 6 | - cargo doc && mv target/doc doc 7 | - curl http://www.rust-ci.org/artifacts/put?t=$RUSTCI_TOKEN | sh 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "duktape" 4 | version = "0.0.2" 5 | authors = ["Eric Kidd "] 6 | 7 | description = "Embedded JavaScript interpreter with a small footprint" 8 | license = "Unlicense" 9 | readme = "README.md" 10 | 11 | repository = "https://github.com/emk/duktape-rs" 12 | documentation = "http://www.rust-ci.org/emk/ducktape-rs/doc/ducktape/" 13 | 14 | [dependencies] 15 | cesu8 = "*" 16 | abort_on_panic = "*" 17 | rustc-serialize = "*" 18 | log = "*" 19 | 20 | [dependencies.duktape_sys] 21 | path = "duktape_sys" 22 | version = "*" 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/emk/duktape-rs.svg)](https://travis-ci.org/emk/duktape-rs) 2 | 3 | [Documentation][apidoc]. 4 | 5 | [apidoc]: http://www.rust-ci.org/emk/duktape-rs/doc/duktape/ 6 | 7 | WORK IN PROGRESS. 8 | 9 | A Rust wrapper for [Duktape](http://duktape.org/). Things to do before 10 | this is minimally useful: 11 | 12 | - [x] Handle non-UTF-8 strings. 13 | - [x] Call JavaScript functions by name. 14 | - [x] Define functions. 15 | - [x] Call specified Rust functions from JavaScript. 16 | - [x] Return errors from Rust to JavaScript. 17 | - [ ] Convert to use `Encodable`/`Decodable` everywhere. 18 | - [x] Convert parameters to use `Encodable`. 19 | - [ ] Replace `Value` with `serialize::Json`. 20 | - [ ] Convert return values to use `Decodable`. 21 | - [ ] Add nice macros. 22 | - [ ] Provide macro for calling functions. 23 | - [ ] Provide macro for defining functions. 24 | 25 | -------------------------------------------------------------------------------- /duktape_sys/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /duktape_sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "duktape_sys" 4 | version = "0.0.2" 5 | authors = ["Eric Kidd "] 6 | links = "duktape" 7 | build = "build.rs" 8 | 9 | description = "Unsafe, low-level wrapper for duktape JavaScript interpreter" 10 | license = "MIT" 11 | 12 | repository = "https://github.com/emk/duktape-rs" 13 | 14 | # Minimize distributed package size by excluding large, unused directories. 15 | exclude = [ 16 | "duktape/examples", 17 | "duktape/src-separate" 18 | ] 19 | 20 | [build-dependencies] 21 | gcc = "*" 22 | -------------------------------------------------------------------------------- /duktape_sys/build.rs: -------------------------------------------------------------------------------- 1 | #![feature(os)] 2 | #![feature(path)] 3 | #![feature(collections)] 4 | 5 | extern crate gcc; 6 | 7 | use std::default::Default; 8 | use std::os::{getenv, setenv}; 9 | 10 | fn main() { 11 | // Make sure we get a thread-safe build. Without this, duktape refuses 12 | // to set DUK_USE_VARIADIC_MACROS and falls back to global variables. 13 | let mut cflags = getenv("CFLAGS").unwrap_or("".to_string()); 14 | cflags.push_str(" -std=c99"); 15 | setenv("CFLAGS", cflags); 16 | 17 | gcc::compile_library("libduktape.a", &gcc::Config { 18 | include_directories: vec!(Path::new("duktape/src")), 19 | .. Default::default() 20 | }, &["duktape/src/duktape.c", "src/glue.c"]); 21 | } 22 | -------------------------------------------------------------------------------- /duktape_sys/src/bindings.h: -------------------------------------------------------------------------------- 1 | // This file is based on duktape.h, with manual cleanups for bindgen 2 | // compatibility. 3 | 4 | // We need to define this if we want thread-safe APIs. 5 | #define DUK_API_VARIADIC_MACROS 6 | 7 | // Glue to make things compile. Remove the types from the generated output 8 | // manually; we have generated.rs for that. 9 | #include 10 | #include 11 | #include 12 | #define DUK_API_NORETURN(DECL) DECL; 13 | #define DUK_EXTERNAL_DECL 14 | typedef size_t duk_size_t; 15 | typedef ptrdiff_t duk_ptrdiff_t; 16 | typedef int duk_int_t; 17 | typedef unsigned int duk_uint_t; 18 | typedef double duk_double_t; 19 | typedef int duk_bool_t; 20 | typedef duk_int_t duk_idx_t; 21 | typedef duk_uint_t duk_uarridx_t; 22 | typedef int duk_ret_t; 23 | typedef duk_int_t duk_errcode_t; 24 | typedef duk_int_t duk_codepoint_t; 25 | typedef duk_uint_t duk_ucodepoint_t; 26 | typedef uint16_t duk_uint16_t; 27 | typedef int32_t duk_int32_t; 28 | typedef uint32_t duk_uint32_t; 29 | 30 | /* 31 | * Duktape public API for Duktape 1.0.2. 32 | * See the API reference for documentation on call semantics. 33 | * The exposed API is inside the DUK_API_PUBLIC_H_INCLUDED 34 | * include guard. Other parts of the header are Duktape 35 | * internal and related to platform/compiler/feature detection. 36 | * 37 | * Git commit a476318bf025137c2847c808a8334d8b7db985f2 (v1.0.2). 38 | * 39 | * See Duktape AUTHORS.rst and LICENSE.txt for copyright and 40 | * licensing information. 41 | */ 42 | 43 | /* LICENSE.txt */ 44 | /* 45 | * =============== 46 | * Duktape license 47 | * =============== 48 | * 49 | * (http://opensource.org/licenses/MIT) 50 | * 51 | * Copyright (c) 2013-2014 by Duktape authors (see AUTHORS.rst) 52 | * 53 | * Permission is hereby granted, free of charge, to any person obtaining a copy 54 | * of this software and associated documentation files (the "Software"), to deal 55 | * in the Software without restriction, including without limitation the rights 56 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 57 | * copies of the Software, and to permit persons to whom the Software is 58 | * furnished to do so, subject to the following conditions: 59 | * 60 | * The above copyright notice and this permission notice shall be included in 61 | * all copies or substantial portions of the Software. 62 | * 63 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 64 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 65 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 66 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 67 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 68 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 69 | * THE SOFTWARE. 70 | * 71 | */ 72 | 73 | /* AUTHORS.rst */ 74 | /* 75 | * =============== 76 | * Duktape authors 77 | * =============== 78 | * 79 | * Copyright 80 | * ========= 81 | * 82 | * Duktape copyrights are held by its authors. Each author has a copyright 83 | * to their contribution, and agrees to irrevocably license the contribution 84 | * under the Duktape ``LICENSE.txt``. 85 | * 86 | * Authors 87 | * ======= 88 | * 89 | * Please include an e-mail address, a link to your GitHub profile, or something 90 | * similar to allow your contribution to be identified accurately. 91 | * 92 | * The following people have contributed code and agreed to irrevocably license 93 | * their contributions under the Duktape ``LICENSE.txt`` (in order of appearance): 94 | * 95 | * * Sami Vaarala 96 | * * Niki Dobrev 97 | * * Andreas \u00d6man 98 | * 99 | * Other contributions 100 | * =================== 101 | * 102 | * The following people have contributed something other than code (e.g. reported 103 | * bugs, provided ideas, etc; in order of appearance): 104 | * 105 | * * Greg Burns 106 | * * Anthony Rabine 107 | * * Carlos Costa 108 | * * Aur\u00e9lien Bouilland 109 | * * Preet Desai (Pris Matic) 110 | * * judofyr (http://www.reddit.com/user/judofyr) 111 | * * Jason Woofenden 112 | * * Micha\u0142 Przyby\u015b 113 | * * Anthony Howe 114 | * * Conrad Pankoff 115 | * * Jim Schimpf 116 | * * Rajaran Gaunker (https://github.com/zimbabao) 117 | * * Andreas \u00d6man 118 | * * Doug Sanden 119 | * * Remo Eichenberger (https://github.com/remoe) 120 | * * David Demelier 121 | */ 122 | 123 | /* 124 | * Public API specific typedefs 125 | * 126 | * (duk_context *) maps directly to internal type (duk_hthread *). 127 | * Currently only primitive typedefs have a '_t' suffix. 128 | * 129 | * Many types are wrapped by Duktape for portability to rare platforms 130 | * where e.g. 'int' is a 16-bit type. See practical typing discussion 131 | * in Duktape web documentation. 132 | */ 133 | 134 | struct duk_memory_functions; 135 | struct duk_function_list_entry; 136 | struct duk_number_list_entry; 137 | 138 | typedef void duk_context; 139 | typedef struct duk_memory_functions duk_memory_functions; 140 | typedef struct duk_function_list_entry duk_function_list_entry; 141 | typedef struct duk_number_list_entry duk_number_list_entry; 142 | 143 | typedef duk_ret_t (*duk_c_function)(duk_context *ctx); 144 | typedef void *(*duk_alloc_function) (void *udata, duk_size_t size); 145 | typedef void *(*duk_realloc_function) (void *udata, void *ptr, duk_size_t size); 146 | typedef void (*duk_free_function) (void *udata, void *ptr); 147 | typedef void (*duk_fatal_function) (duk_context *ctx, duk_errcode_t code, const char *msg); 148 | typedef void (*duk_decode_char_function) (void *udata, duk_codepoint_t codepoint); 149 | typedef duk_codepoint_t (*duk_map_char_function) (void *udata, duk_codepoint_t codepoint); 150 | typedef duk_ret_t (*duk_safe_call_function) (duk_context *ctx); 151 | 152 | struct duk_memory_functions { 153 | duk_alloc_function alloc_func; 154 | duk_realloc_function realloc_func; 155 | duk_free_function free_func; 156 | void *udata; 157 | }; 158 | 159 | struct duk_function_list_entry { 160 | const char *key; 161 | duk_c_function value; 162 | duk_idx_t nargs; 163 | }; 164 | 165 | struct duk_number_list_entry { 166 | const char *key; 167 | duk_double_t value; 168 | }; 169 | 170 | /* 171 | * Context management 172 | */ 173 | 174 | DUK_EXTERNAL_DECL 175 | duk_context *duk_create_heap(duk_alloc_function alloc_func, 176 | duk_realloc_function realloc_func, 177 | duk_free_function free_func, 178 | void *alloc_udata, 179 | duk_fatal_function fatal_handler); 180 | DUK_EXTERNAL_DECL void duk_destroy_heap(duk_context *ctx); 181 | 182 | #define duk_create_heap_default() \ 183 | duk_create_heap(NULL, NULL, NULL, NULL, NULL) 184 | 185 | /* 186 | * Memory management 187 | * 188 | * Raw functions have no side effects (cannot trigger GC). 189 | */ 190 | 191 | DUK_EXTERNAL_DECL void *duk_alloc_raw(duk_context *ctx, duk_size_t size); 192 | DUK_EXTERNAL_DECL void duk_free_raw(duk_context *ctx, void *ptr); 193 | DUK_EXTERNAL_DECL void *duk_realloc_raw(duk_context *ctx, void *ptr, duk_size_t size); 194 | DUK_EXTERNAL_DECL void *duk_alloc(duk_context *ctx, duk_size_t size); 195 | DUK_EXTERNAL_DECL void duk_free(duk_context *ctx, void *ptr); 196 | DUK_EXTERNAL_DECL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size); 197 | DUK_EXTERNAL_DECL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs); 198 | DUK_EXTERNAL_DECL void duk_gc(duk_context *ctx, duk_uint_t flags); 199 | 200 | /* 201 | * Error handling 202 | */ 203 | 204 | DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_throw(duk_context *ctx)); 205 | 206 | DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...)); 207 | #ifdef DUK_API_VARIADIC_MACROS 208 | #define duk_error(ctx,err_code,...) \ 209 | duk_error_raw((ctx), (duk_errcode_t) (err_code), __FILE__, (duk_int_t) __LINE__, __VA_ARGS__) 210 | #else 211 | DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...)); 212 | /* One problem with this macro is that expressions like the following fail 213 | * to compile: "(void) duk_error(...)". But because duk_error() is noreturn, 214 | * they make little sense anyway. 215 | */ 216 | #define duk_error \ 217 | duk_api_global_filename = __FILE__, \ 218 | duk_api_global_line = (duk_int_t) __LINE__, \ 219 | duk_error_stash /* arguments follow */ 220 | #endif 221 | 222 | DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_fatal(duk_context *ctx, duk_errcode_t err_code, const char *err_msg)); 223 | 224 | /* 225 | * Other state related functions 226 | */ 227 | 228 | DUK_EXTERNAL_DECL duk_bool_t duk_is_strict_call(duk_context *ctx); 229 | DUK_EXTERNAL_DECL duk_bool_t duk_is_constructor_call(duk_context *ctx); 230 | 231 | /* 232 | * Stack management 233 | */ 234 | 235 | DUK_EXTERNAL_DECL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index); 236 | DUK_EXTERNAL_DECL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t index); 237 | DUK_EXTERNAL_DECL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t index); 238 | DUK_EXTERNAL_DECL void duk_require_valid_index(duk_context *ctx, duk_idx_t index); 239 | 240 | DUK_EXTERNAL_DECL duk_idx_t duk_get_top(duk_context *ctx); 241 | DUK_EXTERNAL_DECL void duk_set_top(duk_context *ctx, duk_idx_t index); 242 | DUK_EXTERNAL_DECL duk_idx_t duk_get_top_index(duk_context *ctx); 243 | DUK_EXTERNAL_DECL duk_idx_t duk_require_top_index(duk_context *ctx); 244 | 245 | /* Although extra/top could be an unsigned type here, using a signed type 246 | * makes the API more robust to calling code calculation errors or corner 247 | * cases (where caller might occasionally come up with negative values). 248 | * Negative values are treated as zero, which is better than casting them 249 | * to a large unsigned number. (This principle is used elsewhere in the 250 | * API too.) 251 | */ 252 | DUK_EXTERNAL_DECL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra); 253 | DUK_EXTERNAL_DECL void duk_require_stack(duk_context *ctx, duk_idx_t extra); 254 | DUK_EXTERNAL_DECL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top); 255 | DUK_EXTERNAL_DECL void duk_require_stack_top(duk_context *ctx, duk_idx_t top); 256 | 257 | /* 258 | * Stack manipulation (other than push/pop) 259 | */ 260 | 261 | DUK_EXTERNAL_DECL void duk_swap(duk_context *ctx, duk_idx_t index1, duk_idx_t index2); 262 | DUK_EXTERNAL_DECL void duk_swap_top(duk_context *ctx, duk_idx_t index); 263 | DUK_EXTERNAL_DECL void duk_dup(duk_context *ctx, duk_idx_t from_index); 264 | DUK_EXTERNAL_DECL void duk_dup_top(duk_context *ctx); 265 | DUK_EXTERNAL_DECL void duk_insert(duk_context *ctx, duk_idx_t to_index); 266 | DUK_EXTERNAL_DECL void duk_replace(duk_context *ctx, duk_idx_t to_index); 267 | DUK_EXTERNAL_DECL void duk_copy(duk_context *ctx, duk_idx_t from_index, duk_idx_t to_index); 268 | DUK_EXTERNAL_DECL void duk_remove(duk_context *ctx, duk_idx_t index); 269 | DUK_EXTERNAL_DECL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy); 270 | 271 | #define duk_xmove_top(to_ctx,from_ctx,count) \ 272 | duk_xcopymove_raw((to_ctx), (from_ctx), (count), 0 /*is_copy*/) 273 | #define duk_xcopy_top(to_ctx,from_ctx,count) \ 274 | duk_xcopymove_raw((to_ctx), (from_ctx), (count), 1 /*is_copy*/) 275 | 276 | /* 277 | * Push operations 278 | * 279 | * Push functions return the absolute (relative to bottom of frame) 280 | * position of the pushed value for convenience. 281 | * 282 | * Note: duk_dup() is technically a push. 283 | */ 284 | 285 | DUK_EXTERNAL_DECL void duk_push_undefined(duk_context *ctx); 286 | DUK_EXTERNAL_DECL void duk_push_null(duk_context *ctx); 287 | DUK_EXTERNAL_DECL void duk_push_boolean(duk_context *ctx, duk_bool_t val); 288 | DUK_EXTERNAL_DECL void duk_push_true(duk_context *ctx); 289 | DUK_EXTERNAL_DECL void duk_push_false(duk_context *ctx); 290 | DUK_EXTERNAL_DECL void duk_push_number(duk_context *ctx, duk_double_t val); 291 | DUK_EXTERNAL_DECL void duk_push_nan(duk_context *ctx); 292 | DUK_EXTERNAL_DECL void duk_push_int(duk_context *ctx, duk_int_t val); 293 | DUK_EXTERNAL_DECL void duk_push_uint(duk_context *ctx, duk_uint_t val); 294 | DUK_EXTERNAL_DECL const char *duk_push_string(duk_context *ctx, const char *str); 295 | DUK_EXTERNAL_DECL const char *duk_push_lstring(duk_context *ctx, const char *str, duk_size_t len); 296 | DUK_EXTERNAL_DECL void duk_push_pointer(duk_context *ctx, void *p); 297 | DUK_EXTERNAL_DECL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...); 298 | DUK_EXTERNAL_DECL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap); 299 | 300 | DUK_EXTERNAL_DECL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags); 301 | #define duk_push_string_file(ctx,path) \ 302 | duk_push_string_file_raw((ctx), (path), 0) 303 | 304 | DUK_EXTERNAL_DECL void duk_push_this(duk_context *ctx); 305 | DUK_EXTERNAL_DECL void duk_push_current_function(duk_context *ctx); 306 | DUK_EXTERNAL_DECL void duk_push_current_thread(duk_context *ctx); 307 | DUK_EXTERNAL_DECL void duk_push_global_object(duk_context *ctx); 308 | DUK_EXTERNAL_DECL void duk_push_heap_stash(duk_context *ctx); 309 | DUK_EXTERNAL_DECL void duk_push_global_stash(duk_context *ctx); 310 | DUK_EXTERNAL_DECL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx); 311 | 312 | DUK_EXTERNAL_DECL duk_idx_t duk_push_object(duk_context *ctx); 313 | DUK_EXTERNAL_DECL duk_idx_t duk_push_array(duk_context *ctx); 314 | DUK_EXTERNAL_DECL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_idx_t nargs); 315 | DUK_EXTERNAL_DECL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags); 316 | 317 | #define duk_push_thread(ctx) \ 318 | duk_push_thread_raw((ctx), 0 /*flags*/) 319 | 320 | #define duk_push_thread_new_globalenv(ctx) \ 321 | duk_push_thread_raw((ctx), DUK_THREAD_NEW_GLOBAL_ENV /*flags*/) 322 | 323 | DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...); 324 | #ifdef DUK_API_VARIADIC_MACROS 325 | #define duk_push_error_object(ctx,err_code,...) \ 326 | duk_push_error_object_raw((ctx),(err_code),__FILE__,__LINE__,__VA_ARGS__) 327 | #else 328 | DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...); 329 | #define duk_push_error_object \ 330 | duk_api_global_filename = __FILE__, \ 331 | duk_api_global_line = __LINE__, \ 332 | duk_push_error_object_stash /* arguments follow */ 333 | #endif 334 | 335 | DUK_EXTERNAL_DECL void *duk_push_buffer(duk_context *ctx, duk_size_t size, duk_bool_t dynamic); 336 | DUK_EXTERNAL_DECL void *duk_push_fixed_buffer(duk_context *ctx, duk_size_t size); 337 | DUK_EXTERNAL_DECL void *duk_push_dynamic_buffer(duk_context *ctx, duk_size_t size); 338 | 339 | /* 340 | * Pop operations 341 | */ 342 | 343 | DUK_EXTERNAL_DECL void duk_pop(duk_context *ctx); 344 | DUK_EXTERNAL_DECL void duk_pop_n(duk_context *ctx, duk_idx_t count); 345 | DUK_EXTERNAL_DECL void duk_pop_2(duk_context *ctx); 346 | DUK_EXTERNAL_DECL void duk_pop_3(duk_context *ctx); 347 | 348 | /* 349 | * Type checks 350 | * 351 | * duk_is_none(), which would indicate whether index it outside of stack, 352 | * is not needed; duk_is_valid_index() gives the same information. 353 | */ 354 | 355 | DUK_EXTERNAL_DECL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index); 356 | DUK_EXTERNAL_DECL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t index, duk_int_t type); 357 | DUK_EXTERNAL_DECL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t index); 358 | DUK_EXTERNAL_DECL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t index, duk_uint_t mask); 359 | 360 | DUK_EXTERNAL_DECL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t index); 361 | DUK_EXTERNAL_DECL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t index); 362 | DUK_EXTERNAL_DECL duk_bool_t duk_is_null_or_undefined(duk_context *ctx, duk_idx_t index); 363 | DUK_EXTERNAL_DECL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t index); 364 | DUK_EXTERNAL_DECL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t index); 365 | DUK_EXTERNAL_DECL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t index); 366 | DUK_EXTERNAL_DECL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t index); 367 | DUK_EXTERNAL_DECL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t index); 368 | DUK_EXTERNAL_DECL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t index); 369 | DUK_EXTERNAL_DECL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t index); 370 | 371 | DUK_EXTERNAL_DECL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t index); 372 | DUK_EXTERNAL_DECL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t index); 373 | DUK_EXTERNAL_DECL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t index); 374 | DUK_EXTERNAL_DECL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t index); 375 | DUK_EXTERNAL_DECL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t index); 376 | DUK_EXTERNAL_DECL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t index); 377 | 378 | DUK_EXTERNAL_DECL duk_bool_t duk_is_callable(duk_context *ctx, duk_idx_t index); 379 | DUK_EXTERNAL_DECL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index); 380 | DUK_EXTERNAL_DECL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index); 381 | 382 | DUK_EXTERNAL_DECL duk_bool_t duk_is_primitive(duk_context *ctx, duk_idx_t index); 383 | #define duk_is_object_coercible(ctx,index) \ 384 | duk_check_type_mask((ctx), (index), DUK_TYPE_MASK_BOOLEAN | \ 385 | DUK_TYPE_MASK_NUMBER | \ 386 | DUK_TYPE_MASK_STRING | \ 387 | DUK_TYPE_MASK_OBJECT | \ 388 | DUK_TYPE_MASK_BUFFER | \ 389 | DUK_TYPE_MASK_POINTER) 390 | 391 | /* 392 | * Get operations: no coercion, returns default value for invalid 393 | * indices and invalid value types. 394 | * 395 | * duk_get_undefined() and duk_get_null() would be pointless and 396 | * are not included. 397 | */ 398 | 399 | DUK_EXTERNAL_DECL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t index); 400 | DUK_EXTERNAL_DECL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t index); 401 | DUK_EXTERNAL_DECL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t index); 402 | DUK_EXTERNAL_DECL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t index); 403 | DUK_EXTERNAL_DECL const char *duk_get_string(duk_context *ctx, duk_idx_t index); 404 | DUK_EXTERNAL_DECL const char *duk_get_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len); 405 | DUK_EXTERNAL_DECL void *duk_get_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size); 406 | DUK_EXTERNAL_DECL void *duk_get_pointer(duk_context *ctx, duk_idx_t index); 407 | DUK_EXTERNAL_DECL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t index); 408 | DUK_EXTERNAL_DECL duk_context *duk_get_context(duk_context *ctx, duk_idx_t index); 409 | DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index); 410 | 411 | /* 412 | * Require operations: no coercion, throw error if index or type 413 | * is incorrect. No defaulting. 414 | */ 415 | 416 | #define duk_require_type_mask(ctx,index,mask) \ 417 | ((void) duk_check_type_mask((ctx), (index), (mask) | DUK_TYPE_MASK_THROW)) 418 | 419 | DUK_EXTERNAL_DECL void duk_require_undefined(duk_context *ctx, duk_idx_t index); 420 | DUK_EXTERNAL_DECL void duk_require_null(duk_context *ctx, duk_idx_t index); 421 | DUK_EXTERNAL_DECL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t index); 422 | DUK_EXTERNAL_DECL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t index); 423 | DUK_EXTERNAL_DECL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t index); 424 | DUK_EXTERNAL_DECL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t index); 425 | DUK_EXTERNAL_DECL const char *duk_require_string(duk_context *ctx, duk_idx_t index); 426 | DUK_EXTERNAL_DECL const char *duk_require_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len); 427 | DUK_EXTERNAL_DECL void *duk_require_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size); 428 | DUK_EXTERNAL_DECL void *duk_require_pointer(duk_context *ctx, duk_idx_t index); 429 | DUK_EXTERNAL_DECL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t index); 430 | DUK_EXTERNAL_DECL duk_context *duk_require_context(duk_context *ctx, duk_idx_t index); 431 | 432 | #define duk_require_object_coercible(ctx,index) \ 433 | ((void) duk_check_type_mask((ctx), (index), DUK_TYPE_MASK_BOOLEAN | \ 434 | DUK_TYPE_MASK_NUMBER | \ 435 | DUK_TYPE_MASK_STRING | \ 436 | DUK_TYPE_MASK_OBJECT | \ 437 | DUK_TYPE_MASK_BUFFER | \ 438 | DUK_TYPE_MASK_POINTER | \ 439 | DUK_TYPE_MASK_THROW)) 440 | 441 | /* 442 | * Coercion operations: in-place coercion, return coerced value where 443 | * applicable. If index is invalid, throw error. Some coercions may 444 | * throw an expected error (e.g. from a toString() or valueOf() call) 445 | * or an internal error (e.g. from out of memory). 446 | */ 447 | 448 | DUK_EXTERNAL_DECL void duk_to_undefined(duk_context *ctx, duk_idx_t index); 449 | DUK_EXTERNAL_DECL void duk_to_null(duk_context *ctx, duk_idx_t index); 450 | DUK_EXTERNAL_DECL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t index); 451 | DUK_EXTERNAL_DECL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t index); 452 | DUK_EXTERNAL_DECL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t index); 453 | DUK_EXTERNAL_DECL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t index); 454 | DUK_EXTERNAL_DECL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t index); 455 | DUK_EXTERNAL_DECL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t index); 456 | DUK_EXTERNAL_DECL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t index); 457 | DUK_EXTERNAL_DECL const char *duk_to_string(duk_context *ctx, duk_idx_t index); 458 | DUK_EXTERNAL_DECL const char *duk_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len); 459 | DUK_EXTERNAL_DECL void *duk_to_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size); 460 | DUK_EXTERNAL_DECL void *duk_to_fixed_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size); 461 | DUK_EXTERNAL_DECL void *duk_to_dynamic_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size); 462 | DUK_EXTERNAL_DECL void *duk_to_pointer(duk_context *ctx, duk_idx_t index); 463 | DUK_EXTERNAL_DECL void duk_to_object(duk_context *ctx, duk_idx_t index); 464 | DUK_EXTERNAL_DECL void duk_to_defaultvalue(duk_context *ctx, duk_idx_t index, duk_int_t hint); 465 | DUK_EXTERNAL_DECL void duk_to_primitive(duk_context *ctx, duk_idx_t index, duk_int_t hint); 466 | 467 | /* safe variants of a few coercion operations */ 468 | DUK_EXTERNAL_DECL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len); 469 | #define duk_safe_to_string(ctx,index) \ 470 | duk_safe_to_lstring((ctx), (index), NULL) 471 | 472 | /* 473 | * Misc conversion 474 | */ 475 | 476 | DUK_EXTERNAL_DECL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index); 477 | DUK_EXTERNAL_DECL void duk_base64_decode(duk_context *ctx, duk_idx_t index); 478 | DUK_EXTERNAL_DECL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index); 479 | DUK_EXTERNAL_DECL void duk_hex_decode(duk_context *ctx, duk_idx_t index); 480 | DUK_EXTERNAL_DECL const char *duk_json_encode(duk_context *ctx, duk_idx_t index); 481 | DUK_EXTERNAL_DECL void duk_json_decode(duk_context *ctx, duk_idx_t index); 482 | 483 | /* 484 | * Buffer 485 | */ 486 | 487 | DUK_EXTERNAL_DECL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size_t new_size); 488 | 489 | /* 490 | * Property access 491 | * 492 | * The basic function assumes key is on stack. The _string variant takes 493 | * a C string as a property name, while the _index variant takes an array 494 | * index as a property name (e.g. 123 is equivalent to the key "123"). 495 | */ 496 | 497 | DUK_EXTERNAL_DECL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_index); 498 | DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key); 499 | DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index); 500 | DUK_EXTERNAL_DECL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_index); 501 | DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key); 502 | DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index); 503 | DUK_EXTERNAL_DECL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_index); 504 | DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key); 505 | DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index); 506 | DUK_EXTERNAL_DECL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_index); 507 | DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key); 508 | DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index); 509 | 510 | DUK_EXTERNAL_DECL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key); 511 | DUK_EXTERNAL_DECL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key); 512 | 513 | /* 514 | * Object prototype 515 | */ 516 | 517 | DUK_EXTERNAL_DECL void duk_get_prototype(duk_context *ctx, duk_idx_t index); 518 | DUK_EXTERNAL_DECL void duk_set_prototype(duk_context *ctx, duk_idx_t index); 519 | 520 | /* 521 | * Object finalizer 522 | */ 523 | 524 | DUK_EXTERNAL_DECL void duk_get_finalizer(duk_context *ctx, duk_idx_t index); 525 | DUK_EXTERNAL_DECL void duk_set_finalizer(duk_context *ctx, duk_idx_t index); 526 | 527 | /* 528 | * Global object 529 | */ 530 | 531 | DUK_EXTERNAL_DECL void duk_set_global_object(duk_context *ctx); 532 | 533 | /* 534 | * Duktape/C function magic value 535 | */ 536 | 537 | DUK_EXTERNAL_DECL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index); 538 | DUK_EXTERNAL_DECL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t magic); 539 | DUK_EXTERNAL_DECL duk_int_t duk_get_current_magic(duk_context *ctx); 540 | 541 | /* 542 | * Module helpers: put multiple function or constant properties 543 | */ 544 | 545 | DUK_EXTERNAL_DECL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_index, const duk_function_list_entry *funcs); 546 | DUK_EXTERNAL_DECL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_index, const duk_number_list_entry *numbers); 547 | 548 | /* 549 | * Variable access 550 | */ 551 | 552 | /* XXX: These calls are incomplete and not usable now. They are not (yet) 553 | * part of the public API. 554 | */ 555 | DUK_EXTERNAL_DECL void duk_get_var(duk_context *ctx); 556 | DUK_EXTERNAL_DECL void duk_put_var(duk_context *ctx); 557 | DUK_EXTERNAL_DECL duk_bool_t duk_del_var(duk_context *ctx); 558 | DUK_EXTERNAL_DECL duk_bool_t duk_has_var(duk_context *ctx); 559 | 560 | /* 561 | * Object operations 562 | */ 563 | 564 | DUK_EXTERNAL_DECL void duk_compact(duk_context *ctx, duk_idx_t obj_index); 565 | DUK_EXTERNAL_DECL void duk_enum(duk_context *ctx, duk_idx_t obj_index, duk_uint_t enum_flags); 566 | DUK_EXTERNAL_DECL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, duk_bool_t get_value); 567 | 568 | /* 569 | * String manipulation 570 | */ 571 | 572 | DUK_EXTERNAL_DECL void duk_concat(duk_context *ctx, duk_idx_t count); 573 | DUK_EXTERNAL_DECL void duk_join(duk_context *ctx, duk_idx_t count); 574 | DUK_EXTERNAL_DECL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decode_char_function callback, void *udata); 575 | DUK_EXTERNAL_DECL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char_function callback, void *udata); 576 | DUK_EXTERNAL_DECL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t start_char_offset, duk_size_t end_char_offset); 577 | DUK_EXTERNAL_DECL void duk_trim(duk_context *ctx, duk_idx_t index); 578 | DUK_EXTERNAL_DECL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t index, duk_size_t char_offset); 579 | 580 | /* 581 | * Ecmascript operators 582 | */ 583 | 584 | DUK_EXTERNAL_DECL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2); 585 | DUK_EXTERNAL_DECL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2); 586 | 587 | /* 588 | * Function (method) calls 589 | */ 590 | 591 | DUK_EXTERNAL_DECL void duk_call(duk_context *ctx, duk_idx_t nargs); 592 | DUK_EXTERNAL_DECL void duk_call_method(duk_context *ctx, duk_idx_t nargs); 593 | DUK_EXTERNAL_DECL void duk_call_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs); 594 | DUK_EXTERNAL_DECL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs); 595 | DUK_EXTERNAL_DECL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs); 596 | DUK_EXTERNAL_DECL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs); 597 | DUK_EXTERNAL_DECL void duk_new(duk_context *ctx, duk_idx_t nargs); 598 | DUK_EXTERNAL_DECL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets); 599 | 600 | /* 601 | * Thread management 602 | */ 603 | 604 | /* There are currently no native functions to yield/resume, due to the internal 605 | * limitations on coroutine handling. These will be added later. 606 | */ 607 | 608 | /* 609 | * Compilation and evaluation 610 | */ 611 | 612 | DUK_EXTERNAL_DECL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags); 613 | DUK_EXTERNAL_DECL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags); 614 | 615 | /* plain */ 616 | #define duk_eval(ctx) \ 617 | ((void) duk_push_string((ctx), __FILE__), \ 618 | (void) duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL)) 619 | 620 | #define duk_eval_noresult(ctx) \ 621 | ((void) duk_push_string((ctx), __FILE__), \ 622 | (void) duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL | DUK_COMPILE_NORESULT)) 623 | 624 | #define duk_peval(ctx) \ 625 | ((void) duk_push_string((ctx), __FILE__), \ 626 | duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL | DUK_COMPILE_SAFE)) 627 | 628 | #define duk_peval_noresult(ctx) \ 629 | ((void) duk_push_string((ctx), __FILE__), \ 630 | duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NORESULT)) 631 | 632 | #define duk_compile(ctx,flags) \ 633 | ((void) duk_compile_raw((ctx), NULL, 0, (flags))) 634 | 635 | #define duk_pcompile(ctx,flags) \ 636 | (duk_compile_raw((ctx), NULL, 0, (flags) | DUK_COMPILE_SAFE)) 637 | 638 | /* string */ 639 | #define duk_eval_string(ctx,src) \ 640 | ((void) duk_push_string((ctx), __FILE__), \ 641 | (void) duk_eval_raw((ctx), (src), 0, DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) 642 | 643 | #define duk_eval_string_noresult(ctx,src) \ 644 | ((void) duk_push_string((ctx), __FILE__), \ 645 | (void) duk_eval_raw((ctx), (src), 0, DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT)) 646 | 647 | #define duk_peval_string(ctx,src) \ 648 | ((void) duk_push_string((ctx), __FILE__), \ 649 | duk_eval_raw((ctx), (src), 0, DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) 650 | 651 | #define duk_peval_string_noresult(ctx,src) \ 652 | ((void) duk_push_string((ctx), __FILE__), \ 653 | duk_eval_raw((ctx), (src), 0, DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT)) 654 | 655 | #define duk_compile_string(ctx,flags,src) \ 656 | ((void) duk_push_string((ctx), __FILE__), \ 657 | (void) duk_compile_raw((ctx), (src), 0, (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) 658 | 659 | #define duk_compile_string_filename(ctx,flags,src) \ 660 | ((void) duk_compile_raw((ctx), (src), 0, (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) 661 | 662 | #define duk_pcompile_string(ctx,flags,src) \ 663 | ((void) duk_push_string((ctx), __FILE__), \ 664 | duk_compile_raw((ctx), (src), 0, (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) 665 | 666 | #define duk_pcompile_string_filename(ctx,flags,src) \ 667 | (duk_compile_raw((ctx), (src), 0, (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) 668 | 669 | /* lstring */ 670 | #define duk_eval_lstring(ctx,buf,len) \ 671 | ((void) duk_push_string((ctx), __FILE__), \ 672 | (void) duk_eval_raw((ctx), buf, len, DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE)) 673 | 674 | #define duk_eval_lstring_noresult(ctx,buf,len) \ 675 | ((void) duk_push_string((ctx), __FILE__), \ 676 | (void) duk_eval_raw((ctx), buf, len, DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT)) 677 | 678 | #define duk_peval_lstring(ctx,buf,len) \ 679 | ((void) duk_push_string((ctx), __FILE__), \ 680 | duk_eval_raw((ctx), buf, len, DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_SAFE)) 681 | 682 | #define duk_peval_lstring_noresult(ctx,buf,len) \ 683 | ((void) duk_push_string((ctx), __FILE__), \ 684 | duk_eval_raw((ctx), buf, len, DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT)) 685 | 686 | #define duk_compile_lstring(ctx,flags,buf,len) \ 687 | ((void) duk_push_string((ctx), __FILE__), \ 688 | (void) duk_compile_raw((ctx), buf, len, (flags) | DUK_COMPILE_NOSOURCE)) 689 | 690 | #define duk_compile_lstring_filename(ctx,flags,buf,len) \ 691 | ((void) duk_compile_raw((ctx), buf, len, (flags) | DUK_COMPILE_NOSOURCE)) 692 | 693 | #define duk_pcompile_lstring(ctx,flags,buf,len) \ 694 | ((void) duk_push_string((ctx), __FILE__), \ 695 | duk_compile_raw((ctx), buf, len, (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE)) 696 | 697 | #define duk_pcompile_lstring_filename(ctx,flags,buf,len) \ 698 | (duk_compile_raw((ctx), buf, len, (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE)) 699 | 700 | /* file */ 701 | #define duk_eval_file(ctx,path) \ 702 | ((void) duk_push_string_file_raw((ctx), (path), 0), \ 703 | (void) duk_push_string((ctx), (path)), \ 704 | (void) duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL)) 705 | 706 | #define duk_eval_file_noresult(ctx,path) \ 707 | ((void) duk_push_string_file_raw((ctx), (path), 0), \ 708 | (void) duk_push_string((ctx), (path)), \ 709 | (void) duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL | DUK_COMPILE_NORESULT)) 710 | 711 | #define duk_peval_file(ctx,path) \ 712 | ((void) duk_push_string_file_raw((ctx), (path), DUK_STRING_PUSH_SAFE), \ 713 | (void) duk_push_string((ctx), (path)), \ 714 | duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL | DUK_COMPILE_SAFE)) 715 | 716 | #define duk_peval_file_noresult(ctx,path) \ 717 | ((void) duk_push_string_file_raw((ctx), (path), DUK_STRING_PUSH_SAFE), \ 718 | (void) duk_push_string((ctx), (path)), \ 719 | duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NORESULT)) 720 | 721 | #define duk_compile_file(ctx,flags,path) \ 722 | ((void) duk_push_string_file_raw((ctx), (path), 0), \ 723 | (void) duk_push_string((ctx), (path)), \ 724 | (void) duk_compile_raw((ctx), NULL, 0, (flags))) 725 | 726 | #define duk_pcompile_file(ctx,flags,path) \ 727 | ((void) duk_push_string_file_raw((ctx), (path), DUK_STRING_PUSH_SAFE), \ 728 | (void) duk_push_string((ctx), (path)), \ 729 | duk_compile_raw((ctx), NULL, 0, (flags) | DUK_COMPILE_SAFE)) 730 | 731 | /* 732 | * Logging 733 | */ 734 | 735 | DUK_EXTERNAL_DECL void duk_log(duk_context *ctx, duk_int_t level, const char *fmt, ...); 736 | 737 | /* 738 | * Debugging 739 | */ 740 | 741 | DUK_EXTERNAL_DECL void duk_push_context_dump(duk_context *ctx); 742 | -------------------------------------------------------------------------------- /duktape_sys/src/bindings.rs: -------------------------------------------------------------------------------- 1 | /* Automatically generated by rust-bindgen, and tweaked by hand. */ 2 | 3 | // We might be able to add derive(Copy) if it proves necessary. 4 | #![allow(missing_copy_implementations)] 5 | 6 | // Import more accurate versions of our typedefs. 7 | use generated::*; 8 | 9 | // Everything from here down is from bindgen, with uses of va_list 10 | // commented out, and `extern "C"` replaced by `unsafe extern "C"`. 11 | pub type duk_context = ::libc::c_void; 12 | pub type duk_memory_functions = Struct_duk_memory_functions; 13 | pub type duk_function_list_entry = Struct_duk_function_list_entry; 14 | pub type duk_number_list_entry = Struct_duk_number_list_entry; 15 | pub type duk_c_function = 16 | ::std::option::Option duk_ret_t>; 17 | pub type duk_alloc_function = 18 | ::std::option::Option *mut ::libc::c_void>; 21 | pub type duk_realloc_function = 22 | ::std::option::Option *mut ::libc::c_void>; 26 | pub type duk_free_function = 27 | ::std::option::Option; 30 | pub type duk_fatal_function = 31 | ::std::option::Option; 34 | pub type duk_decode_char_function = 35 | ::std::option::Option; 38 | pub type duk_map_char_function = 39 | ::std::option::Option duk_codepoint_t>; 42 | pub type duk_safe_call_function = 43 | ::std::option::Option duk_ret_t>; 44 | #[repr(C)] 45 | pub struct Struct_duk_memory_functions { 46 | pub alloc_func: duk_alloc_function, 47 | pub realloc_func: duk_realloc_function, 48 | pub free_func: duk_free_function, 49 | pub udata: *mut ::libc::c_void, 50 | } 51 | #[repr(C)] 52 | pub struct Struct_duk_function_list_entry { 53 | pub key: *const ::libc::c_char, 54 | pub value: duk_c_function, 55 | pub nargs: duk_idx_t, 56 | } 57 | #[repr(C)] 58 | pub struct Struct_duk_number_list_entry { 59 | pub key: *const ::libc::c_char, 60 | pub value: duk_double_t, 61 | } 62 | extern "C" { } 63 | extern "C" { 64 | pub fn duk_create_heap(alloc_func: duk_alloc_function, 65 | realloc_func: duk_realloc_function, 66 | free_func: duk_free_function, 67 | alloc_udata: *mut ::libc::c_void, 68 | fatal_handler: duk_fatal_function) 69 | -> *mut duk_context; 70 | pub fn duk_destroy_heap(ctx: *mut duk_context); 71 | pub fn duk_alloc_raw(ctx: *mut duk_context, size: duk_size_t) 72 | -> *mut ::libc::c_void; 73 | pub fn duk_free_raw(ctx: *mut duk_context, ptr: *mut ::libc::c_void); 74 | pub fn duk_realloc_raw(ctx: *mut duk_context, ptr: *mut ::libc::c_void, 75 | size: duk_size_t) -> *mut ::libc::c_void; 76 | pub fn duk_alloc(ctx: *mut duk_context, size: duk_size_t) 77 | -> *mut ::libc::c_void; 78 | pub fn duk_free(ctx: *mut duk_context, ptr: *mut ::libc::c_void); 79 | pub fn duk_realloc(ctx: *mut duk_context, ptr: *mut ::libc::c_void, 80 | size: duk_size_t) -> *mut ::libc::c_void; 81 | pub fn duk_get_memory_functions(ctx: *mut duk_context, 82 | out_funcs: *mut duk_memory_functions); 83 | pub fn duk_gc(ctx: *mut duk_context, flags: duk_uint_t); 84 | pub fn duk_throw(ctx: *mut duk_context); 85 | pub fn duk_error_raw(ctx: *mut duk_context, err_code: duk_errcode_t, 86 | filename: *const ::libc::c_char, line: duk_int_t, 87 | fmt: *const ::libc::c_char, ...); 88 | pub fn duk_fatal(ctx: *mut duk_context, err_code: duk_errcode_t, 89 | err_msg: *const ::libc::c_char); 90 | pub fn duk_is_strict_call(ctx: *mut duk_context) -> duk_bool_t; 91 | pub fn duk_is_constructor_call(ctx: *mut duk_context) -> duk_bool_t; 92 | pub fn duk_normalize_index(ctx: *mut duk_context, index: duk_idx_t) 93 | -> duk_idx_t; 94 | pub fn duk_require_normalize_index(ctx: *mut duk_context, 95 | index: duk_idx_t) -> duk_idx_t; 96 | pub fn duk_is_valid_index(ctx: *mut duk_context, index: duk_idx_t) 97 | -> duk_bool_t; 98 | pub fn duk_require_valid_index(ctx: *mut duk_context, index: duk_idx_t); 99 | pub fn duk_get_top(ctx: *mut duk_context) -> duk_idx_t; 100 | pub fn duk_set_top(ctx: *mut duk_context, index: duk_idx_t); 101 | pub fn duk_get_top_index(ctx: *mut duk_context) -> duk_idx_t; 102 | pub fn duk_require_top_index(ctx: *mut duk_context) -> duk_idx_t; 103 | pub fn duk_check_stack(ctx: *mut duk_context, extra: duk_idx_t) 104 | -> duk_bool_t; 105 | pub fn duk_require_stack(ctx: *mut duk_context, extra: duk_idx_t); 106 | pub fn duk_check_stack_top(ctx: *mut duk_context, top: duk_idx_t) 107 | -> duk_bool_t; 108 | pub fn duk_require_stack_top(ctx: *mut duk_context, top: duk_idx_t); 109 | pub fn duk_swap(ctx: *mut duk_context, index1: duk_idx_t, 110 | index2: duk_idx_t); 111 | pub fn duk_swap_top(ctx: *mut duk_context, index: duk_idx_t); 112 | pub fn duk_dup(ctx: *mut duk_context, from_index: duk_idx_t); 113 | pub fn duk_dup_top(ctx: *mut duk_context); 114 | pub fn duk_insert(ctx: *mut duk_context, to_index: duk_idx_t); 115 | pub fn duk_replace(ctx: *mut duk_context, to_index: duk_idx_t); 116 | pub fn duk_copy(ctx: *mut duk_context, from_index: duk_idx_t, 117 | to_index: duk_idx_t); 118 | pub fn duk_remove(ctx: *mut duk_context, index: duk_idx_t); 119 | pub fn duk_xcopymove_raw(to_ctx: *mut duk_context, 120 | from_ctx: *mut duk_context, count: duk_idx_t, 121 | is_copy: duk_bool_t); 122 | pub fn duk_push_undefined(ctx: *mut duk_context); 123 | pub fn duk_push_null(ctx: *mut duk_context); 124 | pub fn duk_push_boolean(ctx: *mut duk_context, val: duk_bool_t); 125 | pub fn duk_push_true(ctx: *mut duk_context); 126 | pub fn duk_push_false(ctx: *mut duk_context); 127 | pub fn duk_push_number(ctx: *mut duk_context, val: duk_double_t); 128 | pub fn duk_push_nan(ctx: *mut duk_context); 129 | pub fn duk_push_int(ctx: *mut duk_context, val: duk_int_t); 130 | pub fn duk_push_uint(ctx: *mut duk_context, val: duk_uint_t); 131 | pub fn duk_push_string(ctx: *mut duk_context, str: *const ::libc::c_char) 132 | -> *const ::libc::c_char; 133 | pub fn duk_push_lstring(ctx: *mut duk_context, str: *const ::libc::c_char, 134 | len: duk_size_t) -> *const ::libc::c_char; 135 | pub fn duk_push_pointer(ctx: *mut duk_context, p: *mut ::libc::c_void); 136 | pub fn duk_push_sprintf(ctx: *mut duk_context, 137 | fmt: *const ::libc::c_char, ...) 138 | -> *const ::libc::c_char; 139 | //pub fn duk_push_vsprintf(ctx: *mut duk_context, 140 | // fmt: *const ::libc::c_char, ap: va_list) 141 | // -> *const ::libc::c_char; 142 | pub fn duk_push_string_file_raw(ctx: *mut duk_context, 143 | path: *const ::libc::c_char, 144 | flags: duk_uint_t) 145 | -> *const ::libc::c_char; 146 | pub fn duk_push_this(ctx: *mut duk_context); 147 | pub fn duk_push_current_function(ctx: *mut duk_context); 148 | pub fn duk_push_current_thread(ctx: *mut duk_context); 149 | pub fn duk_push_global_object(ctx: *mut duk_context); 150 | pub fn duk_push_heap_stash(ctx: *mut duk_context); 151 | pub fn duk_push_global_stash(ctx: *mut duk_context); 152 | pub fn duk_push_thread_stash(ctx: *mut duk_context, 153 | target_ctx: *mut duk_context); 154 | pub fn duk_push_object(ctx: *mut duk_context) -> duk_idx_t; 155 | pub fn duk_push_array(ctx: *mut duk_context) -> duk_idx_t; 156 | pub fn duk_push_c_function(ctx: *mut duk_context, func: duk_c_function, 157 | nargs: duk_idx_t) -> duk_idx_t; 158 | pub fn duk_push_thread_raw(ctx: *mut duk_context, flags: duk_uint_t) 159 | -> duk_idx_t; 160 | pub fn duk_push_error_object_raw(ctx: *mut duk_context, 161 | err_code: duk_errcode_t, 162 | filename: *const ::libc::c_char, 163 | line: duk_int_t, 164 | fmt: *const ::libc::c_char, ...) 165 | -> duk_idx_t; 166 | pub fn duk_push_buffer(ctx: *mut duk_context, size: duk_size_t, 167 | dynamic: duk_bool_t) -> *mut ::libc::c_void; 168 | pub fn duk_push_fixed_buffer(ctx: *mut duk_context, size: duk_size_t) 169 | -> *mut ::libc::c_void; 170 | pub fn duk_push_dynamic_buffer(ctx: *mut duk_context, size: duk_size_t) 171 | -> *mut ::libc::c_void; 172 | pub fn duk_pop(ctx: *mut duk_context); 173 | pub fn duk_pop_n(ctx: *mut duk_context, count: duk_idx_t); 174 | pub fn duk_pop_2(ctx: *mut duk_context); 175 | pub fn duk_pop_3(ctx: *mut duk_context); 176 | pub fn duk_get_type(ctx: *mut duk_context, index: duk_idx_t) -> duk_int_t; 177 | pub fn duk_check_type(ctx: *mut duk_context, index: duk_idx_t, 178 | _type: duk_int_t) -> duk_bool_t; 179 | pub fn duk_get_type_mask(ctx: *mut duk_context, index: duk_idx_t) 180 | -> duk_uint_t; 181 | pub fn duk_check_type_mask(ctx: *mut duk_context, index: duk_idx_t, 182 | mask: duk_uint_t) -> duk_bool_t; 183 | pub fn duk_is_undefined(ctx: *mut duk_context, index: duk_idx_t) 184 | -> duk_bool_t; 185 | pub fn duk_is_null(ctx: *mut duk_context, index: duk_idx_t) -> duk_bool_t; 186 | pub fn duk_is_null_or_undefined(ctx: *mut duk_context, index: duk_idx_t) 187 | -> duk_bool_t; 188 | pub fn duk_is_boolean(ctx: *mut duk_context, index: duk_idx_t) 189 | -> duk_bool_t; 190 | pub fn duk_is_number(ctx: *mut duk_context, index: duk_idx_t) 191 | -> duk_bool_t; 192 | pub fn duk_is_nan(ctx: *mut duk_context, index: duk_idx_t) -> duk_bool_t; 193 | pub fn duk_is_string(ctx: *mut duk_context, index: duk_idx_t) 194 | -> duk_bool_t; 195 | pub fn duk_is_object(ctx: *mut duk_context, index: duk_idx_t) 196 | -> duk_bool_t; 197 | pub fn duk_is_buffer(ctx: *mut duk_context, index: duk_idx_t) 198 | -> duk_bool_t; 199 | pub fn duk_is_pointer(ctx: *mut duk_context, index: duk_idx_t) 200 | -> duk_bool_t; 201 | pub fn duk_is_array(ctx: *mut duk_context, index: duk_idx_t) 202 | -> duk_bool_t; 203 | pub fn duk_is_function(ctx: *mut duk_context, index: duk_idx_t) 204 | -> duk_bool_t; 205 | pub fn duk_is_c_function(ctx: *mut duk_context, index: duk_idx_t) 206 | -> duk_bool_t; 207 | pub fn duk_is_ecmascript_function(ctx: *mut duk_context, index: duk_idx_t) 208 | -> duk_bool_t; 209 | pub fn duk_is_bound_function(ctx: *mut duk_context, index: duk_idx_t) 210 | -> duk_bool_t; 211 | pub fn duk_is_thread(ctx: *mut duk_context, index: duk_idx_t) 212 | -> duk_bool_t; 213 | pub fn duk_is_callable(ctx: *mut duk_context, index: duk_idx_t) 214 | -> duk_bool_t; 215 | pub fn duk_is_dynamic_buffer(ctx: *mut duk_context, index: duk_idx_t) 216 | -> duk_bool_t; 217 | pub fn duk_is_fixed_buffer(ctx: *mut duk_context, index: duk_idx_t) 218 | -> duk_bool_t; 219 | pub fn duk_is_primitive(ctx: *mut duk_context, index: duk_idx_t) 220 | -> duk_bool_t; 221 | pub fn duk_get_boolean(ctx: *mut duk_context, index: duk_idx_t) 222 | -> duk_bool_t; 223 | pub fn duk_get_number(ctx: *mut duk_context, index: duk_idx_t) 224 | -> duk_double_t; 225 | pub fn duk_get_int(ctx: *mut duk_context, index: duk_idx_t) -> duk_int_t; 226 | pub fn duk_get_uint(ctx: *mut duk_context, index: duk_idx_t) 227 | -> duk_uint_t; 228 | pub fn duk_get_string(ctx: *mut duk_context, index: duk_idx_t) 229 | -> *const ::libc::c_char; 230 | pub fn duk_get_lstring(ctx: *mut duk_context, index: duk_idx_t, 231 | out_len: *mut duk_size_t) -> *const ::libc::c_char; 232 | pub fn duk_get_buffer(ctx: *mut duk_context, index: duk_idx_t, 233 | out_size: *mut duk_size_t) -> *mut ::libc::c_void; 234 | pub fn duk_get_pointer(ctx: *mut duk_context, index: duk_idx_t) 235 | -> *mut ::libc::c_void; 236 | pub fn duk_get_c_function(ctx: *mut duk_context, index: duk_idx_t) 237 | -> duk_c_function; 238 | pub fn duk_get_context(ctx: *mut duk_context, index: duk_idx_t) 239 | -> *mut duk_context; 240 | pub fn duk_get_length(ctx: *mut duk_context, index: duk_idx_t) 241 | -> duk_size_t; 242 | pub fn duk_require_undefined(ctx: *mut duk_context, index: duk_idx_t); 243 | pub fn duk_require_null(ctx: *mut duk_context, index: duk_idx_t); 244 | pub fn duk_require_boolean(ctx: *mut duk_context, index: duk_idx_t) 245 | -> duk_bool_t; 246 | pub fn duk_require_number(ctx: *mut duk_context, index: duk_idx_t) 247 | -> duk_double_t; 248 | pub fn duk_require_int(ctx: *mut duk_context, index: duk_idx_t) 249 | -> duk_int_t; 250 | pub fn duk_require_uint(ctx: *mut duk_context, index: duk_idx_t) 251 | -> duk_uint_t; 252 | pub fn duk_require_string(ctx: *mut duk_context, index: duk_idx_t) 253 | -> *const ::libc::c_char; 254 | pub fn duk_require_lstring(ctx: *mut duk_context, index: duk_idx_t, 255 | out_len: *mut duk_size_t) 256 | -> *const ::libc::c_char; 257 | pub fn duk_require_buffer(ctx: *mut duk_context, index: duk_idx_t, 258 | out_size: *mut duk_size_t) 259 | -> *mut ::libc::c_void; 260 | pub fn duk_require_pointer(ctx: *mut duk_context, index: duk_idx_t) 261 | -> *mut ::libc::c_void; 262 | pub fn duk_require_c_function(ctx: *mut duk_context, index: duk_idx_t) 263 | -> duk_c_function; 264 | pub fn duk_require_context(ctx: *mut duk_context, index: duk_idx_t) 265 | -> *mut duk_context; 266 | pub fn duk_to_undefined(ctx: *mut duk_context, index: duk_idx_t); 267 | pub fn duk_to_null(ctx: *mut duk_context, index: duk_idx_t); 268 | pub fn duk_to_boolean(ctx: *mut duk_context, index: duk_idx_t) 269 | -> duk_bool_t; 270 | pub fn duk_to_number(ctx: *mut duk_context, index: duk_idx_t) 271 | -> duk_double_t; 272 | pub fn duk_to_int(ctx: *mut duk_context, index: duk_idx_t) -> duk_int_t; 273 | pub fn duk_to_uint(ctx: *mut duk_context, index: duk_idx_t) -> duk_uint_t; 274 | pub fn duk_to_int32(ctx: *mut duk_context, index: duk_idx_t) 275 | -> duk_int32_t; 276 | pub fn duk_to_uint32(ctx: *mut duk_context, index: duk_idx_t) 277 | -> duk_uint32_t; 278 | pub fn duk_to_uint16(ctx: *mut duk_context, index: duk_idx_t) 279 | -> duk_uint16_t; 280 | pub fn duk_to_string(ctx: *mut duk_context, index: duk_idx_t) 281 | -> *const ::libc::c_char; 282 | pub fn duk_to_lstring(ctx: *mut duk_context, index: duk_idx_t, 283 | out_len: *mut duk_size_t) -> *const ::libc::c_char; 284 | pub fn duk_to_buffer(ctx: *mut duk_context, index: duk_idx_t, 285 | out_size: *mut duk_size_t) -> *mut ::libc::c_void; 286 | pub fn duk_to_fixed_buffer(ctx: *mut duk_context, index: duk_idx_t, 287 | out_size: *mut duk_size_t) 288 | -> *mut ::libc::c_void; 289 | pub fn duk_to_dynamic_buffer(ctx: *mut duk_context, index: duk_idx_t, 290 | out_size: *mut duk_size_t) 291 | -> *mut ::libc::c_void; 292 | pub fn duk_to_pointer(ctx: *mut duk_context, index: duk_idx_t) 293 | -> *mut ::libc::c_void; 294 | pub fn duk_to_object(ctx: *mut duk_context, index: duk_idx_t); 295 | pub fn duk_to_defaultvalue(ctx: *mut duk_context, index: duk_idx_t, 296 | hint: duk_int_t); 297 | pub fn duk_to_primitive(ctx: *mut duk_context, index: duk_idx_t, 298 | hint: duk_int_t); 299 | pub fn duk_safe_to_lstring(ctx: *mut duk_context, index: duk_idx_t, 300 | out_len: *mut duk_size_t) 301 | -> *const ::libc::c_char; 302 | pub fn duk_base64_encode(ctx: *mut duk_context, index: duk_idx_t) 303 | -> *const ::libc::c_char; 304 | pub fn duk_base64_decode(ctx: *mut duk_context, index: duk_idx_t); 305 | pub fn duk_hex_encode(ctx: *mut duk_context, index: duk_idx_t) 306 | -> *const ::libc::c_char; 307 | pub fn duk_hex_decode(ctx: *mut duk_context, index: duk_idx_t); 308 | pub fn duk_json_encode(ctx: *mut duk_context, index: duk_idx_t) 309 | -> *const ::libc::c_char; 310 | pub fn duk_json_decode(ctx: *mut duk_context, index: duk_idx_t); 311 | pub fn duk_resize_buffer(ctx: *mut duk_context, index: duk_idx_t, 312 | new_size: duk_size_t) -> *mut ::libc::c_void; 313 | pub fn duk_get_prop(ctx: *mut duk_context, obj_index: duk_idx_t) 314 | -> duk_bool_t; 315 | pub fn duk_get_prop_string(ctx: *mut duk_context, obj_index: duk_idx_t, 316 | key: *const ::libc::c_char) -> duk_bool_t; 317 | pub fn duk_get_prop_index(ctx: *mut duk_context, obj_index: duk_idx_t, 318 | arr_index: duk_uarridx_t) -> duk_bool_t; 319 | pub fn duk_put_prop(ctx: *mut duk_context, obj_index: duk_idx_t) 320 | -> duk_bool_t; 321 | pub fn duk_put_prop_string(ctx: *mut duk_context, obj_index: duk_idx_t, 322 | key: *const ::libc::c_char) -> duk_bool_t; 323 | pub fn duk_put_prop_index(ctx: *mut duk_context, obj_index: duk_idx_t, 324 | arr_index: duk_uarridx_t) -> duk_bool_t; 325 | pub fn duk_del_prop(ctx: *mut duk_context, obj_index: duk_idx_t) 326 | -> duk_bool_t; 327 | pub fn duk_del_prop_string(ctx: *mut duk_context, obj_index: duk_idx_t, 328 | key: *const ::libc::c_char) -> duk_bool_t; 329 | pub fn duk_del_prop_index(ctx: *mut duk_context, obj_index: duk_idx_t, 330 | arr_index: duk_uarridx_t) -> duk_bool_t; 331 | pub fn duk_has_prop(ctx: *mut duk_context, obj_index: duk_idx_t) 332 | -> duk_bool_t; 333 | pub fn duk_has_prop_string(ctx: *mut duk_context, obj_index: duk_idx_t, 334 | key: *const ::libc::c_char) -> duk_bool_t; 335 | pub fn duk_has_prop_index(ctx: *mut duk_context, obj_index: duk_idx_t, 336 | arr_index: duk_uarridx_t) -> duk_bool_t; 337 | pub fn duk_get_global_string(ctx: *mut duk_context, 338 | key: *const ::libc::c_char) -> duk_bool_t; 339 | pub fn duk_put_global_string(ctx: *mut duk_context, 340 | key: *const ::libc::c_char) -> duk_bool_t; 341 | pub fn duk_get_prototype(ctx: *mut duk_context, index: duk_idx_t); 342 | pub fn duk_set_prototype(ctx: *mut duk_context, index: duk_idx_t); 343 | pub fn duk_get_finalizer(ctx: *mut duk_context, index: duk_idx_t); 344 | pub fn duk_set_finalizer(ctx: *mut duk_context, index: duk_idx_t); 345 | pub fn duk_set_global_object(ctx: *mut duk_context); 346 | pub fn duk_get_magic(ctx: *mut duk_context, index: duk_idx_t) 347 | -> duk_int_t; 348 | pub fn duk_set_magic(ctx: *mut duk_context, index: duk_idx_t, 349 | magic: duk_int_t); 350 | pub fn duk_get_current_magic(ctx: *mut duk_context) -> duk_int_t; 351 | pub fn duk_put_function_list(ctx: *mut duk_context, obj_index: duk_idx_t, 352 | funcs: *const duk_function_list_entry); 353 | pub fn duk_put_number_list(ctx: *mut duk_context, obj_index: duk_idx_t, 354 | numbers: *const duk_number_list_entry); 355 | pub fn duk_get_var(ctx: *mut duk_context); 356 | pub fn duk_put_var(ctx: *mut duk_context); 357 | pub fn duk_del_var(ctx: *mut duk_context) -> duk_bool_t; 358 | pub fn duk_has_var(ctx: *mut duk_context) -> duk_bool_t; 359 | pub fn duk_compact(ctx: *mut duk_context, obj_index: duk_idx_t); 360 | pub fn duk_enum(ctx: *mut duk_context, obj_index: duk_idx_t, 361 | enum_flags: duk_uint_t); 362 | pub fn duk_next(ctx: *mut duk_context, enum_index: duk_idx_t, 363 | get_value: duk_bool_t) -> duk_bool_t; 364 | pub fn duk_concat(ctx: *mut duk_context, count: duk_idx_t); 365 | pub fn duk_join(ctx: *mut duk_context, count: duk_idx_t); 366 | pub fn duk_decode_string(ctx: *mut duk_context, index: duk_idx_t, 367 | callback: duk_decode_char_function, 368 | udata: *mut ::libc::c_void); 369 | pub fn duk_map_string(ctx: *mut duk_context, index: duk_idx_t, 370 | callback: duk_map_char_function, 371 | udata: *mut ::libc::c_void); 372 | pub fn duk_substring(ctx: *mut duk_context, index: duk_idx_t, 373 | start_char_offset: duk_size_t, 374 | end_char_offset: duk_size_t); 375 | pub fn duk_trim(ctx: *mut duk_context, index: duk_idx_t); 376 | pub fn duk_char_code_at(ctx: *mut duk_context, index: duk_idx_t, 377 | char_offset: duk_size_t) -> duk_codepoint_t; 378 | pub fn duk_equals(ctx: *mut duk_context, index1: duk_idx_t, 379 | index2: duk_idx_t) -> duk_bool_t; 380 | pub fn duk_strict_equals(ctx: *mut duk_context, index1: duk_idx_t, 381 | index2: duk_idx_t) -> duk_bool_t; 382 | pub fn duk_call(ctx: *mut duk_context, nargs: duk_idx_t); 383 | pub fn duk_call_method(ctx: *mut duk_context, nargs: duk_idx_t); 384 | pub fn duk_call_prop(ctx: *mut duk_context, obj_index: duk_idx_t, 385 | nargs: duk_idx_t); 386 | pub fn duk_pcall(ctx: *mut duk_context, nargs: duk_idx_t) -> duk_int_t; 387 | pub fn duk_pcall_method(ctx: *mut duk_context, nargs: duk_idx_t) 388 | -> duk_int_t; 389 | pub fn duk_pcall_prop(ctx: *mut duk_context, obj_index: duk_idx_t, 390 | nargs: duk_idx_t) -> duk_int_t; 391 | pub fn duk_new(ctx: *mut duk_context, nargs: duk_idx_t); 392 | pub fn duk_safe_call(ctx: *mut duk_context, func: duk_safe_call_function, 393 | nargs: duk_idx_t, nrets: duk_idx_t) -> duk_int_t; 394 | pub fn duk_eval_raw(ctx: *mut duk_context, 395 | src_buffer: *const ::libc::c_char, 396 | src_length: duk_size_t, flags: duk_uint_t) 397 | -> duk_int_t; 398 | pub fn duk_compile_raw(ctx: *mut duk_context, 399 | src_buffer: *const ::libc::c_char, 400 | src_length: duk_size_t, flags: duk_uint_t) 401 | -> duk_int_t; 402 | pub fn duk_log(ctx: *mut duk_context, level: duk_int_t, 403 | fmt: *const ::libc::c_char, ...); 404 | pub fn duk_push_context_dump(ctx: *mut duk_context); 405 | } 406 | -------------------------------------------------------------------------------- /duktape_sys/src/generate.c: -------------------------------------------------------------------------------- 1 | // Tool for extracting platform-specific sizes and constants from duktape.h. 2 | // To use: 3 | // 4 | // gcc -I../duktape/src -o generate generate.c 5 | // ./generate > generated.rs 6 | 7 | #include 8 | #include "duktape.h" 9 | 10 | // Translate types to Rust. 11 | #define INT_TYPE(TYPE) \ 12 | printf("pub type %s = %s%lu;\n", #TYPE, ((TYPE) -1) > 0 ? "u" : "i", \ 13 | 8*sizeof(TYPE)); 14 | 15 | // Convert typedefs to constants. 16 | #define CONST_L(TYPE, NAME) \ 17 | printf("pub const %s: %s = %ld;\n", #NAME, #TYPE, NAME) 18 | #define CONST(TYPE, NAME) \ 19 | printf("pub const %s: %s = %d;\n", #NAME, #TYPE, NAME) 20 | 21 | int main(int argc, char **argv) { 22 | // File header. 23 | printf("//! Platform-specific values generated by defgen.c.\n\n"); 24 | printf("use libc::types::os::arch::c95::{c_long, c_double};\n\n"); 25 | 26 | // Print type declarations. 27 | INT_TYPE(duk_errcode_t); 28 | INT_TYPE(duk_idx_t); 29 | INT_TYPE(duk_int_t); 30 | INT_TYPE(duk_ret_t); 31 | INT_TYPE(duk_uint_t); 32 | INT_TYPE(duk_bool_t); 33 | INT_TYPE(duk_uarridx_t); 34 | INT_TYPE(duk_codepoint_t); 35 | INT_TYPE(duk_ucodepoint_t); 36 | INT_TYPE(duk_size_t); 37 | INT_TYPE(duk_ptrdiff_t); 38 | INT_TYPE(duk_int32_t); 39 | INT_TYPE(duk_uint32_t); 40 | INT_TYPE(duk_uint16_t); 41 | printf("pub type duk_double_t = c_double;\n"); 42 | 43 | // This is an integer with an "L" specifier. 44 | CONST_L(c_long, DUK_VERSION); 45 | CONST(duk_idx_t, DUK_INVALID_INDEX); 46 | CONST(duk_int_t, DUK_VARARGS); 47 | // This type is fairly arbitrary: It's small and non-negative, and I 48 | // can't find any place in the API which would take it. 49 | CONST(duk_idx_t, DUK_API_ENTRY_STACK); 50 | CONST(duk_int_t, DUK_TYPE_NONE); 51 | CONST(duk_int_t, DUK_TYPE_UNDEFINED); 52 | CONST(duk_int_t, DUK_TYPE_NULL); 53 | CONST(duk_int_t, DUK_TYPE_BOOLEAN); 54 | CONST(duk_int_t, DUK_TYPE_NUMBER); 55 | CONST(duk_int_t, DUK_TYPE_STRING); 56 | CONST(duk_int_t, DUK_TYPE_OBJECT); 57 | CONST(duk_int_t, DUK_TYPE_BUFFER); 58 | CONST(duk_int_t, DUK_TYPE_POINTER); 59 | CONST(duk_uint_t, DUK_TYPE_MASK_NONE); 60 | CONST(duk_uint_t, DUK_TYPE_MASK_UNDEFINED); 61 | CONST(duk_uint_t, DUK_TYPE_MASK_NULL); 62 | CONST(duk_uint_t, DUK_TYPE_MASK_BOOLEAN); 63 | CONST(duk_uint_t, DUK_TYPE_MASK_NUMBER); 64 | CONST(duk_uint_t, DUK_TYPE_MASK_STRING); 65 | CONST(duk_uint_t, DUK_TYPE_MASK_OBJECT); 66 | CONST(duk_uint_t, DUK_TYPE_MASK_BUFFER); 67 | CONST(duk_uint_t, DUK_TYPE_MASK_POINTER); 68 | CONST(duk_uint_t, DUK_TYPE_MASK_THROW); 69 | CONST(duk_int_t, DUK_HINT_NONE); 70 | CONST(duk_int_t, DUK_HINT_STRING); 71 | CONST(duk_int_t, DUK_HINT_NUMBER); 72 | CONST(duk_uint_t, DUK_ENUM_INCLUDE_NONENUMERABLE); 73 | CONST(duk_uint_t, DUK_ENUM_INCLUDE_INTERNAL); 74 | CONST(duk_uint_t, DUK_ENUM_OWN_PROPERTIES_ONLY); 75 | CONST(duk_uint_t, DUK_ENUM_ARRAY_INDICES_ONLY); 76 | CONST(duk_uint_t, DUK_ENUM_SORT_ARRAY_INDICES); 77 | CONST(duk_uint_t, DUK_ENUM_NO_PROXY_BEHAVIOR); 78 | CONST(duk_uint_t, DUK_COMPILE_EVAL); 79 | CONST(duk_uint_t, DUK_COMPILE_FUNCTION); 80 | CONST(duk_uint_t, DUK_COMPILE_STRICT); 81 | CONST(duk_uint_t, DUK_COMPILE_SAFE); 82 | CONST(duk_uint_t, DUK_COMPILE_NORESULT); 83 | CONST(duk_uint_t, DUK_COMPILE_NOSOURCE); 84 | CONST(duk_uint_t, DUK_COMPILE_STRLEN); 85 | CONST(duk_uint_t, DUK_THREAD_NEW_GLOBAL_ENV); 86 | CONST(duk_uint_t, DUK_STRING_PUSH_SAFE); 87 | CONST(duk_errcode_t, DUK_ERR_UNIMPLEMENTED_ERROR); 88 | CONST(duk_errcode_t, DUK_ERR_UNSUPPORTED_ERROR); 89 | CONST(duk_errcode_t, DUK_ERR_INTERNAL_ERROR); 90 | CONST(duk_errcode_t, DUK_ERR_ALLOC_ERROR); 91 | CONST(duk_errcode_t, DUK_ERR_ASSERTION_ERROR); 92 | CONST(duk_errcode_t, DUK_ERR_API_ERROR); 93 | CONST(duk_errcode_t, DUK_ERR_UNCAUGHT_ERROR); 94 | CONST(duk_errcode_t, DUK_ERR_ERROR); 95 | CONST(duk_errcode_t, DUK_ERR_EVAL_ERROR); 96 | CONST(duk_errcode_t, DUK_ERR_RANGE_ERROR); 97 | CONST(duk_errcode_t, DUK_ERR_REFERENCE_ERROR); 98 | CONST(duk_errcode_t, DUK_ERR_SYNTAX_ERROR); 99 | CONST(duk_errcode_t, DUK_ERR_TYPE_ERROR); 100 | CONST(duk_errcode_t, DUK_ERR_URI_ERROR); 101 | CONST(duk_ret_t, DUK_RET_UNIMPLEMENTED_ERROR); 102 | CONST(duk_ret_t, DUK_RET_UNSUPPORTED_ERROR); 103 | CONST(duk_ret_t, DUK_RET_INTERNAL_ERROR); 104 | CONST(duk_ret_t, DUK_RET_ALLOC_ERROR); 105 | CONST(duk_ret_t, DUK_RET_ASSERTION_ERROR); 106 | CONST(duk_ret_t, DUK_RET_API_ERROR); 107 | CONST(duk_ret_t, DUK_RET_UNCAUGHT_ERROR); 108 | CONST(duk_ret_t, DUK_RET_ERROR); 109 | CONST(duk_ret_t, DUK_RET_EVAL_ERROR); 110 | CONST(duk_ret_t, DUK_RET_RANGE_ERROR); 111 | CONST(duk_ret_t, DUK_RET_REFERENCE_ERROR); 112 | CONST(duk_ret_t, DUK_RET_SYNTAX_ERROR); 113 | CONST(duk_ret_t, DUK_RET_TYPE_ERROR); 114 | CONST(duk_ret_t, DUK_RET_URI_ERROR); 115 | // TODO: Double-check type of DUK_EXEC_*. 116 | CONST(duk_int_t, DUK_EXEC_SUCCESS); 117 | CONST(duk_int_t, DUK_EXEC_ERROR); 118 | CONST(duk_int_t, DUK_LOG_TRACE); 119 | CONST(duk_int_t, DUK_LOG_DEBUG); 120 | CONST(duk_int_t, DUK_LOG_INFO); 121 | CONST(duk_int_t, DUK_LOG_WARN); 122 | CONST(duk_int_t, DUK_LOG_ERROR); 123 | CONST(duk_int_t, DUK_LOG_FATAL); 124 | 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /duktape_sys/src/generated.rs: -------------------------------------------------------------------------------- 1 | //! Platform-specific values generated by defgen.c. 2 | 3 | use libc::types::os::arch::c95::{c_long, c_double}; 4 | 5 | pub type duk_errcode_t = i32; 6 | pub type duk_idx_t = i32; 7 | pub type duk_int_t = i32; 8 | pub type duk_ret_t = i32; 9 | pub type duk_uint_t = u32; 10 | pub type duk_bool_t = i32; 11 | pub type duk_uarridx_t = u32; 12 | pub type duk_codepoint_t = i32; 13 | pub type duk_ucodepoint_t = u32; 14 | pub type duk_size_t = u64; 15 | pub type duk_ptrdiff_t = i64; 16 | pub type duk_int32_t = i32; 17 | pub type duk_uint32_t = u32; 18 | pub type duk_uint16_t = u16; 19 | pub type duk_double_t = c_double; 20 | pub const DUK_VERSION: c_long = 10002; 21 | pub const DUK_INVALID_INDEX: duk_idx_t = -2147483648; 22 | pub const DUK_VARARGS: duk_int_t = -1; 23 | pub const DUK_API_ENTRY_STACK: duk_idx_t = 64; 24 | pub const DUK_TYPE_NONE: duk_int_t = 0; 25 | pub const DUK_TYPE_UNDEFINED: duk_int_t = 1; 26 | pub const DUK_TYPE_NULL: duk_int_t = 2; 27 | pub const DUK_TYPE_BOOLEAN: duk_int_t = 3; 28 | pub const DUK_TYPE_NUMBER: duk_int_t = 4; 29 | pub const DUK_TYPE_STRING: duk_int_t = 5; 30 | pub const DUK_TYPE_OBJECT: duk_int_t = 6; 31 | pub const DUK_TYPE_BUFFER: duk_int_t = 7; 32 | pub const DUK_TYPE_POINTER: duk_int_t = 8; 33 | pub const DUK_TYPE_MASK_NONE: duk_uint_t = 1; 34 | pub const DUK_TYPE_MASK_UNDEFINED: duk_uint_t = 2; 35 | pub const DUK_TYPE_MASK_NULL: duk_uint_t = 4; 36 | pub const DUK_TYPE_MASK_BOOLEAN: duk_uint_t = 8; 37 | pub const DUK_TYPE_MASK_NUMBER: duk_uint_t = 16; 38 | pub const DUK_TYPE_MASK_STRING: duk_uint_t = 32; 39 | pub const DUK_TYPE_MASK_OBJECT: duk_uint_t = 64; 40 | pub const DUK_TYPE_MASK_BUFFER: duk_uint_t = 128; 41 | pub const DUK_TYPE_MASK_POINTER: duk_uint_t = 256; 42 | pub const DUK_TYPE_MASK_THROW: duk_uint_t = 1024; 43 | pub const DUK_HINT_NONE: duk_int_t = 0; 44 | pub const DUK_HINT_STRING: duk_int_t = 1; 45 | pub const DUK_HINT_NUMBER: duk_int_t = 2; 46 | pub const DUK_ENUM_INCLUDE_NONENUMERABLE: duk_uint_t = 1; 47 | pub const DUK_ENUM_INCLUDE_INTERNAL: duk_uint_t = 2; 48 | pub const DUK_ENUM_OWN_PROPERTIES_ONLY: duk_uint_t = 4; 49 | pub const DUK_ENUM_ARRAY_INDICES_ONLY: duk_uint_t = 8; 50 | pub const DUK_ENUM_SORT_ARRAY_INDICES: duk_uint_t = 16; 51 | pub const DUK_ENUM_NO_PROXY_BEHAVIOR: duk_uint_t = 32; 52 | pub const DUK_COMPILE_EVAL: duk_uint_t = 1; 53 | pub const DUK_COMPILE_FUNCTION: duk_uint_t = 2; 54 | pub const DUK_COMPILE_STRICT: duk_uint_t = 4; 55 | pub const DUK_COMPILE_SAFE: duk_uint_t = 8; 56 | pub const DUK_COMPILE_NORESULT: duk_uint_t = 16; 57 | pub const DUK_COMPILE_NOSOURCE: duk_uint_t = 32; 58 | pub const DUK_COMPILE_STRLEN: duk_uint_t = 64; 59 | pub const DUK_THREAD_NEW_GLOBAL_ENV: duk_uint_t = 1; 60 | pub const DUK_STRING_PUSH_SAFE: duk_uint_t = 1; 61 | pub const DUK_ERR_UNIMPLEMENTED_ERROR: duk_errcode_t = 50; 62 | pub const DUK_ERR_UNSUPPORTED_ERROR: duk_errcode_t = 51; 63 | pub const DUK_ERR_INTERNAL_ERROR: duk_errcode_t = 52; 64 | pub const DUK_ERR_ALLOC_ERROR: duk_errcode_t = 53; 65 | pub const DUK_ERR_ASSERTION_ERROR: duk_errcode_t = 54; 66 | pub const DUK_ERR_API_ERROR: duk_errcode_t = 55; 67 | pub const DUK_ERR_UNCAUGHT_ERROR: duk_errcode_t = 56; 68 | pub const DUK_ERR_ERROR: duk_errcode_t = 100; 69 | pub const DUK_ERR_EVAL_ERROR: duk_errcode_t = 101; 70 | pub const DUK_ERR_RANGE_ERROR: duk_errcode_t = 102; 71 | pub const DUK_ERR_REFERENCE_ERROR: duk_errcode_t = 103; 72 | pub const DUK_ERR_SYNTAX_ERROR: duk_errcode_t = 104; 73 | pub const DUK_ERR_TYPE_ERROR: duk_errcode_t = 105; 74 | pub const DUK_ERR_URI_ERROR: duk_errcode_t = 106; 75 | pub const DUK_RET_UNIMPLEMENTED_ERROR: duk_ret_t = -50; 76 | pub const DUK_RET_UNSUPPORTED_ERROR: duk_ret_t = -51; 77 | pub const DUK_RET_INTERNAL_ERROR: duk_ret_t = -52; 78 | pub const DUK_RET_ALLOC_ERROR: duk_ret_t = -53; 79 | pub const DUK_RET_ASSERTION_ERROR: duk_ret_t = -54; 80 | pub const DUK_RET_API_ERROR: duk_ret_t = -55; 81 | pub const DUK_RET_UNCAUGHT_ERROR: duk_ret_t = -56; 82 | pub const DUK_RET_ERROR: duk_ret_t = -100; 83 | pub const DUK_RET_EVAL_ERROR: duk_ret_t = -101; 84 | pub const DUK_RET_RANGE_ERROR: duk_ret_t = -102; 85 | pub const DUK_RET_REFERENCE_ERROR: duk_ret_t = -103; 86 | pub const DUK_RET_SYNTAX_ERROR: duk_ret_t = -104; 87 | pub const DUK_RET_TYPE_ERROR: duk_ret_t = -105; 88 | pub const DUK_RET_URI_ERROR: duk_ret_t = -106; 89 | pub const DUK_EXEC_SUCCESS: duk_int_t = 0; 90 | pub const DUK_EXEC_ERROR: duk_int_t = 1; 91 | pub const DUK_LOG_TRACE: duk_int_t = 0; 92 | pub const DUK_LOG_DEBUG: duk_int_t = 1; 93 | pub const DUK_LOG_INFO: duk_int_t = 2; 94 | pub const DUK_LOG_WARN: duk_int_t = 3; 95 | pub const DUK_LOG_ERROR: duk_int_t = 4; 96 | pub const DUK_LOG_FATAL: duk_int_t = 5; 97 | -------------------------------------------------------------------------------- /duktape_sys/src/glue.c: -------------------------------------------------------------------------------- 1 | #include "duktape.h" 2 | 3 | /// A custom add-on to the duktape API, replacing the macro 4 | /// `duk_push_error_object`, 5 | extern duk_idx_t 6 | duk_push_error_object_string(duk_context *ctx, duk_errcode_t err_code, 7 | const char *filename, duk_int_t line, 8 | const char *message) 9 | { 10 | return duk_push_error_object_raw(ctx, err_code, filename, line, "%s", 11 | message); 12 | } 13 | -------------------------------------------------------------------------------- /duktape_sys/src/glue.rs: -------------------------------------------------------------------------------- 1 | //! Replacements for parts of the C API that can't be used directly by Rust, 2 | //! including preprocessor macros and varargs functions. 3 | 4 | use generated::*; 5 | use bindings::*; 6 | 7 | extern "C" { 8 | /// A wrapper around duk_push_error_object, which relies on varargs in 9 | /// the original API. 10 | pub fn duk_push_error_object_string( 11 | ctx: *mut duk_context, err_code: duk_errcode_t, 12 | filename: *const i8, line: duk_int_t, 13 | message: *const i8) -> duk_idx_t; 14 | } 15 | -------------------------------------------------------------------------------- /duktape_sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! EXPERIMENTAL: Low-level, unsafe wrapper arround the duktape API. 2 | //! 3 | //! Note that some of this code is generated based on the specific 4 | //! compiler, operating system and processor, so various details may change 5 | //! depending on the system you're targeting. Do not assume that constants 6 | //! or integer sizes are the same everywhere! 7 | //! 8 | //! We do not yet provide replacements for duktape function macros, but 9 | //! pull requests are very welcome. 10 | 11 | #![feature(libc)] 12 | 13 | #![allow(non_camel_case_types)] 14 | 15 | extern crate libc; 16 | 17 | pub use generated::*; 18 | pub use bindings::*; 19 | pub use glue::*; 20 | 21 | mod generated; 22 | mod bindings; 23 | mod glue; 24 | 25 | #[test] 26 | fn test_eval() { 27 | use std::ptr::null_mut; 28 | unsafe { 29 | // Create a heap. 30 | let ctx = duk_create_heap(None, None, None, null_mut(), None); 31 | 32 | // Run a short code snippet. 33 | let code = "2+3"; 34 | let filename = "input"; 35 | duk_push_lstring(ctx, filename.as_ptr() as *const i8, 36 | filename.len() as duk_size_t); 37 | let result = duk_eval_raw(ctx, code.as_ptr() as *const i8, 38 | code.len() as duk_size_t, 39 | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | 40 | DUK_COMPILE_SAFE); 41 | assert_eq!(DUK_EXEC_SUCCESS, result); 42 | 43 | // Get the result and make sure it's correct. 44 | assert_eq!(1, duk_is_number(ctx, -1)); 45 | assert_eq!(5.0, duk_get_number(ctx, -1)); 46 | duk_pop(ctx); 47 | 48 | duk_destroy_heap(ctx); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/context.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use std::ffi::CString; 3 | use std::mem::transmute; 4 | use std::ops::Deref; 5 | use std::ptr::null_mut; 6 | use std::slice::from_raw_buf; 7 | use libc::c_void; 8 | use cesu8::{to_cesu8, from_cesu8}; 9 | use ffi::*; 10 | use errors::*; 11 | use types::Value; 12 | use encoder::{Encoder, DuktapeEncodable}; 13 | 14 | /// To avoid massive debugging frustration, wrap stack manipulation code in 15 | /// this macro. 16 | macro_rules! assert_stack_height_unchanged { 17 | ($ctx:ident, $body:block) => { 18 | { 19 | let initial_stack_height = duk_get_top($ctx.ptr); 20 | let result = $body; 21 | assert_eq!(initial_stack_height, duk_get_top($ctx.ptr)); 22 | result 23 | } 24 | } 25 | } 26 | 27 | /// Convert a duktape-format string into a Rust `String`. 28 | pub unsafe fn from_lstring(data: *const i8, len: duk_size_t) -> 29 | DuktapeResult 30 | { 31 | let ptr = data as *const u8; 32 | let bytes = from_raw_buf(&ptr, len as usize); 33 | match from_cesu8(bytes) { 34 | Ok(str) => Ok(str.into_owned()), 35 | Err(_) => Err(DuktapeError::from_str("can't convert string to UTF-8")) 36 | } 37 | } 38 | 39 | /// A "internal" property key used for storing Rust function pointers, which 40 | /// can't be accessed from JavaScript without a lot of trickery. 41 | const RUST_FN_PROP: [i8; 5] = [-1, 'r' as i8, 'f' as i8, 'n' as i8, 0]; 42 | 43 | /// A Rust callback which can be invoked from JavaScript. 44 | pub type Callback = fn (&mut Context, &[Value<'static>]) -> 45 | DuktapeResult>; 46 | 47 | /// A duktape interpreter context. An individual context is not 48 | /// re-entrant: You may only access it from one thread at a time. 49 | pub struct Context { 50 | ptr: *mut duk_context, 51 | owned: bool 52 | } 53 | 54 | impl Context { 55 | /// Create a new duktape context. 56 | pub fn new() -> DuktapeResult { 57 | let ptr = unsafe { 58 | duk_create_heap(None, None, None, null_mut(), None) 59 | }; 60 | if ptr.is_null() { 61 | Err(DuktapeError::from_str("Could not create heap")) 62 | } else { 63 | Ok(Context{ptr: ptr, owned: true}) 64 | } 65 | } 66 | 67 | /// Create a new duktape context by wrapping an existing mutable 68 | /// pointer. This is potentially unsafe, because it allows you to 69 | /// create two Rust objects pointing to the same duktape interpreter! 70 | /// So if you create a Context using this API 71 | pub unsafe fn from_borrowed_mut_ptr(ptr: *mut duk_context) -> Context { 72 | Context{ptr: ptr, owned: false} 73 | } 74 | 75 | /// Get the underlying context pointer. You generally don't need this 76 | /// unless you're implementing low-level add-ons to this library. 77 | pub unsafe fn as_mut_ptr(&mut self) -> *mut duk_context { self.ptr } 78 | 79 | /// Debugging: Dump the interpreter context. 80 | #[allow(dead_code)] 81 | fn dump_context(&mut self) -> String { 82 | unsafe { 83 | duk_push_context_dump(self.ptr); 84 | let mut len: duk_size_t = 0; 85 | let str = duk_safe_to_lstring(self.ptr, -1, &mut len); 86 | let result = from_lstring(str, len) 87 | .unwrap_or_else(|_| "Couldn't dump context".to_string()); 88 | duk_pop(self.ptr); 89 | result 90 | } 91 | } 92 | 93 | /// Get the specified value from our context, and convert it to a Rust 94 | /// type. This is a low-level, unsafe function, and you won't normally 95 | /// need to call it. 96 | unsafe fn get(&mut self, idx: duk_idx_t) -> DuktapeResult> { 97 | match duk_get_type(self.ptr, idx) { 98 | DUK_TYPE_UNDEFINED => Ok(Value::Undefined), 99 | DUK_TYPE_NULL => Ok(Value::Null), 100 | DUK_TYPE_BOOLEAN => { 101 | let val = duk_get_boolean(self.ptr, idx); 102 | Ok(Value::Bool(val != 0)) 103 | } 104 | DUK_TYPE_NUMBER => { 105 | Ok(Value::Number(duk_get_number(self.ptr, idx))) 106 | } 107 | DUK_TYPE_STRING => { 108 | let mut len: duk_size_t = 0; 109 | let str = duk_get_lstring(self.ptr, idx, &mut len); 110 | Ok(Value::String(Cow::Owned(try!(from_lstring(str, len))))) 111 | } 112 | _ => panic!("Cannot convert duktape data type") 113 | } 114 | } 115 | 116 | /// Push a value to the call stack. 117 | pub unsafe fn push_old(&mut self, val: &Value) { 118 | match val { 119 | &Value::Undefined => duk_push_undefined(self.ptr), 120 | &Value::Null => duk_push_null(self.ptr), 121 | &Value::Bool(v) => duk_push_boolean(self.ptr, if v { 1 } else { 0 }), 122 | &Value::Number(v) => duk_push_number(self.ptr, v), 123 | &Value::String(ref v) => { 124 | let encoded = to_cesu8(v.deref()); 125 | let buf = encoded.deref(); 126 | duk_push_lstring(self.ptr, buf.as_ptr() as *const i8, 127 | buf.len() as duk_size_t); 128 | } 129 | } 130 | } 131 | 132 | /// Push an encodable value onto the call stack. We can push any data 133 | /// type that implements Encodable. 134 | pub unsafe fn push(&mut self, object: &T) { 135 | let mut encoder = Encoder::new(self.ptr); 136 | object.duktape_encode(&mut encoder).unwrap(); 137 | } 138 | 139 | /// Interpret the value on the top of the stack as either a return 140 | /// value or an error, depending on the value of `status`. 141 | unsafe fn get_result(&mut self, status: duk_int_t) -> 142 | DuktapeResult> 143 | { 144 | if status == DUK_EXEC_SUCCESS { 145 | self.get(-1) 146 | } else { 147 | let mut len: duk_size_t = 0; 148 | let str = duk_safe_to_lstring(self.ptr, -1, &mut len); 149 | let msg = try!(from_lstring(str, len)); 150 | Err(DuktapeError::from_str(&msg[])) 151 | } 152 | } 153 | 154 | /// Given the status code returned by a duktape exec function, pop 155 | /// either a value or an error from the stack, convert it, and return 156 | /// it. 157 | pub unsafe fn pop_result(&mut self, status: duk_int_t) -> 158 | DuktapeResult> 159 | { 160 | let result = self.get_result(status); 161 | duk_pop(self.ptr); 162 | result 163 | } 164 | 165 | /// Evaluate JavaScript source code and return the result. 166 | pub fn eval(&mut self, code: &str) -> DuktapeResult> { 167 | self.eval_from("", code) 168 | } 169 | 170 | /// Evaluate JavaScript source code and return the result. The 171 | /// `filename` parameter will be used in any error messages. 172 | pub fn eval_from(&mut self, filename: &str, code: &str) -> 173 | DuktapeResult> 174 | { 175 | unsafe { 176 | assert_stack_height_unchanged!(self, { 177 | // Push our filename parameter and evaluate our code. 178 | duk_push_lstring(self.ptr, filename.as_ptr() as *const i8, 179 | filename.len() as duk_size_t); 180 | let status = duk_eval_raw(self.ptr, code.as_ptr() as *const i8, 181 | code.len() as duk_size_t, 182 | DUK_COMPILE_EVAL | 183 | DUK_COMPILE_NOSOURCE | 184 | DUK_COMPILE_SAFE); 185 | self.pop_result(status) 186 | }) 187 | } 188 | } 189 | 190 | /// Call the global JavaScript function named `fn_name` with `args`, and 191 | /// return the result. 192 | pub fn call(&mut self, fn_name: &str, args: &[&DuktapeEncodable]) -> 193 | DuktapeResult> 194 | { 195 | unsafe { 196 | assert_stack_height_unchanged!(self, { 197 | duk_push_global_object(self.ptr); 198 | let c_str = CString::from_slice(fn_name.as_bytes()); 199 | duk_get_prop_string(self.ptr, -1, c_str.as_ptr()); 200 | { 201 | let mut encoder = Encoder::new(self.ptr); 202 | for arg in args.iter() { 203 | (*arg).duktape_encode(&mut encoder).unwrap(); 204 | } 205 | } 206 | let status = duk_pcall(self.ptr, args.len() as i32); 207 | let result = self.pop_result(status); 208 | duk_pop(self.ptr); // Remove global object. 209 | result 210 | }) 211 | } 212 | } 213 | 214 | /// Register a Rust callback as a global JavaScript function. 215 | pub fn register(&mut self, fn_name: &str, f: Callback, 216 | arg_count: Option) { 217 | let c_arg_count = 218 | arg_count.map(|n| n as duk_int_t).unwrap_or(DUK_VARARGS); 219 | unsafe { 220 | assert_stack_height_unchanged!(self, { 221 | // Push our global context and a pointer to our standard 222 | // wrapper function. 223 | duk_push_global_object(self.ptr); 224 | duk_push_c_function(self.ptr, 225 | Some(rust_duk_callback), 226 | c_arg_count); 227 | 228 | // Store `f` as a hidden property in our function. 229 | duk_push_pointer(self.ptr, f as *mut c_void); 230 | duk_put_prop_string(self.ptr, -2, RUST_FN_PROP.as_ptr()); 231 | 232 | // Store our function in a global property. 233 | let c_str = CString::from_slice(fn_name.as_bytes()); 234 | duk_put_prop_string(self.ptr, -2, c_str.as_ptr()); 235 | duk_pop(self.ptr); 236 | }) 237 | } 238 | } 239 | } 240 | 241 | impl Drop for Context { 242 | fn drop(&mut self) { 243 | if self.owned { 244 | unsafe { duk_destroy_heap(self.ptr); } 245 | } 246 | } 247 | } 248 | 249 | /// Our generic callback function. 250 | unsafe extern "C" fn rust_duk_callback(ctx: *mut duk_context) -> duk_ret_t { 251 | // ERROR-HANDLING NOTE: Try to avoid any Rust panics or duktape unwinds 252 | // inside this function. They sort-of work--at least well enough to 253 | // debug this crate--but they probably corrupt at least one of the two 254 | // heaps. 255 | 256 | // Here, we create a mutable Context pointing into an existing duktape 257 | // heap. But this is theoretically safe, because the only way to 258 | // invoke JavaScript code is to use a mutable context while calling 259 | // into C. So this is really an indirect mutable borrow. 260 | assert!(ctx != null_mut()); 261 | let mut ctx = Context::from_borrowed_mut_ptr(ctx); 262 | //println!("In callback: {}", ctx.dump_context()); 263 | 264 | // Recover our Rust function pointer. 265 | let f: Callback = assert_stack_height_unchanged!(ctx, { 266 | duk_push_current_function(ctx.ptr); 267 | duk_get_prop_string(ctx.ptr, -1, RUST_FN_PROP.as_ptr()); 268 | let p = duk_get_pointer(ctx.ptr, -1); 269 | duk_pop_n(ctx.ptr, 2); 270 | assert!(p != null_mut()); 271 | transmute(p) 272 | }); 273 | 274 | // Coerce our arguments to Rust values. 275 | let arg_count = duk_get_top(ctx.ptr) as usize; 276 | let mut args = Vec::with_capacity(arg_count); 277 | for i in range(0, arg_count) { 278 | match ctx.get(i as duk_idx_t) { 279 | Ok(arg) => args.push(arg), 280 | // Can't convert argument to Rust. 281 | // TODO: Need testcase. 282 | Err(_) => return DUK_RET_TYPE_ERROR 283 | } 284 | } 285 | //println!("args: {}", args); 286 | 287 | // Call our function. 288 | let result = 289 | abort_on_panic!("unexpected panic in code called from JavaScript", { 290 | f(&mut ctx, &args[]) 291 | }); 292 | 293 | // Return our result. 294 | match result { 295 | // No return value. 296 | Ok(Value::Undefined) => { 0 } 297 | // A single return value. 298 | Ok(ref val) => { ctx.push_old(val); 1 } 299 | Err(ref err) => { 300 | let code = err_code(err) as duk_int_t; 301 | match err_message(err) { 302 | // An error with an actual error message. 303 | &Some(ref _msg) => { 304 | // The following would more-or-less work, but it 305 | // performs a non-local exit from a Rust function using 306 | // C APIs, which is a Bad Idea. 307 | //to_cesu8(&msg[]).with_c_str(|c_str| { 308 | // duk_push_error_object_string(ctx.ptr, code, 309 | // file!().as_ptr() 310 | // as *const i8, 311 | // line!() as i32, 312 | // c_str as *const i8); 313 | //}); 314 | //duk_throw(ctx.ptr); 315 | //-1 316 | DUK_RET_ERROR 317 | } 318 | // A generic error using one of the standard codes. 319 | &None => { -code } 320 | } 321 | } 322 | } 323 | } 324 | 325 | #[test] 326 | fn test_eval() { 327 | let mut ctx = Context::new().unwrap(); 328 | assert_eq!(Value::Undefined, ctx.eval("undefined").unwrap()); 329 | assert_eq!(Value::Null, ctx.eval("null").unwrap()); 330 | assert_eq!(Value::Bool(true), ctx.eval("true").unwrap()); 331 | assert_eq!(Value::Bool(false), ctx.eval("false").unwrap()); 332 | assert_eq!(Value::Number(5.0), ctx.eval("2 + 3").unwrap()); 333 | assert_eq!(Value::String(Cow::Borrowed("é")), ctx.eval("'é'").unwrap()); 334 | } 335 | 336 | #[test] 337 | fn test_unicode_supplementary_planes() { 338 | // Pay careful attention to characters U+10000 and greater, because 339 | // duktape uses CESU-8 internally, which isn't _quite_ valid UTF-8. 340 | // This is thanks to the fact that JavaScript uses 16-bit characters 341 | // and allows manipulating invalid UTF-16 data with mismatched 342 | // surrogate pairs. 343 | let mut ctx = Context::new().unwrap(); 344 | assert_eq!(Value::String(Cow::Borrowed("𓀀")), ctx.eval("'𓀀'").unwrap()); 345 | assert_eq!(Value::String(Cow::Borrowed("𓀀")), 346 | ctx.eval("'\\uD80C\\uDC00'").unwrap()); 347 | 348 | ctx.eval("function id(x) { return x; }").unwrap(); 349 | assert_eq!(Ok(Value::String(Cow::Borrowed("𓀀"))), 350 | ctx.call("id", &[&"𓀀"])); 351 | } 352 | 353 | #[test] 354 | fn test_eval_errors() { 355 | let mut ctx = Context::new().unwrap(); 356 | assert_eq!(true, ctx.eval("3 +").is_err()); 357 | } 358 | 359 | #[test] 360 | fn test_call_function_by_name() { 361 | use rustc_serialize::json::Json; 362 | 363 | let mut ctx = Context::new().unwrap(); 364 | ctx.eval("function add(x, y) { return x+y; }").unwrap(); 365 | assert_eq!(Ok(Value::Number(3.0)), ctx.call("add", &[&2.0f64, &1.0f64])); 366 | 367 | ctx.eval("function id(x) { return x; }").unwrap(); 368 | assert_eq!(Ok(Value::Null), ctx.call("id", &[&Json::Null])); 369 | assert_eq!(Ok(Value::Bool(true)), ctx.call("id", &[&true])); 370 | assert_eq!(Ok(Value::Bool(false)), ctx.call("id", &[&false])); 371 | assert_eq!(Ok(Value::Number(1.5)), ctx.call("id", &[&1.5f64])); 372 | assert_eq!(Ok(Value::String(Cow::Borrowed("é"))), 373 | ctx.call("id", &[&"é"])); 374 | } 375 | 376 | #[cfg(test)] 377 | #[allow(missing_docs)] 378 | mod test { 379 | use errors::*; 380 | use types::*; 381 | use super::*; 382 | 383 | pub fn rust_add(_ctx: &mut Context, args: &[Value<'static>]) -> 384 | DuktapeResult> 385 | { 386 | let mut sum = 0.0; 387 | for arg in args.iter() { 388 | // TODO: Type checking. 389 | if let &Value::Number(n) = arg { 390 | sum += n; 391 | } 392 | } 393 | Ok(Value::Number(sum)) 394 | } 395 | 396 | macro_rules! rust_callback { 397 | ($name:ident, $retval:expr) => { 398 | pub fn $name(_ctx: &mut Context, _args: &[Value<'static>]) -> 399 | DuktapeResult> 400 | { 401 | $retval 402 | } 403 | } 404 | } 405 | 406 | rust_callback!{rust_return_undefined, Ok(Value::Undefined)} 407 | rust_callback!{rust_return_simple_error, 408 | Err(DuktapeError::from_code(ErrorCode::Type))} 409 | rust_callback!{rust_return_custom_error, 410 | Err(DuktapeError::from_str("custom error"))} 411 | } 412 | 413 | #[test] 414 | fn test_callbacks() { 415 | let mut ctx = Context::new().unwrap(); 416 | 417 | // An ordinary function, with arguments and a useful return value. 418 | ctx.register("add", test::rust_add, Some(2)); 419 | assert_eq!(Value::Number(5.0), ctx.eval("add(2.0, 3.0)").unwrap()); 420 | 421 | // A funtion which returns `undefined` (the same as having no return 422 | // value). 423 | ctx.register("ret_undefined", test::rust_return_undefined, Some(0)); 424 | assert_eq!(Value::Undefined, ctx.eval("ret_undefined()").unwrap()); 425 | 426 | // A function which returns a numeric error code (special-cased in 427 | // duktape). 428 | ctx.register("simple_error", test::rust_return_simple_error, Some(0)); 429 | assert!(ctx.eval("simple_error()").is_err()); 430 | 431 | // A function which returns a custom error with a string. 432 | ctx.register("custom_error", test::rust_return_custom_error, Some(0)); 433 | let res = ctx.eval("custom_error()"); 434 | assert!(res.is_err()); 435 | } 436 | -------------------------------------------------------------------------------- /src/decoder.rs: -------------------------------------------------------------------------------- 1 | use std::iter::Iterator; 2 | use rustc_serialize::Decodable; 3 | use ffi::*; 4 | use errors::*; 5 | use context::{Context, from_lstring}; 6 | 7 | /// Translates JavaScript values into Rust values. 8 | #[allow(dead_code)] // WIP 9 | pub struct Decoder { 10 | /// An internal `Context` object, for convenience. We own this, 11 | /// because if we use a reference to somebody else's, the lifetimes 12 | /// make it very hard to work with &Encodable references. 13 | ctx: Context 14 | } 15 | 16 | impl Decoder { 17 | /// Create a new decoder which pops values from `ctx`. If you create 18 | /// one of these, you're responsible for making sure it gets used 19 | /// safely. 20 | #[allow(dead_code)] // WIP 21 | pub unsafe fn new(ctx: *mut duk_context) -> Decoder { 22 | Decoder{ctx: Context::from_borrowed_mut_ptr(ctx)} 23 | } 24 | } 25 | 26 | /// A value which can be encoded and passed to JavaScript code. 27 | pub trait DuktapeDecodable: Decodable {} 28 | impl DuktapeDecodable for T {} 29 | 30 | macro_rules! read_and_convert { 31 | ($name:ident -> $ty:ident, $reader:ident -> $in_ty:ident) => { 32 | fn $name(&mut self) -> DuktapeResult<$ty> { 33 | self.$reader().map(|: v: $in_ty| v as $ty) 34 | } 35 | } 36 | } 37 | 38 | macro_rules! read_with { 39 | ($name:ident -> $ty:ident, $tester:ident, 40 | |$slf:ident, $idx:ident| $reader:block) => { 41 | fn $name(&mut $slf) -> DuktapeResult<$ty> { 42 | unsafe { 43 | let $idx = -1; 44 | if $tester($slf.ctx.as_mut_ptr(), $idx) != 0 { 45 | let result = $reader; 46 | duk_pop($slf.ctx.as_mut_ptr()); 47 | result 48 | } else { 49 | duk_pop($slf.ctx.as_mut_ptr()); 50 | Err(DuktapeError::from_str("Expected number")) 51 | } 52 | } 53 | } 54 | } 55 | } 56 | 57 | #[allow(unused_variables)] 58 | impl ::rustc_serialize::Decoder for Decoder { 59 | type Error = DuktapeError; 60 | 61 | fn read_nil(&mut self) -> DuktapeResult<()> 62 | { 63 | unimplemented!() 64 | } 65 | 66 | read_and_convert!(read_usize-> usize,read_f64 -> f64); 67 | read_and_convert!(read_u64 -> u64, read_f64 -> f64); 68 | read_and_convert!(read_u32 -> u32, read_f64 -> f64); 69 | read_and_convert!(read_u16 -> u16, read_f64 -> f64); 70 | read_and_convert!(read_u8 -> u8, read_f64 -> f64); 71 | read_and_convert!(read_isize-> isize,read_f64 -> f64); 72 | read_and_convert!(read_i64 -> i64, read_f64 -> f64); 73 | read_and_convert!(read_i32 -> i32, read_f64 -> f64); 74 | read_and_convert!(read_i16 -> i16, read_f64 -> f64); 75 | read_and_convert!(read_i8 -> i8, read_f64 -> f64); 76 | 77 | read_with!(read_bool -> bool, duk_is_boolean, |self, idx| { 78 | Ok(duk_get_boolean(self.ctx.as_mut_ptr(), idx) != 0) 79 | }); 80 | 81 | read_with!(read_f64 -> f64, duk_is_number, |self, idx| { 82 | Ok(duk_get_number(self.ctx.as_mut_ptr(), idx)) 83 | }); 84 | read_and_convert!(read_f32 -> f32, read_f64 -> f64); 85 | 86 | fn read_char(&mut self) -> DuktapeResult { 87 | fn err(msg: &str) -> DuktapeResult { 88 | Err(DuktapeError::from_str(msg)) 89 | } 90 | match self.read_str() { 91 | Ok(ref s) => { 92 | // Try to read exactly one character. 93 | let mut iter = s.chars(); 94 | let result = match iter.next() { 95 | None => return err("Expected char, got \"\""), 96 | Some(c) => c 97 | }; 98 | match iter.next() { 99 | None => Ok(result), 100 | Some(_) => { 101 | err(format!("Expected char, got \"{}\"", s).as_slice()) 102 | } 103 | } 104 | } 105 | Err(err) => Err(err) 106 | } 107 | } 108 | 109 | read_with!(read_str -> String, duk_is_string, |self, idx| { 110 | let mut len = 0; 111 | let ptr = duk_get_lstring(self.ctx.as_mut_ptr(), idx, &mut len); 112 | from_lstring(ptr, len) 113 | }); 114 | 115 | // Compound types: 116 | fn read_enum(&mut self, name: &str, 117 | f: F) -> DuktapeResult 118 | where F: FnOnce(&mut Decoder) -> DuktapeResult 119 | { 120 | unimplemented!() 121 | } 122 | 123 | fn read_enum_variant(&mut self, 124 | names: &[&str], 125 | f: F) 126 | -> DuktapeResult 127 | where F: FnMut(&mut Decoder, usize) -> DuktapeResult 128 | { 129 | unimplemented!() 130 | } 131 | fn read_enum_variant_arg(&mut self, 132 | a_idx: usize, 133 | f: F) 134 | -> DuktapeResult 135 | where F: FnOnce(&mut Decoder) -> DuktapeResult 136 | { 137 | unimplemented!() 138 | } 139 | 140 | fn read_enum_struct_variant(&mut self, 141 | names: &[&str], 142 | f: F) 143 | -> DuktapeResult 144 | where F: FnMut(&mut Decoder, usize) -> DuktapeResult 145 | { 146 | unimplemented!() 147 | } 148 | fn read_enum_struct_variant_field(&mut self, 149 | f_name: &str, 150 | f_idx: usize, 151 | f: F) 152 | -> DuktapeResult 153 | where F: FnOnce(&mut Decoder) -> DuktapeResult 154 | { 155 | unimplemented!() 156 | } 157 | 158 | fn read_struct(&mut self, s_name: &str, len: usize, f: F) 159 | -> DuktapeResult 160 | where F: FnOnce(&mut Decoder) -> DuktapeResult 161 | { 162 | unimplemented!() 163 | } 164 | fn read_struct_field(&mut self, 165 | f_name: &str, 166 | f_idx: usize, 167 | f: F) 168 | -> DuktapeResult 169 | where F: FnOnce(&mut Decoder) -> DuktapeResult 170 | { 171 | unimplemented!() 172 | } 173 | 174 | fn read_tuple(&mut self, len: usize, f: F) -> DuktapeResult 175 | where F: FnOnce(&mut Decoder) -> DuktapeResult 176 | { 177 | unimplemented!() 178 | } 179 | fn read_tuple_arg(&mut self, a_idx: usize, f: F) -> DuktapeResult 180 | where F: FnOnce(&mut Decoder) -> DuktapeResult 181 | { 182 | unimplemented!() 183 | } 184 | 185 | fn read_tuple_struct(&mut self, 186 | s_name: &str, 187 | len: usize, 188 | f: F) 189 | -> DuktapeResult 190 | where F: FnOnce(&mut Decoder) -> DuktapeResult 191 | { 192 | unimplemented!() 193 | } 194 | fn read_tuple_struct_arg(&mut self, 195 | a_idx: usize, 196 | f: F) 197 | -> DuktapeResult 198 | where F: FnOnce(&mut Decoder) -> DuktapeResult 199 | { 200 | unimplemented!() 201 | } 202 | 203 | // Specialized types: 204 | fn read_option(&mut self, f: F) -> DuktapeResult 205 | where F: FnMut(&mut Decoder, bool) -> DuktapeResult 206 | { 207 | unimplemented!() 208 | } 209 | 210 | fn read_seq(&mut self, f: F) -> DuktapeResult 211 | where F: FnOnce(&mut Decoder, usize) -> DuktapeResult 212 | { 213 | unimplemented!() 214 | } 215 | fn read_seq_elt(&mut self, idx: usize, f: F) -> DuktapeResult 216 | where F: FnOnce(&mut Decoder) -> DuktapeResult 217 | { 218 | unimplemented!() 219 | } 220 | 221 | fn read_map(&mut self, f: F) -> DuktapeResult 222 | where F: FnOnce(&mut Decoder, usize) -> DuktapeResult 223 | { 224 | unimplemented!() 225 | } 226 | fn read_map_elt_key(&mut self, idx: usize, f: F) -> DuktapeResult 227 | where F: FnOnce(&mut Decoder) -> DuktapeResult 228 | { 229 | unimplemented!() 230 | } 231 | fn read_map_elt_val(&mut self, idx: usize, f: F) -> DuktapeResult 232 | where F: FnOnce(&mut Decoder) -> DuktapeResult 233 | { 234 | unimplemented!() 235 | } 236 | 237 | // Failure 238 | fn error(&mut self, err: &str) -> DuktapeError 239 | { 240 | unimplemented!() 241 | } 242 | } 243 | 244 | #[test] 245 | fn test_decoder() { 246 | //use std::collections::HashMap; 247 | use std::fmt::Debug; 248 | use encoder::{Encoder, DuktapeEncodable}; 249 | 250 | let mut ctx = Context::new().unwrap(); 251 | 252 | fn assert_decode(ctx: &mut Context, value: &T) 253 | where T: DuktapeEncodable + DuktapeDecodable + PartialEq + Debug 254 | { 255 | let mut encoder = unsafe { Encoder::new(ctx.as_mut_ptr()) }; 256 | value.duktape_encode(&mut encoder).unwrap(); 257 | let mut decoder = unsafe { Decoder::new(ctx.as_mut_ptr()) }; 258 | let decoded: DuktapeResult = Decodable::decode(&mut decoder); 259 | println!("decoding {:?} {:?}", value, decoded); 260 | assert_eq!(value, &decoded.unwrap()); 261 | } 262 | 263 | macro_rules! assert_decode { 264 | ($val:expr) => { assert_decode(&mut ctx, &$val) } 265 | } 266 | 267 | // TODO: Refactor everything below into a combined Encode/Decode test 268 | // suite. 269 | 270 | // Simple types. 271 | assert_decode!(1us); 272 | assert_decode!(1u64); 273 | assert_decode!(1u32); 274 | assert_decode!(1u16); 275 | assert_decode!(1u8); 276 | assert_decode!(-1is); 277 | assert_decode!(-1i64); 278 | assert_decode!(-1i32); 279 | assert_decode!(-1i16); 280 | assert_decode!(-1i8); 281 | assert_decode!(true); 282 | assert_decode!(false); 283 | assert_decode!(1.0f64); 284 | assert_decode!(1.0f32); 285 | assert_decode!("string".to_string()); 286 | // serialize::json::encode handles characters below U+10000 incorrectly. 287 | //assert_decode!('c'); // https://github.com/rust-lang/rust/issues/19719 288 | assert_decode!('𓀀'); 289 | 290 | //// Enums. 291 | //#[derive(RustcEncodable, Decodable, PartialEq, Show)] 292 | //enum ExEnum { Foo, Bar(f64), Baz{x: f64, y: f64} } 293 | //assert_decode!(ExEnum::Foo); 294 | //assert_decode!(ExEnum::Bar(1.0)); 295 | //assert_decode!(ExEnum::Baz{x: 1.0, y: 2.0}); 296 | 297 | //// Structs. 298 | //#[derive(RustcEncodable, Decodable, PartialEq, Show)] 299 | //struct ExStruct { x: f64, y: f64 } 300 | //assert_decode!(ExStruct{x: 1.0, y: 2.0}); 301 | 302 | //// Tuples. 303 | //assert_decode!((1u, 2us)); 304 | 305 | //// Tuple structs. 306 | //#[derive(RustcEncodable, Decodable, PartialEq, Show)] 307 | //struct ExTupleStruct(f64); 308 | //assert_decode!(ExTupleStruct(1.0)); 309 | 310 | //// Options. 311 | //let none_f64: Option = None; 312 | //assert_decode!(none_f64); 313 | //assert_decode!(Some(1.0f64)); 314 | 315 | //// Sequences. 316 | //let seq = vec!(1.0f64); 317 | //assert_decode!(seq); 318 | 319 | // Maps. 320 | //let mut hash: HashMap = HashMap::new(); 321 | //hash.insert("test".to_string(), 3); 322 | //assert_decode!(&hash); 323 | //let mut hash2: HashMap = HashMap::new(); 324 | //hash2.insert(7, 3); 325 | //assert_decode!(hash2); 326 | } 327 | -------------------------------------------------------------------------------- /src/encoder.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Deref; 2 | use std::ptr::null_mut; 3 | use rustc_serialize::Encodable; 4 | use cesu8::to_cesu8; 5 | use ffi::*; 6 | use errors::*; 7 | use context::Context; 8 | 9 | /// Translates Rust values into JavaScript values. 10 | pub struct Encoder { 11 | /// An internal `Context` object, for convenience. We own this, 12 | /// because if we use a reference to somebody else's, the lifetimes 13 | /// make it very hard to work with &Encodable references. 14 | ctx: Context 15 | } 16 | 17 | impl Encoder { 18 | /// Create a new encoder which pushes values to `ctx`. If you create 19 | /// one of these, you're responsible for making sure it gets used 20 | /// safely. 21 | pub unsafe fn new(ctx: *mut duk_context) -> Encoder { 22 | Encoder{ctx: Context::from_borrowed_mut_ptr(ctx)} 23 | } 24 | } 25 | 26 | type EncodeResult = DuktapeResult<()>; 27 | 28 | /// A value which can be encoded and passed to JavaScript code. 29 | pub trait DuktapeEncodable { 30 | /// An object-safe wrapper around Encodable::encode. 31 | fn duktape_encode(&self, s: &mut Encoder) -> EncodeResult; 32 | } 33 | 34 | impl DuktapeEncodable for T { 35 | fn duktape_encode(&self, s: &mut Encoder) -> EncodeResult { 36 | self.encode(s) 37 | } 38 | } 39 | 40 | impl ::rustc_serialize::Encoder for Encoder { 41 | type Error = DuktapeError; 42 | 43 | fn emit_nil(&mut self) -> EncodeResult { 44 | unsafe { duk_push_null(self.ctx.as_mut_ptr()); } 45 | Ok(()) 46 | } 47 | 48 | // Integral types map to floats. 49 | fn emit_usize(&mut self, v: usize) -> EncodeResult { self.emit_f64(v as f64)} 50 | fn emit_u64(&mut self, v: u64) -> EncodeResult { self.emit_f64(v as f64) } 51 | fn emit_u32(&mut self, v: u32) -> EncodeResult { self.emit_f64(v as f64) } 52 | fn emit_u16(&mut self, v: u16) -> EncodeResult { self.emit_f64(v as f64) } 53 | fn emit_u8(&mut self, v: u8) -> EncodeResult { self.emit_f64(v as f64) } 54 | fn emit_isize(&mut self, v: isize) -> EncodeResult { self.emit_f64(v as f64)} 55 | fn emit_i64(&mut self, v: i64) -> EncodeResult { self.emit_f64(v as f64) } 56 | fn emit_i32(&mut self, v: i32) -> EncodeResult { self.emit_f64(v as f64) } 57 | fn emit_i16(&mut self, v: i16) -> EncodeResult { self.emit_f64(v as f64) } 58 | fn emit_i8(&mut self, v: i8) -> EncodeResult { self.emit_f64(v as f64) } 59 | 60 | fn emit_bool(&mut self, v: bool) -> EncodeResult { 61 | unsafe { duk_push_boolean(self.ctx.as_mut_ptr(), if v { 1 } else { 0 }) } 62 | Ok(()) 63 | } 64 | 65 | fn emit_f64(&mut self, v: f64) -> EncodeResult { 66 | unsafe {duk_push_number(self.ctx.as_mut_ptr(), v) }; Ok(()) 67 | } 68 | fn emit_f32(&mut self, v: f32) -> EncodeResult { self.emit_f64(v as f64) } 69 | 70 | fn emit_char(&mut self, v: char) -> EncodeResult { 71 | let s = v.to_string(); 72 | self.emit_str(s.as_slice()) 73 | } 74 | fn emit_str(&mut self, v: &str) -> EncodeResult { 75 | let encoded = to_cesu8(v); 76 | let buf = encoded.deref(); 77 | unsafe { 78 | duk_push_lstring(self.ctx.as_mut_ptr(), buf.as_ptr() as *const i8, 79 | buf.len() as duk_size_t); 80 | } 81 | Ok(()) 82 | } 83 | 84 | fn emit_enum(&mut self, _name: &str, f: F) -> DuktapeResult<()> 85 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 86 | { 87 | f(self) 88 | } 89 | 90 | fn emit_enum_variant(&mut self, v_name: &str, _v_id: usize, 91 | len: usize, f: F) -> DuktapeResult<()> 92 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 93 | { 94 | if len == 0 { 95 | self.emit_str(v_name.as_slice()) 96 | } else { 97 | unsafe { 98 | duk_push_object(self.ctx.as_mut_ptr()); 99 | self.emit_str("variant").unwrap(); 100 | self.emit_str(v_name.as_slice()).unwrap(); 101 | duk_put_prop(self.ctx.as_mut_ptr(), -3); 102 | 103 | self.emit_str("fields").unwrap(); 104 | duk_push_array(self.ctx.as_mut_ptr()); 105 | f(self).unwrap(); 106 | duk_put_prop(self.ctx.as_mut_ptr(), -3); 107 | } 108 | Ok(()) 109 | } 110 | } 111 | 112 | fn emit_enum_variant_arg(&mut self, a_idx: usize, f: F) -> 113 | DuktapeResult<()> 114 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 115 | { 116 | unsafe { 117 | f(self).unwrap(); 118 | duk_put_prop_index(self.ctx.as_mut_ptr(), -2, a_idx as u32); 119 | } 120 | Ok(()) 121 | } 122 | 123 | #[allow(unused_variables)] 124 | fn emit_enum_struct_variant(&mut self, v_name: &str, v_id: usize, 125 | len: usize, f: F) -> DuktapeResult<()> 126 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 127 | { 128 | // TODO: Not called during normal serialization. 129 | unimplemented!() 130 | } 131 | 132 | #[allow(unused_variables)] 133 | fn emit_enum_struct_variant_field(&mut self, f_name: &str, f_idx: usize, f: F) -> DuktapeResult<()> 134 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 135 | { 136 | // TODO: Not called during normal serialization. 137 | unimplemented!() 138 | } 139 | 140 | fn emit_struct(&mut self, _name: &str, _len: usize, f: F) -> DuktapeResult<()> 141 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 142 | { 143 | unsafe { duk_push_object(self.ctx.as_mut_ptr()); } 144 | f(self) 145 | } 146 | 147 | fn emit_struct_field(&mut self, f_name: &str, _f_idx: usize, f: F) -> DuktapeResult<()> 148 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 149 | { 150 | self.emit_str(f_name).unwrap(); 151 | f(self).unwrap(); 152 | unsafe { duk_put_prop(self.ctx.as_mut_ptr(), -3); } 153 | Ok(()) 154 | } 155 | 156 | fn emit_tuple(&mut self, len: usize, f: F) -> DuktapeResult<()> 157 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 158 | { 159 | self.emit_seq(len, f) 160 | } 161 | 162 | fn emit_tuple_arg(&mut self, idx: usize, f: F) -> DuktapeResult<()> 163 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 164 | { 165 | self.emit_seq_elt(idx, f) 166 | } 167 | 168 | #[allow(unused_variables)] 169 | fn emit_tuple_struct(&mut self, name: &str, len: usize, f: F) -> DuktapeResult<()> 170 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 171 | { 172 | // TODO: Not currently used. 173 | unimplemented!() 174 | } 175 | 176 | #[allow(unused_variables)] 177 | fn emit_tuple_struct_arg(&mut self, f_idx: usize, f: F) -> DuktapeResult<()> 178 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 179 | { 180 | // TODO: Not currently used. 181 | unimplemented!() 182 | } 183 | 184 | fn emit_option(&mut self, f: F) -> DuktapeResult<()> 185 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 186 | { 187 | f(self) 188 | } 189 | 190 | fn emit_option_none(&mut self) -> EncodeResult 191 | { 192 | self.emit_nil() 193 | } 194 | 195 | fn emit_option_some(&mut self, f: F) -> DuktapeResult<()> 196 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 197 | { 198 | f(self) 199 | } 200 | 201 | fn emit_seq(&mut self, _len: usize, f: F) -> DuktapeResult<()> 202 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 203 | { 204 | unsafe { duk_push_array(self.ctx.as_mut_ptr()); } 205 | f(self) 206 | } 207 | 208 | fn emit_seq_elt(&mut self, idx: usize, f: F) -> DuktapeResult<()> 209 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 210 | { 211 | f(self).unwrap(); 212 | unsafe { duk_put_prop_index(self.ctx.as_mut_ptr(), -2, idx as u32); } 213 | Ok(()) 214 | } 215 | 216 | fn emit_map(&mut self, _len: usize, f: F) -> DuktapeResult<()> 217 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 218 | { 219 | unsafe { duk_push_object(self.ctx.as_mut_ptr()); } 220 | f(self) 221 | } 222 | 223 | fn emit_map_elt_key(&mut self, _idx: usize, f: F) -> DuktapeResult<()> 224 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 225 | { 226 | f(self).unwrap(); 227 | unsafe { duk_safe_to_lstring(self.ctx.as_mut_ptr(), -1, null_mut()); } 228 | Ok(()) 229 | } 230 | 231 | fn emit_map_elt_val(&mut self, _idx: usize, f: F) -> DuktapeResult<()> 232 | where F: FnOnce(&mut Encoder) -> DuktapeResult<()> 233 | { 234 | f(self).unwrap(); 235 | unsafe { duk_put_prop(self.ctx.as_mut_ptr(), -3); } 236 | Ok(()) 237 | } 238 | } 239 | 240 | #[test] 241 | fn test_encoder() { 242 | use std::collections::HashMap; 243 | use types::Value; 244 | 245 | let mut ctx = Context::new().unwrap(); 246 | ctx.eval(r" 247 | function assert_json(expected, value) { 248 | var value_json = JSON.stringify(value); 249 | //print('checking', expected, value_json); 250 | return JSON.stringify(JSON.parse(expected)) == value_json || value_json; 251 | }").unwrap(); 252 | 253 | fn assert_json( 254 | ctx: &mut Context, expected: &str, value: &T) 255 | { 256 | match ctx.call("assert_json", &[&expected, value]) { 257 | Ok(Value::Bool(true)) => {}, 258 | Ok(Value::String(ref got)) => 259 | panic!("expected {:?}, got {:?}", expected, got), 260 | ref result => panic!("unexpected value: {:?}", result) 261 | } 262 | } 263 | 264 | macro_rules! assert_encode { 265 | ($val:expr) => { 266 | { 267 | let v = $val; 268 | let expected = ::rustc_serialize::json::encode(&v).unwrap(); 269 | assert_json(&mut ctx, expected.as_slice(), &v); 270 | } 271 | } 272 | } 273 | 274 | // Simple types. 275 | assert_encode!(1us); 276 | assert_encode!(1u64); 277 | assert_encode!(1u32); 278 | assert_encode!(1u16); 279 | assert_encode!(1u8); 280 | assert_encode!(-1is); 281 | assert_encode!(-1i64); 282 | assert_encode!(-1i32); 283 | assert_encode!(-1i16); 284 | assert_encode!(-1i8); 285 | assert_encode!(true); 286 | assert_encode!(false); 287 | assert_encode!(1.0f64); 288 | assert_encode!(1.0f32); 289 | assert_encode!("string"); 290 | // serialize::json::encode handles characters below U+10000 incorrectly. 291 | //assert_encode!('c'); // https://github.com/rust-lang/rust/issues/19719 292 | assert_encode!('𓀀'); 293 | 294 | // Enums. 295 | #[derive(RustcEncodable)] 296 | enum ExEnum { Foo, Bar(f64), Baz{x: f64, y: f64} } 297 | assert_encode!(&ExEnum::Foo); 298 | assert_encode!(&ExEnum::Bar(1.0)); 299 | assert_encode!(&ExEnum::Baz{x: 1.0, y: 2.0}); 300 | 301 | // Structs. 302 | #[derive(RustcEncodable)] 303 | struct ExStruct { x: f64, y: f64 } 304 | assert_encode!(&ExStruct{x: 1.0, y: 2.0}); 305 | 306 | // Tuples. 307 | assert_encode!(&(1us, 2us)); 308 | 309 | // Tuple structs. 310 | #[derive(RustcEncodable)] 311 | struct ExTupleStruct(f64); 312 | assert_encode!(&ExTupleStruct(1.0)); 313 | 314 | // Options. 315 | let none_f64: Option = None; 316 | assert_encode!(&none_f64); 317 | assert_encode!(&Some(1.0f64)); 318 | 319 | // Sequences. 320 | let seq = [1.0f64]; 321 | assert_encode!(seq.as_slice()); 322 | 323 | // Maps. 324 | let mut hash: HashMap = HashMap::new(); 325 | hash.insert("test".to_string(), 3); 326 | assert_encode!(&hash); 327 | let mut hash2: HashMap = HashMap::new(); 328 | hash2.insert(7, 3); 329 | assert_encode!(&hash2); 330 | } 331 | -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fmt; 3 | use std::result::Result; 4 | use ffi::*; 5 | 6 | /// These are the standard error codes, which make it easy to return 7 | /// pre-defined errors from duktape functions implemented in Rust. 8 | #[allow(missing_docs)] 9 | #[derive(Copy, Show, PartialEq, Eq)] 10 | #[repr(i32)] 11 | pub enum ErrorCode { 12 | Unimplemented = DUK_ERR_UNIMPLEMENTED_ERROR, 13 | Unsupported = DUK_ERR_UNSUPPORTED_ERROR, 14 | Internal = DUK_ERR_INTERNAL_ERROR, 15 | Alloc = DUK_ERR_ALLOC_ERROR, 16 | Assertion = DUK_ERR_ASSERTION_ERROR, 17 | Api = DUK_ERR_API_ERROR, 18 | Uncaught = DUK_ERR_UNCAUGHT_ERROR, 19 | Error = DUK_ERR_ERROR, 20 | Eval = DUK_ERR_EVAL_ERROR, 21 | Range = DUK_ERR_RANGE_ERROR, 22 | Reference = DUK_ERR_REFERENCE_ERROR, 23 | Syntax = DUK_ERR_SYNTAX_ERROR, 24 | Type = DUK_ERR_TYPE_ERROR, 25 | Uri = DUK_ERR_URI_ERROR 26 | } 27 | 28 | /// A duktape API error. The is used as both the return type of duktape of 29 | /// functions, and also the return type of Rust functions called from 30 | /// duktape. 31 | #[derive(Show, PartialEq, Eq)] 32 | pub struct DuktapeError { 33 | /// The error code, if a specific one is available, or 34 | /// `ErrorCode::Error` if we have nothing better. 35 | code: ErrorCode, 36 | 37 | /// Errors have some sort of internal structure, but the duktape 38 | /// documentation always just converts them to strings. So that's all 39 | /// we'll store for now. 40 | message: Option 41 | } 42 | 43 | impl DuktapeError { 44 | /// Create an error specifying just the error code. 45 | pub fn from_code(code: ErrorCode) -> DuktapeError { 46 | DuktapeError{code: code, message: None} 47 | } 48 | 49 | /// Create an error, specifying an error message. 50 | pub fn from_str(message: &str) -> DuktapeError { 51 | DuktapeError{code: ErrorCode::Error, message: Some(message.to_string())} 52 | } 53 | } 54 | 55 | /// Re-exported within the crate, but not outside. 56 | pub fn err_code(err: &DuktapeError) -> ErrorCode { err.code } 57 | pub fn err_message(err: &DuktapeError) -> &Option { &err.message } 58 | 59 | impl Error for DuktapeError { 60 | fn description(&self) -> &str { "script error:" } 61 | 62 | fn cause(&self) -> Option<&Error> { None } 63 | } 64 | 65 | impl fmt::Display for DuktapeError { 66 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 67 | match (&self.message, self.code) { 68 | (&Some(ref msg), _) => write!(f, "{}", msg), 69 | (&None, ErrorCode::Error) => write!(f, "an unknown error occurred"), 70 | (&None, code) => 71 | write!(f, "type: {:?} code: {:?}", code, code as duk_int_t) 72 | } 73 | } 74 | } 75 | 76 | /// Either a return value of type `T`, or a duktape error. 77 | pub type DuktapeResult = Result; 78 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Rust interface to [Duktape][] JavaScript interpreter. This is still 2 | //! a work in progress! 3 | //! 4 | //! [Source code](https://github.com/emk/duktape-rs). 5 | //! 6 | //! ``` 7 | //! use duktape::{Context,Value,DuktapeResult}; 8 | //! 9 | //! fn add_example() -> DuktapeResult> { 10 | //! // Create a new JavaScript interpreter. This will be automatically 11 | //! // cleaned up when `ctx` goes out of scope. 12 | //! let mut ctx = try!(Context::new()); 13 | //! 14 | //! // Load some code from a string. 15 | //! try!(ctx.eval("function add(x, y) { return x+y; }")); 16 | //! 17 | //! // Call the function we defined. 18 | //! ctx.call("add", &[&2.0f64, &1.0f64]) 19 | //! } 20 | //! 21 | //! assert_eq!(Ok(Value::Number(3.0)), add_example()); 22 | //! ``` 23 | //! 24 | //! We also have preliminary support for defining JavaScript functions 25 | //! using Rust, but it's still too ugly to show off. 26 | //! 27 | //! [Duktape]: http://duktape.org/ 28 | 29 | #![feature(std_misc)] 30 | #![feature(collections)] 31 | #![feature(core)] 32 | #![feature(libc)] 33 | 34 | #![warn(missing_docs)] 35 | 36 | #[macro_use] extern crate log; 37 | extern crate "rustc-serialize" as rustc_serialize; 38 | extern crate libc; 39 | extern crate cesu8; 40 | #[macro_use] extern crate abort_on_panic; 41 | extern crate "duktape_sys" as ffi; 42 | 43 | pub use errors::{ErrorCode, DuktapeError, DuktapeResult}; 44 | pub use types::Value; 45 | pub use context::{Context, Callback}; 46 | 47 | mod errors; 48 | mod types; 49 | mod encoder; 50 | mod decoder; 51 | mod context; 52 | -------------------------------------------------------------------------------- /src/types.rs: -------------------------------------------------------------------------------- 1 | use libc::types::os::arch::c95::c_double; 2 | use std::string::CowString; 3 | 4 | /// A value that can be passed to and from JavaScript. This does not 5 | /// include all the types that can be stored internally! 6 | #[derive(Show, PartialEq)] 7 | pub enum Value<'a> { 8 | /// An undefined JavaScript value. 9 | Undefined, 10 | /// A JavaScript `null` value. 11 | Null, 12 | /// A JavaScript boolean value. 13 | Bool(bool), 14 | /// A JavaScript numeric value. 15 | Number(c_double), 16 | /// A JavaScript string value. 17 | String(CowString<'a>) 18 | } 19 | --------------------------------------------------------------------------------